Skip to content

fix(auth): preserve callable credentials across provider switches - #108039

Closed
tudorpastorglencore wants to merge 1 commit into
NousResearch:mainfrom
tudorpastorglencore:fix/azure-provider-switch-callable
Closed

tudorpastorglencore wants to merge 1 commit into
NousResearch:mainfrom
tudorpastorglencore:fix/azure-provider-switch-callable

Conversation

@tudorpastorglencore

Copy link
Copy Markdown

What does this PR do?

Preserves callable provider credentials when Hermes switches between providers and re-resolves runtime credentials on the next turn.

This fixes the Claude -> Azure/OpenAI failure where an Entra token provider was converted to a string API key, causing Azure HTTP 401 responses. It also prevents callable credentials from being persisted in TUI session overrides.

Related Issue

Related to #72421 and #88667. Companion to #107344.

Type of Change

  • Bug fix (non-breaking change that fixes incorrect behavior)

Changes Made

  • Preserve callable credentials in named custom-provider re-resolution.
  • Preserve Azure Entra callable credentials and Entra metadata.
  • Materialize callable credentials only at model-probe boundaries.
  • Avoid persisting raw api_key values in TUI model overrides.
  • Add regression coverage for Azure, custom providers, model probes, and TUI switching.

How to Test

  1. Start Hermes with a callable-token provider.
  2. Switch from an OpenAI/Azure model to Claude.
  3. Switch back to the OpenAI/Azure model.
  4. Submit another prompt and verify the request succeeds with bearer authentication.

Automated validation:

  • 96 targeted provider/probe/TUI tests passed.
  • 102 related runtime/session tests passed.
  • Ruff passed.
  • Windows-footgun check passed.
  • Compatibility-pointer check passed.
    The full repository suite was started but exceeded the local 10-minute limit; its first failure was an unrelated Pydantic warning-precondition test.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard comp/tui Terminal UI (ui-tui/ + tui_gateway/) area/auth Authentication, OAuth, credential pools provider/openai OpenAI / Codex Responses API sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Sep 11, 2026
session["model_override"] = {
"model": result.new_model, "provider": result.target_provider,
"base_url": result.base_url, "api_key": result.api_key, "api_mode": result.api_mode}
"base_url": result.base_url, "api_mode": result.api_mode}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing api_key here breaks rebuilds after switching to a credential-bearing model_aliases entry. I reproduced this on this head: the initial /model private-alias switch uses the configured alias key, but _resolve_agent_model_runtime(session["model_override"], None) then receives only provider: custom and the base URL and returns no-key-required. The recorded base keeps the in-memory key and rebuilds correctly. sanitize_model_override() already removes api_key before sessions.json persistence, so please retain it in the live override or persist non-secret alias identity and re-resolve it during rebuild.

teknium1 pushed a commit that referenced this pull request Sep 19, 2026
…olve Azure Foundry

Auxiliary tasks on `provider: auto` (title generation, context compression,
smart approval) forward the main runtime's api_key into
`_resolve_azure_foundry_runtime` as `explicit_api_key`. Under
`auth_mode: entra_id` that api_key is the Entra token-provider callable;
the resolver's first line stringified it, so the truthy function repr took
the "explicit string" escape hatch, was relabelled `auth_mode: api_key` and
sent to Azure as a static key -> HTTP 401 on every aux call while the main
conversation worked.

A forwarded value recognised by `is_token_provider()` now stays the runtime
api_key with `auth_mode: entra_id` and the config's Entra metadata. The
explicit STRING escape hatch (`--api-key` while config says entra_id) is
unchanged, and api_key mode remains string-only: a callable there falls
through to the env/.env key as before.

Semantic hunk ported from #108039 (reformat/bloat stripped: unrelated
callable handling in models.py / runtime_provider_custom.py /
tui_gateway.model_switch left out); #72463 by kyssta-exe filed the same
fix first against the pre-split runtime_provider.py.

Fixes #72421

Co-authored-by: kyssta-exe <kyssta-exe@users.noreply.github.com>
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks @tudorpastorglencore — the work in this PR has landed on main via:

Your contribution is credited there (cherry-picked authorship / co-author trailer or credit in the PR body; see the linked PR for what was kept and what was trimmed). Closing this one as landed / superseded so the backlog reflects reality. If something in your original diff is still missing on current main, please comment and we'll reopen or follow up.

@teknium1 teknium1 closed this Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/cli CLI entry point, hermes_cli/, setup wizard comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists provider/openai OpenAI / Codex Responses API sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants