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

@ -1162,3 +1162,79 @@ def test_load_pool_does_not_seed_qwen_oauth_when_no_token(tmp_path, monkeypatch)
assert not pool.has_credentials()
assert pool.entries() == []
# ---------------------------------------------------------------------------
# Tests for CredentialPool.remove_entry (added in commit fc00f699)
# ---------------------------------------------------------------------------
def _build_pool_with_entries(tmp_path, monkeypatch, provider="openrouter", entries=None):
"""Helper: build a CredentialPool directly without seeding side-effects."""
monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
monkeypatch.setattr("agent.credential_pool._seed_from_singletons", lambda p, e: (False, set()))
monkeypatch.setattr("agent.credential_pool._seed_from_env", lambda p, e: (False, set()))
if entries is None:
entries = [
{
"id": "cred-1",
"label": "primary",
"auth_type": "api_key",
"priority": 0,
"source": "manual",
"access_token": "tok-1",
},
{
"id": "cred-2",
"label": "secondary",
"auth_type": "api_key",
"priority": 1,
"source": "manual",
"access_token": "tok-2",
},
]
_write_auth_store(tmp_path, {"version": 1, "credential_pool": {provider: entries}})
from agent.credential_pool import load_pool
return load_pool(provider)
def test_remove_entry_removes_by_id(tmp_path, monkeypatch):
"""remove_entry should remove the entry with matching id and return it."""
pool = _build_pool_with_entries(tmp_path, monkeypatch)
removed = pool.remove_entry("cred-1")
assert removed is not None
assert removed.id == "cred-1"
remaining_ids = [e.id for e in pool.entries()]
assert "cred-1" not in remaining_ids
assert "cred-2" in remaining_ids
def test_remove_entry_returns_none_for_unknown_id(tmp_path, monkeypatch):
"""remove_entry returns None when no entry matches the given id."""
pool = _build_pool_with_entries(tmp_path, monkeypatch)
result = pool.remove_entry("nonexistent-id")
assert result is None
# Pool should still have both original entries
assert len(pool.entries()) == 2
def test_remove_entry_renumbers_priorities(tmp_path, monkeypatch):
"""After remove_entry, remaining entries receive sequential priorities 0, 1, ..."""
pool = _build_pool_with_entries(
tmp_path,
monkeypatch,
entries=[
{"id": "cred-1", "label": "a", "auth_type": "api_key", "priority": 0, "source": "manual", "access_token": "tok-1"},
{"id": "cred-2", "label": "b", "auth_type": "api_key", "priority": 1, "source": "manual", "access_token": "tok-2"},
{"id": "cred-3", "label": "c", "auth_type": "api_key", "priority": 2, "source": "manual", "access_token": "tok-3"},
],
)
pool.remove_entry("cred-2")
remaining = sorted(pool.entries(), key=lambda e: e.priority)
assert [e.priority for e in remaining] == [0, 1]
assert [e.id for e in remaining] == ["cred-1", "cred-3"]