Commit graph

544 commits

Author SHA1 Message Date
美電球
6fcc80bf44
Reformat WhatsAppConfig struct fields alignment 2026-02-27 20:20:00 +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 Ray
b1a6b3898d
Merge branch 'sipeed:main' into reasoning-chnl 2026-02-27 14:50:14 +05:30
lxowalle
29d4019e62
fix: set max tokens to 32k, default model to null (#858)
* * Set default value of max tokens to 32768

* * set max tokens to 32k, default model to null

* * Fix format error
2026-02-27 17:02:25 +08:00
Avisek
f96cf3f8cc feat: Add reasoning_channel_id to communication platform configurations and improve message bus context cancellation handling. 2026-02-27 16:58:42 +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
lxowalle
b6927c9a7a
Prompt to modify the max_tool_iterations parameter. (#855)
* Prompt to modify the max_tool_iterations parameter.

* fix typo and set max iterations to 50
2026-02-27 15:42:47 +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
mosir
b8c0d136c8
Merge branch 'sipeed:main' into fix/atomic-file-writes 2026-02-27 00:21:27 +08:00
Yiliu
3a3862340a fix(agent): resolve fallback model aliases from model_list 2026-02-26 23:50:40 +08:00
Yiliu
fb96645ea9 fix(providers): support lookup-based fallback candidate resolution 2026-02-26 23:50:33 +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
Hoshina
1d4fe4652a fix(bus): increase message bus buffer size from 16 to 64
Prevents potential backpressure under load when multiple channels
publish concurrently in gateway mode, where SDK callbacks blocking
on a full buffer can cause message loss or timeouts.
2026-02-26 22:46:57 +08:00
ex-takashima
0a7c929905 fix(media): separate import groups for gci linter
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 22:45:59 +09:00
ex-takashima
94aa2b1788 fix(media): use project logger and harden map cleanup
- Replace stdlib log.Printf with logger.InfoCF/WarnCF for consistency
  with the rest of the codebase (addresses @nikolasdehor review point #3)
- ReleaseAll: clean refToScope/refs mappings even if refs entry is missing
- CleanExpired: guard refToScope lookup before scope cleanup
- Add TestReleaseAllCleansMappingsIfRefsMissing for robustness

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 22:39:58 +09:00
mosir
433af435a9 style: fix gci import grouping in config, cron, and skills installer 2026-02-26 20:38:11 +08:00
mosir
d88700971f merge: resolve conflicts with main 2026-02-26 20:29:24 +08:00
penglp
a161bf9e24 Merge branch 'main' of https://github.com/sipeed/picoclaw 2026-02-26 19:29:32 +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
daming大铭
b1c61cd8df
Merge pull request #808 from alexhoshina/config/change-default-dm-scope-to-per-channel-peer
config: change default dm_scope to per-channel-peer
2026-02-26 17:39:16 +08:00
ian
f3c1162001
feat(skills): add retry for HTTP requests in skill installer (#261)
* feat(skills): add retry mechanism for HTTP requests

Implement a retry mechanism with exponential backoff for HTTP requests in the skill installer. This improves reliability when fetching skills from GitHub by automatically retrying failed requests up to 3 times.

Add comprehensive tests to verify retry behavior under different scenarios including success on different attempts and proper delay between retries.

* fix: improve http request retry logic with status code checks

Add shouldRetry helper function to determine retryable status codes.
Close response body between retry attempts and break early for non-retryable status codes.

* refactor: remove unused BuiltinSkill struct

The struct was not being used anywhere in the codebase, so it's safe to remove it to reduce clutter and improve maintainability.

* refactor(http): move retry logic to utils package

Extract HTTP retry functionality from skills package to utils for better reusability
Add context-aware sleep function and comprehensive tests

* refactor(http): extract retry delay unit to variable

Extract hardcoded retry delay unit to a variable for better testability and flexibility. Update tests to use milliseconds for faster execution while maintaining the same behavior.

* test(http_retry): remove t.Parallel from test cases

* test(http_retry): remove redundant test cases for retry success

The removed test cases for success on second and third attempts were redundant since the retry logic is already covered by other tests. This simplifies the test suite while maintaining coverage.
2026-02-26 20:35:26 +11:00
Hoshina
21654f1335 config: change default dm_scope to per-channel-peer
Change the default value of session.dm_scope from "main" to
"per-channel-peer" to provide better conversation isolation by
default. This prevents context leakage between different users
and channels.
2026-02-26 16:51:18 +08:00
Yiliu
438f764c7a
fix(providers): support per-model request_timeout in model_list (#733)
* fix(providers): support per-model request_timeout in model_list

* fix(lint): format provider constructors for golines

* refactor(providers): adopt functional options and preserve timeout migration

* docs(readme): sync request_timeout guidance across translated docs

---------

Co-authored-by: Yiliu <yiliu@affiliate-guide.com>
2026-02-26 19:08:19 +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
ex-takashima
d804f9cb3f fix(media): guard Interval<=0 panic, two-phase ReleaseAll
Address Codex (GPT-5.2) review feedback:
- Start: guard against Interval<=0 or MaxAge<=0 to prevent
  time.NewTicker panic on misconfiguration
- ReleaseAll: split into two phases (collect under lock, delete
  after unlock) matching CleanExpired pattern
- ReleaseAll: log file removal errors
- Add TestStartZeroIntervalNoPanic and TestStartZeroMaxAgeNoPanic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 16:33:32 +09:00
ex-takashima
b705e58528 fix(media): address review comments on TTL cleanup
- CleanExpired: split into two phases — collect expired entries under
  lock, then delete files after releasing the lock to minimize contention
- CleanExpired: guard against zero MaxAge (no-op if unconfigured)
- CleanExpired: log file removal errors instead of silently ignoring
- Start: protect with startOnce to prevent multiple goroutines
- Stop: rename once -> stopOnce for clarity
- cmd_gateway: call mediaStore.Stop() on error path after Start()
- Add TestCleanExpiredZeroMaxAge and double-Start test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 16:22:49 +09:00
mosir
16a1c96e40
Merge branch 'sipeed:main' into fix/atomic-file-writes 2026-02-26 13:50:55 +08:00
美電球
95b246f5a0
Merge pull request #790 from rordd/fix/gemini-prompt-cache-key
fix: exclude prompt_cache_key for Gemini API requests
2026-02-26 13:17:28 +08:00
Aditya Kalro
49612adf8a Rebuilt after the refactoring of the base channel implementation. 2026-02-25 20:50:40 -08:00
lxowalle
8f606733a2
fix: hide compressed historical messages notification (#799) 2026-02-26 12:36:19 +08:00
penglp
78ba0575b7 Merge branch 'main' of https://github.com/sipeed/picoclaw 2026-02-26 10:47:35 +08:00
임창욱
ea902429f2 fix: exclude prompt_cache_key for Gemini API requests
Gemini's OpenAI-compat endpoint rejects unknown fields.
Only send prompt_cache_key to OpenAI-native endpoints.
2026-02-25 14:48:51 -08:00
mosir
87e674ba15
Merge branch 'sipeed:main' into fix/atomic-file-writes 2026-02-25 23:44:27 +08:00
George Wang
ef1989f12e
Update pkg/tools/web.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-25 23:04:41 +08:00
George Wang
c8a553f109 add proxy support for TavilySearchProvider 2026-02-25 22:37:05 +08:00
mosir
6e754a86f3 merge: resolve conflicts with main 2026-02-25 21:53:04 +08:00
Zhaoyikaiii
740cdcaeaf
fix: remove redundant tools definitions from system prompt (#771)
* fix: remove redundant tools definitions from system prompt

Tools are already provided to the LLM via JSON schema through
ToProviderDefs(), so the text-based tools section in the system
prompt is redundant.

This removes the buildToolsSection() logic and the tools field
from ContextBuilder, reducing system prompt length while maintaining
the "ALWAYS use tools" rule reminder.

Fixes #731

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

* fix: correct spelling 'initialized' (was 'initialised')

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-25 20:44:07 +08:00
daming大铭
53578da51b
Merge pull request #617 from Zhaoyikaiii/fix/repeated-context-reprocessing
fix: implement caching for system prompt to avoid repeated context reprocessing (fixes #607)
2026-02-25 19:51:23 +08:00
daming大铭
f7fc8bb6e9
Merge pull request #770 from xiaket/ci-golangci-cleanup
(ci) golangci cleanup
2026-02-25 19:18:11 +08:00
daming大铭
9c7933dd00
Merge pull request #730 from winterfx/main
fix: multi-tool-call results incorrectly dropped causing LLM API 400
2026-02-25 19:12:03 +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
6830790692 enable predeclared
Find code that shadows one of Go's predeclared identifiers.

Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-02-25 21:31:07 +11:00
Kai Xia
4e6589d51f enable prealloc
Find slice declarations that could potentially be pre-allocated.

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
1fab1967d2 enable goprintffuncname
Checks that printf-like functions are named with `f` at the end.

Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-02-25 21:14:19 +11:00
Kai Xia
06daa30e75 enable dogsled
Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()).

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
Zhaoyikaiii
edc78191c9
style: fix gci formatting in protocoltypes/types.go 2026-02-25 15:36:54 +08:00
Zhaoyikaiii
1f7cbd9164
fix: cache system prompt with mtime-based auto-invalidation (#607)
Avoid rebuilding the entire system prompt on every BuildMessages() call
by caching the static portion (identity, bootstrap, skills summary,
memory) and only recomputing it when workspace source files change.

Key changes:

- ContextBuilder caches the static prompt behind an RWMutex with
  double-checked locking. Source file changes are detected via cheap
  os.Stat mtime checks so no explicit invalidation is needed.

- Track file existence at cache time (existedAtCache map) so that
  newly created or deleted bootstrap/memory files also trigger a
  rebuild — the old modifiedSince() silently returned false on
  os.IsNotExist.

- Walk the skills directory recursively with filepath.WalkDir to
  catch content-only edits at any nesting depth; directory mtime
  alone misses in-place file modifications on most filesystems.

- ToolRegistry.sortedToolNames() sorts tool names before iteration,
  ensuring deterministic tool definition order across calls — a
  prerequisite for LLM-side prefix/KV cache reuse.

- Merge all context (static + dynamic + summary) into a single
  system message for provider compatibility: the Anthropic adapter
  extracts messages[0] as the top-level system parameter, and Codex
  reads only the first system message as instructions.

- Fix a data race in BuildMessages() where cachedSystemPrompt was
  read without holding the lock in a debug log statement.

- Add tests: single system message invariant, mtime auto-invalidation,
  new-file creation detection, skill file content change, explicit
  InvalidateCache, cache stability, concurrent access (20 goroutines
  x 50 iterations, passes go test -race), and a benchmark.
2026-02-25 15:27:45 +08:00
penglp
81c8c07b79 fix:Openrouter in providers and modellist 2026-02-25 14:44:49 +08: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
Achton Smidt Winther
ec6da7a530
fix: reject empty task in spawn tool (#740)
The spawn tool accepts empty strings as valid task arguments, which
causes a subagent to run with no meaningful work. The subagent's
completion message is then routed back to the originating channel
(e.g. Signal, Discord), where the main agent processes it and may
hallucinate an unrelated response that gets sent to users.

Validate that the task parameter is non-empty after trimming whitespace.

Related: #545

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 07:39:49 +11:00
Nikita Nafranets
a4b6cea103 fix: distinguish network timeouts from context window errors
HTTP timeouts (context deadline exceeded, Client.Timeout) were
incorrectly classified as context window errors, triggering useless
history compression. Replace broad substring checks ("context",
"token", "length") with specific patterns for real context limit
errors and explicitly exclude timeout errors from that path.

Additionally, timeout errors were not retried at all — the retry
loop only handled context window errors. Now timeouts are retried
up to 2 times with exponential backoff (5s, 10s).
2026-02-24 21:54:44 +03:00
mosir
f86de3cbb9 Merge remote-tracking branch 'sipeed/main' into fix/atomic-file-writes 2026-02-25 00:03:55 +08:00
mosir
7a2d353d0f Merge branch 'main' of github.com:mosir/picoclaw into fix/atomic-file-writes 2026-02-24 23:59:05 +08:00
mosir
11996f1a0b refactor(pkg): move atomic file write to dedicated fileutil package 2026-02-24 23:57:13 +08:00
daming大铭
fd26fa7459
Merge pull request #587 from nayihz/feat_webtool_proxy
feat: add HTTP proxy support for web tools
2026-02-24 23:51:01 +08:00
mosir
4aed3591e7 refactor(pkg/utils): improve WriteFileAtomic with stronger durability guarantees 2026-02-24 23:49:40 +08:00
daming大铭
eb138a3f13
Merge pull request #642 from Lixeer/main
fix: better session management for `github_copilot_provider`
2026-02-24 23:18:14 +08:00
Lixeer
d09c64fcee fix: implement code review suggestions
Address all feedback from PR review:
- Lock granularity
- Empty response handling
- Shutdown race condition
- Interface naming
2026-02-24 22:33:04 +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
winterfx
b47a39af9c fix: handle multi-tool-call orphan detection in sanitizeHistoryForProvider
Walk backwards over preceding tool messages to find the nearest assistant
with ToolCalls, instead of only checking the immediate predecessor. Add
unit tests for sanitizeHistoryForProvider covering key edge cases.
2026-02-24 21:35:15 +08:00
ex-takashima
4ada4063d7 feat(media): integrate TTL cleanup into FileMediaStore
Add background TTL-based cleanup (L2 safety net) directly into
FileMediaStore so file deletion and in-memory ref removal happen
atomically under the same mutex, preventing dangling references.

- Add storedAt timestamp and refToScope reverse map to mediaEntry
- Add CleanExpired() for atomic TTL-based expiration
- Add Start()/Stop() for background goroutine lifecycle
- Add MediaCleanupConfig (enabled, max_age, interval) to config
- Wire up in cmd_gateway.go with config-driven defaults
- Add 8 new tests including concurrent cleanup safety

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 21:24:32 +09:00
daming大铭
9cc0f8e685
Merge pull request #724 from mqyang56/fix/model-list-default-value-leak
fix: prevent DefaultConfig template values from leaking into user model_list entries
2026-02-24 19:43:23 +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
yinwm
01e2354b97 fix: align map values for proper formatting 2026-02-24 19:04:38 +08:00
yangmanqing
0d761ca608 fix: prevent DefaultConfig template values from leaking into user model_list entries 2026-02-24 17:57:28 +08:00
nayihz
76f2b42d5b feat: improve web proxy handling and coverage 2026-02-24 17:17:14 +08:00
daming大铭
b6e965e549
Merge pull request #604 from winterfx/fix/reasoning-content-missing
fix: preserve reasoning_content for OpenAI-compatible reasoning models
2026-02-24 14:20:36 +08:00
mosir
c56fcedcb1 refactor(pkg/utils): add unified atomic file write utility 2026-02-24 13:22:52 +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
mattn
6fe3920a4d
perf: refactoring collecting skills (#688)
* perf: refactoring collecting skills

* Fix order to store dir.Name()

* Add tests
2026-02-24 10:07:09 +11:00
Goksu Ceylan
09b1992dd7
fix(security): ensure custom deny patterns extend defaults instead of replacing them (#479)
* fix (security): custom deny patterns denying default patterns

* fix formatting whitespace
2026-02-24 09:02:44 +11:00
0x5487
2fa51d7b86
fix(security): change gateway default bind to 127.0.0.1 (#393)
* chore: Update default host bindings from 0.0.0.0 to 127.0.0.1 for various services and examples.

* config: Update default host bindings to 0.0.0.0 for improved Docker accessibility and add related documentation.

* chore: resolve conflict

* chore: remove link

* docs: Add a tip for Docker users regarding gateway host configuration to the French and Vietnamese READMEs.

* fix: typo issue

* docs: Update Chinese README.zh.md.
2026-02-24 08:54:10 +11:00
Chujiang
8a53cb9665
fix: align Docker Go version with go.mod and optimize logger (#596)
- Update Dockerfile to use golang:1.25-alpine to match go.mod (go 1.25.7)
- Optimize logger by avoiding string concatenation in file writes
- Add explicit empty string assignment for fieldStr when no fields

These changes improve build consistency and reduce memory allocations
in the hot logging path, which is important for the project's goal
of running on resource-constrained devices (<10MB RAM).

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 08:52:16 +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
美電球
ae74fa3812
Merge pull request #541 from edouard-claude/feat/mistral-provider
feat: add native Mistral AI provider support
2026-02-23 21:06:26 +08:00
0x5487
19c698356c
fix(security): workspace sandbox avoid time-of-check/time-of-use (TOCTOU) races (#464)
* chore: Update default host bindings from 0.0.0.0 to 127.0.0.1 for various services and examples.

* config: Update default host bindings to 0.0.0.0 for improved Docker accessibility and add related documentation.

* refactor: reimplement filesystem tools with `os.OpenRoot` for enhanced security and simplified path validation.

* chore: revert other PR content from this branch

* docs: Update Chinese README.

* docs: Update Chinese README.

* docs: Update Chinese README.

* refactor: Reorder filesystem helper functions, extract directory entry formatting logic, and enhance `WriteFileTool`'s result message.

* feat: Enhance `mkdirAllInRoot` to prevent creating directories over existing files and add tests for directory creation functionality.

* Refactor filesystem tools to use a `fileReadWriter` interface for both host and sandboxed I/O, improving atomic writes and error handling.

* refactor: unify filesystem read/write operations with atomic write guarantees and clearer naming.

* refactor: rename `appendFileWithRW` function to `appendFile`

* refactor: unify filesystem access by introducing a `fileSystem` interface and updating tools to use it directly, removing `os.Root` dependency from `sandboxFs`.

* chore: run make fmt

* fix: `validatePath` now returns an error when the workspace is empty.
2026-02-23 20:09:53 +11:00
yinwm
e76e45f30f Merge remote-tracking branch 'origin/main' into refactor/model-to-model-name 2026-02-23 16:56:20 +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
071505e797 Removing the agentMu mutex from the AgentLoop 2026-02-22 21:03:42 -08:00
Vidish
4cc8b90da9
Fix: missing Tavily config in loop.go, and the invalid config param in web_search (#660) 2026-02-23 12:12:34 +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
26bee0b791 refactor(loop): disable media cleanup to prevent premature file deletion 2026-02-23 08:20:15 +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
Vidish
c6865fe852
feat: integrate Tavily search (#340)
* feat: integrate Tavily search

* fix: set include_raw_content to false in Tavily search as wealready get relevant data inside content

* refactor: update Go type declarations to `any`, apply formatting fixes.
2026-02-23 00:30:14 +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
Lixeer
3d605a4f53 fix: run fmt and lint 2026-02-22 23:02:29 +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
Lixeer
a849e02917 fix: better session management for github_copilot_provider 2026-02-22 22:30:53 +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
King Tai
cb0c8703fb
test(tools,utils): add ToolRegistry unit tests and fix Truncate panic on negative maxLen (#517)
Add comprehensive unit tests for the ToolRegistry covering registration,
lookup, execution, context injection, async callbacks, schema generation,
provider definition conversion, and concurrent access.

Fix a defensive edge case in Truncate where a negative maxLen would cause
a slice bounds panic, and add table-driven tests covering boundary
conditions, zero/negative lengths, and Unicode handling.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-22 21:40:59 +11:00
Edouard CLAUDE
34a8ce5af0 fix: remove extra fields from ToolCall JSON serialization
Mistral's API strictly validates tool_calls in assistant messages and
rejects non-standard fields. The ToolCall struct had Name and Arguments
as top-level JSON fields, duplicating data already in Function.Name
and Function.Arguments. OpenAI silently ignored these extras but
Mistral returns 422.

Change json tags to "-" so these internal fields are no longer
serialized to API payloads while remaining available in Go code.
2026-02-22 11:40:21 +04:00
Edouard CLAUDE
65422a16a4 feat: add native Mistral AI provider support
Add Mistral as a first-class provider alongside the 17 existing ones.
Mistral uses the OpenAI-compatible API at https://api.mistral.ai/v1
with provider-specific model prefix stripping (mistral/model → model).

Changes:
- Add Mistral to ProvidersConfig, IsEmpty(), HasProvidersConfig()
- Add mistral entry in default model_list (defaults.go)
- Add mistral protocol in factory_provider.go and getDefaultAPIBase()
- Add mistral prefix stripping in openai_compat normalizeModel()
- Add mistral case in legacy factory.go resolveProviderSelection()
- Add mistral migration entry in ConvertProvidersToModelList()
- Add mistral to supported providers in migrate/config.go
- Add mistral section in config.example.json
- Update AllProviders test (17 → 18 providers)

Tested end-to-end with mistral-small-latest model.
2026-02-22 11:40:21 +04:00
yuchou87
4e330b297c test(mcp): add manager behavior and lifecycle unit tests 2026-02-22 15:13:29 +08:00
yuchou87
16a3b96dde fix(mcp): validate workspace before resolving relative env_file 2026-02-22 15:06:57 +08:00
yuchou87
672da984e5 Merge branch 'main' into mcp-tools-support 2026-02-22 14:48:07 +08:00
winterfx
d224397f40 fix: preserve reasoning_content for OpenAI-compatible reasoning models
Models like Moonshot kimi-k2.5 and DeepSeek-R1 return a
reasoning_content field in assistant messages. When thinking is enabled,
the API requires this field to be echoed back in subsequent requests.
PicoClaw was silently dropping it, causing 400 errors on tool-call
round-trips.

- Add ReasoningContent to Message and LLMResponse types
- Parse reasoning_content in openai_compat parseResponse()
- Carry reasoning_content through assistant tool-call messages
- Add unit test for reasoning_content parsing

Fixes #588
2026-02-21 23:29:40 +08:00
Hoshina
b25b3c1324 fix: golangci-lint run --fix 2026-02-21 16:35:56 +08:00
Hoshina
0066602294 fix: golangci-lint run --fix 2026-02-21 16:20:15 +08:00
Hoshina
3df7f70540 fix: golangci-lint fmt 2026-02-21 16:05:39 +08:00
yuchou87
cfc29a1383 fix(mcp): prevent use-after-close race between CallTool and Close
A race could occur when Close() called conn.Session.Close() concurrently
with an in-flight conn.Session.CallTool(), leading to undefined behavior.

Fix by adding a sync.WaitGroup to Manager:
- CallTool increments the WaitGroup while holding the read lock (after
  checking m.closed), ensuring no new calls are counted after Close sets
  the flag
- Close sets m.closed=true, releases the write lock, then waits for all
  in-flight calls to finish via wg.Wait() before closing sessions
2026-02-21 14:10:48 +08:00
yuchou87
11dbc301f9 perf(agent): cache ListAgentIDs() result before MCP tool registration loop
ListAgentIDs() was called on every iteration of the inner tool loop,
causing repeated allocations. Capture the slice once and reuse it for
both agentCount and the registration loop.
2026-02-21 13:48:41 +08:00
yuchou87
d2b3fc1dd0 fix(mcp): include server name and cause in Close() errors
Previously Close() discarded all underlying errors and returned only
'failed to close N server(s)', making debugging impossible.

Now each error wraps the server name and original cause, and all errors
are joined so callers can inspect the full failure list.
2026-02-21 13:46:06 +08:00
yuchou87
33058b534e fix(mcp): reject empty keys in loadEnvFile
A line like '=value' would result in envVars[""] = "value", producing
an invalid environment entry for the child process. Return an error
instead when the key is empty.
2026-02-21 13:45:00 +08:00
yuchou87
246fdf3f33 fix(mcp): guard against nil result from CallTool
CallTool can return (nil, nil) if the underlying MCP library misbehaves.
Without a nil check, result.IsError would panic. Return an explicit error
ToolResult instead.
2026-02-21 13:40:55 +08:00
yuchou87
d867e86dbe Merge branch 'main' into mcp-tools-support
# Conflicts:
#	config/config.example.json
#	pkg/config/config.go
2026-02-21 13:28:15 +08:00
Luke Milby
80c8b57533
Fix Memory Write (#557)
* fix issue where memory will only trigger when asked to remember something

* updated prompt for memory usage
2026-02-21 08:21:38 +08:00
Meng Zhuo
273a8a2318
Merge pull request #550 from mymmrac/govet-linter
feat(linter): Fix govet linter
2026-02-21 08:20:35 +08:00
Goksu Ceylan
244eb0b47d
fix (security): ExecTool working_dir sandbox escape (#478)
* fix (security) Shell working_dir bypass

* Feedback from @mengzhuo & Discord
- reuse internal security package to validate path
- add tests for workspace escape
2026-02-21 08:15:46 +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