fix(types): batch P1 ty hotfixes + run_agent.py annotation pass

15 P1 ship-stopper runtime bugs from the ty triage plus the cross-bucket
cleanup in run_agent.py. Net: -138 ty diagnostics (1953 -> 1815). Major
wins on not-subscriptable (-34), unresolved-attribute (-29),
invalid-argument-type (-26), invalid-type-form (-20),
unsupported-operator
(-18), invalid-key (-9).

Missing refs (structural):
- tools/rl_training_tool.py: RunState dataclass gains api_log_file,
  trainer_log_file, env_log_file fields; stop-run was closing undeclared
  handles.
- agent/credential_pool.py: remove_entry(entry_id) added, symmetric with
  add_entry; used by hermes_cli/web_server.py OAuth dashboard cleanup.
- hermes_cli/config.py: _CamofoxConfig TypedDict defined (was referenced
  by _BrowserConfig but never declared).
- hermes_cli/gateway.py: _setup_wecom_callback() added, mirroring
  _setup_wecom().
- tui_gateway/server.py: skills_hub imports corrected from
  hermes_cli.skills_hub -> tools.skills_hub.

Typo / deprecation:
- tools/transcription_tools.py: os.sys.modules -> sys.modules.
- gateway/platforms/bluebubbles.py: datetime.utcnow() ->
  datetime.now(timezone.utc).

None-guards:
- gateway/platforms/telegram.py:~2798 - msg.sticker None guard.
- gateway/platforms/discord.py:3602/3637 - interaction.data None +
  SelectMenu narrowing; :3009 - thread_id None before `in`; :1893 -
  guild.member_count None.
- gateway/platforms/matrix.py:2174/2185 - walrus-narrow
  re.search().group().
- agent/display.py:732 - start_time None before elapsed subtraction.
- gateway/run.py:10334 - assert _agent_timeout is not None before `//
  60`.

Platform override signature match:
- gateway/platforms/email.py: send_image accepts metadata kwarg;
  send_document accepts **kwargs (matches base class).

run_agent.py annotation pass:
- callable/any -> Callable/Any in annotation position (15 sites in
  run_agent.py + 5 in cli.py, toolset_distributions.py,
  tools/delegate_tool.py, hermes_cli/dingtalk_auth.py,
  tui_gateway/server.py).
- conversation_history param widened to list[dict[str, Any]] | None.
- OMIT_TEMPERATURE sentinel guarded from leaking into
  call_llm(temperature): kwargs-dict pattern at run_agent.py:7337 +
  scripts/trajectory_compressor.py:618/688.
- build_anthropic_client(timeout) widened to Optional[float].

Tests:
- tests/agent/test_credential_pool.py: remove_entry (id match,
  unknown-id, priority renumbering).
- tests/hermes_cli/test_config_shapes.py: _CamofoxConfig shape +
  nesting.
- tests/tools/test_rl_training_tool.py: RunState log_file fields.
This commit is contained in:
alt-glitch 2026-04-21 20:20:13 +05:30
parent fb6d37495b
commit 15ac253b11
24 changed files with 1726 additions and 254 deletions

View file

@ -14,7 +14,7 @@ import logging
import os
import re
import uuid
from datetime import datetime
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional
from urllib.parse import quote
@ -377,7 +377,7 @@ class BlueBubblesAdapter(BasePlatformAdapter):
payload = {
"addresses": [address],
"message": message,
"tempGuid": f"temp-{datetime.utcnow().timestamp()}",
"tempGuid": f"temp-{datetime.now(timezone.utc).timestamp()}",
}
try:
res = await self._api_post("/api/v1/chat/new", payload)
@ -417,7 +417,7 @@ class BlueBubblesAdapter(BasePlatformAdapter):
)
payload: Dict[str, Any] = {
"chatGuid": guid,
"tempGuid": f"temp-{datetime.utcnow().timestamp()}",
"tempGuid": f"temp-{datetime.now(timezone.utc).timestamp()}",
"message": chunk,
}
if reply_to and self._private_api_enabled and self._helper_connected:

View file

