mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
fix(cli): hermes model treats local Ollama as keyless
The generic API-key flow's first step is the key prompt, so selecting Ollama (local) dead-ended at 'No Ollama (local) API key configured.' — a local server's credential is reachability, not a key. - Skip the API-key prompt for ollama; the runtime substitutes the local-only placeholder bearer. A key for a reverse-proxied server still works via model.api_key. - List the server's installed models live from /api/tags (like the LM Studio branch), with a start-the-server / pull-a-model hint when none are found. - Honor a typed base URL override for providers without a base-url env var by carrying it into model.base_url, which the flow already writes. The provider-catalog contract test exempts ollama from the every- api_key-provider-exposes-an-env-var invariant for the same reason the custom pseudo-provider is exempt: it is configured by server detection, not a pasted credential.
This commit is contained in:
parent
83f88909ef
commit
cd16d9aec3
2 changed files with 32 additions and 10 deletions
|
|
@ -2563,11 +2563,17 @@ def _model_flow_api_key_provider(config, provider_id, current_model=""):
|
|||
if existing_key:
|
||||
break
|
||||
|
||||
existing_key, abort = _prompt_api_key(
|
||||
pconfig, existing_key, provider_id=provider_id
|
||||
)
|
||||
if abort:
|
||||
return
|
||||
if provider_id == "ollama":
|
||||
# Local Ollama servers are unauthenticated — there is no key to
|
||||
# prompt for. The runtime substitutes a placeholder bearer; a key
|
||||
# for a reverse-proxied server can be set via model.api_key.
|
||||
pass
|
||||
else:
|
||||
existing_key, abort = _prompt_api_key(
|
||||
pconfig, existing_key, provider_id=provider_id
|
||||
)
|
||||
if abort:
|
||||
return
|
||||
|
||||
# Gemini free-tier gate: free-tier daily quotas (<= 250 RPD for Flash)
|
||||
# are exhausted in a handful of agent turns, so refuse to wire up the
|
||||
|
|
@ -2659,14 +2665,18 @@ def _model_flow_api_key_provider(config, provider_id, current_model=""):
|
|||
except (KeyboardInterrupt, EOFError):
|
||||
print()
|
||||
override = ""
|
||||
if override and base_url_env:
|
||||
if override:
|
||||
if not override.startswith(("http://", "https://")):
|
||||
print(
|
||||
" Invalid URL — must start with http:// or https://. Keeping current value."
|
||||
)
|
||||
else:
|
||||
elif base_url_env:
|
||||
save_env_value(base_url_env, override)
|
||||
effective_base = override
|
||||
else:
|
||||
# No env var for this provider (e.g. ollama): the override
|
||||
# still takes effect via model.base_url, written below.
|
||||
effective_base = override
|
||||
|
||||
# Model selection — resolution order:
|
||||
# 1. models.dev registry (cached, filtered for agentic/tool-capable models)
|
||||
|
|
@ -2690,6 +2700,15 @@ def _model_flow_api_key_provider(config, provider_id, current_model=""):
|
|||
model_list = []
|
||||
if model_list:
|
||||
print(f" Found {len(model_list)} model(s) from LM Studio")
|
||||
elif provider_id == "ollama":
|
||||
from hermes_cli.models import fetch_ollama_local_models
|
||||
|
||||
model_list = fetch_ollama_local_models(base_url=effective_base, timeout=3.0)
|
||||
if model_list:
|
||||
print(f" Found {len(model_list)} installed model(s) on the Ollama server")
|
||||
else:
|
||||
print(f" No models found — is Ollama running at {effective_base}?")
|
||||
print(" Pull one first (e.g. `ollama pull qwen3:8b`) or enter a name below.")
|
||||
elif provider_id == "ollama-cloud":
|
||||
from hermes_cli.models import fetch_ollama_cloud_models
|
||||
|
||||
|
|
|
|||
|
|
@ -95,11 +95,14 @@ def test_api_key_providers_expose_a_credential_env_var():
|
|||
surface at least one env var to write the key into (otherwise the GUI can't
|
||||
configure it).
|
||||
|
||||
Exemptions: ``aws_sdk`` (bedrock — uses AWS_REGION/AWS_PROFILE) and the
|
||||
Exemptions: ``aws_sdk`` (bedrock — uses AWS_REGION/AWS_PROFILE); the
|
||||
``custom`` bring-your-own-endpoint pseudo-provider, which is configured
|
||||
inline via the local-endpoint flow rather than a fixed env var.
|
||||
inline via the local-endpoint flow rather than a fixed env var; and
|
||||
``ollama``, whose local server is unauthenticated by design — the GUI
|
||||
configures it via server detection, and a key for a reverse-proxied
|
||||
server goes in model.api_key.
|
||||
"""
|
||||
exempt = {"custom"}
|
||||
exempt = {"custom", "ollama"}
|
||||
for d in provider_catalog():
|
||||
if d.auth_type == "api_key" and d.slug not in exempt:
|
||||
assert d.api_key_env_vars, f"{d.slug} is api_key but exposes no env var"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue