2026-02-20 15:25:44 +00:00
|
|
|
package onebot
|
2026-02-14 08:50:21 +00:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"sync"
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"sync/atomic"
|
2026-02-14 08:50:21 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/gorilla/websocket"
|
|
|
|
|
|
|
|
|
|
"github.com/sipeed/picoclaw/pkg/bus"
|
2026-02-20 15:25:44 +00:00
|
|
|
"github.com/sipeed/picoclaw/pkg/channels"
|
2026-02-14 08:50:21 +00:00
|
|
|
"github.com/sipeed/picoclaw/pkg/config"
|
2026-02-22 22:56:48 +00:00
|
|
|
"github.com/sipeed/picoclaw/pkg/identity"
|
2026-02-14 08:50:21 +00:00
|
|
|
"github.com/sipeed/picoclaw/pkg/logger"
|
2026-02-22 15:27:55 +00:00
|
|
|
"github.com/sipeed/picoclaw/pkg/media"
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"github.com/sipeed/picoclaw/pkg/utils"
|
2026-02-14 08:50:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type OneBotChannel struct {
|
2026-02-20 15:25:44 +00:00
|
|
|
*channels.BaseChannel
|
2026-02-26 19:02:40 +00:00
|
|
|
config config.OneBotConfig
|
|
|
|
|
conn *websocket.Conn
|
|
|
|
|
ctx context.Context
|
|
|
|
|
cancel context.CancelFunc
|
|
|
|
|
dedup map[string]struct{}
|
|
|
|
|
dedupRing []string
|
|
|
|
|
dedupIdx int
|
|
|
|
|
mu sync.Mutex
|
|
|
|
|
writeMu sync.Mutex
|
|
|
|
|
echoCounter int64
|
|
|
|
|
selfID int64
|
|
|
|
|
pending map[string]chan json.RawMessage
|
|
|
|
|
pendingMu sync.Mutex
|
|
|
|
|
lastMessageID sync.Map
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type oneBotRawEvent struct {
|
|
|
|
|
PostType string `json:"post_type"`
|
|
|
|
|
MessageType string `json:"message_type"`
|
|
|
|
|
SubType string `json:"sub_type"`
|
|
|
|
|
MessageID json.RawMessage `json:"message_id"`
|
|
|
|
|
UserID json.RawMessage `json:"user_id"`
|
|
|
|
|
GroupID json.RawMessage `json:"group_id"`
|
|
|
|
|
RawMessage string `json:"raw_message"`
|
|
|
|
|
Message json.RawMessage `json:"message"`
|
|
|
|
|
Sender json.RawMessage `json:"sender"`
|
|
|
|
|
SelfID json.RawMessage `json:"self_id"`
|
|
|
|
|
Time json.RawMessage `json:"time"`
|
|
|
|
|
MetaEventType string `json:"meta_event_type"`
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
NoticeType string `json:"notice_type"`
|
2026-02-14 09:23:18 +00:00
|
|
|
Echo string `json:"echo"`
|
|
|
|
|
RetCode json.RawMessage `json:"retcode"`
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
Status json.RawMessage `json:"status"`
|
|
|
|
|
Data json.RawMessage `json:"data"`
|
2026-02-14 11:58:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type BotStatus struct {
|
|
|
|
|
Online bool `json:"online"`
|
2026-02-14 12:02:30 +00:00
|
|
|
Good bool `json:"good"`
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
func isAPIResponse(raw json.RawMessage) bool {
|
|
|
|
|
if len(raw) == 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
var s string
|
|
|
|
|
if json.Unmarshal(raw, &s) == nil {
|
|
|
|
|
return s == "ok" || s == "failed"
|
|
|
|
|
}
|
|
|
|
|
var bs BotStatus
|
|
|
|
|
if json.Unmarshal(raw, &bs) == nil {
|
|
|
|
|
return bs.Online || bs.Good
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
type oneBotSender struct {
|
|
|
|
|
UserID json.RawMessage `json:"user_id"`
|
|
|
|
|
Nickname string `json:"nickname"`
|
|
|
|
|
Card string `json:"card"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type oneBotAPIRequest struct {
|
2026-02-19 20:05:15 +00:00
|
|
|
Action string `json:"action"`
|
|
|
|
|
Params any `json:"params"`
|
|
|
|
|
Echo string `json:"echo,omitempty"`
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
type oneBotMessageSegment struct {
|
2026-02-19 20:05:15 +00:00
|
|
|
Type string `json:"type"`
|
|
|
|
|
Data map[string]any `json:"data"`
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewOneBotChannel(cfg config.OneBotConfig, messageBus *bus.MessageBus) (*OneBotChannel, error) {
|
refactor(channels): standardize group chat trigger filtering (Phase 8)
Add unified ShouldRespondInGroup to BaseChannel, replacing scattered
per-channel group filtering logic. Introduce GroupTriggerConfig (with
mention_only + prefixes), TypingConfig, and PlaceholderConfig types.
Migrate Discord MentionOnly, OneBot checkGroupTrigger, and LINE
hardcoded mention-only to the shared mechanism. Add group trigger
entry points for Slack, Telegram, QQ, Feishu, DingTalk, and WeCom.
Legacy config fields are preserved with automatic migration.
2026-02-22 20:11:11 +00:00
|
|
|
base := channels.NewBaseChannel("onebot", cfg, messageBus, cfg.AllowFrom,
|
|
|
|
|
channels.WithGroupTrigger(cfg.GroupTrigger),
|
2026-02-26 05:24:51 +00:00
|
|
|
channels.WithReasoningChannelID(cfg.ReasoningChannelID),
|
refactor(channels): standardize group chat trigger filtering (Phase 8)
Add unified ShouldRespondInGroup to BaseChannel, replacing scattered
per-channel group filtering logic. Introduce GroupTriggerConfig (with
mention_only + prefixes), TypingConfig, and PlaceholderConfig types.
Migrate Discord MentionOnly, OneBot checkGroupTrigger, and LINE
hardcoded mention-only to the shared mechanism. Add group trigger
entry points for Slack, Telegram, QQ, Feishu, DingTalk, and WeCom.
Legacy config fields are preserved with automatic migration.
2026-02-22 20:11:11 +00:00
|
|
|
)
|
2026-02-14 08:50:21 +00:00
|
|
|
|
|
|
|
|
const dedupSize = 1024
|
|
|
|
|
return &OneBotChannel{
|
|
|
|
|
BaseChannel: base,
|
|
|
|
|
config: cfg,
|
|
|
|
|
dedup: make(map[string]struct{}, dedupSize),
|
|
|
|
|
dedupRing: make([]string, dedupSize),
|
|
|
|
|
dedupIdx: 0,
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
pending: make(map[string]chan json.RawMessage),
|
2026-02-14 08:50:21 +00:00
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
func (c *OneBotChannel) setMsgEmojiLike(messageID string, emojiID int, set bool) {
|
|
|
|
|
go func() {
|
2026-02-19 20:05:15 +00:00
|
|
|
_, err := c.sendAPIRequest("set_msg_emoji_like", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"message_id": messageID,
|
|
|
|
|
"emoji_id": emojiID,
|
|
|
|
|
"set": set,
|
|
|
|
|
}, 5*time.Second)
|
|
|
|
|
if err != nil {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Failed to set emoji like", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"message_id": messageID,
|
|
|
|
|
"error": err.Error(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-26 19:02:40 +00:00
|
|
|
// ReactToMessage implements channels.ReactionCapable.
|
|
|
|
|
// It adds an emoji reaction (ID 289) to group messages and returns an undo function.
|
|
|
|
|
// Private messages return a no-op since reactions are only meaningful in groups.
|
|
|
|
|
func (c *OneBotChannel) ReactToMessage(ctx context.Context, chatID, messageID string) (func(), error) {
|
|
|
|
|
// Only react in group chats
|
|
|
|
|
if !strings.HasPrefix(chatID, "group:") {
|
|
|
|
|
return func() {}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.setMsgEmojiLike(messageID, 289, true)
|
|
|
|
|
|
|
|
|
|
return func() {
|
|
|
|
|
c.setMsgEmojiLike(messageID, 289, false)
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
func (c *OneBotChannel) Start(ctx context.Context) error {
|
|
|
|
|
if c.config.WSUrl == "" {
|
|
|
|
|
return fmt.Errorf("OneBot ws_url not configured")
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.InfoCF("onebot", "Starting OneBot channel", map[string]any{
|
2026-02-14 08:50:21 +00:00
|
|
|
"ws_url": c.config.WSUrl,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
c.ctx, c.cancel = context.WithCancel(ctx)
|
|
|
|
|
|
|
|
|
|
if err := c.connect(); err != nil {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.WarnCF("onebot", "Initial connection failed, will retry in background", map[string]any{
|
2026-02-14 12:25:55 +00:00
|
|
|
"error": err.Error(),
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
go c.listen()
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
c.fetchSelfID()
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c.config.ReconnectInterval > 0 {
|
|
|
|
|
go c.reconnectLoop()
|
2026-02-14 12:25:55 +00:00
|
|
|
} else {
|
|
|
|
|
if c.conn == nil {
|
|
|
|
|
return fmt.Errorf("failed to connect to OneBot and reconnect is disabled")
|
|
|
|
|
}
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-20 15:25:44 +00:00
|
|
|
c.SetRunning(true)
|
2026-02-14 08:50:21 +00:00
|
|
|
logger.InfoC("onebot", "OneBot channel started successfully")
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *OneBotChannel) connect() error {
|
|
|
|
|
dialer := websocket.DefaultDialer
|
|
|
|
|
dialer.HandshakeTimeout = 10 * time.Second
|
|
|
|
|
|
|
|
|
|
header := make(map[string][]string)
|
2026-03-27 16:03:34 +00:00
|
|
|
if c.config.AccessToken.String() != "" {
|
|
|
|
|
header["Authorization"] = []string{"Bearer " + c.config.AccessToken.String()}
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-25 09:43:45 +00:00
|
|
|
conn, resp, err := dialer.Dial(c.config.WSUrl, header)
|
|
|
|
|
if resp != nil {
|
|
|
|
|
resp.Body.Close()
|
|
|
|
|
}
|
2026-02-14 08:50:21 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
conn.SetPongHandler(func(appData string) error {
|
|
|
|
|
_ = conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
_ = conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
|
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
c.mu.Lock()
|
|
|
|
|
c.conn = conn
|
|
|
|
|
c.mu.Unlock()
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
go c.pinger(conn)
|
|
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
logger.InfoC("onebot", "WebSocket connected")
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
func (c *OneBotChannel) pinger(conn *websocket.Conn) {
|
|
|
|
|
ticker := time.NewTicker(30 * time.Second)
|
|
|
|
|
defer ticker.Stop()
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
select {
|
|
|
|
|
case <-c.ctx.Done():
|
|
|
|
|
return
|
|
|
|
|
case <-ticker.C:
|
|
|
|
|
c.writeMu.Lock()
|
|
|
|
|
err := conn.WriteMessage(websocket.PingMessage, nil)
|
|
|
|
|
c.writeMu.Unlock()
|
|
|
|
|
if err != nil {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Ping write failed, stopping pinger", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"error": err.Error(),
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *OneBotChannel) fetchSelfID() {
|
|
|
|
|
resp, err := c.sendAPIRequest("get_login_info", nil, 5*time.Second)
|
|
|
|
|
if err != nil {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.WarnCF("onebot", "Failed to get_login_info", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"error": err.Error(),
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type loginInfo struct {
|
|
|
|
|
UserID json.RawMessage `json:"user_id"`
|
|
|
|
|
Nickname string `json:"nickname"`
|
|
|
|
|
}
|
|
|
|
|
for _, extract := range []func() (*loginInfo, error){
|
|
|
|
|
func() (*loginInfo, error) {
|
|
|
|
|
var w struct {
|
|
|
|
|
Data loginInfo `json:"data"`
|
|
|
|
|
}
|
|
|
|
|
err := json.Unmarshal(resp, &w)
|
|
|
|
|
return &w.Data, err
|
|
|
|
|
},
|
|
|
|
|
func() (*loginInfo, error) {
|
|
|
|
|
var f loginInfo
|
|
|
|
|
err := json.Unmarshal(resp, &f)
|
|
|
|
|
return &f, err
|
|
|
|
|
},
|
|
|
|
|
} {
|
|
|
|
|
info, err := extract()
|
|
|
|
|
if err != nil || len(info.UserID) == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if uid, err := parseJSONInt64(info.UserID); err == nil && uid > 0 {
|
|
|
|
|
atomic.StoreInt64(&c.selfID, uid)
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.InfoCF("onebot", "Bot self ID retrieved", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"self_id": uid,
|
|
|
|
|
"nickname": info.Nickname,
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.WarnCF("onebot", "Could not parse self ID from get_login_info response", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"response": string(resp),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 20:05:15 +00:00
|
|
|
func (c *OneBotChannel) sendAPIRequest(action string, params any, timeout time.Duration) (json.RawMessage, error) {
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
c.mu.Lock()
|
|
|
|
|
conn := c.conn
|
|
|
|
|
c.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
if conn == nil {
|
|
|
|
|
return nil, fmt.Errorf("WebSocket not connected")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo := fmt.Sprintf("api_%d_%d", time.Now().UnixNano(), atomic.AddInt64(&c.echoCounter, 1))
|
|
|
|
|
|
|
|
|
|
ch := make(chan json.RawMessage, 1)
|
|
|
|
|
c.pendingMu.Lock()
|
|
|
|
|
c.pending[echo] = ch
|
|
|
|
|
c.pendingMu.Unlock()
|
|
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
|
c.pendingMu.Lock()
|
|
|
|
|
delete(c.pending, echo)
|
|
|
|
|
c.pendingMu.Unlock()
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
req := oneBotAPIRequest{
|
|
|
|
|
Action: action,
|
|
|
|
|
Params: params,
|
|
|
|
|
Echo: echo,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data, err := json.Marshal(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to marshal API request: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.writeMu.Lock()
|
2026-02-22 14:25:07 +00:00
|
|
|
_ = conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
err = conn.WriteMessage(websocket.TextMessage, data)
|
2026-02-22 14:25:07 +00:00
|
|
|
_ = conn.SetWriteDeadline(time.Time{})
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
c.writeMu.Unlock()
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to write API request: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
case resp := <-ch:
|
2026-02-23 13:34:37 +00:00
|
|
|
if resp == nil {
|
|
|
|
|
return nil, fmt.Errorf("API request %s: channel stopped", action)
|
|
|
|
|
}
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
return resp, nil
|
|
|
|
|
case <-time.After(timeout):
|
|
|
|
|
return nil, fmt.Errorf("API request %s timed out after %v", action, timeout)
|
|
|
|
|
case <-c.ctx.Done():
|
2026-02-25 09:58:49 +00:00
|
|
|
return nil, fmt.Errorf("context canceled")
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
func (c *OneBotChannel) reconnectLoop() {
|
2026-02-27 08:35:07 +00:00
|
|
|
interval := max(time.Duration(c.config.ReconnectInterval)*time.Second, 5*time.Second)
|
2026-02-14 08:50:21 +00:00
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
select {
|
|
|
|
|
case <-c.ctx.Done():
|
|
|
|
|
return
|
|
|
|
|
case <-time.After(interval):
|
|
|
|
|
c.mu.Lock()
|
|
|
|
|
conn := c.conn
|
|
|
|
|
c.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
if conn == nil {
|
|
|
|
|
logger.InfoC("onebot", "Attempting to reconnect...")
|
|
|
|
|
if err := c.connect(); err != nil {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.ErrorCF("onebot", "Reconnect failed", map[string]any{
|
2026-02-14 08:50:21 +00:00
|
|
|
"error": err.Error(),
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
go c.listen()
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
c.fetchSelfID()
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *OneBotChannel) Stop(ctx context.Context) error {
|
|
|
|
|
logger.InfoC("onebot", "Stopping OneBot channel")
|
2026-02-20 15:25:44 +00:00
|
|
|
c.SetRunning(false)
|
2026-02-14 08:50:21 +00:00
|
|
|
|
|
|
|
|
if c.cancel != nil {
|
|
|
|
|
c.cancel()
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
c.pendingMu.Lock()
|
|
|
|
|
for echo, ch := range c.pending {
|
2026-02-23 13:34:37 +00:00
|
|
|
select {
|
|
|
|
|
case ch <- nil: // non-blocking wake for blocked sendAPIRequest goroutines
|
|
|
|
|
default:
|
|
|
|
|
}
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
delete(c.pending, echo)
|
|
|
|
|
}
|
|
|
|
|
c.pendingMu.Unlock()
|
|
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
c.mu.Lock()
|
|
|
|
|
if c.conn != nil {
|
|
|
|
|
c.conn.Close()
|
|
|
|
|
c.conn = nil
|
|
|
|
|
}
|
|
|
|
|
c.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
func (c *OneBotChannel) Send(ctx context.Context, msg bus.OutboundMessage) ([]string, error) {
|
2026-02-14 08:50:21 +00:00
|
|
|
if !c.IsRunning() {
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, channels.ErrNotRunning
|
2026-02-22 17:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check ctx before entering write path
|
|
|
|
|
select {
|
|
|
|
|
case <-ctx.Done():
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, ctx.Err()
|
2026-02-22 17:45:48 +00:00
|
|
|
default:
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.mu.Lock()
|
|
|
|
|
conn := c.conn
|
|
|
|
|
c.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
if conn == nil {
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, fmt.Errorf("OneBot WebSocket not connected")
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
action, params, err := c.buildSendRequest(msg)
|
|
|
|
|
if err != nil {
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, err
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
echo := fmt.Sprintf("send_%d", atomic.AddInt64(&c.echoCounter, 1))
|
2026-02-14 08:50:21 +00:00
|
|
|
|
|
|
|
|
req := oneBotAPIRequest{
|
|
|
|
|
Action: action,
|
|
|
|
|
Params: params,
|
|
|
|
|
Echo: echo,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data, err := json.Marshal(req)
|
|
|
|
|
if err != nil {
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, fmt.Errorf("failed to marshal OneBot request: %w", err)
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.writeMu.Lock()
|
2026-02-22 14:25:07 +00:00
|
|
|
_ = conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
2026-02-14 08:50:21 +00:00
|
|
|
err = conn.WriteMessage(websocket.TextMessage, data)
|
2026-02-22 14:25:07 +00:00
|
|
|
_ = conn.SetWriteDeadline(time.Time{})
|
2026-02-14 08:50:21 +00:00
|
|
|
c.writeMu.Unlock()
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.ErrorCF("onebot", "Failed to send message", map[string]any{
|
2026-02-14 08:50:21 +00:00
|
|
|
"error": err.Error(),
|
|
|
|
|
})
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, fmt.Errorf("onebot send: %w", channels.ErrTemporary)
|
2026-02-20 15:25:44 +00:00
|
|
|
}
|
|
|
|
|
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, nil
|
2026-02-20 15:25:44 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-22 19:10:57 +00:00
|
|
|
// SendMedia implements the channels.MediaSender interface.
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
func (c *OneBotChannel) SendMedia(ctx context.Context, msg bus.OutboundMediaMessage) ([]string, error) {
|
2026-02-22 19:10:57 +00:00
|
|
|
if !c.IsRunning() {
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, channels.ErrNotRunning
|
2026-02-22 19:10:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
case <-ctx.Done():
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, ctx.Err()
|
2026-02-22 19:10:57 +00:00
|
|
|
default:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.mu.Lock()
|
|
|
|
|
conn := c.conn
|
|
|
|
|
c.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
if conn == nil {
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, fmt.Errorf("OneBot WebSocket not connected")
|
2026-02-22 19:10:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
store := c.GetMediaStore()
|
|
|
|
|
if store == nil {
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, fmt.Errorf("no media store available: %w", channels.ErrSendFailed)
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-22 19:10:57 +00:00
|
|
|
// Build media segments
|
|
|
|
|
var segments []oneBotMessageSegment
|
|
|
|
|
for _, part := range msg.Parts {
|
|
|
|
|
localPath, err := store.Resolve(part.Ref)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.ErrorCF("onebot", "Failed to resolve media ref", map[string]any{
|
|
|
|
|
"ref": part.Ref,
|
|
|
|
|
"error": err.Error(),
|
|
|
|
|
})
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-26 15:36:06 +00:00
|
|
|
var segType string
|
2026-02-22 19:10:57 +00:00
|
|
|
switch part.Type {
|
|
|
|
|
case "image":
|
|
|
|
|
segType = "image"
|
|
|
|
|
case "video":
|
|
|
|
|
segType = "video"
|
|
|
|
|
case "audio":
|
|
|
|
|
segType = "record"
|
|
|
|
|
default:
|
|
|
|
|
segType = "file"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
segments = append(segments, oneBotMessageSegment{
|
|
|
|
|
Type: segType,
|
|
|
|
|
Data: map[string]any{"file": "file://" + localPath},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if part.Caption != "" {
|
|
|
|
|
segments = append(segments, oneBotMessageSegment{
|
|
|
|
|
Type: "text",
|
|
|
|
|
Data: map[string]any{"text": part.Caption},
|
|
|
|
|
})
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-22 19:10:57 +00:00
|
|
|
if len(segments) == 0 {
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, nil
|
2026-02-22 19:10:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chatID := msg.ChatID
|
|
|
|
|
var action, idKey string
|
|
|
|
|
var rawID string
|
|
|
|
|
if rest, ok := strings.CutPrefix(chatID, "group:"); ok {
|
|
|
|
|
action, idKey, rawID = "send_group_msg", "group_id", rest
|
|
|
|
|
} else if rest, ok := strings.CutPrefix(chatID, "private:"); ok {
|
|
|
|
|
action, idKey, rawID = "send_private_msg", "user_id", rest
|
|
|
|
|
} else {
|
|
|
|
|
action, idKey, rawID = "send_private_msg", "user_id", chatID
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
id, err := strconv.ParseInt(rawID, 10, 64)
|
|
|
|
|
if err != nil {
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, fmt.Errorf("invalid %s in chatID: %s: %w", idKey, chatID, channels.ErrSendFailed)
|
2026-02-22 19:10:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo := fmt.Sprintf("send_%d", atomic.AddInt64(&c.echoCounter, 1))
|
|
|
|
|
|
|
|
|
|
req := oneBotAPIRequest{
|
|
|
|
|
Action: action,
|
|
|
|
|
Params: map[string]any{idKey: id, "message": segments},
|
|
|
|
|
Echo: echo,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data, err := json.Marshal(req)
|
|
|
|
|
if err != nil {
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, fmt.Errorf("failed to marshal OneBot request: %w", err)
|
2026-02-22 19:10:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.writeMu.Lock()
|
|
|
|
|
_ = conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
|
|
|
|
err = conn.WriteMessage(websocket.TextMessage, data)
|
|
|
|
|
_ = conn.SetWriteDeadline(time.Time{})
|
|
|
|
|
c.writeMu.Unlock()
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.ErrorCF("onebot", "Failed to send media message", map[string]any{
|
|
|
|
|
"error": err.Error(),
|
|
|
|
|
})
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, fmt.Errorf("onebot send media: %w", channels.ErrTemporary)
|
2026-02-22 19:10:57 +00:00
|
|
|
}
|
|
|
|
|
|
feat(channels): make Channel.Send return delivered message IDs (#2190)
* feat(channels): Channel.Send and MediaSender.SendMedia return delivered message IDs
Change Channel.Send signature from (ctx, msg) error to (ctx, msg) ([]string, error)
and MediaSender.SendMedia similarly, so callers can capture platform message IDs
for threading, reactions, and history annotation.
Adapters that return real IDs: Telegram (per-chunk MessageID), Discord (Message.ID),
Slack Send (ts), QQ (sentMsg.ID), Matrix (EventID). Slack SendMedia returns nil
because UploadFileV2 does not expose the posted message timestamp in its response.
All other adapters return nil IDs.
preSend and sendWithRetry in manager.go updated to propagate ([]string, bool).
README examples updated for both English and Chinese docs.
* style: apply golangci-lint fixes (golines)
* docs: fix Send migration guide — restore old error-only signature in before/after example
2026-03-31 03:07:32 +00:00
|
|
|
return nil, nil
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
func (c *OneBotChannel) buildMessageSegments(chatID, content string) []oneBotMessageSegment {
|
|
|
|
|
var segments []oneBotMessageSegment
|
2026-02-14 08:50:21 +00:00
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
if lastMsgID, ok := c.lastMessageID.Load(chatID); ok {
|
|
|
|
|
if msgID, ok := lastMsgID.(string); ok && msgID != "" {
|
|
|
|
|
segments = append(segments, oneBotMessageSegment{
|
|
|
|
|
Type: "reply",
|
2026-02-19 20:05:15 +00:00
|
|
|
Data: map[string]any{"id": msgID},
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
})
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
segments = append(segments, oneBotMessageSegment{
|
|
|
|
|
Type: "text",
|
2026-02-19 20:05:15 +00:00
|
|
|
Data: map[string]any{"text": content},
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return segments
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 20:05:15 +00:00
|
|
|
func (c *OneBotChannel) buildSendRequest(msg bus.OutboundMessage) (string, any, error) {
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
chatID := msg.ChatID
|
|
|
|
|
segments := c.buildMessageSegments(chatID, msg.Content)
|
|
|
|
|
|
|
|
|
|
var action, idKey string
|
|
|
|
|
var rawID string
|
|
|
|
|
if rest, ok := strings.CutPrefix(chatID, "group:"); ok {
|
|
|
|
|
action, idKey, rawID = "send_group_msg", "group_id", rest
|
|
|
|
|
} else if rest, ok := strings.CutPrefix(chatID, "private:"); ok {
|
|
|
|
|
action, idKey, rawID = "send_private_msg", "user_id", rest
|
|
|
|
|
} else {
|
|
|
|
|
action, idKey, rawID = "send_private_msg", "user_id", chatID
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
id, err := strconv.ParseInt(rawID, 10, 64)
|
2026-02-14 08:50:21 +00:00
|
|
|
if err != nil {
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
return "", nil, fmt.Errorf("invalid %s in chatID: %s", idKey, chatID)
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
2026-02-19 20:05:15 +00:00
|
|
|
return action, map[string]any{idKey: id, "message": segments}, nil
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *OneBotChannel) listen() {
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
c.mu.Lock()
|
|
|
|
|
conn := c.conn
|
|
|
|
|
c.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
if conn == nil {
|
|
|
|
|
logger.WarnC("onebot", "WebSocket connection is nil, listener exiting")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
for {
|
|
|
|
|
select {
|
|
|
|
|
case <-c.ctx.Done():
|
|
|
|
|
return
|
|
|
|
|
default:
|
|
|
|
|
_, message, err := conn.ReadMessage()
|
|
|
|
|
if err != nil {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.ErrorCF("onebot", "WebSocket read error", map[string]any{
|
2026-02-14 08:50:21 +00:00
|
|
|
"error": err.Error(),
|
|
|
|
|
})
|
|
|
|
|
c.mu.Lock()
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
if c.conn == conn {
|
2026-02-14 08:50:21 +00:00
|
|
|
c.conn.Close()
|
|
|
|
|
c.conn = nil
|
|
|
|
|
}
|
|
|
|
|
c.mu.Unlock()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
_ = conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
2026-02-14 08:50:21 +00:00
|
|
|
|
|
|
|
|
var raw oneBotRawEvent
|
|
|
|
|
if err := json.Unmarshal(message, &raw); err != nil {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.WarnCF("onebot", "Failed to unmarshal raw event", map[string]any{
|
2026-02-14 08:50:21 +00:00
|
|
|
"error": err.Error(),
|
|
|
|
|
"payload": string(message),
|
|
|
|
|
})
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "WebSocket event", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"length": len(message),
|
|
|
|
|
"post_type": raw.PostType,
|
|
|
|
|
"sub_type": raw.SubType,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if raw.Echo != "" {
|
|
|
|
|
c.pendingMu.Lock()
|
|
|
|
|
ch, ok := c.pending[raw.Echo]
|
|
|
|
|
c.pendingMu.Unlock()
|
|
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
|
select {
|
|
|
|
|
case ch <- message:
|
|
|
|
|
default:
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Received API response (no waiter)", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"echo": raw.Echo,
|
|
|
|
|
"status": string(raw.Status),
|
|
|
|
|
})
|
|
|
|
|
}
|
2026-02-14 08:50:21 +00:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
if isAPIResponse(raw.Status) {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Received API response without echo, skipping", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"status": string(raw.Status),
|
|
|
|
|
})
|
|
|
|
|
continue
|
|
|
|
|
}
|
2026-02-14 08:50:21 +00:00
|
|
|
|
|
|
|
|
c.handleRawEvent(&raw)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseJSONInt64(raw json.RawMessage) (int64, error) {
|
|
|
|
|
if len(raw) == 0 {
|
|
|
|
|
return 0, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var n int64
|
|
|
|
|
if err := json.Unmarshal(raw, &n); err == nil {
|
|
|
|
|
return n, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var s string
|
|
|
|
|
if err := json.Unmarshal(raw, &s); err == nil {
|
|
|
|
|
return strconv.ParseInt(s, 10, 64)
|
|
|
|
|
}
|
|
|
|
|
return 0, fmt.Errorf("cannot parse as int64: %s", string(raw))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseJSONString(raw json.RawMessage) string {
|
|
|
|
|
if len(raw) == 0 {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
var s string
|
|
|
|
|
if err := json.Unmarshal(raw, &s); err == nil {
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string(raw)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type parseMessageResult struct {
|
|
|
|
|
Text string
|
|
|
|
|
IsBotMentioned bool
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
Media []string
|
|
|
|
|
ReplyTo string
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-22 15:27:55 +00:00
|
|
|
func (c *OneBotChannel) parseMessageSegments(
|
|
|
|
|
raw json.RawMessage,
|
|
|
|
|
selfID int64,
|
|
|
|
|
store media.MediaStore,
|
|
|
|
|
scope string,
|
|
|
|
|
) parseMessageResult {
|
2026-02-14 08:50:21 +00:00
|
|
|
if len(raw) == 0 {
|
|
|
|
|
return parseMessageResult{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var s string
|
|
|
|
|
if err := json.Unmarshal(raw, &s); err == nil {
|
|
|
|
|
mentioned := false
|
|
|
|
|
if selfID > 0 {
|
|
|
|
|
cqAt := fmt.Sprintf("[CQ:at,qq=%d]", selfID)
|
|
|
|
|
if strings.Contains(s, cqAt) {
|
|
|
|
|
mentioned = true
|
|
|
|
|
s = strings.ReplaceAll(s, cqAt, "")
|
|
|
|
|
s = strings.TrimSpace(s)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return parseMessageResult{Text: s, IsBotMentioned: mentioned}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 20:05:15 +00:00
|
|
|
var segments []map[string]any
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
if err := json.Unmarshal(raw, &segments); err != nil {
|
|
|
|
|
return parseMessageResult{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var textParts []string
|
|
|
|
|
mentioned := false
|
|
|
|
|
selfIDStr := strconv.FormatInt(selfID, 10)
|
2026-02-22 15:27:55 +00:00
|
|
|
var mediaRefs []string
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
var replyTo string
|
|
|
|
|
|
2026-02-22 15:27:55 +00:00
|
|
|
// Helper to register a local file with the media store
|
|
|
|
|
storeFile := func(localPath, filename string) string {
|
|
|
|
|
if store != nil {
|
|
|
|
|
ref, err := store.Store(localPath, media.MediaMeta{
|
2026-03-23 04:13:59 +00:00
|
|
|
Filename: filename,
|
|
|
|
|
Source: "onebot",
|
|
|
|
|
CleanupPolicy: media.CleanupPolicyDeleteOnCleanup,
|
2026-02-22 15:27:55 +00:00
|
|
|
}, scope)
|
|
|
|
|
if err == nil {
|
|
|
|
|
return ref
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return localPath // fallback
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
for _, seg := range segments {
|
|
|
|
|
segType, _ := seg["type"].(string)
|
2026-02-19 20:05:15 +00:00
|
|
|
data, _ := seg["data"].(map[string]any)
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
|
|
|
|
|
switch segType {
|
|
|
|
|
case "text":
|
|
|
|
|
if data != nil {
|
|
|
|
|
if t, ok := data["text"].(string); ok {
|
|
|
|
|
textParts = append(textParts, t)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case "at":
|
|
|
|
|
if data != nil && selfID > 0 {
|
|
|
|
|
qqVal := fmt.Sprintf("%v", data["qq"])
|
|
|
|
|
if qqVal == selfIDStr || qqVal == "all" {
|
|
|
|
|
mentioned = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case "image", "video", "file":
|
|
|
|
|
if data != nil {
|
|
|
|
|
url, _ := data["url"].(string)
|
|
|
|
|
if url != "" {
|
|
|
|
|
defaults := map[string]string{"image": "image.jpg", "video": "video.mp4", "file": "file"}
|
|
|
|
|
filename := defaults[segType]
|
|
|
|
|
if f, ok := data["file"].(string); ok && f != "" {
|
|
|
|
|
filename = f
|
|
|
|
|
} else if n, ok := data["name"].(string); ok && n != "" {
|
|
|
|
|
filename = n
|
|
|
|
|
}
|
|
|
|
|
localPath := utils.DownloadFile(url, filename, utils.DownloadOptions{
|
|
|
|
|
LoggerPrefix: "onebot",
|
|
|
|
|
})
|
|
|
|
|
if localPath != "" {
|
2026-02-22 15:27:55 +00:00
|
|
|
mediaRefs = append(mediaRefs, storeFile(localPath, filename))
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
textParts = append(textParts, fmt.Sprintf("[%s]", segType))
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case "record":
|
|
|
|
|
if data != nil {
|
|
|
|
|
url, _ := data["url"].(string)
|
|
|
|
|
if url != "" {
|
|
|
|
|
localPath := utils.DownloadFile(url, "voice.amr", utils.DownloadOptions{
|
|
|
|
|
LoggerPrefix: "onebot",
|
|
|
|
|
})
|
|
|
|
|
if localPath != "" {
|
2026-02-22 19:47:12 +00:00
|
|
|
textParts = append(textParts, "[voice]")
|
|
|
|
|
mediaRefs = append(mediaRefs, storeFile(localPath, "voice.amr"))
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
|
|
|
|
|
case "reply":
|
|
|
|
|
if data != nil {
|
|
|
|
|
if id, ok := data["id"]; ok {
|
|
|
|
|
replyTo = fmt.Sprintf("%v", id)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case "face":
|
|
|
|
|
if data != nil {
|
|
|
|
|
faceID, _ := data["id"]
|
|
|
|
|
textParts = append(textParts, fmt.Sprintf("[face:%v]", faceID))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case "forward":
|
|
|
|
|
textParts = append(textParts, "[forward message]")
|
|
|
|
|
|
|
|
|
|
default:
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
|
|
|
|
|
return parseMessageResult{
|
|
|
|
|
Text: strings.TrimSpace(strings.Join(textParts, "")),
|
|
|
|
|
IsBotMentioned: mentioned,
|
2026-02-22 15:27:55 +00:00
|
|
|
Media: mediaRefs,
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
ReplyTo: replyTo,
|
|
|
|
|
}
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *OneBotChannel) handleRawEvent(raw *oneBotRawEvent) {
|
|
|
|
|
switch raw.PostType {
|
|
|
|
|
case "message":
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
if userID, err := parseJSONInt64(raw.UserID); err == nil && userID > 0 {
|
2026-02-22 22:56:48 +00:00
|
|
|
// Build minimal sender for allowlist check
|
|
|
|
|
sender := bus.SenderInfo{
|
|
|
|
|
Platform: "onebot",
|
|
|
|
|
PlatformID: strconv.FormatInt(userID, 10),
|
|
|
|
|
CanonicalID: identity.BuildCanonicalID("onebot", strconv.FormatInt(userID, 10)),
|
|
|
|
|
}
|
|
|
|
|
if !c.IsAllowedSender(sender) {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Message rejected by allowlist", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"user_id": userID,
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
c.handleMessage(raw)
|
|
|
|
|
|
|
|
|
|
case "message_sent":
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Bot sent message event", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"message_type": raw.MessageType,
|
|
|
|
|
"message_id": parseJSONString(raw.MessageID),
|
|
|
|
|
})
|
|
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
case "meta_event":
|
|
|
|
|
c.handleMetaEvent(raw)
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
case "notice":
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
c.handleNoticeEvent(raw)
|
|
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
case "request":
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Request event received", map[string]any{
|
2026-02-14 08:50:21 +00:00
|
|
|
"sub_type": raw.SubType,
|
|
|
|
|
})
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
case "":
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Event with empty post_type (possibly API response)", map[string]any{
|
2026-02-14 08:50:21 +00:00
|
|
|
"echo": raw.Echo,
|
|
|
|
|
"status": raw.Status,
|
|
|
|
|
})
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
default:
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Unknown post_type", map[string]any{
|
2026-02-14 08:50:21 +00:00
|
|
|
"post_type": raw.PostType,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
func (c *OneBotChannel) handleMetaEvent(raw *oneBotRawEvent) {
|
|
|
|
|
if raw.MetaEventType == "lifecycle" {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.InfoCF("onebot", "Lifecycle event", map[string]any{"sub_type": raw.SubType})
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
} else if raw.MetaEventType != "heartbeat" {
|
|
|
|
|
logger.DebugCF("onebot", "Meta event: "+raw.MetaEventType, nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *OneBotChannel) handleNoticeEvent(raw *oneBotRawEvent) {
|
2026-02-19 20:05:15 +00:00
|
|
|
fields := map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"notice_type": raw.NoticeType,
|
|
|
|
|
"sub_type": raw.SubType,
|
|
|
|
|
"group_id": parseJSONString(raw.GroupID),
|
|
|
|
|
"user_id": parseJSONString(raw.UserID),
|
|
|
|
|
"message_id": parseJSONString(raw.MessageID),
|
|
|
|
|
}
|
|
|
|
|
switch raw.NoticeType {
|
|
|
|
|
case "group_recall", "group_increase", "group_decrease",
|
|
|
|
|
"friend_add", "group_admin", "group_ban":
|
|
|
|
|
logger.InfoCF("onebot", "Notice: "+raw.NoticeType, fields)
|
|
|
|
|
default:
|
|
|
|
|
logger.DebugCF("onebot", "Notice: "+raw.NoticeType, fields)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *OneBotChannel) handleMessage(raw *oneBotRawEvent) {
|
|
|
|
|
// Parse fields from raw event
|
2026-02-14 08:50:21 +00:00
|
|
|
userID, err := parseJSONInt64(raw.UserID)
|
|
|
|
|
if err != nil {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.WarnCF("onebot", "Failed to parse user_id", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"error": err.Error(),
|
|
|
|
|
"raw": string(raw.UserID),
|
|
|
|
|
})
|
|
|
|
|
return
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
groupID, _ := parseJSONInt64(raw.GroupID)
|
|
|
|
|
selfID, _ := parseJSONInt64(raw.SelfID)
|
|
|
|
|
messageID := parseJSONString(raw.MessageID)
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
if selfID == 0 {
|
|
|
|
|
selfID = atomic.LoadInt64(&c.selfID)
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-22 15:27:55 +00:00
|
|
|
// Compute scope for media store before parsing (parsing may download files)
|
|
|
|
|
var chatIDForScope string
|
|
|
|
|
switch raw.MessageType {
|
|
|
|
|
case "group":
|
|
|
|
|
chatIDForScope = "group:" + strconv.FormatInt(groupID, 10)
|
|
|
|
|
default:
|
|
|
|
|
chatIDForScope = "private:" + strconv.FormatInt(userID, 10)
|
|
|
|
|
}
|
|
|
|
|
scope := channels.BuildMediaScope("onebot", chatIDForScope, messageID)
|
|
|
|
|
|
|
|
|
|
parsed := c.parseMessageSegments(raw.Message, selfID, c.GetMediaStore(), scope)
|
2026-02-14 08:50:21 +00:00
|
|
|
isBotMentioned := parsed.IsBotMentioned
|
|
|
|
|
|
|
|
|
|
content := raw.RawMessage
|
|
|
|
|
if content == "" {
|
|
|
|
|
content = parsed.Text
|
|
|
|
|
} else if selfID > 0 {
|
|
|
|
|
cqAt := fmt.Sprintf("[CQ:at,qq=%d]", selfID)
|
|
|
|
|
if strings.Contains(content, cqAt) {
|
|
|
|
|
isBotMentioned = true
|
|
|
|
|
content = strings.ReplaceAll(content, cqAt, "")
|
|
|
|
|
content = strings.TrimSpace(content)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
if parsed.Text != "" && content != parsed.Text && (len(parsed.Media) > 0 || parsed.ReplyTo != "") {
|
|
|
|
|
content = parsed.Text
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-14 08:50:21 +00:00
|
|
|
var sender oneBotSender
|
|
|
|
|
if len(raw.Sender) > 0 {
|
|
|
|
|
if err := json.Unmarshal(raw.Sender, &sender); err != nil {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.WarnCF("onebot", "Failed to parse sender", map[string]any{
|
2026-02-14 08:50:21 +00:00
|
|
|
"error": err.Error(),
|
|
|
|
|
"sender": string(raw.Sender),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
if c.isDuplicate(messageID) {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Duplicate message, skipping", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"message_id": messageID,
|
2026-02-14 08:50:21 +00:00
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if content == "" {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Received empty message, ignoring", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"message_id": messageID,
|
2026-02-14 08:50:21 +00:00
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
senderID := strconv.FormatInt(userID, 10)
|
2026-02-14 08:50:21 +00:00
|
|
|
var chatID string
|
2026-04-01 05:58:31 +00:00
|
|
|
var contextChatID string
|
|
|
|
|
var contextChatType string
|
2026-02-14 08:50:21 +00:00
|
|
|
|
2026-02-22 13:57:12 +00:00
|
|
|
metadata := map[string]string{}
|
2026-02-14 08:50:21 +00:00
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
if parsed.ReplyTo != "" {
|
|
|
|
|
metadata["reply_to_message_id"] = parsed.ReplyTo
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch raw.MessageType {
|
2026-02-14 08:50:21 +00:00
|
|
|
case "private":
|
|
|
|
|
chatID = "private:" + senderID
|
2026-04-01 05:58:31 +00:00
|
|
|
contextChatID = senderID
|
|
|
|
|
contextChatType = "direct"
|
2026-02-14 08:50:21 +00:00
|
|
|
|
|
|
|
|
case "group":
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
groupIDStr := strconv.FormatInt(groupID, 10)
|
2026-02-14 08:50:21 +00:00
|
|
|
chatID = "group:" + groupIDStr
|
2026-04-01 05:58:31 +00:00
|
|
|
contextChatID = groupIDStr
|
|
|
|
|
contextChatType = "group"
|
2026-02-14 08:50:21 +00:00
|
|
|
metadata["group_id"] = groupIDStr
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
senderUserID, _ := parseJSONInt64(sender.UserID)
|
2026-02-14 08:50:21 +00:00
|
|
|
if senderUserID > 0 {
|
|
|
|
|
metadata["sender_user_id"] = strconv.FormatInt(senderUserID, 10)
|
|
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
if sender.Card != "" {
|
|
|
|
|
metadata["sender_name"] = sender.Card
|
|
|
|
|
} else if sender.Nickname != "" {
|
|
|
|
|
metadata["sender_name"] = sender.Nickname
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(channels): standardize group chat trigger filtering (Phase 8)
Add unified ShouldRespondInGroup to BaseChannel, replacing scattered
per-channel group filtering logic. Introduce GroupTriggerConfig (with
mention_only + prefixes), TypingConfig, and PlaceholderConfig types.
Migrate Discord MentionOnly, OneBot checkGroupTrigger, and LINE
hardcoded mention-only to the shared mechanism. Add group trigger
entry points for Slack, Telegram, QQ, Feishu, DingTalk, and WeCom.
Legacy config fields are preserved with automatic migration.
2026-02-22 20:11:11 +00:00
|
|
|
respond, strippedContent := c.ShouldRespondInGroup(isBotMentioned, content)
|
|
|
|
|
if !respond {
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.DebugCF("onebot", "Group message ignored (no trigger)", map[string]any{
|
2026-02-14 08:50:21 +00:00
|
|
|
"sender": senderID,
|
|
|
|
|
"group": groupIDStr,
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"is_mentioned": isBotMentioned,
|
2026-02-14 08:50:21 +00:00
|
|
|
"content": truncate(content, 100),
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
content = strippedContent
|
|
|
|
|
|
|
|
|
|
default:
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.WarnCF("onebot", "Unknown message type, cannot route", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"type": raw.MessageType,
|
|
|
|
|
"message_id": messageID,
|
|
|
|
|
"user_id": userID,
|
2026-02-14 08:50:21 +00:00
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 20:05:15 +00:00
|
|
|
logger.InfoCF("onebot", "Received "+raw.MessageType+" message", map[string]any{
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
"sender": senderID,
|
|
|
|
|
"chat_id": chatID,
|
|
|
|
|
"message_id": messageID,
|
|
|
|
|
"length": len(content),
|
|
|
|
|
"content": truncate(content, 100),
|
|
|
|
|
"media_count": len(parsed.Media),
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if sender.Nickname != "" {
|
|
|
|
|
metadata["nickname"] = sender.Nickname
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
c.lastMessageID.Store(chatID, messageID)
|
|
|
|
|
|
2026-02-22 22:56:48 +00:00
|
|
|
senderInfo := bus.SenderInfo{
|
|
|
|
|
Platform: "onebot",
|
|
|
|
|
PlatformID: senderID,
|
|
|
|
|
CanonicalID: identity.BuildCanonicalID("onebot", senderID),
|
|
|
|
|
DisplayName: sender.Nickname,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !c.IsAllowedSender(senderInfo) {
|
|
|
|
|
logger.DebugCF("onebot", "Message rejected by allowlist (senderInfo)", map[string]any{
|
|
|
|
|
"sender": senderID,
|
|
|
|
|
})
|
|
|
|
|
return
|
feat(onebot): enhance OneBot channel (#192)
* fix: change BotStatus type to json.RawMessage and add isAPIResponse function
* feat(onebot): add rich media, API callback, keepalive and voice transcription
Comprehensive improvements to the OneBot channel for better NapCatQQ
compatibility:
- Add echo-based API callback mechanism (sendAPIRequest) for
request/response correlation via pending map
- Add WebSocket ping/pong keepalive (30s ping, 60s read deadline)
- Fetch bot self ID via get_login_info on connect/reconnect
- Refactor parseMessageContentEx into parseMessageSegments supporting
image, record, video, file, reply, face, forward segments
- Add voice transcription via Groq transcriber (SetTranscriber)
- Switch to message segment array format for sending with auto reply
quote via lastMessageID tracking
- Add message_sent event handling and detailed notice event processing
(recall, poke, group increase/decrease, friend add, etc.)
- Use sync/atomic for echoCounter, optimize listen() lock pattern
- Clean up pending callbacks on Stop(), defer temp file cleanup
- Mount Groq transcriber on OneBot channel in main.go gateway
* feat(onebot): add user ID allowlist check for incoming messages
- Currently, the agent does not respond to messages sent by users outside the allowlist.
* refactor(onebot): simplify channel implementation and add emoji reaction
- onebot.go from 1179 to 980 lines (~17%)
2026-02-19 06:39:35 +00:00
|
|
|
}
|
2026-02-14 08:50:21 +00:00
|
|
|
|
2026-04-01 05:58:31 +00:00
|
|
|
inboundCtx := bus.InboundContext{
|
|
|
|
|
Channel: c.Name(),
|
|
|
|
|
ChatID: contextChatID,
|
|
|
|
|
ChatType: contextChatType,
|
|
|
|
|
SenderID: senderID,
|
|
|
|
|
MessageID: messageID,
|
|
|
|
|
Mentioned: isBotMentioned,
|
|
|
|
|
ReplyToMessageID: parsed.ReplyTo,
|
|
|
|
|
Raw: metadata,
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-01 12:56:48 +00:00
|
|
|
c.HandleInboundContext(c.ctx, chatID, content, parsed.Media, inboundCtx, senderInfo)
|
2026-02-14 08:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *OneBotChannel) isDuplicate(messageID string) bool {
|
|
|
|
|
if messageID == "" || messageID == "0" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.mu.Lock()
|
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
if _, exists := c.dedup[messageID]; exists {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if old := c.dedupRing[c.dedupIdx]; old != "" {
|
|
|
|
|
delete(c.dedup, old)
|
|
|
|
|
}
|
|
|
|
|
c.dedupRing[c.dedupIdx] = messageID
|
|
|
|
|
c.dedup[messageID] = struct{}{}
|
|
|
|
|
c.dedupIdx = (c.dedupIdx + 1) % len(c.dedupRing)
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func truncate(s string, n int) string {
|
|
|
|
|
runes := []rune(s)
|
|
|
|
|
if len(runes) <= n {
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
return string(runes[:n]) + "..."
|
|
|
|
|
}
|