* 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.
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>
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>
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>
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>
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>
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>
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.
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>
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.
* 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>
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.
- 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
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.
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.
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
Keep both KimiCodeUserAgent test (from this branch) and
serializeMessages tests (from upstream) — no overlap.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
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>
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>
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>