@ -1890,7 +1890,7 @@ class DiscordAdapter(BasePlatformAdapter):
# Fetch full member list (requires members intent)
try:
members = guild.members
if len(members) < guild.member_count:
if guild.member_count is not None and len(members) < guild.member_count:
members = [m async for m in guild.fetch_members(limit=None)]
except Exception as e:
logger.warning("Failed to fetch members for guild %s: %s", guild.name, e)
@ -3006,7 +3006,7 @@ class DiscordAdapter(BasePlatformAdapter):
# Skip the mention check if the message is in a thread where
# the bot has previously participated (auto-created or replied in).
in_bot_thread = is_thread and thread_id in self._threads
in_bot_thread = is_thread and thread_id is not None and thread_id in self._threads
if require_mention and not is_free_channel and not in_bot_thread:
if self._client.user not in message.mentions and not mention_prefix:
@ -3599,7 +3599,9 @@ if DISCORD_AVAILABLE:
)
return
provider_slug = interaction.data["values"][0] # ty: ignore[not-subscriptable]
if interaction.data is None:
return
provider_slug = interaction.data["values"][0] # ty: ignore[invalid-key]
self._selected_provider = provider_slug
provider = next(
(p for p in self.providers if p["slug"] == provider_slug), None
@ -3634,7 +3636,9 @@ if DISCORD_AVAILABLE:
return
self.resolved = True
model_id = interaction.data["values"][0] # ty: ignore[not-subscriptable]
if interaction.data is None:
return
model_id = interaction.data["values"][0] # ty: ignore[invalid-key]
try:
result_text = await self.on_model_selected(

View file

@ -532,6 +532,7 @@ class EmailAdapter(BasePlatformAdapter):
image_url: str,
caption: Optional[str] = None,
reply_to: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None,
) -> SendResult:
"""Send an image URL as part of an email body."""
text = caption or ""
@ -545,6 +546,7 @@ class EmailAdapter(BasePlatformAdapter):
caption: Optional[str] = None,
file_name: Optional[str] = None,
reply_to: Optional[str] = None,
**kwargs,
) -> SendResult:
"""Send a file as an email attachment."""
try:

View file

@ -2170,8 +2170,8 @@ class MatrixAdapter(BasePlatformAdapter):
ul_match = re.match(r"^[\s]*[-*+]\s+(.+)$", line)
if ul_match:
items = []
while i < len(lines) and re.match(r"^[\s]*[-*+]\s+(.+)$", lines[i]):
items.append(re.match(r"^[\s]*[-*+]\s+(.+)$", lines[i]).group(1))
while i < len(lines) and (m := re.match(r"^[\s]*[-*+]\s+(.+)$", lines[i])):
items.append(m.group(1))
i += 1
li = "".join(f"<li>{item}</li>" for item in items)
out_lines.append(f"<ul>{li}</ul>")
@ -2181,8 +2181,8 @@ class MatrixAdapter(BasePlatformAdapter):
ol_match = re.match(r"^[\s]*\d+[.)]\s+(.+)$", line)
if ol_match:
items = []
while i < len(lines) and re.match(r"^[\s]*\d+[.)]\s+(.+)$", lines[i]):
items.append(re.match(r"^[\s]*\d+[.)]\s+(.+)$", lines[i]).group(1))
while i < len(lines) and (m := re.match(r"^[\s]*\d+[.)]\s+(.+)$", lines[i])):
items.append(m.group(1))
i += 1
li = "".join(f"<li>{item}</li>" for item in items)
out_lines.append(f"<ol>{li}</ol>")

View file

@ -2796,6 +2796,8 @@ class TelegramAdapter(BasePlatformAdapter):
)
sticker = msg.sticker
if sticker is None:
return
emoji = sticker.emoji or ""
set_name = sticker.set_name or ""

View file

@ -10331,6 +10331,7 @@ class GatewayRunner:
if _timed_out_agent and hasattr(_timed_out_agent, "interrupt"):
_timed_out_agent.interrupt(_INTERRUPT_REASON_TIMEOUT)
assert _agent_timeout is not None # narrowed by _idle_secs >= _agent_timeout above
_timeout_mins = int(_agent_timeout // 60) or 1
# Construct a user-facing message with diagnostic context.