Skip to content

fix(gateway): preserve media attachments in /steer and /goal kickoff events - #57946

Open
Ahmett101 wants to merge 2 commits into
NousResearch:mainfrom
Ahmett101:fix/57928-slash-cmd-media-passthrough
Open

fix(gateway): preserve media attachments in /steer and /goal kickoff events#57946
Ahmett101 wants to merge 2 commits into
NousResearch:mainfrom
Ahmett101:fix/57928-slash-cmd-media-passthrough

Conversation

@Ahmett101

Copy link
Copy Markdown
Contributor

Summary

When a Telegram user invokes /steer or /goal with an attached file (document, photo, audio) captioned with the slash command, the file is silently dropped because only event.get_command_args() is forwarded. /queue already preserves media_urls / media_types / reply_to_* in its synthesized MessageEvent (#20906); /steer and /goal built the same MessageEvent(...) pattern but discarded every non-text field.

/subgoal was reported as affected, but its handler does not enqueue a synthetic MessageEvent — it only mutates the goal manager. No fix seam, out of scope.

Changes

gateway/run.py (/steer, ~L9010-9050): snapshot media_urls / media_types once at the top of the /steer branch, copy them through both fallback MessageEvent constructions (pending sentinel + no-agent), and append an [Attached files: <p1>, <p2>] hint to steer_text on the running-agent path so the model can read_file() the listed paths. AIAgent.steer() is text-only by contract (see run_agent.py:2719), so the API is unchanged.

gateway/slash_commands.py (/goal kickoff, ~L2269-2287): mirror the passthrough shape /queue uses, copy the same field set, and only flip message_type away from MessageType.TEXT when there is real media.

tests/gateway/test_steer_command.py: 3 new tests — running-agent carries [Attached files: …] hint; pending-sentinel fallback preserves media+reply fields; no-media regression guard so a plain /steer hello still steers with just "hello".

tests/gateway/test_goal_command_media_passthrough_57928.py (new): 2 tests — /goal <text> with attachment preserves media on kickoff; /goal <text> without attachment stays MessageType.TEXT.

How to Test

pytest tests/gateway/test_steer_command.py \
       tests/gateway/test_goal_command_media_passthrough_57928.py -q

All 10 tests in those two files pass (5 pre-existing + 5 new). The full slash-command family (10 files, 104 tests) stays green.

Risk & Impact

Low. Pure passthrough: the same field set /queue already trusts since #20906. No public API change (AIAgent.steer() signature unchanged). Worst-case regression: a user who attached a file to /steer and expected a path-free prompt body will now see [Attached files: …] in the steer text — but that case is the bug itself.

Closes #57928

Ahmett101 added 2 commits July 3, 2026 23:38
…cal and remote mode (NousResearch#57911)

A bare-new-session (Cmd+N without a project scope) in remote mode used to
inherit the remembered cwd under workspaceCwdKey()'s remote variant — i.e.
the last project the user attached to on that backend. Symptom: Cmd+N landed
on the wrong project's workspace (e.g. a configuration discussion thread
opened in the tradingview directory).

The remote branch in workspaceCwdForNewSession is the entire bug class:
- It overrides the configured-default-pre-attaches rule, so users who
  configured an explicit default didn't get it under remote mode either.
- The bare-new-session path has no notion of "remember where I was" —
  that's startSessionInWorktree's job. The remembered cwd is only meant
  to assist resume/restore (ensureDefaultWorkspaceCwd, which keeps its
  remote-keyed sticky seed and is unaffected by this change).

Drop the mode === 'remote' early return and route both modes through
getConfiguredDefaultProjectDir(), matching the proposed fix in the issue.

Test: the existing 'keeps remote workspace memory separate from local and
other remotes' case set the local key then switched connection to remote,
so under the buggy code it returned '' regardless — it never gated the
regression. Add a remote-key repro and a symmetric explicit-default test
so the fix is observable from the suite.
…events (NousResearch#57928)

When a Telegram user invoked /steer, /goal, /subgoal with an attached file
(photo, document, audio), the attachment was silently dropped because
only the slash-command args string was extracted from the MessageEvent
and forwarded. /queue already carries media_urls / media_types /
reply_to_* through the synthesized MessageEvent (NousResearch#20906); /steer and
/goal used the same MessageEvent(...) construction but lost every
non-text field. /subgoal doesn't synthesize events so it was a false
positive in the report — skipped.

Two layered fixes:

1. gateway/run.py (L9010-9050, /steer): before extracting steer_text,
   snapshot media_urls / media_types from the original event. For the
   fallback 'no agent / pending sentinel' MessageEvent, copy them
   through alongside reply_to_*. For the 'running agent' path the
   AIAgent.steer() API is text-only by contract — append an
   '[Attached files: ...]' hint to the steered text so the model knows
   which paths to read_file(). The hint mirrors the shape the normal
   message pipeline uses to surface attachment paths.

2. gateway/slash_commands.py (L2271-2287, /goal kickoff MessageEvent):
   mirror the same passthrough shape as /queue, and only switch
   message_type away from MessageType.TEXT when there is actually a
   media attachment (no fake attachment metadata on text-only /goal).

Tests: tests/gateway/test_steer_command.py gains three — the
'running-agent steers with [Attached files:] hint', the 'pending
sentinel fallback preserves all media fields', and a regression guard
that without media the steer text is just the command args. New
tests/gateway/test_goal_command_media_passthrough_57928.py covers the
/goal kickoff: with-attachment preserves media; without-attachment
stays MessageType.TEXT. 53/53 in the slash-command family pass.
@alt-glitch alt-glitch added type/bug Something isn't working comp/gateway Gateway runner, session dispatch, delivery platform/telegram Telegram bot adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages P2 Medium — degraded but workaround exists labels Jul 3, 2026
@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 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 P2 Medium — degraded but workaround exists platform/telegram Telegram bot adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG - file attachment broken

3 participants