Skip to content

GH-55: feat(sdk/integrations/slack): add Socket Mode ChatBridge + adapter (first ext dep: gorilla/websocket)#58

Merged
alekspetrov merged 3 commits into
mainfrom
pilot/GH-55
Jun 3, 2026
Merged

GH-55: feat(sdk/integrations/slack): add Socket Mode ChatBridge + adapter (first ext dep: gorilla/websocket)#58
alekspetrov merged 3 commits into
mainfrom
pilot/GH-55

Conversation

@alekspetrov

Copy link
Copy Markdown
Contributor

Summary

Automated PR created by Pilot for task GH-55.

Closes #55

Changes

GitHub Issue #55: feat(sdk/integrations/slack): add Socket Mode ChatBridge + adapter (first ext dep: gorilla/websocket)

Context

Second half of the Slack chat connector — depends on the client/data issue.
Implement the Socket Mode listener + the core.ChatBridge/ChatCapable adapter.
Source from /tmp/pilot-src/internal/adapters/slack/ (socket_mode.go,
socketmode.go, handler.go). Mirror sdk/integrations/telegram/ (bridge.go +
adapter.go) and the chat contract (.agent/system/chat-bridge-design.md).

This is the first SDK runtime external dependency — Socket Mode needs a
WebSocket client (github.com/gorilla/websocket, as in Pilot). go.mod require

  • go.sum appear in the repo for the first time → run make tidy and commit
    both go.mod and go.sum
    . sdk/{core,log,util,testutil} stay stdlib-only.

Implementation

Add to sdk/integrations/slack/: socketmode.go (WS client), bridge.go
(core.ChatBridge), adapter.go (core.ChatCapable), + tests. Transformations:

  • Remove every github.com/qf-studio/pilot/... import; inject *slog.Logger.
  • Port the Socket Mode WS client (connect to the Slack gateway via apps.connections.open,
    hello/authenticate, heartbeat, read envelopes, ack). Uses gorilla/websocket.
  • adapter.go: Adapter with Name() "slack" + NewChatBridge(core.ChatDeps) core.ChatBridge. Compile-time: var _ core.Adapter = (*Adapter)(nil),
    var _ core.ChatCapable = (*Adapter)(nil), var _ core.ChatBridge = (*bridge)(nil).
  • bridge.go implements core.ChatBridge:
    • Start(ctx) — run the Socket Mode loop; for each inbound envelope map to a
      core.MessageEvent: message/app_mentionAction:"message" (text with
      bot-mention stripped, sanitized in the loop before the handler — CRITICAL,
      the feat(sdk/integrations/github): port client, types, converter, notifier, webhook #28-class rule); leading /Action:"command" (Command+Args, no
      execution); block_actionsAction:"callback" (CallbackID = action_id,
      Data = value). Enforce AllowedChannels/AllowedUsers. ChannelID = channel,
      ThreadID = thread_ts.
    • Send(ctx, OutboundMessage) (MessageRef, error)PostMessage, or
      PostInteractiveMessage rendering OutboundMessage.Buttons as a Block Kit
      actions block. MessageRef = {ChannelID, MessageID: ts, ThreadID}.
    • Edit(ctx, ref, text)UpdateMessage by ts.
    • Ack(ctx, callbackID) — ack the Socket Mode envelope for that interaction.
  • Tests use sdk/testutil fakes; include a guard that inbound Text with
    invisible-Unicode smuggling is sanitized before the handler sees it. Use an
    httptest/fake-WS seam so tests don't hit the network.

⛔ Touch ONLY sdk/integrations/slack/ and the top-level go.mod/go.sum for
the new dep. Do not modify sdk/core/ or other connectors.

Acceptance

  • socketmode.go, bridge.go, adapter.go (+ tests) exist; the 3 compile-time core assertions present; Name() returns "slack".
  • Start maps message/command/callback (block_actions) to core.MessageEvent; inbound Text sanitized in the live loop before HandleMessage (grep shows the call-site).
  • go.mod + go.sum committed (gorilla/websocket); go mod tidy a no-op when re-run; sdk/{core,log,util,testutil} still stdlib-only.
  • grep -rn "qf-studio/pilot" sdk/ nothing; no command EXECUTION; Send renders Buttons as Block Kit.
  • go build ./..., go vet ./..., go test -race ./sdk/integrations/slack/..., gofmt -l sdk/ all clean.

Implements core.ChatBridge and core.ChatCapable for Slack via Socket Mode.

- socketmode.go: WebSocket client (SocketModeClient + SocketModeHandler);
  handles connect/reconnect via apps.connections.open, ping/pong heartbeat,
  envelope ack, and all envelope types (events_api, interactive, slash_commands).
  First SDK runtime external dep: github.com/gorilla/websocket v1.5.3.
- bridge.go: core.ChatBridge implementation; maps events_api message/app_mention
  to Action:"message" (sanitized) or Action:"command" for /- prefixed text;
  maps interactive block_actions to Action:"callback" (CallbackID=action_id,
  Data=value); enforces AllowedChannels/AllowedUsers; renders Buttons as Block
  Kit actions block in Send; Edit via chat.update; Ack is no-op (WS-level ack
  handled automatically by SocketModeHandler).
- adapter.go: Adapter with Name()="slack", NewChatBridge, and three compile-time
  core interface assertions.
- types.go: add ThreadTS to InteractiveMessage for threaded sends.
- go.mod + go.sum: gorilla/websocket v1.5.3 (direct dep).

sdk/{core,log,util,testutil} remain stdlib-only.
@alekspetrov alekspetrov merged commit 5749561 into main Jun 3, 2026
3 checks passed
@alekspetrov alekspetrov deleted the pilot/GH-55 branch June 3, 2026 09:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(sdk/integrations/slack): add Socket Mode ChatBridge + adapter (first ext dep: gorilla/websocket)

1 participant