Skip to content

feat(v0.2): bundled Slack + Discord chat-platform adapters ([slack] / [discord] extras) #7

Description

@pardamike

Problem

The FAQ promises bundled Slack and Discord adapters for v0.2. Unlike the HTTP / OpenAI / Anthropic adapters, Slack and Discord bots are event-driven: you post a message to a channel and the bot replies asynchronously. The ChatbotAdapter.send_message(prompt) -> ChatbotResponse contract is synchronous, so each adapter must post a message and then wait for the bot-under-test's reply (filtered by author id) in that channel/thread, with a timeout.

An OpenAI Assistants adapter was also considered — skip it. The Assistants API is deprecated with an Aug 26 2026 sunset; a new adapter would be dead code. The existing [openai] adapter (Chat Completions / Responses) is the right surface; extend it if stateful threads are needed.

Proposed approach

  • adapters/slack_chat.pySlackChatbotAdapter + AsyncSlackChatbotAdapter, [slack] extra (slack-sdk>=3.40). WebClient only (no Bolt / Socket Mode / event loop). send_message: chat_postMessage → poll conversations_replies(oldest=sent_ts), filter for the bot's user/bot id. Exponential backoff (first sleep ~3s, cap ~8s) to respect the non-Marketplace 1 req/min cap on conversations.replies. session_id → a thread anchored on the first message's ts; reset_session drops it.
  • adapters/discord_chat.pyDiscordChatbotAdapter + AsyncDiscordChatbotAdapter, [discord] extra (discord.py>=2.7). REST polling (GET /channels/{id}/messages?after={sent_id}) — avoids a persistent gateway connection and the MESSAGE_CONTENT privileged intent. Filter for author.id == bot_user_id.
  • Common: lazy import + install hint; constructor channel_id, bot_user_id, token from env, timeout_s=30, poll_interval_s, reply_strategy: "first" | "concat" (for multi-message replies); redact the token from raw; raise WardenBotInfraError on API error / timeout (never AssertionError).
  • Tests mock the HTTP layer (respx) — no real workspace needed in CI; live tests behind an env-var guard.
  • Separate [slack] / [discord] extras (don't force both).

Acceptance criteria

  • SlackChatbotAdapter / AsyncSlackChatbotAdapter satisfy the (async) Protocol; to_sync() round-trips.
  • DiscordChatbotAdapter / AsyncDiscordChatbotAdapter satisfy the (async) Protocol.
  • Lazy import; missing extra → ImportError with install hint.
  • reset_session starts a fresh thread/conversation on the next send_message.
  • Timeout → WardenBotInfraError (not TimeoutError / AssertionError).
  • Token redacted from ChatbotResponse.raw.
  • Slack polling respects the 1 req/min conversations.replies cap (backoff; documented).
  • Unit tests (mocked HTTP) pass with no real credentials; optional live tests behind a guard.
  • [slack] / [discord] extras added; nothing added to the base install.
  • Docs: Slack + Discord how-to (scopes/permissions, finding bot_user_id, rate-limit notes); FAQ link updated.

References

Complexity: needs-maintainer (Slack rate-limit polling strategy + HTTP-mock test pattern).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestneeds-maintainerNeeds maintainer design; not a first issuev0.2v0.2 roadmap

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions