feat: allow setting ollama host (#874)

This commit is contained in:
Yingjie He
2025-01-29 11:34:41 -08:00
committed by GitHub
parent c59bf888e8
commit 129e4a9e44
12 changed files with 40 additions and 12 deletions

View File

@@ -266,7 +266,8 @@ pub async fn configure_provider_dialog() -> Result<bool, Box<dyn Error>> {
let spin = spinner();
spin.start("Checking your configuration...");
let model_config = goose::model::ModelConfig::new(model.clone());
// Use max tokens to speed up the provider test.
let model_config = goose::model::ModelConfig::new(model.clone()).with_max_tokens(Some(10));
let provider = create(provider_name, model_config)?;
let message = Message::user().with_text(

View File

@@ -13,9 +13,11 @@ struct SecretResponse {
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct SecretRequest {
key: String,
value: String,
is_secret: bool,
}
async fn store_secret(
@@ -33,7 +35,13 @@ async fn store_secret(
return Err(StatusCode::UNAUTHORIZED);
}
match Config::global().set_secret(&request.key, Value::String(request.value)) {
let config = Config::global();
let result = if request.is_secret {
config.set_secret(&request.key, Value::String(request.value))
} else {
config.set(&request.key, Value::String(request.value))
};
match result {
Ok(_) => Ok(Json(SecretResponse { error: false })),
Err(_) => Ok(Json(SecretResponse { error: true })),
}

View File

@@ -71,7 +71,7 @@ impl Provider for OllamaProvider {
OLLAMA_DOC_URL,
vec![ConfigKey::new(
"OLLAMA_HOST",
false,
true,
false,
Some(OLLAMA_HOST),
)],

View File

@@ -159,6 +159,9 @@ goose configure
◇ Which model provider should we use?
│ Ollama
◇ Provider Ollama requires OLLAMA_HOST, please enter a value
│ http://localhost:11434
◇ Enter a model from that provider:
│ qwen2.5

View File

@@ -4,6 +4,7 @@ import { Lock } from 'lucide-react';
import { Input } from '../ui/input';
import { Button } from '../ui/button';
import { required_keys } from './models/hardcoded_stuff';
import { isSecretKey } from './api_keys/utils';
// import UnionIcon from "../images/Union@2x.svg";
interface ProviderSetupModalProps {
@@ -30,6 +31,7 @@ export function ProviderSetupModal({
e.preventDefault();
onSubmit(apiKey);
};
const inputType = isSecretKey(keyName) ? 'password' : 'text';
return (
<div className="fixed inset-0 bg-black/20 dark:bg-white/20 backdrop-blur-sm transition-colors animate-[fadein_200ms_ease-in_forwards]">
@@ -49,7 +51,7 @@ export function ProviderSetupModal({
<div className="mt-[24px]">
<div>
<Input
type="password"
type={inputType}
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
placeholder={keyName}
@@ -58,7 +60,7 @@ export function ProviderSetupModal({
/>
<div className="flex mt-4 text-gray-600 dark:text-gray-300">
<Lock className="w-6 h-6" />
<span className="text-sm font-light ml-4 mt-[2px]">{`Your API key will be stored securely in the keychain and used only for making requests to ${provider}`}</span>
<span className="text-sm font-light ml-4 mt-[2px]">{`Your API key or host will be stored securely in the keychain and used only for making requests to ${provider}`}</span>
</div>
</div>
</div>

View File

@@ -2,6 +2,11 @@ import { Provider, ProviderResponse } from './types';
import { getApiUrl, getSecretKey } from '../../../config';
import { special_provider_cases } from '../providers/utils';
export function isSecretKey(keyName: string): boolean {
// Ollama and Databricks use host name right now and it should not be stored as secret.
return keyName != 'DATABRICKS_HOST' && keyName != 'OLLAMA_HOST';
}
export async function getActiveProviders(): Promise<string[]> {
try {
// Fetch the secrets settings

View File

@@ -52,6 +52,7 @@ export function ConfigureBuiltInExtensionModal({
body: JSON.stringify({
key: envKey,
value: value.trim(),
isSecret: true,
}),
});

View File

@@ -54,6 +54,7 @@ export function ConfigureExtensionModal({
body: JSON.stringify({
key: envKey,
value: value.trim(),
isSecret: true,
}),
});

View File

@@ -68,6 +68,7 @@ export function ManualExtensionModal({ isOpen, onClose, onSubmit }: ManualExtens
body: JSON.stringify({
key: envVar.key,
value: envVar.value.trim(),
isSecret: true,
}),
});

View File

@@ -72,7 +72,7 @@ export const required_keys = {
Anthropic: ['ANTHROPIC_API_KEY'],
Databricks: ['DATABRICKS_HOST'],
Groq: ['GROQ_API_KEY'],
Ollama: [],
Ollama: ['OLLAMA_HOST'],
Google: ['GOOGLE_API_KEY'],
OpenRouter: ['OPENROUTER_API_KEY'],
};

View File

@@ -5,7 +5,7 @@ import { supported_providers, provider_aliases, required_keys } from '../models/
import { ProviderSetupModal } from '../ProviderSetupModal';
import { getApiUrl, getSecretKey } from '../../../config';
import { toast } from 'react-toastify';
import { getActiveProviders } from '../api_keys/utils';
import { getActiveProviders, isSecretKey } from '../api_keys/utils';
import { useModel } from '../models/ModelContext';
import { Button } from '../../ui/button';
@@ -107,6 +107,7 @@ export function ConfigureProvidersGrid() {
}
// Store new key
const isSecret = isSecretKey(keyName);
const storeResponse = await fetch(getApiUrl('/secrets/store'), {
method: 'POST',
headers: {
@@ -116,6 +117,7 @@ export function ConfigureProvidersGrid() {
body: JSON.stringify({
key: keyName,
value: apiKey.trim(),
isSecret,
}),
});
@@ -125,10 +127,11 @@ export function ConfigureProvidersGrid() {
throw new Error('Failed to store new key');
}
const toastInfo = isSecret ? 'API key' : 'host';
toast.success(
isUpdate
? `Successfully updated API key for ${provider}`
: `Successfully added API key for ${provider}`
? `Successfully updated ${toastInfo} for ${provider}`
: `Successfully added ${toastInfo} for ${provider}`
);
const updatedKeys = await getActiveProviders();

View File

@@ -14,7 +14,7 @@ import { getDefaultModel } from '../settings/models/hardcoded_stuff';
import { initializeSystem } from '../../utils/providerUtils';
import { getApiUrl, getSecretKey } from '../../config';
import { toast } from 'react-toastify';
import { getActiveProviders } from '../settings/api_keys/utils';
import { getActiveProviders, isSecretKey } from '../settings/api_keys/utils';
import { useNavigate } from 'react-router-dom';
import { BaseProviderGrid, getProviderDescription } from '../settings/providers/BaseProviderGrid';
@@ -99,6 +99,7 @@ export function ProviderGrid({ onSubmit }: ProviderGridProps) {
}
}
const isSecret = isSecretKey(keyName);
const storeResponse = await fetch(getApiUrl('/secrets/store'), {
method: 'POST',
headers: {
@@ -108,6 +109,7 @@ export function ProviderGrid({ onSubmit }: ProviderGridProps) {
body: JSON.stringify({
key: keyName,
value: apiKey.trim(),
isSecret,
}),
});
@@ -118,10 +120,11 @@ export function ProviderGrid({ onSubmit }: ProviderGridProps) {
}
const isUpdate = selectedId && providers.find((p) => p.id === selectedId)?.isConfigured;
const toastInfo = isSecret ? 'API key' : 'host';
toast.success(
isUpdate
? `Successfully updated API key for ${provider}`
: `Successfully added API key for ${provider}`
? `Successfully updated ${toastInfo} for ${provider}`
: `Successfully added ${toastInfo} for ${provider}`
);
const updatedKeys = await getActiveProviders();