1493 Commits

Author SHA1 Message Date
chengyongru
226fdfcb91 feat(channel): add message send retry mechanism with exponential backoff
- Add send_max_retries config option (default: 3, range: 0-10)
- Implement _send_with_retry in ChannelManager with 1s/2s/4s backoff
- Propagate CancelledError for graceful shutdown
- Fix telegram send_delta to raise exceptions for Manager retry
- Add comprehensive tests for retry logic
- Document channel settings in README
2026-03-25 18:38:25 +08:00
Flo
33f357119e
fix(providers): add max_completion_tokens for openai o1 compatibility (#2464) 2026-03-25 15:35:23 +08:00
chengyongru
723ed8172b Merge branch 'main' into nightly 2026-03-25 13:24:15 +08:00
Xubin Ren
b5302b6f3d refactor(provider): preserve extra_content verbatim for Gemini thought_signature round-trip
Replace the flatten/unflatten approach (merging extra_content.google.*
into provider_specific_fields then reconstructing) with direct pass-through:
parse extra_content as-is, store on ToolCallRequest.extra_content, serialize
back untouched.  This is lossless, requires no hardcoded field names, and
covers all three parsing branches (str, dict, SDK object) plus streaming.
2026-03-25 10:00:29 +08:00
Yohei Nishikubo
af84b1b8c0 fix(Gemini): update ToolCallRequest and OpenAICompatProvider to handle thought signatures in extra_content 2026-03-25 10:00:29 +08:00
Yohei Nishikubo
7b720ce9f7 feat(OpenAICompatProvider): enhance tool call handling with provider-specific fields 2026-03-25 10:00:29 +08:00
Xubin Ren
263069583d fix(provider): accept plain text OpenAI-compatible responses
Handle string and dict-shaped responses from OpenAI-compatible backends so non-standard providers no longer crash on missing choices fields. Add regression tests to keep SDK, dict, and plain-text parsing paths aligned.
2026-03-25 01:22:21 +00:00
Seeratul
321214e2e0 Update group policy explanation in README
Clarified instructions for group policy behavior in README.
2026-03-25 09:08:10 +08:00
Seeratul
b7df3a0aea Update README with group policy clarification
Clarify group policy behavior for bot responses in group channels.
2026-03-25 09:08:10 +08:00
xcosmosbox
0ccfcf6588 fix(WeiXin): version migration 2026-03-25 02:58:19 +08:00
xcosmosbox
0dad6124a2 chore(WeiXin): version migration and compatibility update 2026-03-25 02:58:19 +08:00
xcosmosbox
48902ae95a fix(WeiXin): auto-refresh expired QR code during login to improve success rate 2026-03-25 02:58:19 +08:00
xcosmosbox
1f5492ea9e fix(WeiXin): persist _context_tokens with account.json to restore conversations after restart 2026-03-25 02:58:19 +08:00
xcosmosbox
9c872c3458 fix(WeiXin): resolve polling issues in WeiXin plugin
- Prevent repeated retries on expired sessions in the polling thread
- Stop sending messages to invalid agent sessions to eliminate noise logs and unnecessary requests
2026-03-25 02:58:19 +08:00
xcosmosbox
3a9d6ea536 feat(WeXin): add route_tag property to adapt to WeChat official ilinkai 1.0.3 requirements 2026-03-25 02:58:19 +08:00
Xubin Ren
7b31af2204 docs: update news section 2026-03-24 18:11:50 +00:00
Xubin Ren
c3031c9cb8 docs: update news section about litellm 2026-03-24 18:11:03 +00:00
Xubin Ren
3dfdab704e refactor: replace litellm with native openai + anthropic SDKs
- Remove litellm dependency entirely (supply chain risk mitigation)
- Add AnthropicProvider (native SDK) and OpenAICompatProvider (unified)
- Merge CustomProvider into OpenAICompatProvider, delete custom_provider.py
- Add ProviderSpec.backend field for declarative provider routing
- Remove _resolve_model, find_gateway, find_by_model (dead heuristics)
- Pass resolved spec directly into provider — zero internal lookups
- Stub out litellm-dependent model database (cli/models.py)
- Add anthropic>=0.45.0 to dependencies, remove litellm
- 593 tests passed, net -1034 lines
2026-03-25 01:58:48 +08:00
Xubin Ren
38ce054b31 fix(security): pin litellm and add supply chain advisory note 2026-03-24 15:55:43 +00:00
LeftX
b3e35e9476
feat(feishu): support stream output (cardkit) (#2382)
* feat(feishu): add streaming support via CardKit PATCH API

Implement send_delta() for Feishu channel using interactive card
progressive editing:
- First delta creates a card with markdown content and typing cursor
- Subsequent deltas throttled at 0.5s to respect 5 QPS PATCH limit
- stream_end finalizes with full formatted card (tables, rich markdown)

Also refactors _send_message_sync to return message_id (str | None)
and adds _patch_card_sync for card updates.

Includes 17 new unit tests covering streaming lifecycle, config,
card building, and edge cases.

Made-with: Cursor

* feat(feishu): close CardKit streaming_mode on stream end

Call cardkit card.settings after final content update so chat preview
leaves default [生成中...] summary (Feishu streaming docs).

Made-with: Cursor

* style: polish Feishu streaming (PEP8 spacing, drop unused test imports)

Made-with: Cursor

* docs(feishu): document cardkit:card:write for streaming

- README: permissions, upgrade note for existing apps, streaming toggle
- CHANNEL_PLUGIN_GUIDE: Feishu CardKit scope and when to disable streaming

Made-with: Cursor

* docs: address PR 2382 review (test path, plugin guide, README, English docstrings)

- Move Feishu streaming tests to tests/channels/
- Remove Feishu CardKit scope from CHANNEL_PLUGIN_GUIDE (plugin-dev doc only)
- README Feishu permissions: consistent English
- feishu.py: replace Chinese in streaming docstrings/comments

Made-with: Cursor
2026-03-24 15:57:14 +08:00
chengyongru
178216bcbc refactor(tests): optimize unit test structure 2026-03-24 15:21:07 +08:00
chengyongru
72acba5d27 refactor(tests): optimize unit test structure 2026-03-24 15:12:22 +08:00
chengyongru
54b79ce8b7 Merge branch 'main' into nightly 2026-03-24 14:34:44 +08:00
Xubin Ren
d25985be0b fix(filesystem): clarify optional tool argument handling
Keep the mypy-friendly optional execute signatures while returning clearer errors for missing arguments and locking that behavior with regression tests.

Made-with: Cursor
2026-03-24 11:49:10 +08:00
19emtuck
d4a7194c88 remove some none used f string 2026-03-24 11:49:10 +08:00
19emtuck
69f1dcdba7 proposal to adopt mypy some e.g. interfaces problems 2026-03-24 11:49:10 +08:00
Xubin Ren
c00e64a817
Merge PR #2386: feat(channel): enhance Telegram, QQ, Feishu, and WhatsApp
feat: telegram/qq/whatsapp/feishu enhancement
2026-03-24 11:40:15 +08:00
Xubin Ren
a96dd8babb Merge branch 'main' into feat/channel_enhancement
Keep the channel enhancements aligned with the current codebase while preserving a simpler product surface. This keeps QQ, Feishu, Telegram, and WhatsApp improvements together, removes the extra Telegram-only tool hint toggle, and makes WhatsApp mention-only groups actually work.
2026-03-24 03:33:44 +00:00
Xubin Ren
14763a6ad1 fix(provider): accept canonical and alias provider names consistently 2026-03-24 03:03:59 +00:00
Xubin Ren
d454386f32 docs(weixin): clarify source-only installation in README 2026-03-24 02:51:50 +00:00
Xubin Ren
b5c95b1a34
Merge PR #2204: fix(cron): scope cron state to each workspace with safe default-only migration
fix(cron): scope cron state to each workspace with safe default-only migration
2026-03-24 10:46:49 +08:00
Xubin Ren
186357e80c Merge branch 'main' into fix/workspace-scoped-cron-store
Keep cron state workspace-scoped while only migrating legacy jobs into the default workspace. This preserves seamless upgrades for existing installs without polluting intentionally new workspaces.
2026-03-24 02:41:58 +00:00
Xubin Ren
1d58c9b9e1 docs: update channel table and add plugin dev note 2026-03-23 17:17:10 +00:00
Xubin Ren
25288f9951 feat(whatsapp): add outbound media support via bridge 2026-03-24 01:11:33 +08:00
Xubin Ren
bef88a5ea1 docs: require explicit channel login command 2026-03-24 01:11:33 +08:00
Xubin Ren
d164548d9a docs(weixin): add setup guide and focused channel tests 2026-03-24 01:11:33 +08:00
Xubin Ren
0ca639bf22 fix(cli): use discovered class for channel login 2026-03-24 01:11:33 +08:00
chengyongru
556b21d011 refactor(channels): abstract login() into BaseChannel, unify CLI commands
Move channel-specific login logic from CLI into each channel class via a
new `login(force=False)` method on BaseChannel. The `channels login <name>`
command now dynamically loads the channel and calls its login() method.

- WeixinChannel.login(): calls existing _qr_login(), with force to clear saved token
- WhatsAppChannel.login(): sets up bridge and spawns npm process for QR login
- CLI no longer contains duplicate login logic per channel
- Update CHANNEL_PLUGIN_GUIDE to document the login() hook

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 01:11:33 +08:00
ZhangYuanhan-AI
11e1bbbab7 feat(weixin): add outbound media file sending via CDN upload
Previously the WeChat channel's send() method only handled text messages,
completely ignoring msg.media. When the agent called message(media=[...]),
the file was never delivered to the user.

Implement the full WeChat CDN upload protocol following the reference
@tencent-weixin/openclaw-weixin v1.0.2:
  1. Generate a client-side AES-128 key (16 random bytes)
  2. Call getuploadurl with file metadata + hex-encoded AES key
  3. AES-128-ECB encrypt the file and POST to CDN with filekey param
  4. Read x-encrypted-param from CDN response header as download param
  5. Send message with the media item (image/video/file) referencing
     the CDN upload

Also adds:
- _encrypt_aes_ecb() for AES-128-ECB encryption (reverse of existing
  _decrypt_aes_ecb)
- Media type detection from file extension (image/video/file)
- Graceful error handling: failed media sends notify the user via text
  without blocking subsequent text delivery

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 01:11:33 +08:00
ZhangYuanhan-AI
8abbe8a6df fix(agent): instruct LLM to use message tool for file delivery
During testing, we discovered that when a user requests the agent to
send a file (e.g., "send me IMG_1115.png"), the agent would call
read_file to view the content and then reply with text claiming
"file sent" — but never actually deliver the file to the user.

Root cause: The system prompt stated "Reply directly with text for
conversations. Only use the 'message' tool to send to a specific
chat channel", which led the LLM to believe text replies were
sufficient for all responses, including file delivery.

Fix: Add an explicit IMPORTANT instruction in the system prompt
telling the LLM it MUST use the 'message' tool with the 'media'
parameter to send files, and that read_file only reads content
for its own analysis.

Co-Authored-By: qulllee <qullkui@tencent.com>
2026-03-24 01:11:33 +08:00
qulllee
bc9f861bb1 feat: add media message support in agent context and message tool
Cherry-picked from PR #2355 (ad128a7) — only agent/context.py and agent/tools/message.py.

Co-Authored-By: qulllee <qullkui@tencent.com>
2026-03-24 01:11:33 +08:00
ZhangYuanhan-AI
ebc4c2ec35 feat(weixin): add personal WeChat channel via ilinkai HTTP long-poll API
Add a new WeChat (微信) channel that connects to personal WeChat using
the ilinkai.weixin.qq.com HTTP long-poll API. Protocol reverse-engineered
from @tencent-weixin/openclaw-weixin v1.0.2.

Features:
- QR code login flow (nanobot weixin login)
- HTTP long-poll message receiving (getupdates)
- Text message sending with proper WeixinMessage format
- Media download with AES-128-ECB decryption (image/voice/file/video)
- Voice-to-text from WeChat + Groq Whisper fallback
- Quoted message (ref_msg) support
- Session expiry detection and auto-pause
- Server-suggested poll timeout adaptation
- Context token caching for replies
- Auto-discovery via channel registry

No WebSocket, no Node.js bridge, no local WeChat client needed — pure
HTTP with a bot token obtained via QR code scan.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 01:11:33 +08:00
Xubin Ren
2056061765 refine heartbeat session retention boundaries 2026-03-24 00:33:43 +08:00
flobo3
ba0a3d14d9 fix: clear heartbeat session to prevent token overflow
(cherry picked from commit 5c871d75d5b1aac09a8df31e6d1e04ee3d9b0d2c)
2026-03-24 00:33:43 +08:00
Eric Yang
84a7f8af73 refactor(shell): fix syntax error 2026-03-24 00:02:49 +08:00
Eric Yang
e2e1c9c276 refactor(shell): use finally block to reap zombie processes on timeoutx 2026-03-24 00:02:49 +08:00
Eric Yang
dbcc7cb539 refactor(shell): use finally block to reap zombie processes on timeout 2026-03-24 00:02:49 +08:00
Eric Yang
e423ceef9c fix(shell): reap zombie processes when command timeout kills subprocess 2026-03-24 00:02:49 +08:00
Flo
41843b0fb0
fix: clear heartbeat session to prevent token overflow (#2398) 2026-03-23 22:58:41 +08:00
gem12
97fe9ab7d4 feat(agent): replace global lock with per-session locks for concurrent dispatch
Replace the single _processing_lock (asyncio.Lock) with per-session locks
so that different sessions can process LLM requests concurrently, while
messages within the same session remain serialised.

An optional global concurrency cap is available via the
NANOBOT_MAX_CONCURRENT_REQUESTS env var (default 3, <=0 for unlimited).

Also re-binds tool context before each tool execution round to prevent
concurrent sessions from clobbering each other's routing info.

Tested in production and manually reviewed.

(cherry picked from commit c397bb4229e8c3b7f99acea7ffe4bea15e73e957)
2026-03-23 18:57:03 +08:00