Commit Graph

1496 Commits

Author SHA1 Message Date
Hua
15f7d15108 refactor(agent): split slash commands and harden skill sync
Some checks failed
Test Suite / test (3.11) (push) Failing after 1m11s
Test Suite / test (3.12) (push) Failing after 1m16s
Test Suite / test (3.13) (push) Failing after 1m14s
2026-03-24 13:56:02 +08:00
Hua
270dff3d7f Merge remote-tracking branch 'origin/main' 2026-03-24 12:31:06 +08:00
Hua
751e82988c Merge remote-tracking branch 'origin/main'
# Conflicts:
#	nanobot/channels/qq.py
#	nanobot/channels/telegram.py
#	nanobot/channels/whatsapp.py
#	tests/test_qq_channel.py
2026-03-24 12:00:05 +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
Hua
b5ef69b210 Merge remote-tracking branch 'origin/main'
Some checks failed
Test Suite / test (3.11) (push) Failing after 1m9s
Test Suite / test (3.12) (push) Failing after 1m3s
Test Suite / test (3.13) (push) Failing after 1m5s
# Conflicts:
#	nanobot/cli/commands.py
#	tests/test_commands.py
2026-03-24 11:34:35 +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
Hua
fa9492c4d4 Merge remote-tracking branch 'origin/main'
Some checks failed
Test Suite / test (3.11) (push) Failing after 1m49s
Test Suite / test (3.12) (push) Failing after 1m18s
Test Suite / test (3.13) (push) Failing after 1m15s
# Conflicts:
#	nanobot/agent/loop.py
#	nanobot/agent/tools/message.py
#	nanobot/agent/tools/shell.py
#	nanobot/channels/whatsapp.py
#	nanobot/cli/commands.py
#	tests/test_channel_plugins.py
#	tests/test_commands.py
2026-03-24 09:24:56 +08: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
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
Xubin Ren
20494a2c52 refactor command routing for future plugins and clearer CLI structure 2026-03-23 16:48:42 +08:00
kohath
4145f3eacc feat(feishu): add thread reply support for topic group messages 2026-03-23 15:52:14 +08:00
flobo3
b14d5a0a1d feat(whatsapp): add group_policy to control bot response behavior in groups 2026-03-23 15:48:51 +08:00
chengyongru
e4137736f6 fix(qq): handle file:// URI on Windows in _read_media_bytes
urlparse on Windows puts the path in netloc, not path. Use
(parsed.path or parsed.netloc) to get the correct raw path.
2026-03-23 15:48:31 +08:00
Chen Junda
2db2cc18f1 fix(qq): fix local file outbound and add svg as image type (#2294)
- Fix _read_media_bytes treating local paths as URLs: local file
  handling code was dead code placed after an early return inside the
  HTTP try/except block. Restructure to check for local paths (plain
  path or file:// URI) before URL validation, so files like
  /home/.../.nanobot/workspace/generated_image.svg can be read and
  sent correctly.
- Add .svg to _IMAGE_EXTS so SVG files are uploaded as file_type=1
  (image) instead of file_type=4 (file).
- Add tests for local path, file:// URI, and missing file cases.

Fixes: https://github.com/HKUDS/nanobot/pull/1667#issuecomment-4096400955

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 15:48:21 +08:00
Chen Junda
d7373db419 feat(qq): bot can send and receive images and files (#1667)
Implement file upload and sending for QQ C2C messages

Reference: https://github.com/tencent-connect/botpy/blob/master/examples/demo_c2c_reply_file.py

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: chengyongru <chengyongru.ai@gmail.com>
2026-03-23 15:47:59 +08:00
Flo
80ee2729ac feat(telegram): add silent_tool_hints config to disable notifications for tool hints (#2252) 2026-03-23 15:46:08 +08:00
flobo3
9a2b1a3f1a feat(telegram): add react_emoji config for incoming messages 2026-03-23 15:37:11 +08:00
Hua
949c106250 fix(litellm): initialize langsmith flag 2026-03-23 15:08:07 +08:00
Hua
dd48c6fefb Merge remote-tracking branch 'origin/main'
Some checks failed
Test Suite / test (3.11) (push) Failing after 1m14s
Test Suite / test (3.12) (push) Failing after 1m7s
Test Suite / test (3.13) (push) Failing after 1m26s
2026-03-23 12:56:03 +08:00
Xubin Ren
aba0b83a77 fix(memory): reserve completion headroom for consolidation
Trigger token consolidation before prompt usage reaches the full context window so response tokens and tokenizer estimation drift still fit safely within the model budget.

Made-with: Cursor
2026-03-23 11:54:44 +08:00
Xubin Ren
8f5c2d1a06 fix(cli): stop spinner after non-streaming interactive replies 2026-03-23 03:28:10 +00:00
Hua
333a55454e merge: sync origin/main into local main
Some checks failed
Test Suite / test (3.11) (push) Failing after 1m10s
Test Suite / test (3.12) (push) Failing after 1m14s
Test Suite / test (3.13) (push) Failing after 1m50s
2026-03-23 11:23:59 +08:00
Hua
d838a12b56 feat(voice): add persona-driven tts and qq local media upload 2026-03-23 11:10:27 +08:00
chengyongru
a46803cbd7 docs(provider): add mistral intro 2026-03-23 11:07:46 +08:00
Desmond Sow
f64ae3b900 feat(provider): add OpenVINO Model Server provider (#2193)
add OpenVINO Model Server provider
2026-03-23 11:07:46 +08:00
Matt von Rohr
7878340031 feat(providers): add Mistral AI provider
Register Mistral as a first-class provider with LiteLLM routing,
MISTRAL_API_KEY env var, and https://api.mistral.ai/v1 default base.

Includes schema field, registry entry, and tests.
2026-03-23 11:07:46 +08:00
Xubin Ren
9d5e511a6e feat(streaming): centralize think-tag filtering and add Telegram streaming
- Add strip_think() to helpers.py as single source of truth
- Filter deltas in agent loop before dispatching to consumers
- Implement send_delta in TelegramChannel with progressive edit_message_text
- Remove duplicate think filtering from CLI stream.py and telegram.py
- Remove legacy fake streaming (send_message_draft) from Telegram
- Default Telegram streaming to true
- Update CHANNEL_PLUGIN_GUIDE.md with streaming documentation

Made-with: Cursor
2026-03-23 10:20:41 +08:00
Xubin Ren
f2e1cb3662 feat(cli): extract streaming renderer to stream.py with Rich Live
Move ThinkingSpinner and StreamRenderer into a dedicated module to keep
commands.py focused on orchestration. Uses Rich Live with manual refresh
(auto_refresh=False) and ellipsis overflow for stable streaming output.

Made-with: Cursor
2026-03-23 10:20:41 +08:00