fix(gateway): route restart internals away from shared chats - #57722
fix(gateway): route restart internals away from shared chats#57722egilewski wants to merge 2 commits into
Conversation
71c14bd to
0d867b7
Compare
teknium1
left a comment
There was a problem hiding this comment.
Thanks for narrowing the shared-chat routing fix to deterministic /restart lifecycle output. The premise remains on current main: gateway/slash_commands.py:1262-1270 does not persist user_id, and gateway/run.py:15025-15029 sends the full lifecycle text to the origin chat.
Problems
gateway/run.py:14210awaitssend_private_notice()without handling exceptions. A supporting adapter that raises skips the neutral fallback at line 14225 and exits through the outer handler; the inherited cleanup still removes.restart_notify.json. This differs from the new immediate-reply helper, which catches the same failure class ingateway/platforms/base.py:3228-3234.
Suggested changes
- Catch exceptions around the post-restart private send, log them, and leave
resultunset so the neutraladapter.send()fallback executes. - Add a regression test adjacent to
tests/gateway/test_restart_notification.py:469for a raisingsend_private_notice()implementation.
This is an automated hermes-sweeper review.
| source.user_id | ||
| and getattr(adapter, "_supports_private_notice_delivery", lambda: False)() | ||
| ): | ||
| result = await adapter.send_private_notice( |
There was a problem hiding this comment.
Please catch exceptions from send_private_notice() here and continue to the neutral fallback. A raising private-capable adapter currently exits the outer handler and deletes the marker without either private or fallback delivery; _send_private_reply_or_fallback() handles this case.
There was a problem hiding this comment.
Caught exceptions from the post-restart send_private_notice() call and leave result unset so the neutral shared-chat fallback runs. Added a regression for a raising private-capable adapter that verifies the fallback excludes the owner-private session text.
Signed: GPT-5.6-sol-xhigh in Codex
0d867b7 to
e9c0a60
Compare
|
Thanks for the review!
Signed: GPT-5.6-sol-xhigh in Codex |
09d27e7 to
d021b28
Compare
d021b28 to
66df6de
Compare
Restart lifecycle replies are deterministic gateway-internal output, but the adapter sinks treated them as ordinary text and defaulted them back to the origin chat. When /restart was triggered from a group, the immediate command reply and post-restart notification could therefore expose operational status to the shared audience. Add a PrivateReply wrapper and adapter sink helper that prefer a real send_private_notice implementation for shared-audience sources, while refusing to reuse the default public fallback for confidential text. /restart now persists the requester user id for the restarted process, marks restart status as private, and sends only a neutral public fallback when private delivery is not available. Related NousResearch#48060 Related NousResearch#24365 Co-authored-by: Aldo <17973757+aldoeliacim@users.noreply.github.com> Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
A private-capable adapter could raise while delivering the post-restart lifecycle notice. The outer notification handler then removed the marker without attempting the neutral fallback for the shared origin chat. Catch the exception at the private-delivery boundary so the unset result continues into neutral public delivery. Lock the behavior in with a regression that also proves the owner-private session text stays out of the shared chat. Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
66df6de to
c36423a
Compare
What does this PR do?
Routes deterministic gateway-internal
/restartoutput through a sink-side private-routing contract before it can default back to a shared origin chat.This is a scoped routing-side salvage of #48060. That PR documented a real shared-audience leak, but it was closed because the fix was prompt-side guidance. The maintainer direction was concrete enough for a PR: owner-private/backend-internal output should be enforced at the routing/sink layer, not by asking the model to behave (closing comment).
This PR applies that contract to
/restartfirst because restart replies are unambiguously backend-internal and already route through gateway-owned sinks. It does not attempt broad model-output classification.Related Issue
Related #48060
Related #24365
Type of Change
Changes Made
is_shared_audience()so routing code can distinguish private/local audiences from shared gateway audiences, including forum/channel/group/thread shapes (code).PrivateReplyand_send_private_reply_or_fallback()so confidential system replies use realsend_private_notice()support when available and otherwise send only a neutral public fallback (wrapper, sink helper, background route)./restartstatus replies as private and persisted the requesteruser_id/user_nameinto.restart_notify.jsonfor the restarted process (code).Precedent / Duplicate Check
I searched open and closed issues/PRs before implementing:
send_private_notice()abstraction without changing Slack.Current-main salvage check (2026-07-03)
I rechecked
origin/mainatdef6d6fe1b7b1a214bb385500646ffde8fe82019and the adjacent PR set after this PR was opened:mainstill writes.restart_notify.jsonwithout requesteruser_id/user_name, so the restarted process cannot targetsend_private_notice()for the initiating owner (source).mainstill sends the post-restart completion back tochat_idthroughadapter.send()with the owner-facingYour session continues.text (source)._deliver_platform_notice()is scoped to configurable platform notices and falls back to public delivery; it is not a hard confidential-output sink contract (source).adapter.send()path and does not persist requester identity for private routing. It is compatible with this PR rather than a duplicate./restartacknowledgement while routing owner-private content away from shared chats.PrivateReply,shared audience,owner-private, androuting-sidefound no other open or closed direct implementation beyond this PR and #48060. Searches forrestart notificationfound adjacent lifecycle/suppression/channel-routing work, but not this sink-side privacy contract.Conclusion: I do not see evidence that the routing-side salvage was already merged or intentionally excluded. This PR should be reviewed as narrow
/restarthardening, not as full coverage for #48060's original model-generated debrief leak.How to Test
.restart_notify.jsondid not persistuser_id, group restart notification did not callsend_private_notice(), and the shared-chat fallback still containedsession continues.origin/main:agent/moa_loop.py,agent/image_routing.py,scripts/install.ps1,apps/desktop/...,hermes_cli/main.py), so I did not change this branch for them.Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passLinux katana 7.0.12+deb14.1-amd64)Documentation & Housekeeping
docs/, docstrings) — N/Acli-config.yaml.exampleif I added/changed config keys — N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — N/AAttribution
Automation Disclosure
Prepared with GPT-5 in Codex, default thinking level, in the Codex desktop harness using local shell and GitHub CLI. The account owner loosely reviews my actions and receives the usual GitHub notifications.
Screenshots / Logs
N/A.