Commit Graph
72 Commits
Author SHA1 Message Date
wudongxueandXubin Ren 0291d1f716 feat: resolve mentions data 2026-04-07 14:03:55 +08:00
Jiajun XieandXubin Ren 5ee96721f7 ci: add ruff lint check for unused imports and variables
Add CI step to detect unused imports (F401) and unused variables (F841)
with ruff. Clean up existing violations:

- Remove unused Consolidator import in agent/__init__.py
- Remove unused re import in agent/loop.py
- Remove unused Path import in channels/feishu.py
- Remove unused ContentRepositoryConfigError import in channels/matrix.py
- Remove unused field and CommandHandler imports in channels/telegram.py
- Remove unused exception variable in channels/weixin.py
2026-04-07 13:30:49 +08:00
Xubin Ren b719da7400 fix(feishu): use RawRequest for bot info API 2026-04-06 11:39:23 +00:00
Xubin RenandXubin Ren c88d97c652 fix: fall back to heuristic when bot open_id fetch fails
If _fetch_bot_open_id returns None the exact-match path would silently
disable all @mention detection. Restore the old heuristic as a fallback.
Add 6 unit tests for _is_bot_mentioned covering both paths.

Made-with: Cursor
2026-04-06 13:49:38 +08:00
有泉andXubin Ren 1b368a33dc fix(feishu): match bot's own open_id in _is_bot_mentioned to prevent cross-bot false positives
Previously, _is_bot_mentioned used a heuristic (no user_id + open_id
prefix "ou_") which caused other bots in the same group to falsely
think they were mentioned. Now fetches the bot's own open_id via
GET /open-apis/bot/v3/info at startup and does an exact match.
2026-04-06 13:49:38 +08:00
chengyongruandXubin Ren 2cecaf0d5d fix(feishu): support video (media) download by converting type to 'file'
Feishu's GetMessageResource API only accepts 'image' or 'file' as the
type parameter. Video messages have msg_type='media', which was passed
through unchanged, causing error 234001 (Invalid request param). Now
both 'audio' and 'media' are converted to 'file' for download.
2026-04-05 16:53:05 +08:00
Jiajun XieandXubin Ren bb70b6158c feat: auto-remove reaction after message processing complete
- _add_reaction now returns reaction_id on success
- Add _remove_reaction_sync and _remove_reaction methods
- Remove reaction when stream ends to clear processing indicator
- Store reaction_id in metadata for later removal
2026-04-05 16:53:05 +08:00
Xubin RenandXubin Ren e464a81545 fix(feishu): only stream visible cards 2026-03-27 21:59:11 +08:00
LeftXandXubin Ren 0ba71298e6 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-27 21:59:11 +08:00
Xubin RenandXubin Ren f0f0bf02d7 refactor(channel): centralize retry around explicit send failures
Make channel delivery failures raise consistently so retry policy lives in ChannelManager rather than being split across individual channels. Tighten Telegram stream finalization, clarify sendMaxRetries semantics, and align the docs with the behavior the system actually guarantees.
2026-03-25 22:37:11 +08:00
kohathandchengyongru 4145f3eacc feat(feishu): add thread reply support for topic group messages 2026-03-23 15:52:14 +08:00
mamamiyearandXubin Ren d9cb729596 feat: support feishu code block 2026-03-19 13:59:31 +08:00
weipeng0098andXubin Ren 47e2a1e8d7 fix(feishu): use correct msg_type for audio/video files 2026-03-17 17:05:13 +08:00
Xubin RenandXubin Ren 41d59c3b89 test(feishu): cover heading and table markdown rendering 2026-03-17 16:51:02 +08:00
Your NameandXubin Ren 9afbf386c4 fix(feishu): fix markdown rendering issues in headings and tables
- Fix double bold markers (****) when heading text already contains **
- Strip markdown formatting (**bold**, *italic*, ~~strike~~) from table cells
  since Feishu table elements do not support markdown rendering

