Skip to content

Provider auto-detection regression: bare 'mistral-large' routes to openrouter instead of devagentic-local despite env wired #70

@PowerCreek

Description

@PowerCreek

Repro (post v0.15.0 reinstall on devbox)

# Worker env (verified via /proc/PID/environ):
HERMES_HOME=~/.hermes/profiles/polynomial-explorer
DEVAGENTIC_BASE_URL=http://devbox:6071/v1
DEVAGENTIC_API_KEY=<set>

# Symptom:
hermes  # picks provider=openrouter automatically
# Logs: "model switched ... via auto" → openrouter
/model devagentic-local/mistral-large
# Response: "model not found, similar: mistralai/mistral-large"

Earlier session 20260524_023743_715053 had provider=devagentic-local correctly with the same env — regression introduced by the reinstall.

Root cause (read from hermes_cli/models.py)

detect_provider_for_model(model_name, current_provider) walks:

  1. Step 0 — bare provider name (/model nous → switch to nous). N/A for mistral-large.
  2. Step 1 — direct match in static _PROVIDER_MODELS[pid] catalog. devagentic-local is NOT in _PROVIDER_MODELS because its model catalog is fetched dynamically from /v1/models via DevagenticLocalProfile.fetch_models() — it lives in fallback_models = ("devagentic/coder", "devagentic/researcher", "devagentic/orchestrator") plus whatever the live fetch returns. Bare mistral-large is not in the fallback list.
  3. Step 2 — OpenRouter catalog. mistralai/mistral-large IS there → returns ("openrouter", "mistralai/mistral-large").

So when current_provider != "devagentic-local", the auto-detect cannot see mistral-large belongs to a devagentic-local-fetched catalog and routes to OpenRouter.

Why session 20260524_023743_715053 worked

That session was already on current_provider="devagentic-local" when the bare model lookup ran. The check at line ~1842 (if _model_in_provider_catalog(name_lower, current_keys): return None) short-circuits — model belongs to current provider's catalog, don't switch. After the reinstall, current_provider reset to the default (openrouter) and the short-circuit no longer fires.

Why /model devagentic-local/mistral-large ALSO fails

The explicit provider/model syntax routes through parse_model_input (line 1663) → validates the model name against the catalog hermes has for devagentic-local. Hermes' cached catalog for devagentic-local probably only has fallback_models until fetch_models() repopulates it on next session boot. If fetch_models() hits the /v1/models 401 issue (fixed in TechDevGroup/devagentic#216 / PR NousResearch#216) and silently returns None, the cache stays at fallback_models and mistral-large is "not found".

So this regression compounds with NousResearch#216 (/v1/models auth fix) — even after NousResearch#216 ships, hermes still needs to actually CALL fetch_models() at session boot AND cache its result for detect_provider_for_model to see the live catalog.

Suggested fixes (pick one or layer)

Option A — env-aware priority bump (cheapest)

When DEVAGENTIC_BASE_URL + DEVAGENTIC_API_KEY are both set, detect_provider_for_model consults devagentic-local's fetched catalog BEFORE the OpenRouter slug-match fallback. One conditional branch insertion before Step 2. Risk: a network call per auto-detect attempt unless cached.

Option B — populate static catalog from fetched models on boot (cleanest)

On hermes session init, when devagentic-local is configured, call fetch_models() once and merge result into _PROVIDER_MODELS["devagentic-local"]. Subsequent detect_static_provider_for_model calls find mistral-large via Step 1, returns ("devagentic-local", "mistral-large"). Existing current_provider short-circuit becomes irrelevant.

Option C — surface a default_provider env var (hammer)

Add HERMES_DEFAULT_PROVIDER=devagentic-local that sets current_provider at session boot. Worker env makes the provider explicit instead of relying on auto-detect. Operators get reproducible behavior; auto-detect only matters for /model X invocations mid-session.

OPENROUTER_BASE_URL leak check

Verified — none of the auto-detect code reads OPENROUTER_BASE_URL. The OpenRouter routing in Step 2 is from the static slug catalog, not from an env var. Not the cause.

Operator workaround until fix

# Force current_provider before auto-detect runs:
hermes --provider devagentic-local --model devagentic/coder
# Then /model mistral-large works (resolves via Step 0 short-circuit).

OR set the model explicitly via fallback list in plugins/model-providers/devagentic-local/__init__.py to include mistral-large (one-line edit, persists across sessions).

Severity / priority

Not urgent per orchestrator — fusion stack itself is healthy, polynomial-explorer can wait. File for proper fix when bandwidth allows; workaround unblocks the worker immediately.

Related

  • TechDevGroup/devagentic#216 (/v1/models bearer-only fix) — must be deployed on devbox before any fetch_models() approach works
  • TechDevGroup/devagentic#218 (silo-v2 rename) — once deployed + migration run, /v1/models returns the new role catalog including the renamed mistral-large (was silo-mistral)
  • hermes-agent#66 (G6 deploy gap) — same container-rebuild gate

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions