Commit graph

353 commits

Author SHA1 Message Date
Mauro
5db1e94693
Merge pull request #1998 from abnerhexu/main
feat(config): allow placeholder text to be string or list
2026-03-25 22:47:39 +01:00
柚子
ed618e14aa
feat(channels): support multi-message sending via split marker (#2008)
* Add multi-message sending via split marker

* Add marker and length split integration tests

Tests that SplitByMarker and SplitMessage work together correctly, and
that code block boundaries are preserved during marker splitting.

* Simplify message chunking logic in channel worker

Extract splitByLength helper function and remove goto-based control
flow.
The logic now flows more naturally - try marker splitting first, then
fall
back to length-based splitting.

* Update multi-message output instructions in agent context

* Add split_on_marker to config defaults

* Add split_on_marker config option

* Rename 'Multi-Message Sending' setting to 'Chatty Mode'

* Add SplitOnMarker config option
2026-03-26 01:33:49 +08:00
hezixu
123b9db6a9 fix: correct struct field alignment for gci 2026-03-25 18:03:27 +08:00
hezixu
dc956f2feb feat(config): allow placeholder text to be string or list
Allow PlaceholderConfig.Text to accept either a single string or an
array of strings, from which one is randomly selected at runtime.
This maintains backward compatibility with existing single-string configs
while enabling random placeholder selection.

Changes:
- Modify PlaceholderConfig.Text type from string to FlexibleStringSlice
- Add GetRandomText() helper method for random selection
- Update SendPlaceholder in all channels to use GetRandomText()
- Update config.example.json with array placeholder examples
- Update Matrix channel documentation
2026-03-25 17:57:11 +08:00
lxowalle
6bd8fec87a
Fix security config precedence during migration (#1984)
* Fix security config precedence during migration

* add doc

* fix ci

* add baidu search
2026-03-25 15:29:43 +08:00
Cytown
4398e3e070 Merge branch 'main' into fix-doc 2026-03-25 11:13:17 +08:00
uiyzzi
be6bf9f6c6 Add virtual model support for multi-key expansion
Virtual models generated from multi-key expansion are now marked and
filtered during config persistence. Virtual models display with a badge
in the UI and cannot be set as default.
2026-03-25 00:00:36 +08:00
xiwuqi
9fb01bc7f8
fix(config): persist disabled placeholder settings (#1902) 2026-03-24 23:49:01 +08:00
daming大铭
1b9445b806
Merge pull request #1955 from alexhoshina/refactor/wecom
Refactor/wecom
2026-03-24 23:37:35 +08:00
RussellLuo
74a9dcaa5c fix(ci): Make CI happy 2026-03-24 21:51:58 +08:00
RussellLuo
7f163658c9 docs(matrix): Update docs 2026-03-24 21:46:12 +08:00
RussellLuo
fab9603547 feat(matrix): support encrypted messages with E2EE
- Add `crypto_database_path` and `crypto_passphrase` configuration
- Integrate cryptohelper for decrypting `m.room.encrypted` events
- Handle both plaintext and encrypted messages in `handleMessageEvent`
- Enable `goolm` build tag for libsignal crypto support

Fixes #1840.
2026-03-24 21:46:10 +08:00
Hoshina
cd48c3bde8 fix(config): remove stale wecom security merge fields 2026-03-24 20:27:31 +08:00
Hoshina
b0bcf1d3c9 docs(wecom): update examples and docs 2026-03-24 20:23:29 +08:00
Hoshina
a1f95f02bc refactor(wecom): rebuild ai bot channel 2026-03-24 20:23:29 +08:00
lxowalle
8b6cbd9909
Fix: Prevent security.yml from being overwritten during config migration (#1966) 2026-03-24 20:02:58 +08:00
hsguo
fa5ab72022
WeChat Web QR Code Integration (#1961) 2026-03-24 18:37:41 +08:00
wenjie
d23c24ce72
fix(config): normalize empty security config before save/load (#1956)
Normalize missing security sections when attaching, loading, and saving
security config so existing config files without `.security.yml` can still
be updated safely. This fixes Pico channel setup for legacy/existing configs
and adds coverage for the missing security file path and unexported JSON
field behavior.
2026-03-24 17:03:28 +08:00
daming大铭
b17cbe5234
fix: apply security credentials before config validation in web handlers
Merge PR #1929
2026-03-24 16:27:57 +08:00
Cytown
d921bbb667
bug fix for security initial cause can't save model in launcher (#1952) 2026-03-24 16:24:12 +08:00
Cytown
de11f95b65 update security migration documents 2026-03-24 13:38:13 +08:00
Cytown
cf9e0496f7
fix launcher can't save model api_key issue (#1928)
* fix launcher can't save model api_key issue

* add backup for old data before migrate config and fix migrate to empty
security issue
2026-03-24 03:26:11 +01:00
Huaaudio
6ea9636861 fix weixin config 2026-03-24 01:33:05 +01:00
Orkun Manap
dd9adf8a04
feat: add ElevenLabs Scribe STT transcriber and Telegram SendVoice support (#1905)
* feat: add ElevenLabs Scribe STT transcriber and Telegram SendVoice support

Add ElevenLabsTranscriber as an alternative speech-to-text provider using
the ElevenLabs Scribe API (scribe_v1). This enables voice message
transcription for users who already have an ElevenLabs API key, without
requiring a separate Groq account.

Changes:
- Add ElevenLabsTranscriber implementing the Transcriber interface
- Update DetectTranscriber to check providers.elevenlabs.api_key first,
  falling back to Groq for backward compatibility
- Add ElevenLabs to ProvidersConfig
- Add "voice" media type for OGG files with "voice" in filename
- Add SendVoice support in Telegram channel for voice bubble messages
- Add comprehensive tests for ElevenLabs transcriber

Configuration:
  "providers": {
    "elevenlabs": {
      "api_key": "sk_your_key_here"
    }
  }

Closes #1503 (partial)

* fix: move voice-bubble detection into Telegram channel to avoid regression in other channels

Address review feedback: keep inferMediaType returning "audio" for all
OGG files. Voice-bubble detection (SendVoice vs SendAudio) is now done
inside the Telegram channel based on filename, so other channels that
map "audio" explicitly are unaffected.

* fix: align VoiceConfig struct tags to pass golines formatter

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

* fix(agent): use ModelName in loop test added by upstream

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 22:11:10 +01:00
uiyzzi
cf80ec8382 Update config_test.go 2026-03-23 20:58:14 +08:00
uiyzzi
16d23d8cdc feat(security): add sensitive data filtering for tool results sent to
LLM

Prevent LLM from seeing its own credentials (API keys, tokens, secrets)
by filtering sensitive values from tool call results before sending to
the
model. Values are collected from .security.yml and replaced with
[FILTERED] using an efficient strings.Replacer (O(n+m)).

- Add FilterSensitiveData and FilterMinLength to ToolsConfig
- Implement SensitiveDataReplacer() with sync.Once caching in
  SecurityConfig
- Use reflection to collect all sensitive values (Model API keys,
  channel
  tokens, web tool API keys, skills tokens)
- Apply filtering in agent loop at 4 tool result locations
- Add comprehensive tests covering all token types
2026-03-23 20:55:41 +08:00
Kristjan Kruus
1f9d390a64 fix: apply security credentials before config validation in web handlers
- Move SecurityCopyFrom() before validateConfig() in PUT and PATCH handlers
- Make SecurityCopyFrom() call applySecurityConfig() to populate private fields
- Add tests for config save with security-only channel tokens

Without this fix, saving config via the web UI fails with 'channels.pico.token
is required' (and similar for Telegram/Discord) when tokens are stored in
.security.yml, because the validation ran before security credentials were
copied to the config struct.
2026-03-23 14:26:51 +02:00
uiyzzi
c7544f7cb9 feat(providers): add extra_body config to inject custom fields into request body
Allow configuring provider-specific fields like reasoning_split for minimax via
the model config's extra_body map. These fields are merged into the request
body last, giving them precedence over default values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 16:44:12 +08:00
uiyzzi
79df938696 Use getter/setter methods for API key access in ModelConfig 2026-03-23 16:39:43 +08:00
uiyzzi
608ec6d329 Move minimax reasoning_split injection to provider factory
Inject reasoning_split at provider creation time to allow user ExtraBody
settings to be preserved
2026-03-23 16:39:43 +08:00
uiyzzi
f2985b8bee feat(providers): add extra_body config to inject custom fields into request body
Allow configuring provider-specific fields like reasoning_split for minimax via
the model config's extra_body map. These fields are merged into the request
body last, giving them precedence over default values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 16:39:42 +08:00
Cytown
36f9d20de1 Merge branch 'main' into version 2026-03-23 15:00:18 +08:00
Kunal Karmakar
40279c8dde
chore(config): move loglevel settings under gateway (#1912)
* Move log level config to gateway property

* Fix unit test

* Fix linting

* Fix linting

* Add comment for log level
2026-03-23 06:14:53 +01:00
Cytown
5a8aab8143 Merge branch 'main' into version 2026-03-23 11:41:36 +08:00
Cytown
310f788f5f rename security.yml to .security.yml 2026-03-23 11:20:42 +08:00
Cytown
7bf4831059 Merge branch 'main' into version 2026-03-23 10:54:08 +08:00
Caize Wu
3a61892313
Merge pull request #1875 from BeaconCat/docs/readme-restructure-v2
docs: restructure README with Quick Start Guide, i18n, and Weixin channel
2026-03-23 10:30:05 +08:00
Mauro
3500080abb
Merge pull request #1891 from RussellLuo/audio-transcription
feat(voice): add audio-model transcription support
2026-03-23 00:23:30 +01:00
BeaconCat
4bc64497e3 fix(lint): run golangci-lint fmt to fix golines/gci struct tag formatting
golangci-lint v2.10.1 treats golines as a formatter. Running
`golangci-lint fmt` normalizes struct tag alignment in GLMSearchConfig,
WebToolsConfig, and MCPConfig — removing manual padding that golines
flagged as improperly formatted.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 01:10:09 +08:00
BeaconCat
c786f35b32 fix(lint): fix golines/gci formatting in WebToolsConfig
Run golines then gci to reach a stable state that satisfies both linters.
BaiduSearchConfig field caused gofumpt to re-align the struct, shifting
ToolConfig tag spacing and triggering golines on each subsequent fix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 01:03:49 +08:00
BeaconCat
b150d7d523 fix(lint): fix gci import formatting in config.go
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 00:57:14 +08:00
BeaconCat
30db993993 fix(lint): fix golines line length in WebToolsConfig struct
Remove extra alignment space on ToolConfig field introduced by gofumpt
when BaiduSearchConfig was added, keeping all lines under 120 chars.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 00:54:50 +08:00
BeaconCat
60a7098fd3 feat(search): add Baidu Qianfan AI Search provider with i18n docs
- Add BaiduSearchConfig struct and register in WebToolsConfig/defaults
- Insert Baidu Search in priority chain: DuckDuckGo > Baidu > GLM Search
- Use perplexityTimeout (30s) — Qianfan is LLM-based
- Fix response parsing: use references[] field per API spec
- Add baidu_search block to config.example.json

docs: sync configuration.md and README Documentation table across all languages

- Complete truncated configuration.md for fr/ja/pt-br/vi/zh: add Spawn
  async flow diagram, Providers table, Model Configuration (all vendors,
  examples, load balancing, migration), Provider Architecture, Scheduled
  Tasks, and Advanced Topics links
- Add Hooks/Steering/SubTurn entries to Documentation table in all 8
  READMEs (en/zh/fr/id/it/ja/pt-br/vi), ordered before Troubleshooting
- Add Baidu Search row to web search table in all 8 READMEs and
  tools_configuration.md (en + 5 i18n); zh README reorders search
  engines with China-friendly options first
- Add Matrix channel docs translations (fr/ja/pt-br/vi)
- Add Weixin channel to chat-apps.md and all README Channels tables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 00:51:27 +08:00
RussellLuo
fca01583bf fix(lint): align VoiceConfig env tags 2026-03-23 00:03:44 +08:00
yinwm
c48954d32d merge: sync main into refactor/agent 2026-03-22 21:44:17 +08:00
RussellLuo
8ad4b9b497 feat(voice): add audio-model transcription support
- Add `AudioModelTranscriber` for model-based audio transcription via LLM providers
- Support selecting a transcription model with `voice.model_name` in config
- Keep Groq transcription as a fallback and move it into dedicated files with focused tests
- Serialize `data:audio/...` media as input_audio for OpenAI-compatible providers
- Improve transcription logging by rendering error fields as strings
- Add coverage for transcriber detection, audio-model behavior, provider audio serialization, and Groq transcription

Fixes #1890.
2026-03-22 20:07:22 +08:00
Cytown
284ced1f5c Merge branch 'main' into version 2026-03-22 19:58:33 +08:00
Administrator
f7f27e237a merge: resolve conflicts between refactor/agent and main 2026-03-22 19:21:58 +08:00
Hua Audio
dd82794255
Feat/weixin openclaw port (#1873)
* init

* fix lint

* fix go test

* update docs

* incorporate pr review

* Update pkg/channels/weixin/weixin.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* feat(weixin): add media sync and typing support

* test(weixin): cover media and sync helpers

---------

Co-authored-by: zhangmikoto <i@electromaster.me>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Hoshina <hoshina@evaz.org>
2026-03-22 14:23:39 +08:00
Administrator
88d754b172 merge main 2026-03-22 13:47:14 +08:00
Cytown
3dfe484f66 make yaml indent with 2 2026-03-22 11:07:22 +08:00
Cytown
4e876ebeee remove useless logs output 2026-03-22 09:52:25 +08:00
Cytown
7c854fe6d7 Merge branch 'main' into version 2026-03-22 02:53:55 +08:00
Cytown
e455eb5e67 refactor: seperate security.yml for store keys 2026-03-22 01:55:00 +08:00
Administrator
670b433f1a refactor: replace interface{} with any for improved type clarity 2026-03-21 18:24:56 +08:00
Administrator
1bd144ac13 Merge branch 'upstream-main' into feat/subturn-poc 2026-03-21 17:13:26 +08:00
Administrator
087e8519c5 refactor: improve code readability and consistency across multiple files 2026-03-21 17:12:45 +08:00
Kunal Karmakar
647071d342 Add default value for config 2026-03-21 06:54:49 +00:00
Kunal Karmakar
92b7687068 Add configurable logger 2026-03-21 06:54:49 +00:00
Amir Mamaghani
71134babb9
feat(telegram): stream LLM responses via sendMessageDraft (#1101)
* feat(telegram): stream LLM responses in real-time via sendMessageDraft

Implements real-time token streaming to Telegram using the sendMessageDraft
API (telego v1.6.0). Instead of showing only a "Thinking..." placeholder
until the full response arrives, users now see partial LLM output appear
in the chat as it's generated.

The streaming pipeline threads through all layers:

- StreamingProvider interface (providers/types.go): opt-in ChatStream()
  method that receives an onChunk callback with accumulated text
- OpenAI-compatible SSE streaming (openai_compat/provider.go): parses
  SSE events with stream:true, handles text deltas and tool call assembly
- Anthropic native streaming (anthropic/provider.go): uses SDK's
  NewStreaming() for direct Anthropic API connections
- HTTPProvider delegation (http_provider.go): delegates ChatStream to
  the underlying openai_compat provider
- StreamingCapable + Streamer interfaces (channels/interfaces.go):
  opt-in channel capability like TypingCapable/PlaceholderCapable
- Telegram streamer (telegram/telegram.go): BeginStream returns a
  telegramStreamer that throttles sendMessageDraft calls (3s/200 chars)
  with graceful degradation on API errors
- StreamDelegate bridge (bus/bus.go): decouples agent loop from channel
  manager without tight imports
- Manager integration (manager.go): implements StreamDelegate, tracks
  streamActive state, coordinates with placeholder editing
- Agent loop (loop.go): uses ChatStream when both provider and channel
  support streaming, cancels stream on tool calls, skips PublishOutbound
  when Finalize already delivered the message

Graceful degradation:
- Bots without forum/topics mode: first sendMessageDraft error sets
  failed=true, subsequent Updates become no-ops, Finalize still delivers
  via SendMessage. User sees normal non-streaming behavior.
- Non-streaming providers: type assertion fails, falls back to Chat()
- Config opt-out: streaming.enabled (default true) in telegram config

Closes #1098

* fix(telegram): delete placeholder message when streaming delivers response

When streaming was active, the "Thinking..." placeholder message stayed
in the chat because preSend only deleted the tracking entry without
removing the actual Telegram message. Now preSend deletes the placeholder
via the new MessageDeleter interface when streamActive is set.

* refactor(streaming): remove dead code and simplify streaming wiring

- Delete unused Anthropic ChatStream/parseStream (-131 lines) — factory
  creates HTTPProvider for all OpenAI-compat providers including OpenRouter
- Simplify runLLMIteration from 4 to 3 return values (remove unused
  streamed bool)
- Replace managerStreamer struct with finalizeHookStreamer using embedding
  (Update/Cancel promoted, only Finalize overridden)

* fix(streaming): skip streamer acquisition when SendResponse is false

Heartbeat messages set SendResponse=false but the streaming path
was unconditionally acquiring a streamer, causing HEARTBEAT_OK to
leak to Telegram via streamer.Finalize().

* fix(streaming): guard streamer for non-sendable messages, add streaming config

Skip streamer acquisition for heartbeat (NoHistory=true), preventing
HEARTBEAT_OK from leaking to Telegram via streamer.Finalize().

Add streaming.enabled to Telegram defaults and example config.

* feat(telegram): stream LLM responses in real-time via sendMessageDraft

Implements real-time token streaming to Telegram using the sendMessageDraft
API (telego v1.6.0). Instead of showing only a "Thinking..." placeholder
until the full response arrives, users now see partial LLM output appear
in the chat as it's generated.

The streaming pipeline threads through all layers:

- StreamingProvider interface (providers/types.go): opt-in ChatStream()
  method that receives an onChunk callback with accumulated text
- OpenAI-compatible SSE streaming (openai_compat/provider.go): parses
  SSE events with stream:true, handles text deltas and tool call assembly
- Anthropic native streaming (anthropic/provider.go): uses SDK's
  NewStreaming() for direct Anthropic API connections
- HTTPProvider delegation (http_provider.go): delegates ChatStream to
  the underlying openai_compat provider
- StreamingCapable + Streamer interfaces (channels/interfaces.go):
  opt-in channel capability like TypingCapable/PlaceholderCapable
- Telegram streamer (telegram/telegram.go): BeginStream returns a
  telegramStreamer that throttles sendMessageDraft calls (3s/200 chars)
  with graceful degradation on API errors
- StreamDelegate bridge (bus/bus.go): decouples agent loop from channel
  manager without tight imports
- Manager integration (manager.go): implements StreamDelegate, tracks
  streamActive state, coordinates with placeholder editing
- Agent loop (loop.go): uses ChatStream when both provider and channel
  support streaming, cancels stream on tool calls, skips PublishOutbound
  when Finalize already delivered the message

Graceful degradation:
- Bots without forum/topics mode: first sendMessageDraft error sets
  failed=true, subsequent Updates become no-ops, Finalize still delivers
  via SendMessage. User sees normal non-streaming behavior.
- Non-streaming providers: type assertion fails, falls back to Chat()
- Config opt-out: streaming.enabled (default true) in telegram config

Closes #1098

* fix(telegram): delete placeholder message when streaming delivers response

When streaming was active, the "Thinking..." placeholder message stayed
in the chat because preSend only deleted the tracking entry without
removing the actual Telegram message. Now preSend deletes the placeholder
via the new MessageDeleter interface when streamActive is set.

* refactor(streaming): remove dead code and simplify streaming wiring

- Delete unused Anthropic ChatStream/parseStream (-131 lines) — factory
  creates HTTPProvider for all OpenAI-compat providers including OpenRouter
- Simplify runLLMIteration from 4 to 3 return values (remove unused
  streamed bool)
- Replace managerStreamer struct with finalizeHookStreamer using embedding
  (Update/Cancel promoted, only Finalize overridden)

* fix(streaming): skip streamer acquisition when SendResponse is false

Heartbeat messages set SendResponse=false but the streaming path
was unconditionally acquiring a streamer, causing HEARTBEAT_OK to
leak to Telegram via streamer.Finalize().

* fix(streaming): guard streamer for non-sendable messages, add streaming config

Skip streamer acquisition for heartbeat (NoHistory=true), preventing
HEARTBEAT_OK from leaking to Telegram via streamer.Finalize().

Add streaming.enabled to Telegram defaults and example config.

* fix(picoclaw): add missing closing brace for StreamingProvider interface

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

* fix: resolve golangci-lint formatting issues

Fix gci import ordering in telegram and anthropic provider, and break
long function signature in openai_compat provider to satisfy golines.

* fix: address code review feedback on streaming PR

- Deduplicate Streamer interface: alias channels.Streamer to bus.Streamer
  to prevent type drift across packages
- Increase SSE scanner buffer to 10MB max to handle large single-line
  responses that exceed bufio.Scanner's 64KB default
- Switch draftID generation from math/rand to crypto/rand for
  collision-resistant random IDs
- Add context cancellation check in SSE parsing loop so cancelled
  streams stop processing immediately
- Log Finalize failures with chat_id and content length for debugging
  silent message delivery failures

* feat: make streaming throttle interval and min growth configurable

Move hardcoded streamThrottleInterval (3s) and streamMinGrowth (200)
into StreamingConfig so they can be tuned per deployment via config
or environment variables.

* fix(telegram): use parseTelegramChatID in DeleteMessage and BeginStream

These two functions called undefined parseChatID. Use
parseTelegramChatID with _ for the unused threadID instead of adding
a wrapper function. Fixes all three CI checks.

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

* fix(streaming): set streamActive only after successful Finalize

Move onFinalize hook to run after Streamer.Finalize succeeds, so that
if Finalize fails the streamActive flag stays false and the regular
placeholder fallback path remains available.

Addresses review feedback from @alexhoshina.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 21:04:14 +08:00
Amir Mamaghani
544940807f
feat(pico): add pico_client outbound WebSocket channel (#1198)
* feat(pico): add pico_client outbound WebSocket channel

Add a client-mode counterpart to the existing pico server channel.
pico_client connects to a remote Pico Protocol WebSocket server,
enabling picoclaw to bridge messages with external Pico-compatible
services.

Includes config, factory registration, manager wiring, 8 unit tests,
and a minimal echo-server example for interactive testing.

* fix(pico): address PR #1198 review — goroutine leak, race, auth

- Add per-connection context cancel to picoConn to prevent pingLoop
  goroutine leak on disconnect
- Re-acquire mutex in StartTyping stop closure to avoid stale conn race
- Remove query-param token auth from echo server (header-only)
- Move ListenAndServe to main goroutine where log.Fatal is safe

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

* fix: replace ConsumeInbound with InboundChan select in client test

MessageBus does not expose a ConsumeInbound method. Use a select on
InboundChan() with context cancellation, matching the pattern used in
the bus package tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 20:43:40 +08:00
Administrator
4f646ef2b8 Merge branch 'main' into feat/subturn-poc 2026-03-20 11:51:25 +08:00
美電球
75d86721a3
Feat/wecom aibot processing message config (#1785)
* feat(wecom_aibot): make processing message configurable

* docs(wecom): document ai bot processing message

* test(wecom_aibot): adapt webhook tests to channel interface

* fix: lint err
2026-03-20 00:23:40 +08:00
Administrator
c18d8a2ecc Merge branch 'upstream-main' into feat/subturn-poc 2026-03-19 22:12:51 +08:00
Bijin
38e1fe435a
fix(config): model_list inherits api_key/api_base from providers (#1786)
When both providers and model_list are configured, model_list entries
with empty api_key or api_base now automatically inherit from the
matching provider (matched by protocol prefix in the Model field).

Example: a model_list entry with model='deepseek/deepseek-chat' and
no api_key will inherit from providers.deepseek.api_key.

Explicit model_list values always take precedence.

Changes:
- Add InheritProviderCredentials() in migration.go
- Call it in LoadConfig() after provider-to-model-list conversion
- Add protocolProviderMapping for all 25 supported protocols
- 6 new tests covering inheritance, precedence, and edge cases

Closes #1635
2026-03-19 21:24:46 +08:00
Administrator
583c586db6 Merge branch 'main' into feat/subturn-poc 2026-03-19 20:20:31 +08:00
ZHANG RUI
9a25fad20a
Implement the latest long-connection mode for the WeCom AI Bot. (#1295)
* feat(wecom): add WebSocket long-connection support for WeCom AI Bot

- Introduced WeComAIBotWSChannel to handle WebSocket connections.
- Updated NewWeComAIBotChannel to prioritize WebSocket mode when BotID and Secret are provided.
- Enhanced WeComAIBotConfig to include BotID and Secret for WebSocket mode.
- Implemented message handling for text, image, voice, and mixed messages in WebSocket mode.
- Added tests for WebSocket mode functionality and ensured backward compatibility with webhook mode.
- Refactored existing code to improve clarity and maintainability.

* feat(wecom): implement periodic processing hints and enforce WeCom stream deadline

* feat(wecom): update WeCom AI Bot setup instructions and configuration parameters

* feat(wecom): enhance WeCom AI Bot with image handling and media support

* feat(wecom): refactor WeCom AI Bot task management to use req_id for concurrent message handling

* feat(wecom): refactor WeCom AI Bot to manage request states and late replies

* feat(wecom): add response timeout handling and improve WebSocket command acknowledgment

* fix(wecom): improve error handling for late reply proactive push delivery

* refactor(wecom): reorganize WeCom AI Bot configuration fields for improved readability

* fix(wecom): update error message for websocket delivery failure in late reply proactive push

* feat(wecom): implement shared HTTP clients for WeCom image handling and response URL posting

* refactor(wecom): simplify image download and storage process in storeWSImage

* fix(wecom): improve error logging for WebSocket message handling and proactive push delivery

* fix(wecom): enhance WebSocket connection stability and task cancellation handling

* fix(wecom): improve WS image message handling by ensuring proper error response and initializing mediaRefs

* feat(wecom): enhance WeCom AIBot WebSocket handling with message deduplication and support for file and video messages

* refactor(wecom): rename image handling functions to media handling and enhance media type support

* feat(wecom): implement byte-aware content splitting for WeCom AI Bot stream messages

* refactor(wecom): remove max message length constraint from WeCom AIBot WS channel
2026-03-19 20:06:51 +08:00
Cytown
94fcb25039 Merge branch 'main' into version 2026-03-19 18:16:15 +08:00
Mauro
7673b626b3
feat(tool): debug tool usage via channels (#1332)
* feat(tool): debug usage via channel

* set defaults

* fix conflicts
2026-03-19 18:08:50 +08:00
Cytown
cfd3a1b441 Merge branch 'main' into version 2026-03-19 18:04:58 +08:00
Administrator
54889f21a7 Merge branch 'upstream-main' into feat/subturn-poc 2026-03-19 17:05:09 +08:00
Mauro
a4b5a9eec1
feat(mcp): per server deferred mode (#1654)
* feat(mcp): per server deferred mode

* fix deferred behavior
2026-03-19 17:03:17 +08:00
Administrator
532ea4b56c Merge branch 'upstream-main' into feat/subturn-poc 2026-03-19 16:47:35 +08:00
美電球
828971d549
Feat/qq local file upload (#1722)
* feat(qq): support media uploads and inbound attachments

* docs(qq): document media size limit settings

* chore(web): add QQ media size limit hints

* fix(qq): demote botgo heartbeat logs

* style(qq): fix lint issues
2026-03-19 16:27:34 +08:00
Administrator
29a161e757 fix(tools): prevent nil pointer dereference in spawn tools
Add nil checks in NewSpawnTool and NewSubagentTool constructors to
handle nil manager gracefully. Fix spelling errors (cancelled->canceled)
and remove unused test code. Update tests to use mock spawner.
2026-03-19 13:51:11 +08:00
Administrator
ce311be70b feat(subturn): add configurable runtime parameters under agents.defaults
Replace hardcoded constants with config-driven parameters in agents.defaults:
- MaxDepth, MaxConcurrent, DefaultTimeout, DefaultTokenBudget, ConcurrencyTimeout
- Support JSON config and env vars (PICOCLAW_AGENTS_DEFAULTS_SUBTURN_*)
- Add getSubTurnConfig() for runtime config resolution with defaults
- Apply defaultTokenBudget when no explicit budget is provided

Rationale: SubTurn is agent execution infrastructure, not a tool, so it belongs
in agents.defaults rather than tools config.

Example:
{
  "agents": {
    "defaults": {
      "subturn": {
        "max_depth": 5,
        "max_concurrent": 10,
        "default_timeout_minutes": 10
      }
    }
  }
}
2026-03-19 13:08:46 +08:00
Administrator
c732e63650 Merge branch 'upstream-main' into feat/subturn-poc 2026-03-19 09:16:38 +08:00
Liu Yuan
e73d9d959e
feat(config): support multiple API keys for failover (#1707)
* feat(config): support multiple API keys for failover

Add api_keys field to ModelConfig to support multiple API keys with
automatic failover. When multiple keys are configured, they are expanded
into separate model entries with fallbacks set up for key-level failover.

Example config:
  {
    "model_name": "glm-4.7",
    "model": "zhipu/glm-4.7",
    "api_keys": ["key1", "key2", "key3"]
  }

Expands internally to:
  - glm-4.7 (key1) -> fallbacks: [glm-4.7__key_1, glm-4.7__key_2]
  - glm-4.7__key_1 (key2)
  - glm-4.7__key_2 (key3)

Backward compatible: single api_key still works as before.

* fix(providers): change cooldown tracking from provider to ModelKey

This enables proper key-switching when multiple API keys share the same
provider. Previously, when one key failed, all keys were blocked because
cooldown was tracked per-provider.

Now each (provider, model) combination has independent cooldown, allowing
fallback to alternate keys when one is rate limited.

Includes TestMultiKeyWithModelFallback and related failover tests.
2026-03-19 00:57:20 +08:00
Liqiang Lau
08f305d712
feat: add IsLark field to FeishuConfig to switch between Feishu and Lark domains (#1753)
* feat(feishu): add Lark (international) support via IsLark config field

Add IsLark field to FeishuConfig to switch between Feishu and Lark
domains. Also fix domain inconsistency where WS client defaulted to
LarkBaseUrl while HTTP client used FeishuBaseUrl.

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

* docs: update documentation and web UI for Lark support

Add is_lark field to config example, feishu docs, i18n translations,
and web frontend form.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 00:29:55 +08:00
Administrator
431a53cbb1 Merge branch 'upstream-main' into feat/subturn-poc 2026-03-18 22:57:01 +08:00
Alexander
12f4029610
feat: telegram use parse mode ModeMarkdownV2 instead of ModeHTML (#1018)
* feat: telegram use parse mode ModeMarkdownV2 instead of ModeHTML

* handle expandable block quotation starts, add test for all md2 formats

* fix: linter issue

* feat: added flag use_markdown_v2, corrected config, updated
documentation

* move parseChatID to parser_markdown_to_html

* fix: tests and linter issues

* fix: case with ~

* test: fixed Test_markdownToTelegramMarkdownV2

* fix: regex block-quote line  >

* fix: linter issues

* fix: send chunk param mismatched, in edit msg use HTML parse mode too

* fix: remove from .gitignore redundant comment
2026-03-18 21:29:21 +08:00
Alex
578f90855e
feat: Add Novita provider support (#1677)
* Add Novita provider support

- Add 'novita' prefix to normalizeModel switch in openai_compat provider
- Add Novita provider to all_supported_vendors table in README.md
- Add test cases for Novita model prefix stripping

Novita endpoint: https://api.novita.ai/openai
Default models: deepseek/deepseek-v3.2, zai-org/glm-5, minimax/minimax-m2.5

* feat: complete Novita provider integration

* chore: drop README changes from Novita PR

* fix: remove duplicate function declarations in openai_compat provider

The functions buildToolsList, SupportsNativeSearch, and isNativeSearchHost
were declared twice, causing compilation failures in all CI checks.

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

* fix: break long line in novita test to satisfy golines linter

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 18:29:27 +08:00
dev-miro26
c07f5c948f
refactor: centralize environment variable key constants (#1730)
* refactor: centralize environment variable key constants

* refactor: update environment variable constants and usage in gateway
2026-03-18 18:03:24 +08:00
dataCenter430
f79469c19d
Add model-native search (prefer_native) for OpenAI/Codex (#1618)
* config: add prefer_native and NativeSearchCapable for model-native search

* providers: implement native web search for OpenAI and Codex

* agent: use provider-native search when prefer_native and supported

* tests: add coverage for model-native search

* fix: Golang lint errors

* fix: update the code based on the review

* fix: update codex_provider_test
2026-03-18 11:55:30 +08:00
Meng Zhuo
cefa140bd2
Merge pull request #1622 from afjcjsbx/feat/markdown-output-format-web-fetch
feat(tool): markdown format in web_fetch tool output
2026-03-18 09:15:13 +08:00
Mauro
513537d230
Merge pull request #1702 from Alix-007/fix/issue-1153-model-round-robin-cleanbase
fix(config): start model round robin from the first match
2026-03-17 22:28:48 +01:00
afjcjsbx
8f460726cc fix lint + error check 2026-03-17 17:14:23 +01:00
Mauro
3791f06faf
Merge branch 'main' into feat/markdown-output-format-web-fetch 2026-03-17 16:37:22 +01:00
Alix-007
b4468313e4
feat(web): whitelist private fetch targets (#1688)
* feat(web): whitelist private fetch targets

* test(web): avoid accept error shadowing

---------

Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-03-17 23:22:05 +08:00
Alix-007
fcf406bf2e fix(config): start model round robin from the first match 2026-03-17 21:59:04 +08:00
Administrator
e00a3d9017 Merge upstream/main into feat/subturn-poc
Includes JSONL session persistence (#1170), spawn_status tool, Azure provider,
credential encryption, and various fixes. SubTurn features preserved and
integrated with new spawn_status functionality.
2026-03-17 21:55:20 +08:00
wenjie
8a44410e37
feat: add web gateway hot reload and polling state sync (#1684)
* feat(gateway): support hot reload and empty startup

- extract gateway runtime into pkg/gateway
- add gateway.hot_reload config with default and example values
- allow starting the gateway without a default model via --allow-empty
- stop treating missing enabled channels as a startup error
- update related tests

* feat: replace gateway SSE updates with polling-based state sync

- remove gateway SSE broadcasting and event endpoint
- add polling-based gateway status refresh with stopping state handling
- detect when gateway restart is required after default model changes
- resolve gateway health and websocket proxy targets from configured host
- update gateway UI labels and add backend/frontend test coverage
2026-03-17 18:46:00 +08:00
Desmond Foo
b402888bfa
feat(tools): add SpawnStatusTool for reporting subagent statuses (#1540)
* feat(tools): add SpawnStatusTool for reporting subagent statuses

* feat(tools): enhance SpawnStatusTool to restrict task visibility by conversation context

* feat(tests): add Unicode result truncation and channel filtering tests for SpawnStatusTool

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* feat(tools): enhance SpawnStatusTool with task ID validation and sorting by creation timestamp

* feat(tools): update SpawnStatusTool description and parameter documentation for clarity

* refactor(tests): improve comments for clarity in ChannelFiltering test case

* fix(tools): update no subagents message for clarity and remove unnecessary locking in runTask

* fix(tools): improve description clarity for SpawnStatusTool regarding task context

* feat(tools): add spawn_status tool configuration and registration

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix(agent): improve subagent management for spawn and spawn_status tools

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix(tests): update ResultTruncation_Unicode test to use valid CJK character

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: lxowalle <83055338+lxowalle@users.noreply.github.com>
2026-03-17 14:41:43 +08:00
wenjie
fcb69860c4
feat(web): add configurable cron command execution settings (#1647)
- add tools.cron.allow_command config with a default value of true
- require command_confirm only when cron command execution is disabled
- expose cron command permission and timeout settings in the config UI
- add backend tests and update i18n strings
2026-03-17 09:44:32 +08:00
sky5454
2f10b47f59
feat(credential): part1 add AES-GCM encryption, SecureStore, and onboard ke… (#1521)
* feat(credential): add AES-GCM encryption, SecureStore, and onboard keygen

- pkg/credential: new package with AES-256-GCM enc:// credential format,
  HKDF-SHA256 key derivation (passphrase + optional SSH key binding),
  ErrPassphraseRequired / ErrDecryptionFailed sentinel errors,
  and PassphraseProvider hook for runtime passphrase injection

- pkg/credential/store: lock-free SecureStore via atomic.Pointer[string];
  passphrase never written to disk or os.Environ

- pkg/credential/keygen: ed25519 SSH key generation helper used by onboard

- pkg/config: replace os.Getenv(PassphraseEnvVar) with
  credential.PassphraseProvider() at all three call sites so that
  LoadConfig and SaveConfig use whatever passphrase source is active

- cmd/picoclaw/onboard: prompt for passphrase with echo-off, generate
  picoclaw-specific SSH key, re-encrypt existing config on re-onboard

- docs/credential_encryption.md: design doc for the enc:// format

* fix(credential): address Copilot review comments on PR #1521

- credential.go: decouple ErrPassphraseRequired from env var name;
  message is now 'enc:// passphrase required' since PassphraseProvider
  may come from any source, not just os.Environ

- credential.go: Resolver resolves symlinks via EvalSymlinks before the
  isWithinDir containment check, preventing symlink-based path traversal
  for file:// credential references

- store.go: tighten comment to describe only what SecureStore guarantees
  (in-memory only); remove claims about how callers transport the value

- store_test.go: replace the meaningless GetReturnsCopy test (Go strings
  are immutable, equality across two calls proves nothing) with
  TestSecureStore_ConcurrentSetGet that exercises atomic.Pointer under
  10-goroutine concurrent Set/Get load

- config_test.go: update error-message assertion to match new sentinel text

- docs/credential_encryption.md: remove reference to non-existent
  'picoclaw encrypt' subcommand; describe the onboard flow instead

* fix(config): encryptPlaintextAPIKeys: struct-based encryption, fail-fast, remove raw []byte

* fix(credential): require SSH private key for encryption/decryption, remove passphrase-only mode

* lint: fix credential keygen lint, fix test keygen

* onboard: make encryption opt-in via --enc flag

Encryption (passphrase prompt + SSH key generation) is now only
triggered when the user passes --enc to 'picoclaw onboard'.
Without the flag, onboard skips the credential-encryption setup and
writes a plain config + workspace templates directly.

- Add --enc BoolFlag in NewOnboardCommand()
- Pass encrypt bool into onboard()
- Guard passphrase prompt, SSH key generation, and related env-var
  setup behind the encrypt branch
- Adjust 'Next steps' output so the passphrase reminder only appears
  when --enc was used
2026-03-16 14:06:32 +08:00
afjcjsbx
d5c2bc538a feat(tool): markdown format in output web_fetch tool 2026-03-15 22:12:03 +01:00
Mauro
021aa7d6d5
feat(agent): steering (#1517)
* feat(agent): steering

* fix loop

* fix lint

* fix lint
2026-03-16 00:08:16 +08:00
Kunal Karmakar
5fb4b3bedf
feat(provider): add support for azure openai provider (#1422)
* Add support for azure openai provider

* Add checks for deployment model name

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Addressing @Copilot suggestion to remove the init() function which seemed redundant

* Fix readme

* Fix linting checks

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-14 22:52:34 +08:00
Cytown
dfa36f39cb
add model command to set default model (#1250)
* add model command to set default model

* fix for ci

* fix test for model

* fix active agent not recognized

* implement test for model command

* fix local-model can not set as default issue

* fix review comment

* fix for comment
2026-03-13 14:10:11 +08:00
leamon
0fb92b21b6
enhance skill installer (#1252)
* enhance skill installer

* enhance install skills v2

* go file formate

* fix:use proxy download skills;many chunck download;simple code

* add default config to config.example.json, download skill from github use proxy and token

---------

Co-authored-by: FantasticCode2019 <1443996278@qq.com>
2026-03-13 14:04:02 +08:00