Fixes rendering issues where:
1. Headings like '**text**' were rendered as '****text****'
2. Table cells with '**bold**' showed raw markdown instead of plain text
2026-03-17 16:51:02 +08:00
Xubin Ren 19ae7a167e fix(feishu): avoid breaking tool hint formatting and think stripping 2026-03-14 15:40:53 +00:00
Xubin Ren 44af7eca3f merge: resolve PR #1966 conflicts with main 2026-03-14 15:32:19 +00:00
Xubin Ren a4f6b7d978 merge: resolve PR #1963 conflicts with main 2026-03-14 14:00:00 +00:00
Xubin RenandXubin Ren dbdb43faff feat: channel plugin architecture with decoupled configs
- Add plugin discovery via Python entry_points (group: nanobot.channels)
- Move 11 channel Config classes from schema.py into their own channel modules
- ChannelsConfig now only keeps send_progress + send_tool_hints (extra=allow)
- Each built-in channel parses dict->Pydantic in __init__, zero internal changes
- All channels implement default_config() for onboard auto-population
- nanobot onboard injects defaults for all discovered channels (built-in + plugins)
- Add nanobot plugins list CLI command
- Add Channel Plugin Guide (docs/CHANNEL_PLUGIN_GUIDE.md)
- Fully backward compatible: existing config.json and sessions work as-is
- 340 tests pass, zero regressions
2026-03-14 16:13:38 +08:00
mru4913 670d2a6ff8 feat(feishu): implement message reply/quote support
- Add `reply_to_message: bool = False` config to `FeishuConfig`
- Parse `parent_id` and `root_id` from incoming events into metadata
- Fetch quoted message content via `im.v1.message.get` and prepend
  `[Reply to: ...]` context for the LLM when a user quotes a message
- Add `_reply_message_sync` using `im.v1.message.reply` API so the
  bot's response appears as a threaded quote in Feishu
- First outbound message uses reply API; subsequent chunks fall back
  to `create` to avoid duplicate quote bubbles; progress messages
  always use `create`
- Add 19 unit tests covering all new code paths
2026-03-13 15:02:57 +08:00
Tony 87ab980bd1 refactor(feishu): extract tool hint card sending into dedicated method
- Extract card creation logic into _send_tool_hint_card() helper
- Improves code organization and testability
- Update tests to use pytest.mark.asyncio for cleaner async testing
- Remove redundant asyncio.run() calls in favor of native async test functions
2026-03-13 14:52:15 +08:00
Tony 82064efe51 feat(feishu): improve tool call card formatting for multiple tools
- Format multiple tool calls each on their own line
- Change title from 'Tool Call' to 'Tool Calls' (plural)
- Add explicit 'text' language for code block
- Improves readability and supports displaying longer content
- Update tests to match new formatting
2026-03-13 14:48:36 +08:00
Tony 7261bd8c3f feat(feishu): display tool calls in code block messages
- Tool hint messages with _tool_hint metadata now render as formatted code blocks
- Uses Feishu interactive card message type with markdown code fences
- Shows "Tool Call" header followed by code in a monospace block
- Adds comprehensive unit tests for the new functionality

Co-Authorship-Bot: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:43:47 +08:00
TonyandClaude Opus 4.6 df89bd2dfa feat(feishu): display tool calls in code block messages
- Add special handling for tool hint messages (_tool_hint metadata)
- Send tool calls using Feishu's "code" message type with formatting
- Tool calls now appear as formatted code snippets in Feishu chat
- Add unit tests for the new functionality

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:41:54 +08:00
Re-bin 6141b95037 fix: feishu bot mention detection — user_id can be None, not just empty string 2026-03-12 06:00:39 +00:00
Re-bin bd1ce8f144 Simplify feishu group_policy: default to mention, clean up mention detection 2026-03-12 04:45:57 +00:00
Re-bin 94e9b06086 Merge branch 'main' into pr-1768 2026-03-12 04:38:49 +00:00
Re-bin 254cfd48ba refactor: auto-discover channels via pkgutil, eliminate hardcoded registry 2026-03-11 14:23:19 +00:00
Zek 711903bc5f feat(feishu): add global group mention policy
- Add group_policy config: 'open' (default) or 'mention'
- 'open': Respond to all group messages (backward compatible)
- 'mention': Only respond when @mentioned in any group
- Auto-detect bot mentions by pattern matching:
  * If open_id configured: match against mentions
  * Otherwise: detect bot by empty user_id + ou_ open_id pattern
- Support @_all mentions
- Private chats unaffected (always respond)
- Clean implementation with minimal logging

