-
Notifications
You must be signed in to change notification settings - Fork 83
Description
Problem Statement
The Chat SDK uses an adapter pattern for platforms (@chat-adapter/discord, @chat-adapter/slack) and state (Redis, Memory, community adapters). But the transport layer is hardcoded inside each platform adapter.
For Discord, startGatewayListener() requires discord.js and a long-running Node.js process. This makes it incompatible with all edge and non-Node runtimes (Vercel Edge Functions, Deno Deploy, Netlify Edge Functions, Fastly Compute, Supabase Edge Functions, Cloudflare Workers).
On Vercel Serverless Functions it works via a cron-restart pattern where each cycle creates a fresh discord.js client with an in-memory session store that's discarded on shutdown. Overlapping cycles can cause unpredictable handoff behavior since two clients compete for the same Gateway session.
This is the same problem described in #123 where the Slack adapter hardcodes HTTP webhook transport with no way to swap in Socket Mode. This required a patch of 200+ lines of compiled adapter output to make it work.
Discord has WebSocket vs. HTTP forwarding, Slack has HTTP webhooks vs. Socket Mode. Each time, the transport is locked in because there's no abstraction boundary between platform logic and event delivery.
Proposed Solution
Introduce a transport/listener adapter interface that platform adapters can accept, allowing the event delivery mechanism to be swapped independently of platform logic.
Platform adapters would accept an optional gatewayListener config. startGatewayListener() continues to work as it does today. The interface just allows alternatives for runtimes or deployment patterns where the built-in approach doesn't fit.
This follows the same pattern the SDK already uses for state adapters: a defined interface with a default implementation and community-contributed alternatives.
Alternatives Considered
The current workaround for any platform with a WebSocket-based event source is to independently implement the protocol outside the SDK and forward events in whatever format the adapter's handleWebhook() expects. For Discord, this means matching the GATEWAY_<EVENT> type prefix, x-discord-gateway-token header, and { type, timestamp, data } body shape (e.g. discord-gateway-cloudflare-do (https://github.com/dcartertwo/discord-gateway-cloudflare-do)). For Slack Socket Mode (#123), a community member patched 200+ lines of compiled adapter output to wire in @slack/socket-mode.
Each platform ends up with its own ad-hoc solution, coupled to undocumented internal details that could break with any adapter release. A transport adapter interface would replace these per-platform workarounds with a single extensibility pattern.
Use Case
import { Chat } from "chat";
import { createDiscordAdapter } from "@chat-adapter/discord";
import { createCustomGateway } from "some-community-package";
const bot = new Chat({
userName: "my-bot",
adapters: {
discord: createDiscordAdapter({
botToken: process.env.DISCORD_BOT_TOKEN,
publicKey: process.env.DISCORD_PUBLIC_KEY,
applicationId: process.env.DISCORD_APPLICATION_ID,
// Pluggable transport — replaces startGatewayListener()
gatewayListener: createCustomGateway({ /* runtime-specific config */ }),
}),
},
});
// Same bot logic — transport is transparent
bot.onNewMention(async (thread, message) => {
await thread.post(`Hello! You said: ${message.text}`);
});Priority
Nice to have
Contribution
- I am willing to help implement this feature
Additional Context
Related issues:
- Slack Socket Mode Support #123 — Slack Socket Mode (same problem: alternative transport for an existing platform adapter)
- Add a Generic Webhook / HTTP Adapter for Arbitrary Chat Platforms #96 — Generic Webhook Adapter (related: new platforms via HTTP, not transport within existing adapters)
- Request for Adapters #157 — Community Adapters (transport adapters would be a new category alongside state adapters)