Skip to content

refactor(gateway): extract GatewayMediaMixin from run.py (slice 22 of #54962) - #77751

Open
andrexibiza wants to merge 2 commits into
NousResearch:mainfrom
andrexibiza:refactor/gateway-mixin-media
Open

refactor(gateway): extract GatewayMediaMixin from run.py (slice 22 of #54962)#77751
andrexibiza wants to merge 2 commits into
NousResearch:mainfrom
andrexibiza:refactor/gateway-mixin-media

Conversation

@andrexibiza

@andrexibiza andrexibiza commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Related #54962 #55138

What

Extract the media-processing cluster out of GatewayRunner in gateway/run.py (26,823 → 25,798 lines) into a new gateway/media_mixin.py module — class GatewayMediaMixin — following the codebase's existing mixin pattern (gateway/authz_mixin.py, gateway/kanban_watchers.py, gateway/slash_commands.py).

The 14 methods moved verbatim (zero behavior change):

  • _warn_if_docker_media_delivery_is_risky
  • _prepare_inbound_message_text
  • _prepare_profile_scoped_inbound_message_text
  • _prepare_clarify_reply_text
  • _consume_pending_native_image_paths
  • _enrich_message_with_vision
  • _enrich_message_with_transcription
  • _pending_event_audio_paths
  • _transcribe_pending_audio_event_once
  • _echo_pending_stt_transcripts_once
  • _transcribe_and_echo_pending_voice
  • _should_echo_stt_transcripts
  • _deliver_media_from_response
  • _decide_image_input_mode

GatewayRunner now inherits GatewayMediaMixin first: class GatewayRunner(GatewayMediaMixin, GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, GatewaySlashCommandsMixin). All self.* call sites resolve unchanged via the MRO.

Why

Phase 3 of the large-file decomposition campaign for #54962: mechanically lift cohesive method clusters out of the 26.8k-line gateway/run.py into focused mixins, shrinking the god file without changing behavior. GatewayMediaMixin is the media cluster (gate 4 / tree 17 of the mixin wave).

How the move stays behavior-neutral

  • Methods are byte-identical: each body was sliced from the original line ranges and verified verbatim (only the documented lazy imports below were added).
  • Shared run.py helpers stay in run.py and are imported lazily inside the method that uses them (from gateway.run import ... at call time — the exact pattern gateway/slash_commands.py already uses for _load_gateway_config, _profile_runtime_scope, etc.): _event_media_is_*, _build_document_context_note, _load_gateway_config, _probe_audio_duration, _profile_runtime_scope, _DOCKER_VOLUME_SPEC_RE, _DOCKER_MEDIA_OUTPUT_CONTAINER_PATHS. This keeps the module free of any import-time gateway.run back-reference (no import cycle).
  • _UNSET moves with the cluster and is re-exported: it is used as a default argument (metadata=_UNSET) in _transcribe_and_echo_pending_voice, so it must resolve at class-definition time in the new module. gateway/run.py re-exports it (from gateway.media_mixin import GatewayMediaMixin, _UNSET # noqa: F401), so gateway.run._UNSET stays the same object (verified: r._UNSET is mm._UNSET).
  • Logger name preserved: module-level logger = logging.getLogger("gateway.run") keeps log records' provenance identical.
  • Methods that already carried in-body lazy imports (vision_analyze_tool, transcribe_audio, to_agent_visible_cache_path, decide_image_input_mode, BasePlatformAdapter, etc.) moved with them untouched.

How to test

python -c "import gateway.run; assert hasattr(gateway.run.GatewayRunner, '_prepare_inbound_message_text')"
python -m pytest tests/agent/test_image_routing.py tests/gateway/test_73771_media_resend_dedup.py \
  tests/gateway/test_busy_session_ack.py tests/gateway/test_context_ref_expansion_runtime.py \
  tests/gateway/test_discord_channel_prompts.py tests/gateway/test_fast_command.py \
  tests/gateway/test_image_input_routing_runtime.py tests/gateway/test_native_image_buffer_isolation.py \
  tests/gateway/test_post_stream_media_delivery.py tests/gateway/test_queued_native_image_session_key.py \
  tests/gateway/test_reply_to_injection.py tests/gateway/test_session.py \
  tests/gateway/test_shared_group_sender_prefix.py tests/gateway/test_streaming_tts_gateway_regression.py \
  tests/gateway/test_stt_config.py tests/gateway/test_telegram_audio_vs_voice.py \
  tests/gateway/test_telegram_voice_v0_regressions.py tests/gateway/test_tts_media_routing.py \
  tests/gateway/test_video_context_note.py tests/gateway/test_vision_memory_leak.py \
  tests/gateway/test_weixin.py tests/gateway/test_media_extraction.py tests/gateway/test_audio_cache.py \
  tests/gateway/test_media_cache.py tests/gateway/test_media_download_retry.py \
  tests/gateway/test_media_spaced_paths_and_history_dedupe.py tests/gateway/test_media_tag_cleanup.py \
  tests/gateway/test_media_tag_formatting_variants.py tests/gateway/test_media_tag_separator.py \
  tests/gateway/test_media_metadata_contract.py tests/gateway/test_history_media_current_turn.py -q

Platforms tested

  • Windows 10 (native), Python 3.11 via the repo venv. Import smoke + 260 targeted tests passed.
  • 5 failures in the targeted set (test_image_routing.py::TestExtractImageRefs::test_finds_absolute_path, ...test_finds_home_relative_path, test_73771_media_resend_dedup.py::test_streamed_explicit_media_resend_is_delivered, test_post_stream_media_delivery.py::test_explicit_media_tag_still_delivers_post_stream, test_media_spaced_paths_and_history_dedupe.py::TestHistoryMediaDedupe::test_quoted_spaced_home_path_is_collected_in_delivery_form) are pre-existing on pristine main — stash-proven identical without this change (Windows path-vs-file:// URL-encoding env issue, unrelated to the move).
  • git diff --check clean; scripts/check-windows-footguns.py clean on both files.

Shrink

  • gateway/run.py: 26,823 → 25,798 lines (net −1,025: 1,027 deleted − 2 added import/bases lines)
  • gateway/media_mixin.py: new, 1,077 lines (14 methods, ~1,007 body lines + header/imports/logger/_UNSET)

Scope note

This is a pure mechanical lift — no logic changes, no signature changes, no reordering of behavior. The moved methods are verified byte-identical to their originals modulo the documented lazy imports. Follow-up slices (voice, threads, platform, etc.) continue the campaign from the remaining GatewayRunner clusters.

Part of #54962
Part of #55138

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

@alt-glitch alt-glitch added type/refactor Code restructuring, no behavior change P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Aug 3, 2026
…ousResearch#54962)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
@andrexibiza
andrexibiza force-pushed the refactor/gateway-mixin-media branch from 88683e3 to cde3c94 Compare August 3, 2026 14:30
This was referenced Aug 4, 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