mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix: fake models
This commit is contained in:
parent
77b97b810a
commit
ebe3270430
6 changed files with 40 additions and 38 deletions
|
|
@ -660,12 +660,12 @@ def switch_model(
|
|||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
)
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
validation = {
|
||||
"accepted": True,
|
||||
"persist": True,
|
||||
"accepted": False,
|
||||
"persist": False,
|
||||
"recognized": False,
|
||||
"message": None,
|
||||
"message": f"Could not validate `{new_model}`: {e}",
|
||||
}
|
||||
|
||||
if not validation.get("accepted"):
|
||||
|
|
|
|||
|
|
@ -1842,12 +1842,11 @@ def validate_requested_model(
|
|||
if suggestions:
|
||||
suggestion_text = "\n Similar models: " + ", ".join(f"`{s}`" for s in suggestions)
|
||||
return {
|
||||
"accepted": True,
|
||||
"persist": True,
|
||||
"accepted": False,
|
||||
"persist": False,
|
||||
"recognized": False,
|
||||
"message": (
|
||||
f"Note: `{requested}` was not found in the OpenAI Codex model listing. "
|
||||
f"It may still work if your account has access to it."
|
||||
f"Model `{requested}` was not found in the OpenAI Codex model listing."
|
||||
f"{suggestion_text}"
|
||||
),
|
||||
}
|
||||
|
|
@ -1864,26 +1863,20 @@ def validate_requested_model(
|
|||
"recognized": True,
|
||||
"message": None,
|
||||
}
|
||||
else:
|
||||
# API responded but model is not listed. Accept anyway —
|
||||
# the user may have access to models not shown in the public
|
||||
# listing (e.g. Z.AI Pro/Max plans can use glm-5 on coding
|
||||
# endpoints even though it's not in /models). Warn but allow.
|
||||
suggestions = get_close_matches(requested, api_models, n=3, cutoff=0.5)
|
||||
suggestion_text = ""
|
||||
if suggestions:
|
||||
suggestion_text = "\n Similar models: " + ", ".join(f"`{s}`" for s in suggestions)
|
||||
suggestions = get_close_matches(requested, api_models, n=3, cutoff=0.5)
|
||||
suggestion_text = ""
|
||||
if suggestions:
|
||||
suggestion_text = "\n Similar models: " + ", ".join(f"`{s}`" for s in suggestions)
|
||||
|
||||
return {
|
||||
"accepted": True,
|
||||
"persist": True,
|
||||
"recognized": False,
|
||||
"message": (
|
||||
f"Note: `{requested}` was not found in this provider's model listing. "
|
||||
f"It may still work if your plan supports it."
|
||||
f"{suggestion_text}"
|
||||
),
|
||||
}
|
||||
return {
|
||||
"accepted": False,
|
||||
"persist": False,
|
||||
"recognized": False,
|
||||
"message": (
|
||||
f"Model `{requested}` was not found in this provider's model listing."
|
||||
f"{suggestion_text}"
|
||||
),
|
||||
}
|
||||
|
||||
# api_models is None — couldn't reach API. Accept and persist,
|
||||
# but warn so typos don't silently break things.
|
||||
|
|
|
|||
|
|
@ -401,7 +401,8 @@ class TestValidateFormatChecks:
|
|||
|
||||
def test_no_slash_model_rejected_if_not_in_api(self):
|
||||
result = _validate("gpt-5.4", api_models=["openai/gpt-5.4"])
|
||||
assert result["accepted"] is True
|
||||
assert result["accepted"] is False
|
||||
assert result["persist"] is False
|
||||
assert "not found" in result["message"]
|
||||
|
||||
|
||||
|
|
@ -427,15 +428,15 @@ class TestValidateApiFound:
|
|||
# -- validate — API not found ------------------------------------------------
|
||||
|
||||
class TestValidateApiNotFound:
|
||||
def test_model_not_in_api_accepted_with_warning(self):
|
||||
def test_model_not_in_api_rejected_with_guidance(self):
|
||||
result = _validate("anthropic/claude-nonexistent")
|
||||
assert result["accepted"] is True
|
||||
assert result["persist"] is True
|
||||
assert result["accepted"] is False
|
||||
assert result["persist"] is False
|
||||
assert "not found" in result["message"]
|
||||
|
||||
def test_warning_includes_suggestions(self):
|
||||
result = _validate("anthropic/claude-opus-4.5")
|
||||
assert result["accepted"] is True
|
||||
assert result["accepted"] is False
|
||||
assert "Similar models" in result["message"]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ def test_config_set_model_uses_live_switch_path(monkeypatch):
|
|||
|
||||
def _fake_apply(sid, session, raw):
|
||||
seen["args"] = (sid, session["session_key"], raw)
|
||||
return "new/model"
|
||||
return {"value": "new/model", "warning": "catalog unreachable"}
|
||||
|
||||
monkeypatch.setattr(server, "_apply_model_switch", _fake_apply)
|
||||
resp = server.handle_request(
|
||||
|
|
@ -163,6 +163,7 @@ def test_config_set_model_uses_live_switch_path(monkeypatch):
|
|||
)
|
||||
|
||||
assert resp["result"]["value"] == "new/model"
|
||||
assert resp["result"]["warning"] == "catalog unreachable"
|
||||
assert seen["args"] == ("sid", "session-key", "new/model")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -327,11 +327,11 @@ def _restart_slash_worker(session: dict):
|
|||
session["slash_worker"] = None
|
||||
|
||||
|
||||
def _apply_model_switch(sid: str, session: dict, raw_input: str) -> str:
|
||||
def _apply_model_switch(sid: str, session: dict, raw_input: str) -> dict:
|
||||
agent = session.get("agent")
|
||||
if not agent:
|
||||
os.environ["HERMES_MODEL"] = raw_input
|
||||
return raw_input
|
||||
return {"value": raw_input, "warning": ""}
|
||||
|
||||
from hermes_cli.model_switch import switch_model
|
||||
|
||||
|
|
@ -355,7 +355,7 @@ def _apply_model_switch(sid: str, session: dict, raw_input: str) -> str:
|
|||
os.environ["HERMES_MODEL"] = result.new_model
|
||||
_restart_slash_worker(session)
|
||||
_emit("session.info", sid, _session_info(agent))
|
||||
return result.new_model
|
||||
return {"value": result.new_model, "warning": result.warning_message or ""}
|
||||
|
||||
|
||||
def _compress_session_history(session: dict) -> tuple[int, dict]:
|
||||
|
|
@ -1273,10 +1273,11 @@ def _(rid, params: dict) -> dict:
|
|||
if not value:
|
||||
return _err(rid, 4002, "model value required")
|
||||
if session:
|
||||
value = _apply_model_switch(params.get("session_id", ""), session, value)
|
||||
result = _apply_model_switch(params.get("session_id", ""), session, value)
|
||||
else:
|
||||
os.environ["HERMES_MODEL"] = value
|
||||
return _ok(rid, {"key": key, "value": value})
|
||||
result = {"value": value, "warning": ""}
|
||||
return _ok(rid, {"key": key, "value": result["value"], "warning": result["warning"]})
|
||||
except Exception as e:
|
||||
return _err(rid, 5001, str(e))
|
||||
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ const stripTokens = (text: string, re: RegExp) =>
|
|||
|
||||
const imageTokenMeta = (info: { height?: number; token_estimate?: number; width?: number } | null | undefined) => {
|
||||
const dims = info?.width && info?.height ? `${info.width}x${info.height}` : ''
|
||||
|
||||
const tok =
|
||||
typeof info?.token_estimate === 'number' && info.token_estimate > 0 ? `~${fmtK(info.token_estimate)} tok` : ''
|
||||
|
||||
|
|
@ -1988,6 +1989,11 @@ export function App({ gw }: { gw: GatewayClient }) {
|
|||
}
|
||||
|
||||
sys(`model → ${r.value}`)
|
||||
|
||||
if (r.warning) {
|
||||
sys(`warning: ${r.warning}`)
|
||||
}
|
||||
|
||||
setInfo(prev => (prev ? { ...prev, model: r.value } : prev))
|
||||
}
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue