* feat(discord): add mention_only option for @-mention responses
Add MentionOnly config option to Discord channel. When enabled, the bot
only responds when explicitly @-mentioned, useful for shared servers.
- Add MentionOnly bool field to DiscordConfig
- Store botUserID on startup for mention checking
- Check m.Mentions before processing messages when MentionOnly is true
- Update config example and README documentation
* fix(discord): resolve race condition and strip mention from content
- Get botUserID before opening session to avoid race condition
- Add stripBotMention to remove @mention from message content
- Handles both <@USER_ID> and <@!USER_ID> mention formats
* fix(discord): skip mention_only check for DMs
DMs should always be responded to regardless of mention_only setting.
Added check to skip the mention_only logic when GuildID is empty.
* Update README.md
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Hua Audio <161028864+Huaaudio@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix(onebot): add metadata for direct and group message handling
* fix(qq): add metadata for direct and group message handling
* fix(dingtalk): add metadata for direct and group message handling
* fix(feishu): add metadata for direct and group message handling
* fix(whatsapp): add metadata for direct and group message handlinga
* fix(line): add metadata for direct and group message handling
* fix(maixcam): add metadata for person detection handling
* fix(config): add default session configuration with DMScope
* fix: keep Discord typing indicator alive during agent processing
Discord's ChannelTyping() expires after ~10s, but agent processing
(LLM + tool execution) typically takes 30-60s+. Replace single-fire
ChannelTyping() with a self-managed typing loop inside DiscordChannel.
- startTyping(chatID): goroutine refreshes ChannelTyping every 8s
- stopTyping(chatID): called in Send() when response is dispatched
- Stop() cleans up all typing goroutines on shutdown
- startTyping placed after all early returns to prevent goroutine leaks
Typing lifecycle fully contained in channel layer, no interface changes.
Fixes#390
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add goroutine safety to Discord typing indicator
- Add 5-minute timeout as safety net to prevent indefinite goroutine leaks
when agent produces no outbound message (empty response, panic, etc.)
- Listen on c.ctx.Done() so goroutine exits when channel context is cancelled
- Log ChannelTyping() errors at debug level for diagnostics (rate limits, session closed)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* 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%)
- Accept hard upper limit (maxLen) instead of pre-subtracted value
- Caller now passes actual platform limit (e.g., 2000 for Discord)
- Internal buffer of 500 chars is handled within message.go
- Preferred split at maxLen - 500, may extend to maxLen for code blocks
- Never exceeds maxLen, no more mental math for callers
- Move FindLast, findLast, and SplitMessage from discord.go to pkg/utils/message.go
- Update discord.go to use utils.SplitMessage()
- Makes splitting logic reusable across other channels
Resolve conflicts in pkg/providers/types.go and pkg/agent/loop.go:
- types.go: use protocoltypes aliases from PR #213, keep fallback types
- loop.go: drop old single-agent createToolRegistry (replaced by multi-agent pattern)
Refactor to align with PR #213 patterns:
- instance.go: use NewExecToolWithConfig (accept full config for deny patterns)
- registry.go: pass full config to NewAgentInstance
- loop.go: add Perplexity web search options to registerSharedTools
Resolve conflicts:
- pkg/agent/loop.go: integrate context compression, command handling,
utf8 token estimation, and summarization notification into
multi-agent routing architecture
- pkg/config/config_test.go: merge imports from both branches
- pkg/agent/loop_test.go: update test to use registry-based sessions
- write config and cron store with 0600 instead of 0644
- check allow list in Slack slash commands and app mentions
- pass workspace restrict flag to cron exec tool
Closes#179
Update registerSharedTools to use new WebSearchToolOptions API and
add hardware tools (I2C, SPI) from upstream. Accept upstream's
new web tools config test.
Add LINE Messaging API as the 9th messaging channel using HTTP Webhook.
Supports text/image/audio messages, group chat @mention detection,
reply with quote, and loading animation.
- No external SDK required (standard library only)
- HMAC-SHA256 webhook signature verification
- Reply Token (free) with Push API fallback
- Group chat: respond only when @mentioned
- Quote original message in replies using quoteToken
Closes#146
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve conflicts in loop.go, config.go, config_test.go,
spawn.go, and subagent.go. Integrate upstream ToolResult/AsyncTool
pattern with multi-agent routing features. Rename mockProvider
to mockRegistryProvider in registry_test.go to avoid redeclaration
with upstream's loop_test.go.
The previous implementation used len(codes)-1 in ReplaceAllStringFunc,
which caused all placeholders to point to the same (last) index.
This resulted in only the last code block being displayed correctly
when multiple code blocks were present in a message.
Now using a proper counter variable that increments for each match,
ensuring each code block gets a unique placeholder index.
- Add constants package with IsInternalChannel helper to centralize internal channel checks across agent, channels, and heartbeat services
- Add ToProviderDefs method to ToolRegistry to consolidate tool definition conversion logic used in agent loop and tool loop
- Refactor SubagentTool.Execute to use RunToolLoop for consistent tool execution with iteration tracking
- Remove duplicate inline map definitions and type assertion code throughout codebase
feat(config): add heartbeat interval configuration with default 30 minutes
feat(state): migrate state file from workspace root to state directory
feat(channels): skip internal channels in outbound dispatcher
feat(agent): record last active channel for heartbeat context
refactor(subagent): use configurable default model instead of provider default