Documentation
¶
Overview ¶
Package bot provides bot adapters for various IM platforms.
This package implements a unified interface for connecting to multiple chat platforms, including Discord, Telegram, Feishu (Lark), and DingTalk. Each adapter handles platform-specific connection logic, message formatting, and communication patterns.
Supported Platforms ¶
- Discord: WebSocket connection with real-time message handling
- Telegram: Long polling for message updates
- Feishu/Lark: WebSocket long connection for enterprise messaging
- DingTalk: WebSocket long connection for enterprise messaging
Usage ¶
To use a bot adapter:
- Create a bot instance using the New* function for your platform
- Call Start() with a message handler callback
- Send messages using SendMessage()
- Call Stop() when shutting down
Example:
discordBot := bot.NewDiscordBot(token, channelID)
err := discordBot.Start(func(msg bot.BotMessage) {
fmt.Printf("Received: %s\n", msg.Content)
})
if err != nil {
log.Fatal(err)
}
discordBot.SendMessage(channelID, "Hello, world!")
discordBot.Stop()
Thread Safety ¶
All bot adapters are thread-safe and use internal mutexes to protect shared state. The message handler callback may be called concurrently from multiple goroutines.
Index ¶
- Constants
- func DefaultCredentialsPath() string
- func FormatQuoteBlock(q *QuotedMessage) string
- func MaskSecret(s string) string
- type ApiError
- type Attachment
- type BotAdapter
- type BotMessage
- type C2CMessageData
- type ContentBlock
- type ContentBlockType
- type Credentials
- type Debounceable
- type DefaultTypingIndicator
- type DingTalkBot
- func (d *DingTalkBot) GetMessageHandler() func(BotMessage)
- func (d *DingTalkBot) SendMessage(conversationID, message string) error
- func (d *DingTalkBot) SetMessageHandler(handler func(BotMessage))
- func (d *DingTalkBot) SetProxyManager(mgr proxy.Manager)
- func (d *DingTalkBot) Start(messageHandler func(BotMessage)) error
- func (d *DingTalkBot) Stop() error
- type DiscordBot
- func (d *DiscordBot) GetMessageHandler() func(BotMessage)
- func (d *DiscordBot) SendMessage(channel, message string) error
- func (d *DiscordBot) SetMessageHandler(handler func(BotMessage))
- func (d *DiscordBot) SetProxyManager(mgr proxy.Manager)
- func (d *DiscordBot) Start(messageHandler func(BotMessage)) error
- func (d *DiscordBot) Stop() error
- type DiscordMessage
- type DiscordSessionInterface
- type GatewayPayload
- type HelloData
- type IdentifyData
- type MediaSupporter
- type MentionPolicy
- type PendingQueue
- type ProcessPool
- type QQBot
- func (q *QQBot) AddTypingIndicator(messageID string) bool
- func (q *QQBot) GetMessageHandler() func(BotMessage)
- func (q *QQBot) RemoveTypingIndicator(messageID string) error
- func (q *QQBot) SendMessage(channel, message string) error
- func (q *QQBot) SetMessageHandler(handler func(BotMessage))
- func (q *QQBot) SetProxyManager(mgr proxy.Manager)
- func (q *QQBot) Start(messageHandler func(BotMessage)) error
- func (q *QQBot) Stop() error
- func (q *QQBot) SupportsTypingIndicator() bool
- type QQGatewayResponse
- type QQTokenResponse
- type Quotable
- type QuotedMessage
- type Replyable
- type RichMessageHandle
- type RichMessageOptions
- type RichMessenger
- type SendMessageRequest
- type SendMessageResponse
- type TelegramBot
- func (t *TelegramBot) GetMessageHandler() func(BotMessage)
- func (t *TelegramBot) SendMessage(chatID, message string) error
- func (t *TelegramBot) SetMessageHandler(handler func(BotMessage))
- func (t *TelegramBot) SetProxyManager(mgr proxy.Manager)
- func (t *TelegramBot) Start(messageHandler func(BotMessage)) error
- func (t *TelegramBot) Stop() error
- type Threadable
- type WeixinBot
- func (b *WeixinBot) AddTypingIndicator(messageID string) bool
- func (b *WeixinBot) RemoveTypingIndicator(messageID string) error
- func (b *WeixinBot) SendMessage(channel, message string) error
- func (b *WeixinBot) SetProxyManager(mgr proxy.Manager)
- func (b *WeixinBot) Start(messageHandler func(BotMessage)) error
- func (b *WeixinBot) Stop() error
Constants ¶
const ( QQTokenURL = "https://bots.qq.com/app/getAppAccessToken" QQAPIBase = "https://api.sgroup.qq.com" QQGatewayURL = QQAPIBase + "/gateway" )
QQ Bot API endpoints
const ( OPDispatch = 0 // Event dispatch OPHeartbeat = 1 // Heartbeat OPIdentify = 2 // Identify OPResume = 6 // Resume OPReconnect = 7 // Reconnect request OPInvalidSession = 9 // Invalid session OPHello = 10 // Hello OPHeartbeatAck = 11 // Heartbeat acknowledgement )
WebSocket OP codes (https://bots.qq.com/docs/gateway/gateway-events)
const ( MessageTypeUser = 1 MessageTypeBot = 2 )
const ( MessageStateNew = 0 MessageStateGenerating = 1 MessageStateFinish = 2 )
const ( MessageItemTypeText = 1 MessageItemTypeImage = 2 MessageItemTypeVoice = 3 MessageItemTypeFile = 4 MessageItemTypeVideo = 5 )
const ( QRStatusWait = "wait" QRStatusScaned = "scaned" QRStatusConfirmed = "confirmed" QRStatusExpired = "expired" )
const ( DefaultBaseURL = "https://ilinkai.weixin.qq.com" DefaultBaseVersion = "1.0.0" QRCodePollInterval = 2 * time.Second APITimeout = 15 * time.Second MaxMessageLength = 2000 MaxChunkLength = 2000 SessionExpiredErrCode = -14 )
const (
IntentPublicMessages = 1 << 25 // Public message events (1 << 25)
)
Intents for subscribing to events
Variables ¶
This section is empty.
Functions ¶
func DefaultCredentialsPath ¶ added in v0.1.2
func DefaultCredentialsPath() string
func FormatQuoteBlock ¶ added in v0.1.8
func FormatQuoteBlock(q *QuotedMessage) string
FormatQuoteBlock formats a quoted message for CLI context injection.
func MaskSecret ¶ added in v0.1.8
MaskSecret masks sensitive information for logging
Types ¶
type ApiError ¶ added in v0.1.2
func (*ApiError) IsSessionExpired ¶ added in v0.1.2
type Attachment ¶ added in v0.1.8
type Attachment struct {
Type string // "image", "file", "video", "audio"
FileName string // Original filename
FilePath string // Local path after download
FileKey string // Platform-specific resource key
MimeType string // Inferred MIME type
Size int64 // File size in bytes
}
Attachment represents a downloaded media file attached to a message.
type BotAdapter ¶
type BotAdapter interface {
// Start starts the bot, establishes connection and begins listening for messages
Start(messageHandler func(BotMessage)) error
// SendMessage sends a message to the IM platform
// Adapter is responsible for:
// - Truncating to platform limits
// - Splitting long messages when necessary
// - Platform-specific formatting
SendMessage(channel, message string) error
// SupportsTypingIndicator returns true if the platform supports typing indicators
SupportsTypingIndicator() bool
// AddTypingIndicator adds a typing indicator to a message (if supported)
// messageID is the ID of the user's message to react to
// Returns true if successfully added
AddTypingIndicator(messageID string) bool
// RemoveTypingIndicator removes the typing indicator from a message
RemoveTypingIndicator(messageID string) error
// SetProxyManager sets the proxy manager for the bot
SetProxyManager(mgr proxy.Manager)
// Stop stops the bot and cleans up resources
Stop() error
}
BotAdapter defines the interface for bot adapters
type BotMessage ¶
type BotMessage struct {
Platform string // feishu/discord/telegram
UserID string // Unique user identifier (for permission control)
Channel string // Channel/session ID
MessageID string // Message ID (for typing indicator)
Content string // Message content
Timestamp time.Time
ThreadID string // Optional: thread/topic ID
QuoteID string // Optional: parent message ID (reply context)
ChatType string // Optional: "p2p", "group", "topic"
SenderName string // Optional: display name of sender
MessageType string // Optional: "text", "image", "file", "audio", "video", "post"
Attachments []Attachment // Optional: downloaded media files
}
BotMessage represents a bot message structure
type C2CMessageData ¶
type C2CMessageData struct {
ID string `json:"id"`
Timestamp string `json:"timestamp"`
Author struct {
UserOpenID string `json:"user_openid"`
} `json:"author"`
Content string `json:"content"`
}
C2CMessageData represents C2C (private chat) message data from WebSocket event
type ContentBlock ¶ added in v0.1.8
type ContentBlock struct {
Type ContentBlockType
Title string // Block title (e.g., tool name)
Content string // Markdown content
Collapsed bool // Whether to collapse by default
Meta map[string]string // Tool-specific metadata (command, file_path, etc.)
}
ContentBlock represents a logical piece of rich reply content.
type ContentBlockType ¶ added in v0.1.8
type ContentBlockType string
ContentBlockType enumerates the kinds of content blocks for rich replies.
const ( ContentBlockText ContentBlockType = "text" ContentBlockToolCall ContentBlockType = "tool_call" ContentBlockToolResult ContentBlockType = "tool_result" ContentBlockThinking ContentBlockType = "thinking" ContentBlockStatus ContentBlockType = "status" )
type Credentials ¶ added in v0.1.2
type Debounceable ¶ added in v0.1.8
type Debounceable interface {
DebounceWindow() int // milliseconds; 0 = disabled
}
Debounceable is an optional interface for channels that benefit from message debouncing (coalescing rapid-fire messages).
type DefaultTypingIndicator ¶
type DefaultTypingIndicator struct{}
DefaultTypingIndicator provides default empty implementations for typing indicator methods This can be embedded in bot adapters that don't support typing indicators
func (*DefaultTypingIndicator) AddTypingIndicator ¶
func (d *DefaultTypingIndicator) AddTypingIndicator(messageID string) bool
AddTypingIndicator does nothing (not supported by default)
func (*DefaultTypingIndicator) RemoveTypingIndicator ¶
func (d *DefaultTypingIndicator) RemoveTypingIndicator(messageID string) error
RemoveTypingIndicator does nothing (not supported by default)
func (*DefaultTypingIndicator) SupportsTypingIndicator ¶
func (d *DefaultTypingIndicator) SupportsTypingIndicator() bool
SupportsTypingIndicator returns false (not supported by default)
type DingTalkBot ¶
type DingTalkBot struct {
DefaultTypingIndicator
// contains filtered or unexported fields
}
DingTalkBot implements BotAdapter interface for DingTalk using WebSocket long connection
func NewDingTalkBot ¶
func NewDingTalkBot(clientID, clientSecret string) *DingTalkBot
NewDingTalkBot creates a new DingTalk bot instance
func (*DingTalkBot) GetMessageHandler ¶
func (d *DingTalkBot) GetMessageHandler() func(BotMessage)
GetMessageHandler gets the message handler in a thread-safe manner
func (*DingTalkBot) SendMessage ¶
func (d *DingTalkBot) SendMessage(conversationID, message string) error
SendMessage sends a message to a DingTalk conversation
func (*DingTalkBot) SetMessageHandler ¶
func (d *DingTalkBot) SetMessageHandler(handler func(BotMessage))
SetMessageHandler sets the message handler in a thread-safe manner
func (*DingTalkBot) SetProxyManager ¶
func (d *DingTalkBot) SetProxyManager(mgr proxy.Manager)
SetProxyManager sets the proxy manager for the DingTalk bot
func (*DingTalkBot) Start ¶
func (d *DingTalkBot) Start(messageHandler func(BotMessage)) error
Start establishes WebSocket long connection to DingTalk and begins listening for messages
func (*DingTalkBot) Stop ¶
func (d *DingTalkBot) Stop() error
Stop closes the DingTalk WebSocket connection and cleans up resources
type DiscordBot ¶
type DiscordBot struct {
DefaultTypingIndicator
// contains filtered or unexported fields
}
DiscordBot implements BotAdapter interface for Discord
func NewDiscordBot ¶
func NewDiscordBot(token, channelID string) *DiscordBot
NewDiscordBot creates a new Discord bot instance
func (*DiscordBot) GetMessageHandler ¶
func (d *DiscordBot) GetMessageHandler() func(BotMessage)
GetMessageHandler gets the message handler in a thread-safe manner
func (*DiscordBot) SendMessage ¶
func (d *DiscordBot) SendMessage(channel, message string) error
SendMessage sends a message to a Discord channel
func (*DiscordBot) SetMessageHandler ¶
func (d *DiscordBot) SetMessageHandler(handler func(BotMessage))
SetMessageHandler sets the message handler in a thread-safe manner
func (*DiscordBot) SetProxyManager ¶
func (d *DiscordBot) SetProxyManager(mgr proxy.Manager)
SetProxyManager sets the proxy manager for the Discord bot
func (*DiscordBot) Start ¶
func (d *DiscordBot) Start(messageHandler func(BotMessage)) error
Start establishes connection to Discord and begins listening for messages
func (*DiscordBot) Stop ¶
func (d *DiscordBot) Stop() error
Stop closes the Discord connection and cleans up resources
type DiscordMessage ¶
type DiscordMessage interface {
ID() string
}
DiscordMessage represents a Discord message for our interface
type DiscordSessionInterface ¶
type DiscordSessionInterface interface {
AddHandler(handler interface{}) func()
Open() error
Close() error
ChannelMessageSend(channelID string, content string, options ...discordgo.RequestOption) (*discordgo.Message, error)
}
DiscordSessionInterface defines the interface we need from discordgo.Session This allows us to mock it in tests without depending on concrete types
type GatewayPayload ¶
type GatewayPayload struct {
OP int `json:"op"`
D interface{} `json:"d,omitempty"`
S *int `json:"s,omitempty"`
T string `json:"t,omitempty"`
}
GatewayPayload represents a WebSocket gateway message
type HelloData ¶
type HelloData struct {
HeartbeatInterval int `json:"heartbeat_interval"`
}
HelloData contains heartbeat_interval from OP Hello
type IdentifyData ¶
type IdentifyData struct {
Token string `json:"token"`
Intents int `json:"intents"`
Shard []int `json:"shard"`
}
IdentifyData contains identify payload
type MediaSupporter ¶ added in v0.1.8
type MediaSupporter interface {
DownloadMedia(ctx context.Context, msg *BotMessage) error
}
MediaSupporter is an optional interface for channels that support media download.
type MentionPolicy ¶ added in v0.1.8
type MentionPolicy interface {
ShouldRespond(msg BotMessage) bool
}
MentionPolicy is an optional interface for channels that need to filter messages based on mention rules (e.g. only respond to @bot in groups).
type PendingQueue ¶ added in v0.1.8
type PendingQueue struct {
// contains filtered or unexported fields
}
PendingQueue coalesces messages per key using configurable debounce windows. When a message is added, the timer resets. When the window expires, all accumulated messages for that key are flushed to the handler in a single batch.
func NewPendingQueue ¶ added in v0.1.8
func NewPendingQueue(handler func([]BotMessage)) *PendingQueue
NewPendingQueue creates a new PendingQueue that batches messages per key.
func (*PendingQueue) Add ¶ added in v0.1.8
func (pq *PendingQueue) Add(key string, msg BotMessage, window time.Duration)
Add adds a message to the pending queue for the given key and resets the debounce timer. If the queue is stopped, the message is dropped.
func (*PendingQueue) Block ¶ added in v0.1.8
func (pq *PendingQueue) Block(key string)
Block stops the timer for the given key but keeps accumulated messages. Useful for holding messages while processing.
func (*PendingQueue) Stop ¶ added in v0.1.8
func (pq *PendingQueue) Stop()
Stop cleans up all pending timers. No further flushes will occur.
func (*PendingQueue) Unblock ¶ added in v0.1.8
func (pq *PendingQueue) Unblock(key string)
Unblock restarts the debounce timer for the given key using the stored window duration. If there are no pending messages, this is a no-op.
type ProcessPool ¶ added in v0.1.8
type ProcessPool struct {
// contains filtered or unexported fields
}
ProcessPool limits concurrent CLI runs using a buffered channel as a counting semaphore. A nil or zero-cap pool is a no-op (unlimited concurrency).
func NewProcessPool ¶ added in v0.1.8
func NewProcessPool(maxRuns int) *ProcessPool
NewProcessPool creates a pool with the given capacity. Returns nil if maxRuns <= 0 (no limit).
func (*ProcessPool) Acquire ¶ added in v0.1.8
func (p *ProcessPool) Acquire()
Acquire blocks until a permit is available. No-op if the pool is nil.
func (*ProcessPool) Cap ¶ added in v0.1.8
func (p *ProcessPool) Cap() int
Cap returns the pool capacity, or 0 if unlimited (nil pool).
func (*ProcessPool) Release ¶ added in v0.1.8
func (p *ProcessPool) Release()
Release returns a permit to the pool. No-op if the pool is nil.
type QQBot ¶
type QQBot struct {
DefaultTypingIndicator
// contains filtered or unexported fields
}
QQBot implements BotAdapter interface for QQ Bot Platform (QQ群机器人开放平台) Official API: https://bots.qq.com
func (*QQBot) AddTypingIndicator ¶
AddTypingIndicator does nothing (not supported)
func (*QQBot) GetMessageHandler ¶
func (q *QQBot) GetMessageHandler() func(BotMessage)
GetMessageHandler gets the message handler in a thread-safe manner
func (*QQBot) RemoveTypingIndicator ¶
RemoveTypingIndicator does nothing (not supported)
func (*QQBot) SendMessage ¶
SendMessage sends a message to QQ (C2C private message)
func (*QQBot) SetMessageHandler ¶
func (q *QQBot) SetMessageHandler(handler func(BotMessage))
SetMessageHandler sets the message handler in a thread-safe manner
func (*QQBot) SetProxyManager ¶
SetProxyManager sets the proxy manager for the QQ bot
func (*QQBot) Start ¶
func (q *QQBot) Start(messageHandler func(BotMessage)) error
Start establishes connection to QQ gateway and begins listening for messages
func (*QQBot) SupportsTypingIndicator ¶
SupportsTypingIndicator returns false (QQ doesn't support typing indicators)
type QQGatewayResponse ¶
type QQGatewayResponse struct {
URL string `json:"url"`
}
QQGatewayResponse represents the gateway URL response
type QQTokenResponse ¶
type QQTokenResponse struct {
AccessToken string `json:"access_token"`
ExpiresIn string `json:"expires_in"` // API returns as string
}
QQTokenResponse represents the token response from QQ API
type Quotable ¶ added in v0.1.8
type Quotable interface {
FetchQuotedMessage(ctx context.Context, channelID, messageID string) (*QuotedMessage, error)
}
Quotable is an optional interface for channels that support fetching quoted/referenced messages for context injection.
type QuotedMessage ¶ added in v0.1.8
QuotedMessage represents a referenced message for context injection.
type Replyable ¶ added in v0.1.8
Replyable is an optional interface for channels that support sending replies that reference a specific message (visual thread).
type RichMessageHandle ¶ added in v0.1.8
type RichMessageHandle interface {
Channel() string
Update(blocks []ContentBlock) error // Incremental update during streaming
Finish(blocks []ContentBlock) error // Final update, remove interactive elements
}
RichMessageHandle represents an active rich message being updated.
type RichMessageOptions ¶ added in v0.1.8
type RichMessageOptions struct {
Title string // Optional card title
StopText string // Stop button label (e.g., "Stop")
StopData string // Stop button callback data
ReplyToID string // If set, reply to this message ID
Meta map[string]string // Channel-specific metadata
}
RichMessageOptions configures the creation of a rich message.
type RichMessenger ¶ added in v0.1.8
type RichMessenger interface {
CreateRichMessage(channel string, opts RichMessageOptions) (RichMessageHandle, error)
}
RichMessenger is an optional interface for channels that support streaming rich replies (cards, embeds, etc.).
type SendMessageRequest ¶
type SendMessageRequest struct {
Content string `json:"content"`
MsgType int `json:"msg_type"`
MsgID string `json:"msg_id,omitempty"`
MsgSeq int `json:"msg_seq,omitempty"`
}
SendMessageRequest represents the request payload for sending messages
type SendMessageResponse ¶
type SendMessageResponse struct {
ID string `json:"id"`
}
SendMessageResponse represents the response from sending a message
type TelegramBot ¶
type TelegramBot struct {
DefaultTypingIndicator
// contains filtered or unexported fields
}
TelegramBot implements BotAdapter interface for Telegram using long polling
func NewTelegramBot ¶
func NewTelegramBot(token string) *TelegramBot
NewTelegramBot creates a new Telegram bot instance
func (*TelegramBot) GetMessageHandler ¶
func (t *TelegramBot) GetMessageHandler() func(BotMessage)
GetMessageHandler gets the message handler in a thread-safe manner
func (*TelegramBot) SendMessage ¶
func (t *TelegramBot) SendMessage(chatID, message string) error
SendMessage sends a message to a Telegram chat
func (*TelegramBot) SetMessageHandler ¶
func (t *TelegramBot) SetMessageHandler(handler func(BotMessage))
SetMessageHandler sets the message handler in a thread-safe manner
func (*TelegramBot) SetProxyManager ¶
func (t *TelegramBot) SetProxyManager(mgr proxy.Manager)
SetProxyManager sets the proxy manager for the Telegram bot
func (*TelegramBot) Start ¶
func (t *TelegramBot) Start(messageHandler func(BotMessage)) error
Start establishes long polling connection to Telegram and begins listening for messages
func (*TelegramBot) Stop ¶
func (t *TelegramBot) Stop() error
Stop closes the Telegram long polling connection and cleans up resources
type Threadable ¶ added in v0.1.8
type Threadable interface {
ThreadScope(channelID string, msg BotMessage) string
}
Threadable is an optional interface for channels that support thread/topic isolation within a chat.
type WeixinBot ¶ added in v0.1.2
type WeixinBot struct {
DefaultTypingIndicator
// contains filtered or unexported fields
}
func NewWeixinBot ¶ added in v0.1.2
func (*WeixinBot) AddTypingIndicator ¶ added in v0.1.2
func (*WeixinBot) RemoveTypingIndicator ¶ added in v0.1.2
func (*WeixinBot) SendMessage ¶ added in v0.1.2
func (*WeixinBot) SetProxyManager ¶ added in v0.1.2
func (*WeixinBot) Start ¶ added in v0.1.2
func (b *WeixinBot) Start(messageHandler func(BotMessage)) error