Merge origin/main, resolve conflicts (self._base_url_lower)

This commit is contained in:
Test 2026-03-18 04:09:00 -07:00
commit e7844e9c8d
54 changed files with 2281 additions and 179 deletions

View file

@ -434,6 +434,16 @@ class GatewayRunner:
for session_key in list(managers.keys()):
self._shutdown_gateway_honcho(session_key)
# -- Setup skill availability ----------------------------------------
def _has_setup_skill(self) -> bool:
"""Check if the hermes-agent-setup skill is installed."""
try:
from tools.skill_manager_tool import _find_skill
return _find_skill("hermes-agent-setup") is not None
except Exception:
return False
# -- Voice mode persistence ------------------------------------------
_VOICE_MODE_PATH = _hermes_home / "gateway_voice_mode.json"
@ -1251,6 +1261,13 @@ class GatewayRunner:
if "@" in user_id:
check_ids.add(user_id.split("@")[0])
return bool(check_ids & allowed_ids)
def _get_unauthorized_dm_behavior(self, platform: Optional[Platform]) -> str:
"""Return how unauthorized DMs should be handled for a platform."""
config = getattr(self, "config", None)
if config and hasattr(config, "get_unauthorized_dm_behavior"):
return config.get_unauthorized_dm_behavior(platform)
return "pair"
async def _handle_message(self, event: MessageEvent) -> Optional[str]:
"""
@ -1271,7 +1288,7 @@ class GatewayRunner:
if not self._is_user_authorized(source):
logger.warning("Unauthorized user: %s (%s) on %s", source.user_id, source.user_name, source.platform.value)
# In DMs: offer pairing code. In groups: silently ignore.
if source.chat_type == "dm":
if source.chat_type == "dm" and self._get_unauthorized_dm_behavior(source.platform) == "pair":
platform_name = source.platform.value if source.platform else "unknown"
code = self.pairing_store.generate_code(
platform_name, source.user_id, source.user_name or ""
@ -1874,6 +1891,37 @@ class GatewayRunner:
message_text = await self._enrich_message_with_transcription(
message_text, audio_paths
)
# If STT failed, send a direct message to the user so they
# know voice isn't configured — don't rely on the agent to
# relay the error clearly.
_stt_fail_markers = (
"No STT provider",
"STT is disabled",
"can't listen",
"VOICE_TOOLS_OPENAI_KEY",
)
if any(m in message_text for m in _stt_fail_markers):
_stt_adapter = self.adapters.get(source.platform)
_stt_meta = {"thread_id": source.thread_id} if source.thread_id else None
if _stt_adapter:
try:
_stt_msg = (
"🎤 I received your voice message but can't transcribe it — "
"no speech-to-text provider is configured.\n\n"
"To enable voice: install faster-whisper "
"(`pip install faster-whisper` in the Hermes venv) "
"and set `stt.enabled: true` in config.yaml, "
"then /restart the gateway."
)
# Point to setup skill if it's installed
if self._has_setup_skill():
_stt_msg += "\n\nFor full setup instructions, type: `/skill hermes-agent-setup`"
await _stt_adapter.send(
source.chat_id, _stt_msg,
metadata=_stt_meta,
)
except Exception:
pass
# -----------------------------------------------------------------
# Enrich document messages with context notes for the agent
@ -3943,7 +3991,13 @@ class GatewayRunner:
The enriched message string with transcriptions prepended.
"""
if not getattr(self.config, "stt_enabled", True):
disabled_note = "[The user sent voice message(s), but transcription is disabled in config.]"
disabled_note = "[The user sent voice message(s), but transcription is disabled in config."
if self._has_setup_skill():
disabled_note += (
" You have a skill called hermes-agent-setup that can help "
"users configure Hermes features including voice, tools, and more."
)
disabled_note += "]"
if user_text:
return f"{disabled_note}\n\n{user_text}"
return disabled_note
@ -3970,11 +4024,20 @@ class GatewayRunner:
"No STT provider" in error
or error.startswith("Neither VOICE_TOOLS_OPENAI_KEY nor OPENAI_API_KEY is set")
):
enriched_parts.append(
_no_stt_note = (
"[The user sent a voice message but I can't listen "
"to it right now~ No STT provider is configured "
"(';w;') Let them know!]"
"to it right now — no STT provider is configured. "
"A direct message has already been sent to the user "
"with setup instructions."
)
if self._has_setup_skill():
_no_stt_note += (
" You have a skill called hermes-agent-setup "
"that can help users configure Hermes features "
"including voice, tools, and more."
)
_no_stt_note += "]"
enriched_parts.append(_no_stt_note)
else:
enriched_parts.append(
"[The user sent a voice message but I had trouble "