Conversation
|
@VascoSch92 @enyst, could one of you take a look when you have a moment? This is a focused follow-up to the Socket Mode work from #384: existing |
|
🚦 CI is currently failing on this PR's latest commit. Please fix the failing checks before OpenHands reviews it - this is re-checked automatically once you push a new commit. (A maintainer can also request This is an automated check - no AI was used to generate this comment. |
|
The failed unit-test job is a shared CI dependency failure, not a Slack stream assertion failure: 1,703 tests passed, then all 17 S3 integration cases failed in fixture setup because Docker Hub no longer serves the pinned MinIO image. The registry repair is isolated in #447. |
|
The implementation matches the spec in #442 exactly, but I think the spec itself is wrong. Slack threads are flat, and So The filter only fires when the bot posts a new top-level message, which is the digest case, not the conversational one. It should accept threads the bot has posted into, not only threads the bot rooted. Could you please double check that? And also see if you can create an automation where you show the behaviour? |
|
|
@VascoSch92 Thanks for catching the I also ran the corrected flow against a real Slack workspace over Socket Mode:
The harness exercised the real Slack threadToken-free terminal result |


Why
Slack Socket Mode forwarded
app_mentionevents, but an ordinary human reply in an existing Slack thread arrives as amessageevent. That prevented a user from naturally continuing an automation conversation without mentioning the bot again.The issue's initial
parent_user_id == bot_user_idproposal does not cover the normal conversational shape because Slack threads are flat:parent_user_ididentifies the thread-root author. A human mention therefore creates a human-authored root even after the bot replies inside it.What changed
messageevents whenthread_tsis present.AcceptedEvent.existing_subject_only, defaulting tofalsefor existing transports.dispatch_runtriggers.app_mention-only automations unchanged.Routing decision
app_mentionmessage, bot-authored rootmessage, human-authored rootmessagein an unrelated human threadThe ownership check uses the existing durable
AutomationRun.subject_key. It works across restarts and multiple Socket Mode replicas without a process-local thread cache, Slack history lookup, or schema migration.An automation that wants natural follow-ups must listen for both event keys and resolve the opener and replies to the same subject:
{ "type": "event", "source": "slack", "on": ["app_mention", "message"], "destination": "continue_conversation", "subject_key_expr": "join('/', [team_id, event.channel, event.thread_ts || event.ts])" }Verification
Regression coverage includes:
dispatch_runtrigger being unable to bypass the follow-up-only guard;Results:
uv run pre-commit run --files ... --show-diff-on-failure— passed (Ruff format/lint, pycodestyle, Pyright).total runs: 1.The live proof exercises the real Slack connection,
SlackStreamProvider,accept_event(), durable subject lookup, and queued-run coalescing. It intentionally does not run an LLM or Agent Server; it verifies the routing responsibility owned by this repository.HUMAN: I ran the real Slack mention and unmentioned follow-up flow and reviewed the token-free PASS output.
Operational scope
The Slack app must subscribe to
message.channelsand have thechannels:historybot scope for public-channel replies.The issue also mentions an event-driven
slack-channel-monitorchange inOpenHands/extensions. Currentmainthere contains a cron-polling implementation and does not contain the referencedevent_payload/app_mentionguard, so this PR does not modify that separate implementation.All temporary
.pr/review artifacts were removed in094665aand will not be merged.Fixes #442