Skip to content

refactor(gateway): extract GatewayTurnExecMixin from run.py (slice 29 of #54962) - #77752

Open
andrexibiza wants to merge 3 commits into
NousResearch:mainfrom
andrexibiza:refactor/gateway-mixin-turn-exec
Open

refactor(gateway): extract GatewayTurnExecMixin from run.py (slice 29 of #54962)#77752
andrexibiza wants to merge 3 commits into
NousResearch:mainfrom
andrexibiza:refactor/gateway-mixin-turn-exec

Conversation

@andrexibiza

@andrexibiza andrexibiza commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Related #54962 #55138

What

Third wave of the GatewayRunner mixin decomposition (gate 4 of #54962): extract the turn-execution engine — 21 methods / ~2,935 lines — out of GatewayRunner in gateway/run.py into a new gateway/turn_exec_mixin.py (GatewayTurnExecMixin), following the codebase's existing mixin pattern (gateway/authz_mixin.py, gateway/kanban_watchers.py, gateway/slash_commands.py).

The mixin holds: the agent run entry points (_run_agent, _run_agent_inner), the remote-proxy path (_get_proxy_url, _build_stream_consumer_config, _run_agent_via_proxy), background-task execution (_run_background_task[_inner]), the cached-agent lifecycle (_init_cached_agent_for_turn, _refresh_agent_cache_message_count, _commit_memory_before_soft_evict, _commit_then_release_soft, _release_evicted_agent_soft, _enforce_agent_cache_cap, _sweep_idle_cached_agents), agent resource cleanup (_should_emit_long_running_notification, _defer_agent_cleanup_until_future_done, _cleanup_agent_resources_off_loop, _cleanup_agent_resources), and the gateway-owned executor (_run_in_executor_with_context, _get_executor, _shutdown_executor).

GatewayRunner now reads class GatewayRunner(GatewayTurnExecMixin, GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, GatewaySlashCommandsMixin) — the new mixin is first in the bases; every self.* call site resolves unchanged via the MRO.

Why

gateway/run.py is a ~26.8k-line god file; the campaign (#54962) decomposes it into focused mixins/modules. This slice is behavior-neutral: every method is lifted verbatim. run.py shrinks from 26,824 to 23,855 lines (−2,969).

How this stays behavior-neutral

  • Verbatim moves: 21/21 method bodies identical to the pre-splice run.py (verified by an automated compare against HEAD~2). 14 lines that carried pre-existing trailing whitespace from run.py were whitespace-normalized in the new file (follow-up style commit) so the added file passes git diff --check; run.py's own pre-existing trailing whitespace is untouched. git diff --check over the whole PR diff is clean.
  • MRO: no call-site changes; self._x dispatch is unchanged.
  • Lazy imports for run.py globals: the moved bodies read a handful of run.py module-level names at call time (_load_gateway_config, _hermes_home, _resolve_gateway_model, _profile_runtime_scope, _platform_config_key, the _AGENT_*/_GATEWAY_* constants, TurnRunner, ...). Each such method gets a deferred from gateway.run import ... at the top of its body (the established pattern in gateway/slash_commands.py) — it resolves at call time when gateway.run is fully loaded, preserving monkeypatch semantics (gateway.run._hermes_home patches in 20+ test files keep working). time is lazy-imported the same way because tests replace gateway.run.time wholesale.
  • Logger: module-level logger = logging.getLogger("gateway.run") (same as the kanban/slash mixins) keeps log-record names unchanged.
  • No module-level from gateway.run import — no import cycle; the mixin imports only stdlib + direct deps at module top.

How to test

python -m pytest tests/gateway/test_agent_cache.py tests/gateway/test_proxy_mode.py \
  tests/gateway/test_background_command.py tests/gateway/test_53175_cleanup_off_loop.py \
  tests/gateway/test_73297_memory_flush_on_reset.py tests/gateway/test_35994_reset_button_deadlock.py \
  tests/gateway/test_shutdown_cache_cleanup.py tests/gateway/test_multiplex_background_task_scope.py \
  tests/gateway/test_run_cleanup_progress.py tests/gateway/test_turn_context.py \
  tests/gateway/test_incomplete_gateway_turns.py tests/gateway/test_tool_log_mode.py \
  tests/gateway/test_7100_transient_failure_transcript.py tests/gateway/test_stale_finalize_suppression.py \
  tests/gateway/test_transcript_offset.py tests/gateway/test_42039_duplicate_user_message.py \
  tests/gateway/test_session_id_cache_coherence.py tests/gateway/test_shutdown_memory_provider_messages.py \
  -q --no-header -p no:cacheprovider

Import smoke: import gateway.run; assert hasattr(gateway.run.GatewayRunner, '_run_agent_inner') and all 21 moved methods report __module__ == 'gateway.turn_exec_mixin' with GatewayTurnExecMixin first in GatewayRunner.__mro__.

Platforms tested

  • Windows 10 (git-bash), Python 3.11 (repo venv). Targeted suites: 174 tests across 29 files, all green (95 core batch: agent cache, proxy mode, background command, cleanup, turn context, tool log mode, transcript/incomplete-turn paths, session-id coherence; 79 follow-up batch: executor/run-progress, startup/shutdown, TTS gateway, fallback-chain reload, auto-continue), plus 62 re-run green on the final committed state (post whitespace-fix).
  • scripts/check-windows-footguns.py on the new module: clean.

Scope note

  • Only the 21 listed methods move; everything else in GatewayRunner stays. Two class-level section comments that described the moved proxy cluster travel with it; the _CLEANUP_TIMEOUT_S class attribute stays on GatewayRunner (still referenced via self by the moved cleanup methods through the MRO).
  • The moved methods keep their in-function imports verbatim (e.g. from run_agent import AIAgent); no run.py imports were pruned (other methods may still use them).
  • One source-level test (tests/gateway/test_fallback_chain_reload.py) pins the location of the two fallback_model=self._refresh_fallback_model() agent-construction sites; both sites moved into the mixin, so the test now counts across gateway/run.py + gateway/turn_exec_mixin.py (same invariant, same pattern as the TurnRunner extraction commit 1a3a9de).

Part of #54962
Part of #55138

Part of #78207
Part of #78647
Part of #78791

… of NousResearch#54962)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
…rn_exec_mixin.py

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
@andrexibiza
andrexibiza force-pushed the refactor/gateway-mixin-turn-exec branch from 8420eba to 1d8b456 Compare August 3, 2026 14:30
@alt-glitch alt-glitch added type/refactor Code restructuring, no behavior change comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Aug 3, 2026
andrexibiza added a commit to andrexibiza/hermes-agent that referenced this pull request Aug 5, 2026
This was referenced Aug 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/refactor Code restructuring, no behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants