feat: make ollama host configurable in goose2 (#8912)

This commit is contained in:
Kalvin C
2026-04-29 11:16:10 -07:00
committed by GitHub
parent 5fcdf31ad5
commit 000d7c58de
6 changed files with 120 additions and 6 deletions
+53
View File
@@ -122,6 +122,10 @@ fn apply_ollama_options(payload: &mut Value, model_config: &ModelConfig) {
}
}
fn ollama_host_configured(config: &crate::config::Config) -> bool {
config.get_param::<String>("OLLAMA_HOST").is_ok()
}
impl OllamaProvider {
pub async fn from_env(model: ModelConfig) -> Result<Self> {
let config = crate::config::Config::global();
@@ -262,6 +266,10 @@ impl ProviderDef for OllamaProvider {
true
}
fn inventory_configured() -> bool {
ollama_host_configured(crate::config::Config::global())
}
fn inventory_identity() -> Result<InventoryIdentityInput> {
let config = crate::config::Config::global();
Ok(
@@ -465,6 +473,51 @@ fn stream_ollama(response: Response, mut log: RequestLog) -> Result<MessageStrea
mod tests {
use super::*;
#[test]
fn test_ollama_host_default_does_not_mark_inventory_configured() {
let _guard = env_lock::lock_env([("OLLAMA_HOST", None::<&str>)]);
let config_file = tempfile::NamedTempFile::new().unwrap();
let secrets_file = tempfile::NamedTempFile::new().unwrap();
let config = crate::config::Config::new_with_config_paths(
vec![config_file.path().to_path_buf()],
secrets_file.path(),
)
.unwrap();
assert!(!ollama_host_configured(&config));
}
#[test]
fn test_ollama_host_env_marks_inventory_configured() {
let _guard = env_lock::lock_env([("OLLAMA_HOST", Some("http://127.0.0.1:11435"))]);
let config_file = tempfile::NamedTempFile::new().unwrap();
let secrets_file = tempfile::NamedTempFile::new().unwrap();
let config = crate::config::Config::new_with_config_paths(
vec![config_file.path().to_path_buf()],
secrets_file.path(),
)
.unwrap();
assert!(ollama_host_configured(&config));
}
#[test]
fn test_ollama_host_config_marks_inventory_configured() {
let _guard = env_lock::lock_env([("OLLAMA_HOST", None::<&str>)]);
let config_file = tempfile::NamedTempFile::new().unwrap();
let secrets_file = tempfile::NamedTempFile::new().unwrap();
let config = crate::config::Config::new_with_config_paths(
vec![config_file.path().to_path_buf()],
secrets_file.path(),
)
.unwrap();
config
.set_param("OLLAMA_HOST", "http://127.0.0.1:11435")
.unwrap();
assert!(ollama_host_configured(&config));
}
#[test]
fn test_apply_ollama_options_uses_input_limit() {
let _guard = env_lock::lock_env([("GOOSE_INPUT_LIMIT", Some("8192"))]);
@@ -1,5 +1,26 @@
import { describe, expect, it } from "vitest";
import { resolveAgentProviderCatalogId } from "./providerCatalog";
import {
getCatalogEntry,
resolveAgentProviderCatalogId,
} from "./providerCatalog";
describe("provider catalog", () => {
it("exposes Ollama host configuration", () => {
const ollama = getCatalogEntry("ollama");
expect(ollama?.setupMethod).toBe("config_fields");
expect(ollama?.fields).toEqual([
{
key: "OLLAMA_HOST",
label: "Host",
secret: false,
required: true,
placeholder: "localhost or http://localhost:11434",
defaultValue: "http://localhost:11434",
},
]);
});
});
describe("resolveAgentProviderCatalogId", () => {
it("matches direct catalog ids", () => {
@@ -6,7 +6,6 @@ import {
} from "./providerCatalogAliases";
export const PROVIDER_CATALOG: ProviderCatalogEntry[] = [
// ── Agent providers ──────────────────────────────────────────────
{
id: "goose",
displayName: "Goose",
@@ -92,7 +91,6 @@ export const PROVIDER_CATALOG: ProviderCatalogEntry[] = [
showOnlyWhenInstalled: true,
},
// ── Model providers (power Goose) ────────────────────────────────
{
id: "anthropic",
displayName: "Anthropic",
@@ -164,8 +162,18 @@ export const PROVIDER_CATALOG: ProviderCatalogEntry[] = [
id: "ollama",
displayName: "Ollama",
category: "model",
description: "Run models locally",
setupMethod: "local",
description: "Run local or self-hosted models",
setupMethod: "config_fields",
fields: [
{
key: "OLLAMA_HOST",
label: "Host",
secret: false,
required: true,
placeholder: "localhost or http://localhost:11434",
defaultValue: "http://localhost:11434",
},
],
docsUrl: "https://ollama.com",
tier: "promoted",
},
@@ -73,6 +73,37 @@ describe("ModelProviderRow", () => {
]);
});
it("pre-fills and saves provider field defaults", async () => {
const user = userEvent.setup();
render(
<ModelProviderRow
provider={modelProvider("ollama", "not_configured")}
onGetConfig={onGetConfig}
onSaveFields={onSaveFields}
onRemoveConfig={onRemoveConfig}
onCompleteNativeSetup={onCompleteNativeSetup}
/>,
);
await user.click(screen.getByRole("button", { name: /ollama/i }));
expect(
await screen.findByDisplayValue("http://localhost:11434"),
).toBeVisible();
await user.click(screen.getByRole("button", { name: /^save$/i }));
await waitFor(() => expect(onSaveFields).toHaveBeenCalledTimes(1));
expect(onSaveFields).toHaveBeenCalledWith([
{
key: "OLLAMA_HOST",
value: "http://localhost:11434",
isSecret: false,
},
]);
});
it("shows the connected row while model inventory is still loading", async () => {
const user = userEvent.setup();
@@ -49,7 +49,7 @@ export function createDraftValues(
if (field.secret) {
return [field.key, ""];
}
return [field.key, currentValue?.value ?? ""];
return [field.key, currentValue?.value ?? field.defaultValue ?? ""];
}),
);
}
+1
View File
@@ -19,6 +19,7 @@ export interface ProviderField {
secret: boolean;
required: boolean;
placeholder?: string;
defaultValue?: string;
}
export interface ProviderFieldValue {