docs: update Feishu README with group policy documentation
2026-03-09 17:54:02 +08:00
chengyongru 4044b85d4b fix: ensure feishu audio file has .opus extension for Groq Whisper compatibility 2026-03-09 01:32:10 +08:00
Re-bin 20dfaa5d34 refactor: unify instance path resolution and preserve workspace override 2026-03-08 02:58:25 +00:00
Re-bin 4021f5212c Merge main into pr-332 2026-03-07 15:02:06 +00:00
chengyongru 215360113f feat(feishu): add audio transcription support using Groq Whisper 2026-03-07 16:21:52 +08:00
Re-bin 645e30557b Merge remote-tracking branch 'origin/main' into pr-1605 2026-03-06 06:00:32 +00:00
PiKaqqqqqq c3526a7fdb fix(feishu): smart message format selection (fixes #1548)
Instead of always sending interactive cards, detect the optimal
message format based on content:
- text: short plain text (≤200 chars, no markdown)
- post: medium text with links (≤2000 chars)
- interactive: complex content (code, tables, headings, bold, lists)
2026-03-06 10:11:53 +08:00
pikaqqqqqq 5ced08b1f2 fix(feishu): use msg_type "media" for mp4 video files
Previously, mp4 video files were sent with msg_type "file", which meant
users had to download them to play. Feishu requires msg_type "media" for
audio and video files to enable inline playback in the chat.

Changes:
- Add _VIDEO_EXTS constant for video file extensions (.mp4, .mov, .avi)
- Use msg_type "media" for both audio (_AUDIO_EXTS) and video (_VIDEO_EXTS)
- Keep msg_type "file" for documents and other file types

The upload_file API already uses file_type="mp4" for video files via the
existing _FILE_TYPE_MAP, so only the send msg_type needed fixing.
2026-03-06 01:54:00 +08:00
Re-bin 573fc7cd95 Merge remote-tracking branch 'origin/main' into pr-1384 2026-03-05 15:19:50 +00:00
coldxiangyuandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> 97522bfa03 fix(feishu): isolate lark ws Client event loop from main asyncio loop
Commit 0209ad5 moved `import lark_oapi as lark` inside the start()
method (lazy import) to suppress DeprecationWarnings. This had an
unintended side effect: the import now happens after the main asyncio
loop is already running, so lark_oapi's module-level

    loop = asyncio.get_event_loop()

captures the running main loop. When the WebSocket thread then calls
loop.run_until_complete() inside Client.start(), Python raises:

    RuntimeError: This event loop is already running

and the _connect/_disconnect coroutines are never awaited.

Fix: in run_ws(), create a fresh event loop with asyncio.new_event_loop(),
set it as the thread's current loop, and patch lark_oapi.ws.client.loop
to point to this dedicated loop before calling Client.start(). The loop
is closed on thread exit.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-03-05 17:27:17 +08:00
Sergio Sánchez Vallés e032faaeff Merge branch 'main' of upstream/main into fix/test-failures 2026-03-04 20:04:00 +01:00
Sergio Sánchez Vallés 0209ad57d9 fix(tests): resolve RequestsDependencyWarning and lark-oapi asyncio/websockets DeprecationWarnings 2026-03-04 19:31:39 +01:00
zerone0x 8571df2e63 fix(feishu): split card messages when content has multiple tables
Feishu rejects interactive cards that contain more than one table element
(API error 11310: card table number over limit).

Add FeishuChannel._split_elements_by_table_limit() which partitions the flat
card-elements list into groups of at most one table each.  The send() method
now iterates over these groups and sends each as its own card message, so all
tables are delivered to the user instead of the entire message being dropped.

Single-table and table-free messages are unaffected (one card, same as before).

Fixes #1382
2026-03-01 15:13:44 +01:00
Re-bin 4752e95a24 merge origin/main into pr-1361 2026-03-01 06:36:29 +00:00
Re-bin c2bbd6d20d Merge branch 'main' into pr-1361 2026-03-01 06:30:10 +00:00
Jack LuandGitHub 3ee061b879 Merge branch 'main' into main 2026-03-01 13:35:24 +08:00
yzchen 2fc16596d0 fix(feishu): parse post wrapper payload for rich text messages 2026-03-01 02:17:10 +08:00
Xubin RenandGitHub 422969d468 Merge PR #1348: fix(lark): Remove non-existent stop() call on Lark ws.Client when enable lark channel
fix(lark): Remove non-existent stop() call on Lark ws.Client when enable lark channel
2026-03-01 01:23:27 +08:00
zhangxiaoyu.york 9e2f69bd5a tidy up 2026-03-01 00:51:17 +08:00
zhangxiaoyu.york 5d829ca575 bugfix: remove client.stop 2026-03-01 00:30:03 +08:00
zhangxiaoyu.york b3af59fc8e bugfix: remove client.stop 2026-03-01 00:20:32 +08:00
JK_Lu 977ca725f2 style: unify code formatting and import order
- Remove trailing whitespace and normalize blank lines
- Unify string quotes and line breaks for long lines
- Sort imports alphabetically across modules
2026-02-28 20:55:43 +08:00