Files
hermes-agent/tui_gateway/methods_session_model_guard.py
Victor Nogueira 1693c071a7 fix: session.create refuses a model its provider cannot serve
A composer, script or older client can pin a model override the selected
provider does not serve (gpt-5.5 on anthropic; the incident pair
deepseek/deepseek-v4-flash-0731 on openai-codex). The gateway minted the
session anyway and the FIRST turn died with the provider's 404, leaving a
dead chat the user had to diagnose and recreate.

session.create now checks the pair before any session state exists and
answers JSON-RPC -32602 naming the model, the provider and up to five
closest models from that provider's curated catalog (error.data carries
them structured). The check is offline and refuses only what Hermes knows
belongs elsewhere: a foreign-family name another native vendor's catalog
lists, or any foreign-family name on the strict OAuth catalogs
(openai-codex / xai-oauth). Custom endpoints, aggregators, same-family
names the curated list lacks and names no catalog lists stay permissive.
Without an explicit provider the pair is judged against the provider the
session would build with (profile config, then env) under the profile's
scope.

Direction and reject-before-side-effects shape from #96845 by
@victorftrdba, trimmed to the offline catalog rule.

Fixes #96817
2026-09-19 12:12:05 -07:00

28 lines
1.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""``session.create`` model×provider coherence gate (#96817).
A composer, script or older client can pin a model the selected provider cannot serve
(``gpt-5.5`` on ``anthropic``); the session used to be minted fine and the FIRST turn died with
the provider's 404, leaving a dead chat. The gate is offline (curated catalogs only) and stays
permissive wherever Hermes cannot know better — see ``models_validate.static_model_provider_conflict``.
"""
from __future__ import annotations
def model_override_conflict(params: dict, build_scope) -> dict | None:
"""The conflict record for the create params' model override, or ``None`` when coherent /
undecidable. Without an explicit ``provider`` the pair is judged against the provider the
session would actually build with (profile config, then env) inside ``build_scope`` — the
handler's ``_profile_build_scope(profile_home)`` context manager."""
model = str(params.get("model") or "").strip()
if not model:
return None
from hermes_cli.models_validate import static_model_provider_conflict
from hermes_cli.runtime_provider import resolve_requested_provider
provider = str(params.get("provider") or "").strip()
if not provider:
with build_scope:
provider = resolve_requested_provider()
return static_model_provider_conflict(model, provider)