feat: save account model and thinking settings for Hermes
Rebuild & Deploy / rebuild (push) Successful in 1m9s

This commit is contained in:
snowspeeder committed 2026-10-01 16:38:34 -04:00
1 parent a45569f8c1
commit 6cb4427210
13 files changed
+798 -16

No files matched your search

+9 -1
View File
@@ -111,9 +111,17 @@ async def entrypoint(ctx: JobContext):
await stop_notice()
notice_task = spawn(play_notice(text))
async def model_settings():
# Fetch at each turn, not just on join/poll: saved account changes apply
# immediately to the next request even in already-connected rooms.
current = await resolve_room(ctx.room.name)
if current["user"]["id"] != user_id:
raise RuntimeError("Account mismatch")
return current["model_settings"]
bridge = HermesLLM(base_url=account["hermes_url"], api_key=account["hermes_api_key"], user_id=user_id,
room_id=ctx.room.name, on_progress=progress, on_wait_notice=wait_notice,
on_answer_start=stop_notice)
on_answer_start=stop_notice, get_model_settings=model_settings)
tts = azure.TTS(voice=DEFAULT_VOICE, sample_rate=24000,
speech_key=os.getenv("AZURE_SPEECH_KEY", ""), speech_region=os.getenv("AZURE_SPEECH_REGION", "eastus"))
session = AgentSession(stt=azure.STT(speech_key=os.getenv("AZURE_SPEECH_KEY", ""),
+19 -2
View File
@@ -103,6 +103,7 @@ class HermesLLM(lk_llm.LLM):
on_progress: ProgressCallback,
on_wait_notice: WaitNoticeCallback | None = None,
on_answer_start: Callable[[], Awaitable[None]] | None = None,
get_model_settings: Callable[[], Awaitable[dict[str, str]]] | None = None,
timeout_seconds: float = 600.0,
http_client: httpx.AsyncClient | None = None,
) -> None:
@@ -128,6 +129,7 @@ class HermesLLM(lk_llm.LLM):
self._on_wait_notice = on_wait_notice
self._last_wait_notice: str | None = None
self._on_answer_start = on_answer_start
self._get_model_settings = get_model_settings
self._timeout_seconds = timeout_seconds
self._owns_client = http_client is None
self._client = http_client if http_client is not None else httpx.AsyncClient(follow_redirects=False)
@@ -219,10 +221,25 @@ class HermesLLMStream(lk_llm.LLMStream):
await asyncio.gather(timer, return_exceptions=True)
async def _consume(self) -> None:
settings = {"model": "auto", "thinking_level": "none"}
if self._hermes._get_model_settings is not None:
try:
settings = await self._hermes._get_model_settings()
except Exception:
# Never fall back to stale preferences or run after revocation.
raise HermesLLMError("settings_unavailable") from None
model, effort = settings.get("model"), settings.get("thinking_level")
if (not isinstance(model, str) or not 1 <= len(model) <= 200
or not all(33 <= ord(c) <= 126 for c in model)
or effort not in ("none", "minimal", "low", "medium", "high", "xhigh")):
raise HermesLLMError("invalid_settings")
reasoning = {"enabled": False} if effort == "none" else {"enabled": True, "effort": effort}
payload = {
"model": "hermes-agent", "stream": True,
# Explicit provider is required: Hermes otherwise ignores bare model
# requests by default. Neither provider nor API origin is client input.
"model": model, "provider": "custom:hope-upstream", "stream": True,
"messages": _messages(self.chat_ctx),
"model_options": {"reasoning": {"enabled": False}},
"model_options": {"reasoning": reasoning},
}
finished = False
async with self._hermes._client.stream(