Commit graph

396 commits

Author SHA1 Message Date
daming大铭
cf68166cf2
Merge pull request #1000 from alexhoshina/main
feat(feishu): enhance channel with markdown cards, media, mentions, and editing
2026-03-03 18:30:14 +08:00
Guoguo
1265655ef0
feat(telegram): add base_url support for custom Telegram Bot API server (#1021)
* feat(telegram): add base_url support for custom Telegram Bot API server

Allow users to specify a custom Telegram Bot API server URL via
config field `base_url` or env var `PICOCLAW_CHANNELS_TELEGRAM_BASE_URL`.
Defaults to the official https://api.telegram.org when left empty.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(telegram): trim whitespace and trailing slash from base_url

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:27:57 +08:00
Hoshina
fa1cb9cc74 fix(feishu): address PR #1000 review comments from @xiaket
- Consolidate extractImageKey/extractFileKey/extractFileName into shared
  extractJSONStringField helper to reduce code duplication
- Move mentionPlaceholderRegex to package-level position after imports
- Rename feishuCfg field to config for clarity within FeishuChannel
- Replace @_user_1 heuristic with GET /open-apis/bot/v3/info API call
  at startup for reliable bot @mention detection
- Fix double close on file handle in downloadResource by removing defer
  and using explicit close in both success and error paths
- Add unit tests for common.go and feishu_64.go helpers (53 test cases)
2026-03-03 16:44:24 +08:00
I Putu Eddy Irawan
0e810a2ec4 fix: tighten HTML-expansion test to stay under chunk size
Reduce markdown input from 700 to 600 repeats (3600 runes) so it stays
under the 4000-rune chunk threshold. This ensures the test actually
exercises the HTML-expansion re-splitting logic rather than being split
at the markdown level first.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 09:20:16 +07:00
I Putu Eddy Irawan
df53f4411a fix: format long lines in telegram_test.go to satisfy golines linter
Break function signatures and assert calls that exceed the 120-char
golines limit onto multiple lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 09:11:24 +07:00
Hoshina
595de7814d fix(feishu): remove dead fetchBotOpenID stub and fix misleading comment 2026-03-03 01:39:33 +08:00
Hoshina
42eb6ea410 fix(feishu): address review findings
- Remove stale "falls back to plain text" comment on Send
- Add empty ChatID validation in SendMedia to match Send
- Use messageID+fileKey as local filename to avoid write collisions
- Check allowlist before downloading inbound media to avoid wasted I/O
- Return errUnsupported consistently from all 32-bit stub methods
2026-03-03 01:27:46 +08:00
Hoshina
0bee9d7bcf fix(feishu): resolve lint issues 2026-03-03 01:04:11 +08:00
Hoshina
c9fb681f3b feat(feishu): enhance channel with markdown cards, media, mentions, and editing
Upgrade the Feishu channel from basic text-only to full feature parity with
Telegram/Discord: interactive card messages with markdown rendering, message
editing (MessageEditor), placeholder messages (PlaceholderCapable), emoji
reactions (ReactionCapable), and inbound/outbound media support (MediaSender).

Also add @mention detection with lazy bot open_id discovery, group trigger
filtering with mention awareness, and multi-type inbound message parsing
(text, post, image, file, audio, video).
2026-03-03 00:49:32 +08:00
esubaalew
2e0be92776 fix(wecom): resolve upstream rebase conflicts after channel refactor
Rebase onto latest upstream/main, keep ring-buffer dedupe behavior, move dedupe tests to pkg/channels/wecom, and ensure wecom/channels race tests pass.
2026-03-02 18:54:11 +03:00
esubaalew
29e9b6b4b5 fix(wecom): replace dedupe map rotation with circular queue
The previous dedupe map rotation logic completely cleared the map when it reached max size, causing an 'amnesia cliff' where immediately arriving duplicates of just-forgotten messages would be processed.

This change replaces that with a MessageDeduplicator struct that uses a circular queue (ring buffer) to track insertions. When the limit is reached, it only evicts the absolute oldest message from the map, completely resolving the cliff issue.

This also cleans up the WeCom Bot and App webhook handlers by encapsulating the mutex and map state.
2026-03-02 18:50:51 +03:00
esubaalew
8640c8177c fix(wecom): correctly retain boundary message during dedupe map rotation
When the dedupe map rotates, the previous logic entirely cleared the map, meaning the message that triggered the rotation was immediately forgotten and could be duplicated immediately.

This change seeds the new map with the current message to prevent that. Also adds a defensive nil check.
2026-03-02 18:50:29 +03:00
esubaalew
1e2ab4a5e5 test(wecom): add dedupe helper coverage and align constant usage
Use wecomMaxProcessedMessages in tests and add a concurrent same-message test
to lock in race-safety behavior for markMessageProcessed.
2026-03-02 18:50:29 +03:00
esubaalew
db17cdc86d test(wecom): align dedupe rotation behavior and add helper tests
Match rotation semantics to prior behavior by fully resetting the dedupe map
once the size limit is exceeded, and add focused tests for duplicate detection
and boundary rotation behavior.
2026-03-02 18:50:29 +03:00
esubaalew
18d89937ad fix(wecom): remove message-dedupe data races in bot/app channels
Centralize dedupe map access behind a mutex-safe helper and use it in both
WeCom bot and WeCom app channels to eliminate concurrent map access races while
preserving current dedupe behavior.
2026-03-02 18:50:29 +03:00
daming大铭
25639168ea
Merge pull request #300 from mymmrac/telegram-bot-commands
feat(telegram): Init bot commands on start
2026-03-02 23:43:10 +08:00
I Putu Eddy Irawan
33109a1676 Address Copilot review: handle HTML expansion exceeding Telegram limit
When markdownToTelegramHTML expands a chunk beyond 4096 chars (e.g.
**a** → <b>a</b>), re-split the markdown with a proportionally smaller
maxLen so each resulting HTML chunk fits within Telegram's limit.

Extract sendHTMLChunk helper to avoid duplicating the HTML-send +
plain-text-fallback logic.

Add test case for markdown-short-but-HTML-long scenario to verify
the re-splitting behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 22:35:41 +07:00
I Putu Eddy Irawan
3501962977 test: add unit tests for Telegram Send() method
Cover empty content early return, single-message send,
multi-chunk splitting for long messages, HTML-to-plain-text
fallback per chunk, and error propagation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:54:35 +07:00
美電球
f2ab1a74da
Merge pull request #893 from reevoid/rui-dev
Add WeCom AIBot channel implementation and tests
2026-03-02 21:50:21 +08:00
daming大铭
faec0261d0
Merge pull request #535 from xiaket/ci-enable-dupl-linter
ci: enable duplication linter in CI
2026-03-02 18:55:35 +08:00
Zhang Rui
23f48d7c4e refactor(aibot): remove downloadAndDecryptImage function to streamline image handling 2026-03-02 18:21:53 +08:00
Zhang Rui
edd339e056 fix(wecom): handle empty response by encrypting and returning a default response 2026-03-02 17:42:54 +08:00
Zhang Rui
619948f8ff fix(wecom): improve error message for response_url delivery failure 2026-03-02 17:42:54 +08:00
Zhang Rui
55c556a4c5 fix(wecom): update CanonicalID generation to use identity.BuildCanonicalID for consistency 2026-03-02 17:42:54 +08:00
Zhang Rui
79b7fb7792 fix(wecom): improve error handling in sendViaResponseURL and remove task on failure 2026-03-02 17:42:54 +08:00
Zhang Rui
79bc06c0ba refactor(wecom): simplify stream message structure by introducing WeComAIBotMsgItem and WeComAIBotMsgItemImage types 2026-03-02 17:42:54 +08:00
Zhang Rui
880c402ab7 refactor(wecom): streamline AES encryption/decryption and improve task management logic 2026-03-02 17:42:54 +08:00
Zhang Rui
8f3d611a4c refactor(wecom): replace generateSignature with computeSignature and update related tests 2026-03-02 17:42:54 +08:00
Zhang Rui
81f6787dd5 fix(docs): update WeCom AI Bot timeout duration in README and improve streamTask comments 2026-03-02 17:42:54 +08:00
ZHANG RUI
e88b39f21e Update pkg/channels/wecom/aibot.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-02 17:42:54 +08:00
Zhang Rui
a87e6b0551 feat(wecom-aibot): enhance stream task management with StreamClosedAt and improved cleanup logic 2026-03-02 17:42:54 +08:00
Zhang Rui
4e09c91dda feat(wecom-aibot): add context management for stream tasks to improve agent cancellation 2026-03-02 17:42:54 +08:00
ZHANG RUI
0b6d913dfc Update pkg/channels/wecom/aibot.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-02 17:42:54 +08:00
ZHANG RUI
aa9ce6955b Update pkg/channels/wecom/aibot.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-02 17:42:54 +08:00
ZHANG RUI
e33712deff Update pkg/channels/wecom/aibot.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-02 17:42:54 +08:00
Zhang Rui
e894f8d39a feat(wecom-aibot): add reasoning_channel_id to configuration and enhance message handling limits 2026-03-02 17:42:54 +08:00
Zhang Rui
c7d4012fc9 fix(wecom-aibot): correct variable name in JSON parsing in message callback handler 2026-03-02 17:42:42 +08:00
Zhang Rui
6caee427bb Add WeCom AIBot channel implementation and tests
- Introduced WeCom AIBot channel configuration in config.go with relevant fields.
- Implemented WeCom AIBot channel factory registration in init.go.
- Created unit tests for WeCom AIBot channel functionalities including initialization, start/stop behavior, webhook path handling, message encryption/decryption, and signature generation.
- Set default values for WeCom AIBot configuration in defaults.go.
2026-03-02 17:42:42 +08:00
美電球
3926585786
Merge pull request #916 from alexhoshina/fix/channel-config-cleanup
docs: sync READMEs, examples, and channel docs to match current config
2026-03-01 22:28:55 +08:00
Hoshina
cd3a4e1d1e docs: fix review feedback from PR #916
- Remove Feishu from webhook channel list in README.md and README.zh.md;
  add clarifying note that Feishu uses WebSocket/SDK mode instead
- Replace Chinese text in README.vi.md header with Vietnamese equivalent
- Translate mixed-language WeCom note in README.vi.md to full Vietnamese
- Mark webhook_path as optional (否) in docs/channels/line/README.zh.md
- Remove incorrect yaml struct tags from new-channel example in
  pkg/channels/README.md and README.zh.md (config uses json tags only)
- Fix multi-mode initChannel example to use whatsapp/whatsapp_native
  (matching the "WhatsApp Bridge vs Native" comment) instead of matrix
- Correct ReasoningChannelID description: list the 12 channels that
  have the field and note that PicoConfig does not expose it
2026-03-01 22:21:49 +08:00
Meng Zhuo
f7136b6a5d
Merge pull request #861 from p3ddd/refactor/modernize
refactor(modernize): apply safe modernize fixes
2026-03-01 15:38:59 +08:00
Kai Xia
32c864c309 enable dupl check
Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-03-01 18:17:32 +11:00
Tong Niu
44a52c0cf6
fix(tools): close resp.Body on retry cancel and cache http.Client instances (#940)
* fix(tools): close resp.Body on retry cancel and cache http.Client instances

Fix resp.Body leak in DoRequestWithRetry where req.Body (request) was
incorrectly closed instead of resp.Body (response) on context cancel.
Cache http.Client on web search/fetch provider structs and channel
adapters (WeCom, LINE) to avoid per-call allocation overhead.

* fix(channels): preserve original http client timeouts for LINE and WeCom

Split LINE single 60s client into infoClient (10s) for bot info lookups
and apiClient (30s) for messaging API calls. Lower WeCom cached client
base timeout from 60s to 30s (matching uploadMedia), and ensure it is
always >= the configured ReplyTimeout so the per-request context
deadline remains the effective limit.

* refactor(tools): extract timeout consts and deduplicate WebFetchTool constructors

Address PR review feedback from xiaket:
- Define searchTimeout, perplexityTimeout, fetchTimeout, defaultMaxChars,
  and maxRedirects as package-level consts instead of magic numbers.
- Remove misleading "No proxy" comment in NewWebFetchTool.
- Deduplicate NewWebFetchTool by delegating to NewWebFetchToolWithProxy.

* test(utils): add context cancellation test for DoRequestWithRetry

Verify that resp.Body is properly closed when the context is canceled
during retry sleep, covering the C8 resp.Body leak fix.

* fix(utils): close resp in test to satisfy bodyclose linter

* fix(utils): eliminate flakiness in context cancellation retry test

Synchronize cancellation using an onRoundTrip callback from the
transport wrapper instead of a timing-based context timeout. This
ensures the first client.Do completes before cancel fires, so
cancellation always hits during sleepWithCtx.
2026-03-01 16:55:46 +11:00
I Putu Eddy Irawan
2dccee5044 Address Copilot review feedback for Telegram message chunking
- Add early return for empty content to avoid silent no-op
- Split raw markdown before HTML conversion so SplitMessage's
  code-fence-aware logic works correctly and HTML tags/entities
  are never broken by mid-tag splitting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 09:40:09 +07:00
I Putu Eddy Irawan
a6f4274870 feat: add message chunking in Telegram Send method
Split HTML content into 4000-char chunks before sending to handle cases
where markdown-to-HTML conversion causes messages to exceed Telegram's
4096-character limit. Uses the existing SplitMessage utility which
preserves code block integrity across chunk boundaries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 08:56:12 +07:00
Artem Yadelskyi
b0c8fc4a7e
feat(telegram): Fix conflicts 2026-02-28 23:32:15 +02:00
Artem Yadelskyi
aeed392c3f
Merge branch 'main' into telegram-bot-commands
# Conflicts:
#	pkg/channels/telegram.go
2026-02-28 23:27:26 +02:00
Hoshina
c57a9c14e7 docs: sync READMEs, examples, and channel docs to match current config
- Update config.example.json to remove dead webhook_host/webhook_port
  and unused typing/placeholder fields
- Sync all READMEs (en/zh/ja/pt-br/fr/vi) with current channel config
- Update Discord docs: mention_only → group_trigger
- Update LINE, WeCom, WeComApp channel docs
2026-02-28 22:25:37 +08:00
Hoshina
e9b4886573 fix(wecom): fix context leak in Start() and data race in processedMsgs
Cancel the constructor-created context before overwriting in Start()
to prevent the original cancel function from becoming unreachable.

Move len(processedMsgs) check inside the write lock to eliminate a
data race, and re-insert the current msgID after map reset to prevent
duplicate processing of the in-flight message.

Applies to both WeComBotChannel and WeComAppChannel.
2026-02-28 22:08:14 +08:00
Hoshina
8e06e2adbd fix(wecom): initialize context in constructors to prevent nil panic in tests
The ctx field was only set in Start(), so tests calling handleMessageCallback
without Start() caused a nil pointer dereference in MessageBus.PublishInbound.
2026-02-28 21:45:08 +08:00
Hoshina
62f59f76e3 fix(wecom): use channel context instead of HTTP request context for async message processing
The HTTP request context is canceled as soon as the handler returns the
response, causing PublishInbound to fail with "context canceled" when
processMessage runs asynchronously in a goroutine. Use the channel's
long-lived context (c.ctx) instead.
2026-02-28 21:31:08 +08:00
wenjie
6c8866de6f
fix: propagate error when no channels are enabled during startup (#897) 2026-02-28 16:04:44 +08:00
Hoshina
871b2d7342 fix(whatsapp_native,agent): fixes for resource leak and log noise
- WhatsApp Start(): use deferred cleanup to nil out c.client/c.container
  and disconnect/close resources on any error after struct fields are
  assigned, preventing stale references and double-close in Stop()
- handleReasoning: treat bus.ErrBusClosed as an expected condition
  (DEBUG level) alongside context timeout/cancel, avoiding WARN noise
  during normal shutdown
2026-02-28 14:13:27 +08:00
Hoshina
d1b10a0004 fix(whatsapp_native,agent): address second round of review feedback
- WhatsApp Send(): detect unpaired state (Store.ID == nil) and return
  ErrTemporary instead of attempting to send while QR login is pending
- handleReasoning: check the returned error type (DeadlineExceeded /
  Canceled) instead of ctx.Err() to decide log level, so pubCtx
  timeouts on a full bus are correctly classified as expected
- Test: fill bus with a short-timeout loop instead of hardcoding the
  buffer size (64), making the test resilient to buffer size changes
2026-02-28 12:54:09 +08:00
Hoshina
fc28c2660a fix(whatsapp_native): close TOCTOU race between eventHandler and Stop
Move the stopping check and wg.Add(1) inside reconnectMu in
eventHandler, and set the stopping flag under the same lock in Stop().
This makes the two operations atomic with respect to each other,
preventing the race where:
1. eventHandler checks stopping (false)
2. Stop() sets stopping=true and enters wg.Wait() (wg is 0)
3. eventHandler calls wg.Add(1) → panic or goroutine leak
2026-02-28 12:38:07 +08:00
Petrichor
62bdece7f5
chore: resolve conflicts with upstream/main 2026-02-28 12:21:54 +08:00
Hoshina
9b80fdf885 fix(whatsapp_native,agent): address PR #884 review feedback
- Use c.runCtx for GetQRChannel so the QR producer is canceled on Stop()
- Add atomic stopping guard to prevent wg.Add/wg.Wait race in eventHandler
- Make Stop() context-aware: disconnect client before waiting, respect ctx deadline
- Reduce reasoning publish log noise: use debug level for expected ctx errors
- Add test for handleReasoning when outbound bus is full (timeout path)
2026-02-28 03:05:23 +08:00
Hoshina
c7d75a18f8 fix(whatsapp_native): fix goroutine and resource leak in Start/Stop lifecycle
- Move runCtx/runCancel creation before event handler registration and
  QR loop so Stop() can cancel at any point during startup
- Replace blocking QR event loop in Start() with a background goroutine
  that selects on runCtx.Done(), preventing Start() from hanging
  indefinitely when waiting for QR scan
- Track all background goroutines (QR handler, reconnect) with
  sync.WaitGroup; Stop() waits for them to finish before releasing
  client/container resources
- Cancel runCtx on error paths in Start() to avoid leaked contexts

Fixes resource leak introduced in #655.
2026-02-28 01:39:06 +08:00
美電球
ebfa72a286
Update config file reference from config.yaml to config.json
Closes: #565
2026-02-28 00:36:39 +08:00
美電球
fa68023ac2
Merge branch 'refactor/channel-system' into main 2026-02-27 20:04:08 +08:00
Hoshina
d429dcdd76 chore: fix go fmt formatting issues after rebase
Apply go fmt to files that had formatting inconsistencies
(alignment, indentation) after rebasing onto refactor/channel-system.
2026-02-27 17:35:50 +08:00
Avisek
9f95aad5f3 feat: Introduce LLM reasoning fields to LLM responses and enable routing reasoning output to dedicated channels. 2026-02-27 16:58:42 +08:00
Petrichor
222d1a3086
refactor(modernize): apply safe modernize fixes 2026-02-27 16:35:07 +08:00
nayihz
b5a4bb28b6 feat(discord): add proxy support and tests 2026-02-27 14:42:28 +08:00
Aditya Kalro
42ee9ab1e3 Complete the whatsapp native channel implementation based on the new channel interface 2026-02-26 22:35:52 -08:00
Aditya Kalro
a8644ca1c5 Refactor whatsapp native channel based on the new channel interface 2026-02-26 22:35:20 -08:00
Hoshina
779e4dfc38 docs(channels): add English README for channel system architecture 2026-02-27 03:33:21 +08:00
Hoshina
e5788e7f95 docs(channels): add Chinese README for channel system architecture 2026-02-27 03:33:21 +08:00
Hoshina
29ed650107 feat(channels): auto-orchestrate Placeholder/Typing/Reaction via capability interfaces
Define PlaceholderCapable, TypingCapable, and ReactionCapable interfaces
and have BaseChannel.HandleMessage auto-detect and trigger all three as
independent pipelines on inbound messages. This replaces the scattered
manual orchestration code in each channel's handleMessage with a single
unified dispatch in the framework layer.

Changes:
- Add PlaceholderCapable interface to interfaces.go
- Add ReactionCapable + RecordReactionUndo to interfaces.go
- BaseChannel.HandleMessage auto-triggers Typing → Reaction → Placeholder
- Manager gains reactionUndos sync.Map with TTL janitor cleanup
- Telegram: extract SendPlaceholder from manual code, add StartTyping
- Discord: add SendPlaceholder + StartTyping
- Pico: add SendPlaceholder (uses Pico Protocol message.create)
- Slack: extract ReactToMessage from manual code
- OneBot: extract ReactToMessage, remove leaked pendingEmojiMsg sync.Map
- LINE: move group-chat guard into StartTyping, remove manual orchestration
- Config: add Placeholder to PicoConfig; remove from Slack/LINE/OneBot
  (no MessageEditor, so placeholder config was dead code)
2026-02-27 03:33:21 +08:00
Hoshina
ba98069a00 fix: resolve wastedassign lint warnings in channel subpackages
Remove wasted initial assignments before switch statements in
onebot (segType), telegram (filename), and wecom (mediaType).
2026-02-26 23:36:06 +08:00
Hoshina
35a035bdda fix: port main branch changes to channel subpackages after rebase
Port changes that were applied to the old pkg/channels/*.go files on main
to their new locations in channel subpackages:
- telegram: precompile regex, var transcribedText, GetModelName()
- discord: var transcribedText declaration
- onebot: resp.Body.Close(), "canceled" spelling, remove empty line
- slack: named return values in parseSlackChatID
- wecom: remove sendMarkdownMessage dead code
- whatsapp: resp.Body.Close() after Dial
- gateway/helpers: remove unused errors import
2026-02-26 23:24:35 +08:00
ex-takashima
61eae92b38 fix(line): log loading refresh errors, skip typing without recorder
Address review feedback from @alexhoshina and Codex:
- Log sendLoading errors in ticker goroutine instead of discarding
- Only start typing indicator when PlaceholderRecorder is available
  to avoid wasted API calls and unnecessary goroutine creation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 20:29:09 +09:00
ex-takashima
e268ea82b9 Revert "feat(line): add StartTyping and PlaceholderRecorder integration"
This reverts commit ad736d71cb603cf1f1d20ea17758f95be26952cc.
2026-02-26 20:17:45 +09:00
mattn
8a1fb03974
Perf/precompile regex (#687)
* perf: pre-compile regexes at package level

Move regexp.MustCompile calls from inside methods to package-level
variables in web.go (7 regexes) and loader.go (2 regexes).
This avoids repeated compilation on every invocation.

Amp-Thread-ID: https://ampcode.com/threads/T-019c79c3-ea1c-7471-b09d-be90ba0e1ca0
Co-authored-by: Amp <amp@ampcode.com>

* perf: pre-compile regexes at package level

* retain the helpful comment

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-02-26 20:44:03 +11:00
ex-takashima
e450e9e053 feat(line): add StartTyping and PlaceholderRecorder integration
Implement TypingCapable interface for LINE channel using the
loading animation API (1:1 chats only, no group support).

- Add StartTyping() with 50s periodic refresh and context-based stop
- Integrate PlaceholderRecorder.RecordTypingStop in processEvent
- Skip RecordPlaceholder (LINE has no message edit API)
- Change sendLoading to accept context and return error
- Relax callAPI status check from 200 to 2xx range

Design consulted with Codex (GPT-5.2).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 16:43:41 +09:00
Aditya Kalro
49612adf8a Rebuilt after the refactoring of the base channel implementation. 2026-02-25 20:50:40 -08:00
Kai Xia
b190e6e910 enable whitespace
Whitespace is a linter that checks for unnecessary newlines at the start and end of functions, if, for, etc.

Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-02-25 21:31:07 +11:00
Kai Xia
d8b164b3d4 enable wastedassign
Finds wasted assignment statements.

Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-02-25 21:31:07 +11:00
Kai Xia
09cf8efde6 enable nakedret
Checks that functions with naked returns are not longer than a maximum size (can be zero).

Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-02-25 21:31:07 +11:00
Kai Xia
c5e8e19f54 enable misspell
Finds commonly misspelled English words.

Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-02-25 21:14:19 +11:00
Kai Xia
95f22bc07b enable bodyclose
Checks whether HTTP response body is closed successfully.

Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-02-25 21:14:19 +11:00
Hoshina
c241c55a0d fix(channels): address PR #734 review comments
Rename fastID() to uniqueID() with a security caveat comment clarifying
the ID is not cryptographically secure, and add unit tests for the
refactored index-based split helper functions.
2026-02-25 11:51:21 +08:00
Hoshina
72e897f95a fix(channels): fix memory hazards in channel abstraction layer
Address 7 memory/architecture issues affecting long-running gateway
processes on embedded devices (<10MB RAM):

- Fix dispatcher busy-wait: remove select+default pattern that caused
  CPU spin after context cancellation; SubscribeOutbound handles ctx
  internally
- Add TTL janitor for typingStops/placeholders sync.Map entries to
  prevent unbounded accumulation when outbound paths fail
- Reduce queue buffers from 100 to 16 slots (~84% memory reduction)
- Optimize SplitMessage with index-based rune operations to reduce
  intermediate string/rune allocations
- Replace uuid.New() with atomic counter + random prefix for media
  scope IDs (eliminates per-call crypto/rand syscall)
- Lazy channel worker creation: defer goroutine+buffer allocation
  until channel.Start() succeeds
2026-02-24 22:30:22 +08:00
Kai Xia(夏恺)
100356e8ec
refactor: cleanup dead code and turn on dead code detection in CI (#515)
* cleanup dead code.

Signed-off-by: Kai Xia <kaix+github@fastmail.com>

* add these two back with flag.

Signed-off-by: Kai Xia <kaix+github@fastmail.com>

* fix ci

Signed-off-by: Kai Xia <kaix+github@fastmail.com>

* remove this confusing line

Signed-off-by: Kai Xia <kaix+github@fastmail.com>

* make fmt

Signed-off-by: Kai Xia <kaix+github@fastmail.com>

* remove unused method.

picked up by golangci-lint run

Signed-off-by: Kai Xia <kaix+github@fastmail.com>

---------

Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-02-24 21:52:25 +08:00
daming大铭
d20cb364a2
Merge pull request #677 from yinwm/refactor/model-to-model-name
refactor(config): rename model field to model_name
2026-02-24 19:05:40 +08:00
Hoshina
0ede643e78 chore: apply PR #697 comment translations to refactored channel subpackages
Translate Chinese comments to English in qq, slack, and telegram channel
implementations, following the translation work done in PR #697. The
original PR modified the old parent package files, but these have been
moved to subpackages during the refactor, so translations are applied
to the new locations.
2026-02-24 12:17:11 +08:00
Aditya Kalro
04806bffe3 Moving logging from INFO to DEBUG for messages
Removing extrnaeous comments about mutex in loop.go

Made-with: Cursor
2026-02-23 15:50:55 -08:00
Kai Xia
6fb61539d7 translate Chinese comments
Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-02-24 10:27:49 +11:00
Hoshina
6852f24025 fix: address PR #662 review comments (bus drain, context timeouts, onebot leak)
- Drain buffered messages in MessageBus.Close() so they aren't silently lost
- Replace all context.TODO() with context.WithTimeout(5s) across 7 call sites
- Fix OneBot pending channel leak: send nil sentinel in Stop() and handle
  nil response in sendAPIRequest() to unblock waiting goroutines
2026-02-23 21:34:37 +08:00
yinwm
712f5a8300 refactor(config): rename model field to model_name
The configuration field for specifying the model has been renamed from
"model" to "model_name" for better clarity and consistency with the
model_list configuration.

A GetModelName() accessor method has been added to maintain backward
compatibility. Existing configurations using the old "model" field will
continue to work correctly.

This change affects:
- Configuration structure (AgentDefaults struct)
- All references across the codebase
- Documentation in all language variants
- Example configuration files
2026-02-23 16:55:06 +08:00
Aditya Kalro
25362ec763 Add new build tag for WhatsApp native support to keep the binary smaller. 2026-02-22 19:22:32 -08:00
Aditya Kalro
76f8ab827f Handle dis 2026-02-22 19:18:02 -08:00
Aditya Kalro
91eff9b34c Changing the logging to use the logger package to be consistent. 2026-02-22 19:10:25 -08:00
Aditya Kalro
81234f7e54 Sanitize WhatsApp messages and remove extra log messages. 2026-02-22 18:20:24 -08:00
Hoshina
56d80373eb feat(identity): add unified user identity with canonical platform:id format
Introduce SenderInfo struct and pkg/identity package to standardize user
identification across all channels. Each channel now constructs structured
sender info (platform, platformID, canonicalID, username, displayName)
instead of ad-hoc string IDs. Allow-list matching supports all legacy
formats (numeric ID, @username, id|username) plus the new canonical
"platform:id" format. Session key resolution also handles canonical
peerIDs for backward-compatible identity link matching.
2026-02-23 06:56:48 +08:00
Hoshina
f645e9a377 fix: address PR review feedback across channel system
- MediaStore: use full UUID to prevent ref collisions, preserve and
  expose metadata via ResolveWithMeta, include underlying OS errors
- Agent loop: populate MediaPart Type/Filename/ContentType from
  MediaStore metadata so channels can dispatch media correctly
- SplitMessage: fix byte-vs-rune index mixup in code block header
  parsing, remove dead candidateStr variable
- Pico auth: restrict query-param token behind AllowTokenQuery config
  flag (default false) to prevent token leakage via logs/referer
- HandleMessage: replace context.TODO with caller-propagated ctx,
  log PublishInbound failures instead of silently discarding
- Gateway shutdown: use fresh 15s timeout context for StopAll so
  graceful shutdown is not short-circuited by the cancelled parent ctx
2026-02-23 06:03:23 +08:00
Hoshina
a7276e2632 refactor(channels): move SplitMessage from pkg/utils to pkg/channels
Message splitting is exclusively a Manager responsibility. Moving it
into the channels package eliminates the cross-package dependency and
aligns with the refactoring plan.
2026-02-23 05:46:34 +08:00
Hoshina
5d304a9aeb fix: resolve golangci-lint issues in channel system 2026-02-23 05:22:18 +08:00
Hoshina
60b68b305a feat(channels): add typing/placeholder automation and Pico Protocol channel (Phase 10 + 7)
Phase 10: Define TypingCapable, MessageEditor, PlaceholderRecorder interfaces.
Manager orchestrates outbound typing stop and placeholder editing via preSend.
Migrate Telegram, Discord, Slack, OneBot to register state with Manager instead
of handling locally in Send. Phase 7: Add native WebSocket Pico Protocol channel
as reference implementation of all optional capability interfaces.
2026-02-23 04:55:15 +08:00
Aditya Kalro
c1ed163e77 Added a native WhatsApp channel implementation. 2026-02-22 12:29:27 -08:00
Hoshina
f8b656ec37 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-23 04:11:11 +08:00
Hoshina
e00745489d refactor(channels): remove channel-side voice transcription (Phase 12)
Remove SetTranscriber and inline transcription logic from 4 channels
(Telegram, Discord, Slack, OneBot) and the gateway wiring. Voice/audio
files are still downloaded and stored in MediaStore with simple text
annotations ([voice], [audio: filename], [file: name]). The pkg/voice
package is preserved for future Agent-level transcription middleware.
2026-02-23 03:47:12 +08:00
Hoshina
e10b1e1fd4 feat(channels): add MediaSender optional interface for outbound media
Add outbound media sending capability so the agent can publish media
attachments (images, files, audio, video) through channels via the bus.

- Add MediaPart and OutboundMediaMessage types to bus
- Add PublishOutboundMedia/SubscribeOutboundMedia bus methods
- Add MediaSender interface discovered via type assertion by Manager
- Add media dispatch/worker in Manager with shared retry logic
- Extend ToolResult with Media field and MediaResult constructor
- Publish outbound media from agent loop on tool results
- Implement SendMedia for Telegram, Discord, Slack, LINE, OneBot, WeCom
2026-02-23 03:10:57 +08:00
Hoshina
65a09208c4 refactor(channels): consolidate HTTP servers into shared server managed by Manager
Merge 3 independent channel HTTP servers (LINE :18791, WeCom Bot :18793,
WeCom App :18792) and the health server (:18790) into a single shared
HTTP server on the Gateway address. Channels implement WebhookHandler
and/or HealthChecker interfaces to register their handlers on the shared
mux. Also change Gateway default host from 0.0.0.0 to 127.0.0.1 for
security.
2026-02-23 02:39:09 +08:00
Hoshina
d72c9c1ee6 refactor(channels): standardize Send error classification with sentinel types
All 12 channel Send methods now return proper sentinel errors (ErrNotRunning,
ErrTemporary, ErrRateLimit, ErrSendFailed) instead of plain fmt.Errorf strings,
enabling Manager's sendWithRetry classification logic to actually work.

- Add ClassifySendError/ClassifyNetError helpers in errutil.go for HTTP-based channels
- LINE/WeCom Bot/WeCom App: use ClassifySendError for HTTP status-based classification
- SDK channels (Telegram/Discord/Slack/QQ/DingTalk/Feishu): wrap errors as ErrTemporary
- WebSocket channels (OneBot/WhatsApp/MaixCam): wrap write errors as ErrTemporary
- WhatsApp: add missing IsRunning() check in Send
- WhatsApp/OneBot/MaixCam: add ctx.Done() check before entering write path
- Telegram Stop: clean up placeholders sync.Map to prevent state leaks
2026-02-23 01:45:48 +08:00
Hoshina
afc7a1988f refactor(bus): fix deadlock and concurrency issues in MessageBus
PublishInbound/PublishOutbound held RLock during blocking channel sends,
deadlocking against Close() which needs a write lock when the buffer is
full. ConsumeInbound/SubscribeOutbound used bare receives instead of
comma-ok, causing zero-value processing or busy loops after close.

Replace sync.RWMutex+bool with atomic.Bool+done channel so Publish
methods use a lock-free 3-way select (send / done / ctx.Done). Add
context.Context parameter to both Publish methods so callers can cancel
or timeout blocked sends. Close() now only sets the atomic flag and
closes the done channel—never closes the data channels—eliminating
send-on-closed-channel panics.

- Remove dead code: RegisterHandler, GetHandler, handlers map,
  MessageHandler type (zero callers across the whole repo)
- Add ErrBusClosed sentinel error
- Update all 10 caller sites to pass context
- Add msgBus.Close() to gateway and agent shutdown flows
- Add pkg/bus/bus_test.go with 11 test cases covering basic round-trip,
  context cancellation, closed-bus behavior, concurrent publish+close,
  full-buffer timeout, and idempotent Close
2026-02-23 00:44:45 +08:00
Hoshina
38a26d702c refactor(channels): add per-channel rate limiting and send retry with error classification
Define sentinel error types (ErrNotRunning, ErrRateLimit, ErrTemporary,
ErrSendFailed) so the Manager can classify Send failures and choose the
right retry strategy: permanent errors bail immediately, rate-limit
errors use a fixed 1s delay, and temporary/unknown errors use exponential
backoff (500ms→1s→2s, capped at 8s, up to 3 retries). A per-channel
token-bucket rate limiter (golang.org/x/time/rate) throttles outbound
sends before they hit the platform API.
2026-02-22 23:51:55 +08:00
Hoshina
038fdf5000 refactor(media): add MediaStore for unified media file lifecycle management
Channels previously deleted downloaded media files via defer os.Remove,
racing with the async Agent consumer. Introduce MediaStore to decouple
file ownership: channels register files on download, Agent releases them
after processing via ReleaseAll(scope).

- New pkg/media with MediaStore interface + FileMediaStore implementation
- InboundMessage gains MediaScope field for lifecycle tracking
- BaseChannel gains SetMediaStore/GetMediaStore + BuildMediaScope helper
- Manager injects MediaStore into channels; AgentLoop releases on completion
- Telegram, Discord, Slack, OneBot, LINE channels migrated from defer
  os.Remove to store.Store() with media:// refs
2026-02-22 23:27:55 +08:00
Hoshina
a91de8546c refactor(channels): unify message splitting and add per-channel worker queues
Move message splitting from individual channels (Discord) to the Manager
layer via per-channel worker goroutines. Each channel now declares its
max message length through BaseChannelOption/MessageLengthProvider, and
the Manager automatically splits oversized outbound messages before
dispatch. This prevents one slow channel from blocking all others.

- Add WithMaxMessageLength option and MessageLengthProvider interface
- Set platform-specific limits (Discord 2000, Telegram 4096, Slack 40000, etc.)
- Convert SplitMessage to rune-aware counting for correct Unicode handling
- Replace single dispatcher goroutine with per-channel buffered worker queues
- Remove Discord's internal SplitMessage call (now handled centrally)
2026-02-22 22:46:29 +08:00
Hoshina
c669784216 refactor(channels): unify Start/Stop lifecycle and fix goroutine/context leaks
- OneBot: remove close(ch) race in Stop() pending cleanup; add WriteDeadline to Send/sendAPIRequest
- Telegram: add cancelCtx; Stop() now calls bh.Stop(), cancel(), and cleans up thinking CancelFuncs
- Discord: add cancelCtx via WithCancel; Stop() calls cancel(); remove unused getContext()
- WhatsApp: add cancelCtx; Send() adds WriteDeadline; replace stdlib log with project logger
- MaixCam: add cancelCtx; Send() adds WriteDeadline; Stop() calls cancel() before closing
2026-02-22 22:25:07 +08:00
Hoshina
931093c19d refactor(bus,channels): promote peer and messageID from metadata to structured fields
Add bus.Peer struct and explicit Peer/MessageID fields to InboundMessage,
replacing the implicit peer_kind/peer_id/message_id metadata convention.

- Add Peer{Kind, ID} type to pkg/bus/types.go
- Extend InboundMessage with Peer and MessageID fields
- Change BaseChannel.HandleMessage signature to accept peer and messageID
- Adapt all 12 channel implementations to pass structured peer/messageID
- Simplify agent extractPeer() to read msg.Peer directly
- extractParentPeer unchanged (parent_peer still via metadata)
2026-02-22 21:57:12 +08:00
Hoshina
b25b3c1324 fix: golangci-lint run --fix 2026-02-21 16:35:56 +08:00
Artem Yadelskyi
02b4d9fbe2
feat(linter): Fix govet linter 2026-02-20 22:35:16 +02:00
Artem Yadelskyi
2bf467fbbe
feat(telegram): Fix conflicts 2026-02-20 22:14:02 +02:00
Artem Yadelskyi
50d2616172
Merge branch 'main' into telegram-bot-commands
# Conflicts:
#	pkg/channels/telegram.go
2026-02-20 22:13:26 +02:00
Artem Yadelskyi
e1ba69293e
feat(telegram): Updated log message 2026-02-20 20:34:09 +02:00
Artem Yadelskyi
c319db431e
Merge branch 'main' into telegram-bot-commands 2026-02-20 20:32:00 +02:00
Artem Yadelskyi
26bca10b81
feat(telegram): Do not fail on commands init 2026-02-20 20:31:56 +02:00
Artem Yadelskyi
0675ce7c38
feat(fmt): Fix formatting 2026-02-20 20:03:11 +02:00
Artem Yadelskyi
ad8c2d48c8
Merge branch 'main' into fix-formatting
# Conflicts:
#	cmd/picoclaw/main.go
#	pkg/agent/context.go
#	pkg/agent/loop.go
#	pkg/channels/dingtalk.go
#	pkg/channels/feishu_64.go
#	pkg/channels/line.go
#	pkg/channels/manager.go
#	pkg/config/config.go
#	pkg/migrate/migrate_test.go
#	pkg/providers/anthropic/provider_test.go
#	pkg/providers/claude_provider_test.go
#	pkg/providers/http_provider.go
#	pkg/providers/openai_compat/provider.go
#	pkg/providers/protocoltypes/types.go
#	pkg/providers/types.go
2026-02-20 20:02:53 +02:00
Hoshina
d97848389b refactor(channels): replace bool with atomic.Bool for running state in BaseChannel 2026-02-21 00:00:29 +08:00
Hoshina
cd22272354 refactor(channels): remove redundant setRunning method from BaseChannel 2026-02-20 23:52:41 +08:00
Hoshina
59a889b608 refactor(channels): remove old channel files from parent package 2026-02-20 23:26:33 +08:00
Hoshina
6122ab664b refactor(channels): add channel subpackages and update gateway imports 2026-02-20 23:25:44 +08:00
Hoshina
083e29ebd9 refactor(channels): replace direct constructors with factory registry in manager 2026-02-20 23:19:40 +08:00
Hoshina
dfcf15bfff refactor(channels): add factory registry and export SetRunning on BaseChannel 2026-02-20 23:18:46 +08:00
daming大铭
1ef33c90ed
Merge pull request #474 from swordkee/main
add wecom and wecomApp
2026-02-20 21:17:59 +08:00
swordkee
0f70f783bd feat: add wecom and wecomApp test 2026-02-20 20:01:22 +08:00
swordkee
ca481035a4 feat: add wecom and wecomApp test 2026-02-20 19:39:12 +08:00
Vernon Stinebaker
2fb2a733d4
feat(discord): add mention_only option for @-mention responses (#518)
* 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>
2026-02-20 12:18:37 +01:00
swordkee
14ccfb39d9 feat: add wecom and wecomApp test 2026-02-20 18:28:10 +08:00
swordkee
59772cdbf2 feat: add wecom and wecomApp channel support 2026-02-20 17:40:59 +08:00
yinwm
723f4e84ef Merge upstream main into feat/refactor-provider-by-protocol
Resolved conflicts:
- pkg/config/config.go: Removed duplicate DefaultConfig() (already in defaults.go)

Upstream changes:
- Added Session.DMScope default value ("main")
- Various channel improvements

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 13:29:30 +08:00
hsohinna
4adafa8890
fix(channels): channels session key routing (#489)
* 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
2026-02-20 13:27:08 +08:00
Artem Yadelskyi
a896831903
feat(fmt): Fix formatting 2026-02-19 22:05:15 +02:00
Artem Yadelskyi
2038f04d0d
Merge branch 'main' into fix-formatting
# Conflicts:
#	pkg/agent/loop.go
#	pkg/agent/loop_test.go
#	pkg/channels/discord.go
#	pkg/channels/onebot.go
#	pkg/config/config.go
#	pkg/tools/subagent_tool_test.go
2026-02-19 22:04:48 +02:00
yinwm
f8f1d539d4 Merge remote-tracking branch 'origin/main' into feat/refactor-provider-by-protocol 2026-02-20 00:11:46 +08:00
Jex
213274002a
fix: keep Discord typing indicator alive during agent processing (#391)
* 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>
2026-02-19 13:28:58 +01:00
hsohinna
56a060ff61
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 14:39:35 +08:00
Huaaudio
e35a827624 update documents 2026-02-18 21:44:25 +01:00
Hua
e03124dc8a refactor: improve SplitMessage API clarity
- 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
2026-02-18 20:21:51 +00:00
Hua
94a1b8664b refactor: extract message splitting logic to shared utils
- 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
2026-02-18 20:01:53 +00:00
Artem Yadelskyi
9e120f90ea
feat(fmt): Run formatters 2026-02-18 21:48:23 +02:00
Leandro Barbosa
447c17aeb1 merge: sync upstream/main (PR #213) into feat/multi-agent-routing
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
2026-02-18 11:39:14 -03:00
Artem Yadelskyi
d49ce32010
Merge branch 'main' into telegram-bot-commands 2026-02-17 20:21:46 +02:00
Leandro Barbosa
4fde0175cf
Merge pull request #227 from mattn/fix-shadowing-running
Fix shadowing field runnnig
2026-02-17 12:58:48 -03:00
HansonJames
f0e90e6379 feat: Add the Qwen provider 2026-02-17 22:07:58 +08:00
Leandro Barbosa
12007b5670 merge: sync upstream/main into feat/multi-agent-routing
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
2026-02-16 10:34:55 -03:00
Artem Yadelskyi
1b1e472df2
feat(telegram): Changed command scope 2026-02-16 13:25:24 +02:00
Artem Yadelskyi
d1a66cbf50
feat(telegram): Fix text 2026-02-16 13:24:21 +02:00
Artem Yadelskyi
bfb9d8f644
feat(telegram): Init bot commands on start 2026-02-16 13:20:36 +02:00
is-Xiaoen
5c321a90de
fix: tighten file perms and enforce Slack ACL checks (#186)
- 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
2026-02-16 16:06:39 +08:00
Avisek Ray
9d5728ec5b
feat: implement structured Telegram command handling with a dedicated command service and telegohandler integration. (#164) 2026-02-16 14:20:16 +08:00
Huaaudio
32cb8fdc12
Feat: Discord message length check and auto split (#143)
* feat: discord message auto split

* make fmt

* chore: remove failing discord_test.go

---------

Co-authored-by: Hua <zhangmikoto@gmail.com>
2026-02-16 13:39:26 +08:00
Luke Milby
811e4f8728
add when picoclaw responsed to discord message will show its typing (#236) 2026-02-16 01:37:32 +08:00
Yasuhiro Matsumoto
7ce5b75178
Fix shadowing field runnnig 2026-02-16 00:47:17 +09:00
Meng Zhuo
0f506d4202
Merge pull request #165 from alexhoshina/feat/onebot
feat: add OneBot channel support
2026-02-15 09:12:00 +08:00
lxowalle
dbf2739783 fix: Remove the waiting animation for Telegram replies to reduce the risk of being rate-limited. 2026-02-15 02:26:42 +08:00
Leandro Barbosa
5e89264536 merge: sync upstream/main into feat/multi-agent-routing
Update registerSharedTools to use new WebSearchToolOptions API and
add hardware tools (I2C, SPI) from upstream. Accept upstream's
new web tools config test.
2026-02-14 10:38:04 -03:00
Hoshina
8cff6cf312 fix: improve connection handling in OneBotChannel 2026-02-14 20:25:55 +08:00
Hoshina
60c3d96b5e style: fix alignment of fields in BotStatus struct 2026-02-14 20:02:30 +08:00
Hoshina
773ce9bcb6 fix: update BotStatus type in oneBotRawEvent and adjust status checks 2026-02-14 19:58:19 +08:00
Hoshina
f7421128a0 style: remove unnecessary log messages in WebSocket listener 2026-02-14 17:46:47 +08:00
Hoshina
1fcf3fde0f style: fix format 2026-02-14 17:23:18 +08:00
Hoshina
7fa641a2ed feat: add OneBot channel support 2026-02-14 16:50:21 +08:00
PixelTux
ba0ef4b62c Merge branch 'main' into architecture-32-bit 2026-02-14 09:32:24 +01:00
ex-takashima
ac79a23e0a style: fix gofmt formatting (CRLF -> LF)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 11:21:47 +09:00
ex-takashima
aa7a8b89c3 merge: resolve conflict with upstream main
Merge upstream changes (HeartbeatConfig addition) alongside LINEConfig.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 10:47:06 +09:00
ex-takashima
f294a71bc5 feat(channels): add LINE Official Account channel support
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>
2026-02-14 10:01:20 +09:00
PixelTux
2cb90f2fe6 Merge branch 'main' into architecture-32-bit 2026-02-13 21:18:34 +01:00
lxowalle
1aea912fcd
Merge pull request #83 from carzygod/main
update telegram username support
2026-02-14 00:49:14 +08:00
Leandro Barbosa
8a6fb7d9e3 merge: sync upstream/main into feat/multi-agent-routing
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.
2026-02-13 12:24:26 -03:00
Leandro Barbosa
272536a11a feat: add multi-agent routing with declarative bindings
Implement per-agent workspace/model/session isolation with 7-level
priority routing cascade (peer > parent_peer > guild > team > account >
channel > default). Backward compatible - empty agents.list creates
implicit "main" agent from defaults.

Core components:
- routing/agent_id.go: ID normalization with pre-compiled regex
- routing/session_key.go: 4 DM scope modes with identity links
- routing/route.go: RouteResolver with priority-based binding matcher
- agent/instance.go: Per-agent state (workspace, sessions, tools, model)
- agent/registry.go: Agent lifecycle, route resolution, subagent ACL

Integration:
- config.go: AgentModelConfig (flexible JSON), bindings, session config
- loop.go: Complete rewrite for multi-agent dispatch
- Channel adapters: peer_kind/peer_id metadata (telegram, discord, slack)
- spawn.go: Subagent allowlist enforcement per agent

Validated end-to-end with Discord channel-based bindings, default
fallback routing, and per-agent session persistence.
2026-02-13 12:12:33 -03:00
zeo
1e17bac9f0 fix: correct index bug in extractCodeBlocks and extractInlineCodes
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.
2026-02-13 21:38:14 +08:00
Meng Zhuo
584a3dcc87 misc: fmt code 2026-02-13 17:51:47 +08:00
yinwm
8851152cbd refactor(tools): extract shared logic for internal channels and tool definitions
- 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
2026-02-13 15:05:16 +08:00
yinwm
4dfa133cb8 refactor(heartbeat): add configurable interval and channel-aware routing
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
2026-02-13 11:13:32 +08:00
Wikig
875a16d2d6 update telegram username support 2026-02-13 02:09:59 +08:00
mxrain
1d143fa10a feat: add Telegram proxy support and flexible allow_from matching
- Add proxy config field for Telegram channel to support HTTP/SOCKS proxies
- Use telego.WithHTTPClient to route all Telegram API requests through proxy
- Add FlexibleStringSlice type so allow_from accepts both strings and numbers
- Improve IsAllowed to match numeric ID, username, and @username formats
- Update config.example.json with proxy field
2026-02-12 22:38:47 +08:00
Wutachi
d7da39d62b Fix telegram channel permission check 2026-02-12 02:39:55 -03:00
yinwm
5c8626f07b refactor(channels): consolidate media handling and improve resource cleanup
Extract common file download and audio detection logic to utils package,
implement consistent temp file cleanup with defer, add allowlist checks
before downloading attachments, and improve context management across
Discord, Slack, and Telegram channels. Replace logging with structured
logger and prevent context leaks in transcription and thinking animations.
2026-02-12 12:46:28 +08:00
yinwm
fe4962794d
Merge branch 'main' into telegram-using-telego 2026-02-12 12:06:48 +08:00
yinwm
44e33d8b1c
Merge branch 'main' into issue-31-feat-add-slack-channel-integration-with-socket-mode-threads-reactions-and-slash-commands 2026-02-12 11:59:05 +08:00
Artem Yadelskyi
ca189588e6
feat(telegram): Use Telego instead of go-telegram-bot-api 2026-02-11 23:51:18 +02:00
PixelTux
cddafb403a add build constraints for feishu to support 32-bit builds 2026-02-11 20:59:25 +01:00
Cory LaNou
5eec80c654
feat(channels): add Slack channel integration with Socket Mode
Add Slack as a messaging channel using Socket Mode (WebSocket), bringing
the total supported channels to 8. Features include bidirectional
messaging, thread support with per-thread session context, @mention
handling, ack reactions (👀/), slash commands,
file/attachment support with Groq Whisper audio transcription, and
allowlist filtering by Slack user ID.

Closes #31

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 12:48:32 -06:00
Together
f12c337965 Remove duplicate truncate functions, reuse utils.Truncate
Multiple packages had their own private truncate implementations:
- channels/telegram.go: truncateString (byte-based, no "...")
- channels/dingtalk.go: truncateStringDingTalk (byte-based, no "...")
- voice/transcriber.go: truncateText (byte-based, with "...")

All three are functionally equivalent to the existing utils.Truncate,
which already handles rune-safe truncation and appends "..." correctly.

Replace all private copies with utils.Truncate and delete the dead code.
2026-02-12 00:46:48 +08:00
Harshdeep Sharma
9ec84c6630 Fix typos and update API keys in README 2026-02-11 20:46:01 +08:00
yinwm
4bc9e2d768 fix(cron): add one-time reminders and fix data paths to workspace
- Add at_seconds parameter for one-time reminders (e.g., "remind me in 10 minutes")
- Update every_seconds description to emphasize recurring-only usage
- Route cron delivery: deliver=true sends directly, deliver=false uses agent
- Fix cron data path from ~/.picoclaw/cron to workspace/cron
- Fix sessions path from workspace/../sessions to workspace/sessions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 20:31:41 +08:00
lxowalle
8c8daf64ef Merge branch 'pr-12' 2026-02-11 19:47:11 +08:00
yinwm
2b3de5cae5 add QQ channel support 2026-02-11 00:00:53 +08:00
w0x7ce
c5f6bec44b feat: Add DingTalk channel support via Stream Mode
- Add pkg/channels/dingtalk.go with WebSocket Stream Mode
- Add DingTalkConfig to config.go
- Register DingTalk in manager.go
- Update README with DingTalk setup instructions
- Add open-dingtalk/dingtalk-stream-sdk-go v0.9.1 dependency
2026-02-10 21:33:55 +08:00
lxowalle
9936dbce52 * Discord & Telegram support ASR through groq 2026-02-10 17:11:42 +08:00
Guoguo
f3f7ca7851 fix: enable Feishu message flow 2026-02-10 15:20:00 +08:00
Danieldd28
2df60b2fa3 feat: make context compression dynamic and add thinking animation
- Implement dynamic context window awareness for compression thresholds
- Add 'Thinking' animation for Telegram channel with auto-edit response
- Refactor summarization to handle multi-part batches and oversized messages
2026-02-10 02:00:57 +07:00
lxowalle
e17693b17c * First commit 2026-02-09 19:20:19 +08:00