Commit graph

833 commits

Author SHA1 Message Date
fishtrees
1945436dd4
feat(cron): add execution lifecycle logging (#1185)
- Log job start with name, id, schedule kind, and channel
- Log job completion with duration and next run time
- Log job errors with duration and error message
- Helps diagnose scheduler stalls and connection issues
2026-03-06 20:46:52 +08:00
zihan987
e6f5467711 Fix golines for vivgrid case 2026-03-06 04:20:22 -08:00
Qiaochu Hu
7f6d95c026
fix: handle zero values in cron schedule type assertions (#1147)
Fixes #1126

Go type assertions return true for zero values, which caused recurring
cron jobs (every_seconds/cron_expr) to silently become one-time 'at' tasks
when LLMs filled unused optional parameters with default values (0).

Changes:
- Add validity checks after type assertions: atSeconds > 0, everySeconds > 0, cronExpr != ""
- This ensures zero values are treated as 'not set' rather than valid schedule values
- Recurring tasks like "remind me every 2 hours" now correctly create recurring jobs
2026-03-06 20:11:08 +08:00
BallerIsLeet
23abbb67ea
feat(auth): add Anthropic OAuth setup-token login (#926)
* feat(auth): add Anthropic OAuth setup-token login flow

Add support for Anthropic's OAuth-based setup tokens (sk-ant-oat01-*)
as an alternative to API keys. This includes:

- New `--setup-token` flag on `auth login` command
- Interactive login menu for Anthropic (setup token vs API key)
- Setup token validation and credential storage with oauth auth method
- Usage endpoint integration to show 5h/7d utilization in `auth status`
- Streaming support for OAuth tokens (required by Anthropic API)
- Model ID normalization (dots to hyphens) for API compatibility
- Remove .env.example (secrets should not be templated)

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

* feat(auth):  update related functionality

* refactor(auth): organize constants and improve header casing in requests fo CI

* fix(auth): fix golint again

* fix(auth): handle nil arguments in tool calls for buildParams function

---------

Co-authored-by: Baller <sharonms3377@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:58:23 +08:00
shikihane
c368b5b359
feat(feishu,tools): add outbound media delivery via send_file tool (#1156)
* feat(feishu): implement SendMedia and add send_file tool

Add outbound media support for the Feishu channel so the agent can send
images and files to users via the MediaStore pipeline.

Feishu channel:
- SendMedia dispatches media parts as image or file uploads
- sendImage uploads via Image.Create then sends image message
- sendFile uploads via File.Create then sends file message
- feishuFileType maps extensions to Feishu file_type values

send_file tool:
- New tool lets the LLM send a local file to the current chat
- Validates path, registers file in MediaStore, returns media ref
- Agent loop wires tool registration, MediaStore propagation, and
  context updates

Tested on Radxa Cubie A7A (arm64) with Feishu websocket channel.

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

* fix(agent): publish outbound media regardless of SendResponse flag

The SendResponse flag controls whether the agent loop publishes the
final text response (callers that publish it themselves set this to
false). However, the media publish path was also gated behind this
flag, which meant tool-produced media was silently dropped for normal
channel messages.

Media should be published immediately when a tool returns media refs,
independent of how the text response is delivered.

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

* fix(tools): use magic-bytes MIME detection and add file size limit to send_file

- Replace hardcoded extension-to-MIME map with h2non/filetype (magic
  bytes) + mime.TypeByExtension fallback, consistent with the vision
  pipeline in resolveMediaRefs
- Add configurable max file size check (defaults to config.DefaultMaxMediaSize,
  20 MB) to prevent oversized uploads
- Add tests for magic-bytes detection, extension fallback, size limit,
  and default max size

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

* refactor(agent): add ForEachTool to AgentRegistry for cross-agent tool lookup

Extract the pattern of iterating agents to find a named tool into
AgentRegistry.ForEachTool, simplifying SetMediaStore propagation.

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

* fix(agent,tools): adapt send_file to ctx-based channel injection after upstream refactor

Replace ContextualTool interface (removed upstream) with direct ctx
reading in SendFileTool.Execute, using ToolChannel/ToolChatID helpers.
Remove updateToolContexts which is no longer needed since ExecuteWithContext
already injects channel/chatID into ctx for all tools.

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

* feat(tools): support toggling send_file tool via config

Add SendFileConfig with Enabled field to ToolsConfig, defaulting to
true. Wrap send_file tool registration in loop.go with the config
check, consistent with the pattern used by other tools.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:42:52 +08:00
mosir
aa2d6b39f5 refactor(tools): remove redundant kill -9 pattern 2026-03-06 18:34:46 +08:00
mosir
d0f627697e
Merge branch 'sipeed:main' into fix/reload-config-selfkill-guard 2026-03-06 18:27:46 +08:00
Ming
b716b8a053
feat(commands): centralized command registry with sub-command routing (#959)
* feat(commands): Session management [Phase 1/2] command centralization and registration

* docs: add design for command registry post-review fixes

Documents the architecture decisions for fixing 5 Important issues
from code review: SubCommand pattern, Deps struct, command-group files,
Executor caching, and Telegram registration dedup.

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

* feat(commands): add SubCommand type and EffectiveUsage method

Introduce SubCommand struct for declaring sub-commands structurally
within a parent command Definition. The EffectiveUsage() method
auto-generates usage strings from sub-command names and args,
preventing drift between help text and actual handler behavior.

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

* feat(commands): add Deps struct and secondToken helper, remove dead contains()

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

* feat(commands): add sub-command routing to Executor

Uses Registry.Lookup for O(1) command dispatch instead of iterating
all definitions. Definitions with SubCommands are routed to matching
sub-command handlers. Missing or unknown sub-commands reply with
auto-generated usage.

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

* refactor(commands): split into command-group files with Deps injection

Extract show/list/start/help into individual cmd_*.go files.
Replace config.Config parameter with Deps struct for runtime data.
Restore /show agents and /list agents sub-commands.
Use EffectiveUsage for auto-generated help text.
Bridge external callers (agent/loop.go, telegram.go) with Deps wrapper
until Task 5 fully wires the Deps fields.

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

* perf(commands): cache Executor in AgentLoop, wire Deps with runtime callbacks

Create Executor once in NewAgentLoop instead of per-message. Deps
closures capture AgentLoop pointer for late-bound access to
channelManager and runtime agent model.

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

* fix(telegram): remove duplicate initBotCommands, keep async startCommandRegistration only

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

* chore(commands): restore Outcome comments and annotate Deps.Config

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

* refactor(commands): consolidate /switch into commands package, fix ! prefix

Move /switch model and /switch channel handling from inline loop.go
logic into cmd_switch.go using the SubCommand + Deps pattern. This
removes the OutcomePassthrough branch in handleCommand entirely.

Also replace the hardcoded "/" prefix check with commands.HasCommandPrefix
so that "!" prefixed commands are correctly routed to the Executor.

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

* chore: add docs/plans to .gitignore and untrack existing files

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

* refactor(commands): address code review findings

- Remove dead ExecuteResult.Reply field and unused branch in loop.go
- Extract shared agentsHandler for /show agents and /list agents
- Remove redundant firstToken/secondToken (use nthToken instead)
- Simplify Telegram startup: pass BuiltinDefinitions directly
- Centralize req.Reply nil guard in executeDefinition
- Extract unavailableMsg constant (was duplicated 5 times)
- Remove unused MessageID from Request
- Remove stale "reserved for Phase 2" comment on Deps.Config

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

* refactor(commands): replace Deps with per-request Runtime

Separate stateless Registry (cached on AgentLoop) from per-request
Runtime (passed to handlers at execution time). This enables future
session management features to inject per-request context without
modifying the command registry.

- Rename Deps → Runtime, move to runtime.go
- Change Handler signature: func(ctx, req) error → func(ctx, req, rt *Runtime) error
- NewExecutor now takes (registry, runtime) — executor is created per-request
- BuiltinDefinitions() no longer takes parameters (stateless)
- AgentLoop caches cmdRegistry, builds Runtime via buildRuntime()
- Update all cmd_*.go handlers and tests

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

* style: fix gci import grouping and godoc formatting

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

* fix(onboard): skip legacy AGENT.md when copying embedded workspace templates

The workspace/ directory contains both AGENT.md (legacy) and AGENTS.md
(current). copyEmbeddedToTarget was copying both, causing the test
TestCopyEmbeddedToTargetUsesAgentsMarkdown to fail. Skip AGENT.md
during the walk to match the expected behavior.

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

* refactor(agent): address self-review comments on loop.go

- Move cmdRegistry init into struct literal (review comment #11)
- Rename buildRuntime → buildCommandsRuntime for clarity (review comment #12)
- Add comment to default switch case explaining passthrough (review comment #13)

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

* refactor(commands): address code review findings on naming and correctness

- Rename dispatcher.go → request.go (no Dispatcher type remains)
- Rename cmd_agents.go → handler_agents.go (shared handler, not a top-level command)
- Add modelMu to protect AgentInstance.Model writes in SwitchModel
- Add ListDefinitions to Runtime so /help uses registry instead of BuiltinDefinitions()
- Fix SwitchChannel message: validation-only callback should not say "Switched"
- Propagate Reply errors in executor instead of discarding with _ =
- Add HasCommandPrefix unit test

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

* refactor(onboard): extract legacy filename to constant

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

* fix(agent): handle commands before route error check

Move handleCommand() before the routeErr gate so global commands
(/help, /show, /switch) remain available even when routing fails.
Context-dependent commands that need a routed agent will report
"unavailable" through their nil-Runtime guards.

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

* revert: remove unnecessary AGENT.md skip in onboard

Reverts 02d0c04 and 74deae1. The test failure was caused by a local
leftover workspace/AGENT.md file (gitignored but embedded by go:embed).
Deleting the local file fixes the root cause; the code-level skip was
never needed.

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

* fix: executeDefinition Unknown option

* fix(agent): use routed agent for model commands, restore Telegram command diff

- Remove modelMu: message processing is serial, no concurrent writes
- Pass routed agent to handleCommand/buildCommandsRuntime instead of
  always using default agent
- GetModelInfo/SwitchModel are nil when agent is nil (route failed),
  handlers reply "unavailable"
- Restore GetMyCommands + slices.Equal check before SetMyCommands to
  avoid unnecessary Telegram API calls on restart

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

* fix(commands): remove unintended config mutation in SwitchModel

SwitchModel should only update the routed agent's runtime Model field.
Writing to cfg.Agents.Defaults.ModelName was a behavioral change that
corrupts the default agent config when switching a non-default agent.

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

* refactor(commands): move /switch channel to /check channel

/switch channel only validates availability, not actually switching.
Rename to /check channel to match actual behavior. /switch channel
now shows a redirect message pointing users to the new command.

Addresses review feedback from yinwm on PR #959.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 17:31:40 +08:00
Yajun Yao
7df7e0495c
fix deepseek-chat bug (#1066)
Co-authored-by: FantasticCode2019 <1443996278@qq.com>
2026-03-06 16:04:31 +08:00
zihan987
a2f63e4207 Fix HasProvidersConfig 2026-03-06 00:03:10 -08:00
zihan987
7308f0621b Merge upstream main 2026-03-05 23:58:59 -08:00
Meng Zhuo
9b1e73de9c
Merge pull request #994 from is-Xiaoen/feat/model-routing
feat(routing): intelligent model routing based on structural complexity scoring
2026-03-06 15:47:53 +08:00
美電球
4d965f2c81
Merge pull request #1047 from AaronJny/feat/discord-reply-context
feat(discord): support referenced messages and resolve channel/link references
2026-03-06 15:03:29 +08:00
xiaoen
b84adacc2f fix(routing): address review feedback on CJK estimation and observability
1. CJK token estimation: replace flat rune_count/3 with script-aware
   counting — CJK runes (U+2E80–U+9FFF, U+F900–U+FAFF, U+AC00–U+D7AF)
   count as 1 token each, non-CJK runes at /4. This fixes a 3x
   underestimate for Chinese/Japanese/Korean text that could incorrectly
   route complex CJK messages to the light model.

2. Routing observability: SelectModel now returns the computed score as
   a third value. selectCandidates logs the score on both paths — Info
   level for light model selection, Debug level for primary model
   selection.

3. Added tests: TestExtractFeatures_TokenEstimate_Mixed (CJK+ASCII mix),
   TestRouter_SelectModel_ReturnsScore.

Addresses review feedback from @mingmxren.
2026-03-06 13:10:20 +08:00
mutezebra
92a0db4993
chore(feishu): document reaction emoji option and promote filetype dep
Add an info log for `RandomReactionEmoji` configuration.
2026-03-06 12:53:48 +08:00
mutezebra
9f017d077e
feat(feishu): add random reaction emoji config
- Add random_reaction_emoji config for Feishu channel
- Update .env.example with new env vars
- Update documentation (README.zh.md)
2026-03-06 12:53:47 +08:00
Meng Zhuo
f600829158
Merge pull request #1157 from wangyanfu2/fix-config-shell-command-exec-timeout
fix(tools): make exec tool timeout configurable via config
2026-03-06 11:42:26 +08:00
xiaoen
e433bb8b7f merge: resolve conflicts with upstream/main
Upstream added ThinkingLevel, SummarizeMessageThreshold,
SummarizeTokenPercent, MaxMediaSize, and maybeSummarize.
Our branch added Router, LightCandidates, and selectCandidates.
Both sets of changes are kept. Dead updateToolContexts removed
(upstream deleted it; no callers exist).
2026-03-06 11:27:48 +08:00
wangyanfu2
65e1434e1b style: fix gofmt formatting in ExecConfig struct
Remove extra trailing whitespace between struct tag and inline comment
on TimeoutSeconds field to comply with gofmt formatting rules.
2026-03-06 11:19:25 +08:00
Meng Zhuo
8581d46eaa
Merge pull request #1142 from mattn/fix/handle-io-readall-errors
fix: handle ignored io.ReadAll errors across codebase
2026-03-06 10:25:19 +08:00
Meng Zhuo
651cb2ebda
Merge pull request #1155 from keithy/feature/picoclaw-home-env
feat: honor PICOCLAW_HOME env var for config, auth, and workspace paths
2026-03-06 10:13:14 +08:00
wangyanfu2
e0d2be35c2 fix(tools): make exec tool timeout configurable via config
Add TimeoutSeconds field to ExecConfig so the shell command execution
timeout can be configured instead of being hardcoded to 60s.

- Add TimeoutSeconds int field to ExecConfig in pkg/config/config.go
  with json/env tags (PICOCLAW_TOOLS_EXEC_TIMEOUT_SECONDS)
- Set default value of 60s in DefaultConfig() in pkg/config/defaults.go
- Read TimeoutSeconds from config in NewExecToolWithConfig() in
  pkg/tools/shell.go; falls back to 60s when value is 0 or unset
2026-03-06 09:51:58 +08:00
Keith Patrick
51e8479f99 feat: honor PICOCLAW_HOME env var for config, auth, and workspace paths 2026-03-05 22:08:37 +00:00
Mauro
23da4503c1
Merge pull request #1145 from Esubaalew/fix/upstream-skills-global-toggle
fix(agent): respect global skills toggle for skill tools
2026-03-05 22:17:32 +01:00
Truong Vinh Tran
4599064f2a Merge upstream/main into feat/searxng
Resolved conflicts in 3 files:
- config/config.example.json: keep both searxng and glm_search configs
- pkg/agent/loop.go: adopt upstream's IsToolEnabled guard + keep searxng fields
- pkg/config/config.go: adopt upstream's ToolConfig embed + keep SearXNG field

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:36:05 +01:00
Amir Mamaghani
c10959b645 test(irc): add unit tests for IRC channel
Test NewIRCChannel validation, extractHost, isBotMentioned,
stripBotMention, and isAlphanumeric helper functions.
2026-03-05 19:23:40 +01:00
amagi
c1a3876f7d fix: improve error handling for non-JSON responses by checking content type and using a streaming JSON parser. 2026-03-06 01:51:24 +08:00
Amir Mamaghani
1604582a41 fix: resolve gci lint errors in IRC channel files
Sort irc import alphabetically in helpers.go and fix struct field
alignment in irc.go to satisfy golangci-lint gci formatter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:03:10 +01:00
Yasuhiro Matsumoto
03d6ad420f
fix: resolve merge conflicts in wecom error handling
Combine both shadow variable fix (readErr) and proper error
classification (ClassifySendError) in wecom app and bot channels.
2026-03-05 22:01:32 +09:00
Yasuhiro Matsumoto
b878272962
fix: resolve govet shadow and golines lint errors in wecom channels 2026-03-05 21:54:13 +09:00
esubaalew
f046ba59e8 fix(agent): respect global skills toggle for skill tools 2026-03-05 15:40:06 +03:00
Boris Bliznioukov
00ad6be7ea
Update pkg/agent/loop.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-05 13:30:24 +01:00
mattn
42a32fbf3b
Update pkg/channels/wecom/app.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-05 21:20:51 +09:00
mattn
ee2ebc8bf3
Update pkg/channels/wecom/app.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-05 21:20:40 +09:00
mattn
ca4e44bd0f
Update pkg/channels/wecom/bot.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-05 21:20:31 +09:00
mattn
8d2f2d67b2
Update pkg/channels/line/line.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-05 21:20:20 +09:00
Boris Bliznioukov
968fff07b9
fix: background task results silently dropped
Signed-off-by: Boris Bliznioukov <blib@mail.com>
2026-03-05 13:07:17 +01:00
Yasuhiro Matsumoto
943385105f
fix: handle ignored io.ReadAll errors across codebase
io.ReadAll errors were silently discarded with `body, _ := io.ReadAll(...)`,
which could cause empty or partial data to be used for JSON unmarshaling
or error messages. This adds proper error checks for all instances.
2026-03-05 20:56:38 +09:00
qs3c
9216cd14b5 fix(openai_compat): handle html error bodies and reduce allocations 2026-03-05 19:42:58 +08:00
qs3c
536e9ac9de refactor(skills): reuse shared HTTP retry helper 2026-03-05 19:10:36 +08:00
Amir Mamaghani
40b7b6ee4b feat(channels): add IRC channel integration
Add IRC as a new channel for picoclaw, supporting server connections,
channel joins, DMs, mention-based group triggers, and IRCv3 typing
indicators. Uses ergochat/irc-go for connection management with SASL,
NickServ, and automatic reconnection support.

Closes #1137
2026-03-05 11:48:17 +01:00
zihan987
91f52c4586 Resolve merge conflicts 2026-03-04 23:50:58 -08:00
qs3c
7a2fdc24dc fix(skills): retry ClawHub requests on 429 2026-03-05 15:00:06 +08:00
lxowalle
6f5930624b
Feat/add tool enable or disable configuration (#1071)
* Add tools enable or diable config
2026-03-05 14:53:26 +08:00
zihan987
d1cf680657 Resolve merge conflicts 2026-03-04 22:53:17 -08:00
mosir
0f568aceb7
Merge branch 'sipeed:main' into fix/reload-config-selfkill-guard 2026-03-05 13:58:44 +08:00
美電球
464ae1846e
Merge pull request #1106 from afjcjsbx/fix/prevent-audio-as-image-url
fix(provider) prevent audio as image url
2026-03-05 12:55:46 +08:00
mosir
5c599d2dac fix(exec): block kill command pattern in safety guard 2026-03-05 12:45:53 +08:00
Boris Bliznioukov
aef1e8e8c4
fix: eliminate data races on shared tool instances (#1080)
* fix: eliminate data races on shared tool instances

Signed-off-by: Boris Bliznioukov <blib@mail.com>

* fix: remove unused indirect dependency on github.com/gdamore/tcell/v2

Signed-off-by: Boris Bliznioukov <blib@mail.com>

* fix: reviewer comments improve context handling for tool execution and ensure defaults for non-conversation callers

Signed-off-by: Boris Bliznioukov <blib@mail.com>

---------

Signed-off-by: Boris Bliznioukov <blib@mail.com>
2026-03-05 09:57:33 +08:00
Larry Koo
204038ec60
feat: add extended thinking support for Anthropic models (#1076)
* feat: add extended thinking support for Anthropic models

Support configurable thinking levels (off/low/medium/high/xhigh/adaptive)
via `agents.defaults.thinking_level` config field.

- "adaptive": uses Anthropic's adaptive thinking API (Claude 4.6+)
- "low/medium/high/xhigh": uses budget_tokens (all thinking-capable models)
- "off": disables thinking (default)

API constraints handled:
- Temperature cleared when thinking is enabled
- budget_tokens clamped to max_tokens-1
- Thinking response blocks parsed into Reasoning field

Relates to #645, #966

* fix: address PR review feedback for thinking support

- Add ThinkingCapable interface for provider capability detection
- Warn when thinking_level is set but provider doesn't support it
- Warn when temperature is cleared due to thinking enabled
- Adjust budget values per Anthropic best practices (medium=16K, xhigh=64K)
- Add budget clamp warning and 80% threshold warning
- Add parseResponse thinking block tests
- Add thinking_level field to config.example.json

* refactor: move ThinkingLevel from AgentDefaults to ModelConfig

Thinking is a model-level capability, not a global agent property.
Per-model config avoids silent ignoring on non-Anthropic providers
and eliminates spurious warning logs in multi-provider setups.

Addresses PR #1076 review feedback from @yinwm.
2026-03-05 09:51:18 +08:00
Meng Zhuo
325af2163b
Merge pull request #844 from avianion/feat/add-avian-provider
feat: add Avian as a named LLM provider
2026-03-05 09:45:06 +08:00
afjcjsbx
47d7b9b04c resolve makezero linter error 2026-03-04 23:05:52 +01:00
afjcjsbx
1b990d9acd fix lint 2026-03-04 22:59:58 +01:00
afjcjsbx
c87375588e prevent read binary file in tool 2026-03-04 22:39:08 +01:00
Truong Vinh Tran
de0f15d548 style: fix golines struct tag alignment in SearXNGConfig
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:48:36 +01:00
Truong Vinh Tran
e4daab8b09 Merge upstream/main into feat/searxng
Resolve merge conflicts to keep both SearXNG and GLM Search
providers. Updated search priority order to:
Perplexity > Brave > SearXNG > Tavily > DuckDuckGo > GLM Search

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:42:03 +01:00
Kyle D
0c97cb30d8 fix: update provider count in migration test to include Avian
The TestConvertProvidersToModelList_AllProviders test expected 19
providers but adding Avian brings the total to 20.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:14:58 +00:00
afjcjsbx
b9ee9b33f5 prevent audio as image url 2026-03-04 19:34:08 +01:00
zihan987
0c17c075da Merge remote-tracking branch 'origin_picoclaw/main' 2026-03-04 09:58:20 -08:00
Mauro
3e5b849984
Merge pull request #947 from dim/fix/transcription
Fix voice transcription
2026-03-04 18:37:24 +01:00
zihan987
ea0b634b3b add Vivgrid config 2026-03-04 09:19:03 -08:00
amagi
a305c0a479 fix(openai_compat): avoid predeclared identifier in preview 2026-03-04 23:57:26 +08:00
I Putu Eddy Irawan
11017ac7ba merge: resolve conflicts with upstream/main
Accept upstream versions for all non-Telegram files to keep PR
scope focused on Telegram message chunking only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:27:55 +07:00
I Putu Eddy Irawan
bd0018a5d7 fix: use queue-based re-splitting for HTML expansion validation
After re-splitting an oversized chunk, sub-chunks were sent without
verifying their HTML also fits under 4096 chars. Non-uniform HTML
expansion (e.g. a sub-chunk dense with bold/links) could still exceed
the limit. Use a queue that pushes sub-chunks back for re-validation
instead of sending them blindly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:19:04 +07:00
I Putu Eddy Irawan
3de4cb863b fix: pass original markdown to sendHTMLChunk for plain-text fallback
When HTML parsing fails, the fallback was re-sending the same HTML
string with ParseMode cleared, showing raw HTML tags to users.
Now pass the original markdown chunk so the fallback displays
readable plain text instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:15:17 +07:00
I Putu Eddy Irawan
8bd1935efb telegram: lower MaxMessageLength to 4000 for HTML expansion margin
The Manager splits at MaxMessageLength before calling Send(), and
Telegram's Send() was re-splitting at 4000 internally. Aligning the
channel-level limit to 4000 avoids that redundant second split while
preserving the safety margin for markdown-to-HTML expansion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:46:43 +07:00
daming大铭
c8178f4ad4
Merge pull request #732 from is-Xiaoen/feat/jsonl-memory-store
feat(memory): JSONL-backed session persistence
2026-03-04 19:34:00 +08:00
xiaoen
f9f726c0c1 fix(memory): fsync appended message for consistent durability
addMsg now calls f.Sync() before f.Close(), matching the durability
guarantee of writeMeta and rewriteJSONL (both use WriteFileAtomic
with fsync). Without this, a power loss could leave the appended
line in the kernel page cache only — lost on reboot.
2026-03-04 19:21:34 +08:00
Dimitrij Denissenko
494953fb78 Fix lint 2026-03-04 10:21:59 +00:00
qs3c
4946a8b449 fix(openai_compat): clarify HTML response errors 2026-03-04 17:54:04 +08:00
Guoguo
028605cfd0
feat: execute LLM tool calls in parallel for faster response (#1070)
When the LLM returns multiple tool calls, they are now executed
concurrently using goroutines + sync.WaitGroup instead of sequentially.
Results are collected in an indexed slice and processed in original order
to preserve message ordering. MessageTool.sentInRound is changed to
atomic.Bool for thread safety.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 17:17:28 +08:00
王路路
e0616362fe fix(discord): prevent duplicate link expansion and add regex tests
Address Copilot review feedback:
- Move resolveDiscordRefs(content) before the referenced message
  concatenation to prevent message links in quoted replies from being
  expanded twice.
- Add unit tests for channelRefRe and msgLinkRe regex patterns,
  covering valid/invalid inputs and the 3-link cap.
2026-03-04 15:11:30 +08:00
shikihane
b82bb9acc0
feat(tools): add GLM Search (智谱) web search provider (#1057)
* feat(config): add GLMSearchConfig for GLM Search provider

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

* test(tools): add failing tests for GLM Search provider

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

* feat(tools): add GLMSearchProvider for web search

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

* feat(agent): wire GLM Search config into web search tool registration

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:58:12 +08:00
Rahul Bansal
df1b53fdf9
feat: make summarization message threshold and token percent configurable (#854) (#1029)
Co-authored-by: Rahul Bansal <rahul@hudle.in>
2026-03-04 11:23:01 +08:00
王路路
38263333ed fix(discord): prevent cross-guild message leakage in link expansion
Security fix: resolveDiscordRefs now takes a guildID parameter and
skips message links pointing to a different guild, preventing the bot
from leaking content across guilds.

Also uses s.State.Channel() cache before falling back to API calls
to reduce Discord API usage and rate limit risk.
2026-03-04 10:12:37 +08:00
王路路
c3e029061b refactor(discord): self-review fixes for resolveDiscordRefs
- Guard against nil ReferencedMessage.Author to prevent panic
- Hoist regexp.MustCompile to package-level vars to avoid
  re-compilation on every handleMessage call
- Both are defensive programming improvements
2026-03-04 10:12:37 +08:00
王路路
922604fc7e feat(discord): resolve channel references and expand message links
Add resolveDiscordRefs method that:
1. Resolves <#id> channel mentions to #channel-name by calling
   the Discord API to fetch channel info
2. Expands Discord message links (up to 3) by fetching the linked
   message content and appending it as '[linked message from User]: content'

Applied to both quoted/referenced messages and the main message
content for full context resolution.
2026-03-04 10:12:37 +08:00
王路路
465819e1c6 feat(discord): support referenced/quoted messages in replies
When a user replies to a message in Discord, the bot now reads
m.ReferencedMessage and prepends its content to the incoming
message as '[quoted message from Username]: content'.

This gives the LLM full context of what message the user is
replying to, enabling meaningful follow-up conversations.
2026-03-04 10:11:39 +08:00
Kyle D
a4546ffb8f feat: add Avian as a named LLM provider
Add Avian (https://avian.io) as an OpenAI-compatible provider with
API base https://api.avian.io/v1 and AVIAN_API_KEY env var support.

Models: deepseek/deepseek-v3.2, moonshotai/kimi-k2.5, z-ai/glm-5,
minimax/minimax-m2.5. Supports chat completions, streaming, and
function calling.

Changes:
- Add Avian to ProvidersConfig struct, IsEmpty(), HasProvidersConfig()
- Add avian protocol to factory provider and default API base
- Add avian case to legacy provider selection (factory.go)
- Add avian migration rule for old config format
- Add default model entries to ModelList (deepseek-v3.2, kimi-k2.5)
- Add avian to example config
- Update AllProviders test count from 18 to 19
2026-03-03 19:36:46 +00:00
美電球
bea238c337
Merge pull request #853 from nayihz/feat_discord_proxy
feat(discord): add proxy support and tests
2026-03-04 01:03:57 +08:00
I Putu Eddy Irawan
fe97387f0f Merge remote-tracking branch 'origin/feat/exa-search' into deploy/pi-integration 2026-03-03 22:29:10 +07:00
I Putu Eddy Irawan
b7aaa5b887 Merge remote-tracking branch 'origin/feat/dotenv-loading' into deploy/pi-integration 2026-03-03 22:29:05 +07:00
I Putu Eddy Irawan
8ed351cf28 Merge remote-tracking branch 'origin/feat/telegram-chunking' into deploy/pi-integration 2026-03-03 22:28:59 +07:00
I Putu Eddy Irawan
c5d2298490 Merge remote-tracking branch 'origin/feat/kimi-opencode-providers' into deploy/pi-integration 2026-03-03 22:28:54 +07:00
I Putu Eddy Irawan
d257f1aaef merge: resolve conflict with upstream/main in provider_test.go
Keep both KimiCodeUserAgent test (from this branch) and
serializeMessages tests (from upstream) — no overlap.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 22:18:20 +07:00
I Putu Eddy Irawan
e503c87c18 fix: add LiteLLM to env overrides and fix malformed .env test
- Add missing LITELLM entry to loadProviderEnvOverrides so
  PICOCLAW_PROVIDERS_LITELLM_API_KEY/API_BASE env vars work
- Replace valid .env content in TestLoadConfig_MalformedDotenv_NonFatal
  with genuinely malformed content (bare key without '=') to actually
  exercise the non-fatal error path

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 22:14:25 +07:00
I Putu Eddy Irawan
5b608ae678 test: use guardCommand directly and improve assertions in DiskWiping test
Address Copilot review feedback:
- Use guardCommand() instead of Execute() to avoid running dangerous
  commands (format, mkfs, diskpart) on the host if regex regresses
- Assert error message contains "blocked" for blocked commands
- Replace "go fmt ./..." with "echo go fmt ./..." to avoid accidental
  file modification

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 22:05:32 +07:00
I Putu Eddy Irawan
56ad77b735 Merge upstream/main into feat/dotenv-loading
Resolve go.mod conflict: keep h2non/filetype from upstream,
tcell/v2 stays in direct deps only (not duplicated in indirect).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 22:01:04 +07:00
I Putu Eddy Irawan
5dcd42e5d3 Merge upstream/main into fix/bugfixes
Resolve conflicts:
- provider.go: keep upstream's serializeMessages (supersedes stripSystemParts)
- provider_test.go: keep upstream's serializeMessages tests
- loop_test.go: add slices import needed by upstream tests
- shell.go: merge PR's --format deny fix with upstream's block device
  pattern, safePaths, and absolutePathPattern
- shell_test.go: include tests from both branches

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:55:26 +07:00
I Putu Eddy Irawan
e54b1d39a5 refactor: parse Kimi API hostname once in constructor instead of per-call
Avoid re-parsing apiBase URL on every Chat() invocation by computing
isKimiAPI once in NewProvider(). Also document why the KimiCLI/0.77
User-Agent string is required.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:34:31 +07:00
Mauro
4a7605ee14
Merge pull request #1024 from wangyanfu2/fix-TavilySearch-response
fix: add HTTP status code check in BraveSearchProvider
2026-03-03 11:42:05 +01:00
nayihz
69b1ae48d5 Merge remote-tracking branch 'origin/main' into feat_discord_proxy 2026-03-03 18:38:57 +08:00
daming大铭
a65ccc0d1d
Merge pull request #1020 from shikihane/feat/agent-vision-pipeline-v2
feat(agent): add vision/image support with streaming base64 and filetype detection
2026-03-03 18:35:23 +08:00
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
pikaxinge
3902061db1
fix(agent): invalidate system prompt cache for global/builtin skills (#845)
* fix(agent): invalidate system prompt cache for global/builtin skills

* test(agent): avoid os.Chdir in builtin skill cache test

* fix(agent): harden skill cache invalidation checks
2026-03-03 18:25:00 +08:00
wangyanfu2
7de4cc5ebd fix: add HTTP status code check in BraveSearchProvider
- Add status code validation after reading response body, consistent
  with TavilySearchProvider and PerplexitySearchProvider
2026-03-03 17:54:43 +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
shikihane
6ccb68c63e fix: resolve linter issues (gci import grouping, gofumpt, govet shadow)
- Separate third-party imports from local module imports (gci)
- Fix byte slice literal formatting (gofumpt)
- Rename shadowed err variable to ftErr (govet)
- Remove trailing blank lines in test files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:04:54 +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
shikihane
43227411ee feat(agent): wire media refs through agent pipeline to LLM provider
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:28:20 +08:00
shikihane
03f7ae494f feat(openai_compat): implement serializeMessages with multipart media support
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:28:20 +08:00
shikihane
6fd65825e7 feat(agent): implement resolveMediaRefs with streaming base64 and filetype detection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:28:20 +08:00
shikihane
4c6c05a251 feat(config): add configurable max_media_size with 20MB default
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:27:29 +08:00
shikihane
6689c0b1c0 feat(providers): add Media field to Message struct for vision support
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:27:29 +08:00
daming大铭
de2ccb5da4
Merge pull request #999 from yinwm/fix/mcp-race-condition-and-resource-leak
fix(mcp): resolve TOCTOU race condition and resource leak
2026-03-03 15:06:57 +08:00
xiaoen
1a922c96a8 merge: resolve conflict with main in loop.go
Main reformatted the fallback.Execute call to multi-line (golines);
our branch renamed agent.Candidates → activeCandidates for routing.
Kept both: multi-line formatting + routing variable.
2026-03-03 12:22:45 +08:00
Guoguo
407707a7cc
Revert "feat(agent): add vision/image support to agent pipeline" 2026-03-03 11:38:32 +08:00
Orgmar
12d4570a36
Merge pull request #990 from shikihane/feat/agent-vision-pipeline
feat(agent): add vision/image support to agent pipeline
2026-03-03 11:32:07 +08:00
shikihane
8ebeefc59f fix(agent,openai_compat): address review feedback on vision pipeline
- serializeMessages: preserve ToolCallID/ToolCalls when Media is present
- resolveMediaRefs: add 20MB file size limit to prevent OOM
- mimeFromExtension: return empty string for unknown extensions
- Add 11 unit tests for serializeMessages, resolveMediaRefs, mimeFromExtension

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:13:22 +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
2fc87985d2 fix: add kimi-code migration alias and User-Agent test
- Add "kimi-code" to the moonshot provider's providerNames in
  ConvertProvidersToModelList so configs using
  agents.defaults.provider: "kimi-code" migrate correctly.
- Add TestProviderChat_KimiCodeUserAgent verifying that
  User-Agent: KimiCLI/0.77 is set when apiBase hostname is
  api.kimi.com and not set for other hosts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 09:18:26 +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
Alfonso
946af6b53d
feat: add LiteLLM provider alias support (#930) 2026-03-03 08:23:55 +11: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
yinwm
78aba700d5 fix(mcp): resolve TOCTOU race condition and resource leak
- Use atomic.Bool for closed flag to prevent TOCTOU race between
  CallTool and Close operations
- Add double-check pattern in CallTool for thread-safe closed state
- Use atomic Swap in Close to ensure no new calls can start after
  closed flag is set
- Move MCP manager cleanup defer before initialization to handle
  partial initialization failures
- Update tests to use atomic.Bool operations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:47:25 +08:00
daming大铭
4e348e39ac
Merge branch 'main' into mcp-tools-support 2026-03-03 00:17:39 +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
I Putu Eddy Irawan
84ded81a8c Address Copilot review feedback for .env loading
- Add migrateChannelConfigs() and ValidateModelList() to the fresh-
  install path (no config.json) so legacy env vars are migrated and
  model list is validated consistently with the normal loading path
- Use os.LookupEnv instead of os.Getenv in loadProviderEnvOverrides
  so explicitly empty env vars (e.g. PICOCLAW_PROVIDERS_X_API_BASE=)
  can clear values from config.json
- Guard .env loading with sync.Once to avoid repeated disk I/O and
  noisy log messages when LoadConfig is called from polling handlers
- Add tests: .env file loading, missing config.json with env vars,
  malformed .env non-fatal behavior, and LookupEnv empty-override

Note: go.mod tcell/v2 and tview are correctly listed as direct deps
(they are imported by the launcher TUI); upstream go.mod was stale.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 22:50:59 +07: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
I Putu Eddy Irawan
8219b5a26f Address Copilot review feedback for Exa search provider
- Add explicit empty-results handling ("No results for: <query>")
- Add "Results for: <query> (via Exa)" header and align per-result
  format with Brave/Tavily/DuckDuckGo/Perplexity
- Add tests: provider priority (Perplexity > Exa > Brave), proxy
  propagation, successful search with header/attribution, empty
  results, and max-results capping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 22:43:43 +07: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
4b7e8d9cb9 feat: add Exa AI search provider
Add Exa (https://exa.ai) as a new web search provider option, slotting
into the priority chain between Perplexity and Brave. Configurable via
config.json or PICOCLAW_TOOLS_WEB_EXA_* environment variables.

Results are capped to the requested count for consistency with other
search providers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 22:29:26 +07:00
I Putu Eddy Irawan
d9b4af797d feat: add .env file loading and provider env overrides
Load .env files from the config directory before reading config.json,
enabling secrets and API keys to be stored outside version control.
Supports fresh installs (no config.json) by applying env vars and
provider overrides to the default config.

Adds loadProviderEnvOverrides() for PICOCLAW_PROVIDERS_<NAME>_API_KEY
and _API_BASE environment variables across all standard providers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 22:26:36 +07:00
xiaoen
09e68cb63b fix(routing): resolve golines, gosmopolitan and misspell lint failures
- classifier.go: s/honour/honor/ (American English per misspell)
- router.go: break SelectModel signature across lines (golines)
- router_test.go: break long Message literal (golines)
- router_test.go: replace CJK string literal with rune slice so
  gosmopolitan does not flag the source file; behaviour is identical
2026-03-02 23:11:45 +08:00
I Putu Eddy Irawan
4a067cd9ed
Merge branch 'main' into feat/kimi-opencode-providers 2026-03-02 22:08:50 +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
xiaoen
02e8192349 feat(agent): wire model routing into the agent loop
instance.go:
  - Add Router *routing.Router and LightCandidates []FallbackCandidate
    to AgentInstance.
  - At agent creation, when routing.enabled and light_model resolves
    successfully in model_list, pre-build the Router and resolve the
    light model candidates once. If the light model isn't in model_list,
    log a warning and disable routing for that agent gracefully.

loop.go:
  - Add selectCandidates(agent, userMsg, history) helper.
    It calls Router.SelectModel and returns either agent.Candidates /
    agent.Model (primary tier) or agent.LightCandidates / light_model
    (light tier). Returns primary unchanged when routing is disabled.
  - In runLLMIteration, resolve (activeCandidates, activeModel) once
    before entering the tool-iteration loop. The model tier is sticky
    for the entire turn so a multi-step tool chain doesn't switch
    models mid-way.
  - Replace hard-coded agent.Candidates / agent.Model references in
    callLLM and the debug log with the resolved active values.

The fallback chain and retry logic are untouched. When light_model
returns an error the fallback chain handles escalation normally.
2026-03-02 22:42:52 +08:00
xiaoen
1943c3e660 feat(routing): add language-agnostic model complexity scorer
Add three new files to pkg/routing/:

features.go — ExtractFeatures(msg, history) → Features
  Computes five structural dimensions with zero keyword matching:
  - TokenEstimate: rune_count/3 (CJK-safe token proxy)
  - CodeBlockCount: ``` pairs in the message
  - RecentToolCalls: tool call count in the last 6 history entries
  - ConversationDepth: total messages in session
  - HasAttachments: data URIs or media file extensions

classifier.go — Classifier interface + RuleClassifier
  RuleClassifier uses a weighted sum that is capped at 1.0:
    code block      → +0.40  (triggers heavy model alone at 0.35 threshold)
    token > 200     → +0.35  (triggers heavy model alone)
    tool calls > 3  → +0.25
    token 50-200    → +0.15
    conversation depth > 10 → +0.10
    attachment      → 1.00 (hard gate, always heavy)

router.go — Router wraps config + Classifier
  Router.SelectModel(msg, history, primaryModel) returns either the
  configured light_model or the primary model depending on whether
  the complexity score clears the threshold. Threshold defaults to
  0.35 when zero/negative to prevent misconfiguration.

router_test.go — 34 tests covering all branches and edge cases
2026-03-02 22:42:20 +08:00
xiaoen
c5a21b269f feat(config): add RoutingConfig to AgentDefaults
Introduce RoutingConfig with three fields:
  - enabled: activates per-turn model routing
  - light_model: references a model_name in model_list
  - threshold: complexity score cutoff in [0,1]

When routing.enabled is true and the incoming message scores below
threshold, the agent switches to light_model for that turn. Absent or
disabled config leaves existing behaviour completely unchanged.

Example:
  "agents": {
    "defaults": {
      "model": "claude-sonnet-4-6",
      "routing": {
        "enabled": true,
        "light_model": "gemini-flash",
        "threshold": 0.35
      }
    }
  }
2026-03-02 22:40:52 +08: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
nayihz
9be6fb1a7d Merge branch 'main' into feat_discord_proxy 2026-03-02 18:15:20 +08:00
shikihane
18b36af934 feat(agent): add resolveMediaRefs to convert media:// refs to base64 data URLs
Without this function, media:// refs stored by MediaStore are passed
directly to the LLM API, which rejects them as invalid URLs.

resolveMediaRefs() runs after BuildMessages() and before the LLM call,
converting each media:// ref to a data:image/...;base64,... URL that
vision-capable models can process.

Also adds mimeFromExtension() helper for MIME type inference from
file extensions when ContentType metadata is not available.
2026-03-02 18:08:32 +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
d4824a00b6 refactor(config): remove WebhookHost and WebhookPort from WeComAIBotConfig 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
shikihane
a4e5c391bd fix(openai_compat): preserve reasoning_content in serializeMessages
The serializeMessages() function was not preserving the reasoning_content
field when serializing messages for vision API calls. This caused the
TestProviderChat_PreservesReasoningContentInHistory test to fail.

This fix ensures reasoning_content is included in both text-only messages
and vision messages with media attachments.

Co-authored-by: Zachary Guerrero <zack.grrr@gmail.com>
2026-03-02 17:38:08 +08:00
shikihane
6997edc82e feat(agent): wire Media through agent pipeline (cherry-pick PR #555)
Add Media field to processOptions, pass msg.Media from inbound
messages through to BuildMessages and serializeMessages so
vision-capable LLMs receive image_url content parts.

Based on work by @as3k in sipeed/picoclaw#555.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:18:04 +08:00
Zachary Guerrero
3d54a77c40 feat: add Media field to Message struct and implement serializeMessages for vision API support
- Add Media []string field to Message struct for image/media URLs
- Implement serializeMessages() to format messages with image_url content parts
- Enables OpenAI-compatible vision APIs to receive image attachments
2026-03-02 17:18:04 +08:00
daming大铭
26d1b8e374
Merge pull request #946 from winterfx/fix/preserve-reasoning-content-in-history
fix: preserve reasoning_content in multi-turn conversation history
2026-03-02 16:31:03 +08:00
Huang Rui
d5370c9605
fix(tools): allow /dev/null redirection and add read/write sandbox split (#967)
* fix(tools): allow /dev/null redirection and add read/write sandbox split

- Remove deny pattern that incorrectly blocked redirects to /dev/null
- Expand block device write pattern to cover nvme, mmcblk, vd, xvd,
  hd, loop, dm-, md, sr and nbd in addition to sd
- Add safe path whitelist for kernel pseudo-devices so workspace path
  check does not reject /dev/null, /dev/zero, /dev/random, /dev/urandom,
  /dev/stdin, /dev/stdout and /dev/stderr
- Add allow_read_outside_workspace config option (default true) so file
  read and list tools are unrestricted while write tools stay sandboxed

Closes https://github.com/sipeed/picoclaw/issues/964
Closes https://github.com/sipeed/picoclaw/issues/965

Signed-off-by: Huang Rui <vowstar@gmail.com>

* feat(tools): add configurable allow patterns and path whitelists

- Add custom_allow_patterns to exec config so users can exempt specific
  commands from deny pattern checks
- Add allow_read_paths and allow_write_paths regex lists to tools config
  for whitelisting specific paths outside the workspace
- Introduce whitelistFs that wraps sandboxFs and falls through to hostFs
  for paths matching whitelist patterns
- Use variadic constructor signatures to keep backward compatibility

Suggested-by: lxowalle
Signed-off-by: Huang Rui <vowstar@gmail.com>

---------

Signed-off-by: Huang Rui <vowstar@gmail.com>
2026-03-02 12:22:02 +08:00
Mauro
b26337501c
fix: error check on state (#864) 2026-03-02 11:59:26 +11:00
afjcjsbx
e0667304d1 fixed conflicts 2026-03-01 23:44:21 +01:00
Mauro
b86bf5b7ea
Merge branch 'main' into fix/max-payload-size-in-web-fetch 2026-03-01 22:38:16 +01:00
Dimitrij Denissenko
b74f92ed28 A more neutral and elegant voice.Transcriber interface 2026-03-01 21:02:16 +00:00
Luca Martinetti
fc9f1ec921
fix: return fetched content to LLM in web_fetch tool (#833)
* fix: return fetched content to LLM in web_fetch tool

WebFetchTool.Execute was setting ForLLM to a summary string
("Fetched N bytes from URL ...") instead of the actual extracted
text. This meant the LLM never saw the page content and could not
answer questions based on fetched web pages.

Return the extracted text in ForLLM so the model can use it.

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

* fix: put full JSON result in ForLLM, summary in ForUser

Accept suggestion from afjcjsbx: the LLM should receive the full JSON
result (including extracted text) while the user sees a short summary.
Update tests to match the new field assignment.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:48:11 +11:00
Keith
d4bc28c113
feat(config): Add support for env var configuration (#896)
* feat(config): Add support for env var configuration

This commit introduces support for two environment variables,
allowing users to override the default paths for picoclaw's home
directory and configuration file.

- `PICOCLAW_CONFIG`: Directly specifies the path to the `config.json` file.
This is initialised first, takes precedence over the hardcoded path, and is ideal
for containerized deployments or custom config management.

- `PICOCLAW_HOME`: Overrides the root directory for all picoclaw data, (except the config)
(e.g., `~/.picoclaw`). This is useful for portable installations or placing
data in non-standard locations.

This change provides greater flexibility for running picoclaw in various environments without
being tied to the default home directory structure.

* `README.md` updated explain PICOCLAW_CONFIG and PICOCLAW_HOME

* docs: translate environment variables section to multiple languages

---------

Co-authored-by: picoclaw <picoclaw@sipeed.com>
2026-03-02 07:41:12 +11: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
Tong Niu
d6e88da8ba
fix(pkg):do regex precompile insteadd on the fly (#911)
* fix(pkg/providers):do regex precompile insteadd on the fly

* fix(providers): replace HTTP-specific regex with standalone status code matcher

The precompiled HTTP regex used uppercase "HTTP" which never matched
because ClassifyError lowercases the input. Replace it with a
case-insensitive word-boundary pattern that matches any standalone
3-digit status code (300-599), which also subsumes the HTTP/x.x case.

Add test case for standalone status code extraction.

* fix(providers): restore http regex and add standalone status code matcher

Restore the http-prefixed regex (without unnecessary (?i) flag since
input is already lowercased by ClassifyError) as a mid-priority pattern
to reduce false positives. Add a standalone word-boundary matcher as a
fallback for bare status codes like "429". Fix test to use lowercased
input matching the actual calling convention.

* perf(tools): move path regex compilation from per-call to package init

The path regex in guardCommand was compiled on every call. Hoist it
to a package-level var (absolutePathPattern) alongside defaultDenyPatterns
in a single var block, so it is compiled once at init time.

* style(tools): move inline comment to fix golines formatting error
2026-03-01 23:06:31 +11:00
GhostC
71bdeb41c9
fix: improve error handling in GitHub Copilot provider (#919)
- Fix ignored error from SendAndWait call
- Improve error message for unimplemented stdio mode with helpful guidance
- Add TODO comment with reference link for future stdio implementation
2026-03-01 22:58:41 +11:00
Dimitrij Denissenko
b1386ad71f Fix voice transcription 2026-03-01 08:39:05 +00:00
winterfx
9efdde25ad fix: preserve reasoning_content in multi-turn conversation history
The openaiMessage struct and stripSystemParts() were not carrying over
the ReasoningContent field when serializing conversation history for
API requests. This caused thinking models (e.g. kimi-k2.5) to receive
incomplete assistant messages on subsequent turns, resulting in 400
errors from the Moonshot API.

Add the ReasoningContent field to openaiMessage and copy it in
stripSystemParts(). Also add a test to verify reasoning_content is
preserved when sending conversation history.

Fixes #588
Related: #876

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 16:23:05 +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
434b03ed67 remove wrapper methods
Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-03-01 18:24:11 +11:00
Kai Xia
32c864c309 enable dupl check
Signed-off-by: Kai Xia <kaix+github@fastmail.com>
2026-03-01 18:17:32 +11:00
xiaoen
6d894d6138 refactor(memory): use fileutil.WriteFileAtomic and log corrupt lines
- Replace manual temp+rename in writeMeta and rewriteJSONL with the
  project's standard fileutil.WriteFileAtomic. This adds fsync before
  rename, which is important for flash storage on embedded devices
  where power loss can leave zero-length files after an unsynced rename.
- Log a warning when readMessages skips a corrupt line, so operators
  can see that data was lost after a crash instead of silently dropping it.
- Document the lossy sanitizeKey mapping (telegram:123 → telegram_123)
  as an intentional tradeoff.
2026-03-01 14:46:54 +08:00
xiaoen
cd500d2046 Merge branch 'main' into feat/jsonl-memory-store 2026-03-01 14:35:14 +08: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
DM
cadcdc0b41
fix(skills): use registry-backed search for skills discovery (#929)
* fix(skills): use registry-backed search for skills discovery

Signed-off-by: dwizzle204 <25712917+dwizzle204@users.noreply.github.com>

* fix(skills): address review comments for registry search

Signed-off-by: dwizzle204 <25712917+dwizzle204@users.noreply.github.com>

---------

Signed-off-by: dwizzle204 <25712917+dwizzle204@users.noreply.github.com>
Co-authored-by: dwizzle204 <25712917+dwizzle204@users.noreply.github.com>
2026-03-01 15:20:20 +11:00
yuchou87
a2591e03a9 fix: improve MCP tool name collision safety and registry overwrite warning
- MCPTool.Name(): append FNV-32a hash of original (unsanitized) server+tool
  names whenever sanitization is lossy or total length exceeds 64 chars,
  ensuring names that differ only in disallowed characters remain distinct
- ToolRegistry.Register(): emit warn log when a tool registration overwrites
  an existing tool with the same name, making collisions observable
- scripts/test-docker-mcp.sh: switch shebang from #/bin/bash /Users/yuchou/Work/klook-calendar/klook-google-cal-sync/src/googlecalconversrv/bin/start.sh to #  for portability on minimal distros and Nix environments
2026-03-01 12:00:26 +08:00
daming大铭
33f67e8275
Merge pull request #918 from alexhoshina/fix/wecom-resource-leaks
fix(wecom): fix context leak in Start() and data race in processedMsgs
2026-03-01 10:57:07 +08:00
yuchou87
ef738f4787 fix: address PR review feedback for MCP tools support
- Avoid logging sensitive cfg.Args in ConnectServer; log args_count instead
- Sanitize server/tool name components in MCPTool.Name() to ensure valid
  identifiers for downstream providers (lowercase, [a-z0-9_-] only)
- Add slack as 5th MCP server example in config.example.json
- Move Dockerfile.full and docker-compose.full.yml into docker/ directory
  for consistency with existing docker/Dockerfile and docker/docker-compose.yml
- Fix all Makefile docker-* targets to reference correct compose file paths
- Fix docker/docker-compose.full.yml build context (.. ) and volume paths
- Fix scripts/test-docker-mcp.sh compose file path and replace cowsay test
  with actual @modelcontextprotocol/server-filesystem MCP server test
2026-03-01 10:56:02 +08: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
9c91d66427 Address Copilot review feedback for Kimi/Opencode providers
- Allow APIBase-only config for opencode provider selection (like VLLM)
- Keep moonshot provider on moonshot.cn/v1 default, only use kimi.com/coding/v1 for kimi/kimi-code
- Use url.Parse hostname match for Kimi User-Agent check instead of strings.Contains
- Add opencode to DefaultAPIBase test cases in factory_provider_test.go
- Add opencode migration tests (full config + APIBase-only) in migration_test.go
- Update AllProviders test count to include opencode (18 -> 19)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 09:22:49 +07:00
I Putu Eddy Irawan
81aeaf1ca0 fix: address Copilot review feedback on PR #932
- Deny regex: expand left boundary to match shell separators (;, &&, ||)
  to prevent bypass via chained commands like ";format c:"
- Path regex: add "." to initial char class to catch hidden dirs (/.ssh),
  add "=" to left boundary to catch flag-attached paths (--file=/etc/passwd)
- Add test: ModelName must match user model for GetModelConfig lookup
- Add test: stripSystemParts preserves reasoning_content in wire format
- Add test: forceCompression avoids orphaning tool result messages
- Add test: deny pattern blocks disk-wiping commands with shell separators
  while allowing legitimate --format flags

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 09:08:11 +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
I Putu Eddy Irawan
ec540312da feat: add Kimi/Moonshot and Opencode provider support
- Add "kimi", "kimi-code", "moonshot" provider cases in factory.go
  with default API base https://api.kimi.com/coding/v1
- Add Kimi Code API User-Agent header (KimiCLI/0.77) for api.kimi.com
- Add "opencode" provider with default API base https://opencode.ai/zen/v1
- Add "opencode" to recognized HTTP-compatible protocols in factory_provider
- Add Opencode field to ProvidersConfig, IsEmpty, HasProvidersConfig
- Add opencode migration entry in ConvertProvidersToModelList
- Update moonshot fallback API base from api.moonshot.cn to api.kimi.com
2026-03-01 08:48:04 +07:00
I Putu Eddy Irawan
ee5b61884a fix: migration ModelName, reasoning_content, shell regex, loop boundary
1. migration.go: Set ModelName to userModel when provider matches so
   GetModelConfig(userModel) can find the entry. Previously the migration
   created entries with the provider name as ModelName (e.g. "moonshot")
   but lookup used the model name (e.g. "k2p5"), causing "model not found".

2. openai_compat/provider.go: Preserve reasoning_content in conversation
   history. Thinking models (e.g. Kimi K2, DeepSeek-R1) return
   reasoning_content which must be echoed back. Without it, APIs return
   400: "thinking is enabled but reasoning_content is missing".

3. shell.go: Fix deny pattern regex for format/mkfs/diskpart to use
   (?:^|\s) instead of \b to avoid matching --format flags.
   Fix path extraction regex to use submatch to avoid matching flags
   like -rf as paths.

4. loop.go: Adjust forceCompression mid-point to avoid splitting
   tool-call/result message pairs, which causes API errors.
2026-03-01 08:44:15 +07:00
yuchou87
077d7c8d9b chore: fix lint issues in mcp and agent packages
- Fix gci import ordering in manager.go, manager_test.go
- Fix gofmt formatting in loop.go, manager.go, mcp_tool.go, mcp_tool_test.go
- Fix gofumpt formatting in manager_test.go
- Fix golines line length issues in manager.go, mcp_tool_test.go
- Fix wastedassign: replace redundant zero-value init with var declaration in loop.go
2026-03-01 08:53:13 +08: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
daming大铭
9c9524f934
Merge pull request #914 from alexhoshina/fix/wecom-context-canceled
fix(wecom): use channel context instead of HTTP request context for async message processing
2026-02-28 21:56:17 +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