Commit Graph

1287 Commits

Author SHA1 Message Date
chengyongru
5a220959af docs: add branching strategy and CONTRIBUTING guide
- Add CONTRIBUTING.md with detailed contribution guidelines
- Add branching strategy section to README.md explaining main/nightly branches
- Include maintainer information and development setup instructions
2026-03-16 11:13:46 +08:00
Xubin Ren
5d1528a5f3 fix(heartbeat): inject shared current time context into phase 1 2026-03-16 10:52:26 +08:00
who96
0dda2b23e6 fix(heartbeat): inject current datetime into Phase 1 prompt
Phase 1 _decide() now includes "Current date/time: YYYY-MM-DD HH:MM UTC"
in the user prompt and instructs the LLM to use it for time-aware scheduling.
Without this, the LLM defaults to 'run' for any task description regardless
of whether it is actually due, defeating Phase 1's pre-screening purpose.

Closes #1929
2026-03-16 10:52:26 +08:00
Meng Yuhang
f9ba6197de fix: save DingTalk downloaded files to media dir instead of /tmp 2026-03-15 23:21:22 +08:00
Meng Yuhang
34358eabc9 feat: support file/image/richText message receiving for DingTalk 2026-03-15 23:21:22 +08:00
Xubin Ren
d684fec27a Replace load_skill tool with read_file extra_allowed_dirs for builtin skills access
Instead of adding a separate load_skill tool to bypass workspace restrictions,
extend ReadFileTool with extra_allowed_dirs so it can read builtin skill paths
while keeping write/edit tools locked to the workspace. Fixes the original issue
for both main agent and subagents.

Made-with: Cursor
2026-03-15 23:21:02 +08:00
Ben
45832ea499 Add load_skill tool to bypass workspace restriction for builtin skills
When restrictToWorkspace is enabled, the agent cannot read builtin skill
files via read_file since they live outside the workspace. This adds a
dedicated load_skill tool that reads skills by name through the SkillsLoader,
which accesses files directly via Python without the workspace restriction.

- Add LoadSkillTool to filesystem tools
- Register it in the agent loop
- Update system prompt to instruct agent to use load_skill instead of read_file
- Remove raw filesystem paths from skills summary
2026-03-15 23:21:02 +08:00
Xubin Ren
c4628038c6 fix: handle image_url rejection by retrying without images
Replace the static provider-level supports_vision check with a
reactive fallback: when a model returns an image-unsupported error,
strip image_url blocks from messages and retry once. This avoids
maintaining an inaccurate vision capability table and correctly
handles gateway/unknown model scenarios.

Also extract _safe_chat() to deduplicate try/except boilerplate
in chat_with_retry().
2026-03-15 22:32:34 +08:00
coldxiangyu
de0b5b3d91 fix: filter image_url for non-vision models at provider layer
- Add  field to ProviderSpec (default True)
- Add  and  methods in LiteLLMProvider
- Filter image_url content blocks in  before sending to non-vision models
- Reverts session-layer filtering from original PR (wrong layer)

This fixes the issue where switching from Claude (vision-capable) to
non-vision models (e.g., Baidu Qianfan) causes API errors due to
unsupported image_url content blocks.

The provider layer is the correct place for this filtering because:
1. It has access to model/provider capabilities
2. It only affects non-vision models
3. It preserves session layer purity (storage should not know about model capabilities)
2026-03-15 22:32:34 +08:00
Xubin Ren
196e0ddbb6 fix(openrouter): revert custom_llm_provider, always apply gateway prefix 2026-03-15 10:52:36 +08:00
Xubin Ren
350d110fb9 fix(openrouter): remove litellm_prefix to prevent double-prefixed model names
With custom_llm_provider kwarg handling routing, the openrouter/ prefix
caused model names like anthropic/claude-sonnet-4-6 to become
openrouter/anthropic/claude-sonnet-4-6, which OpenRouter API rejects.
2026-03-15 10:52:36 +08:00
Xubin Ren
5ccf350db1 test(litellm_kwargs): add regression tests for PR #2026 OpenRouter kwargs injection 2026-03-15 10:52:36 +08:00
Paresh Mathur
445e0aa2c4 refactor(openrouter): move litellm kwargs into registry 2026-03-15 10:52:36 +08:00
Paresh Mathur
03b55791b4 fix(openrouter): preserve native model prefix 2026-03-15 10:52:36 +08:00
Xubin Ren
f6cefcc123 Merge PR #1966: feat(feishu): display tool calls in code block messages + fix empty 2026-03-14 15:48:10 +00: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
f1a82c0165 Merge PR #1963: feat(feishu): implement message reply/quote support
feat(feishu): implement message reply/quote support
2026-03-14 23:10:45 +08:00
Xubin Ren
a4f6b7d978 merge: resolve PR #1963 conflicts with main 2026-03-14 14:00:00 +00:00
Xubin Ren
37b994202d Merge PR #1796: fix(telegram): avoid media filename collisions
fix(telegram): avoid media filename collisions
2026-03-14 21:29:07 +08:00
Xubin Ren
86cfbce077 Merge remote-tracking branch 'origin/main' into pr-1796 2026-03-14 13:11:56 +00:00
Xubin Ren
61f0923c66 fix(telegram): include restart in help text 2026-03-14 10:45:37 +00:00
chengyongru
a2acacd8f2 fix: add exception handling to prevent agent loop crash 2026-03-14 18:34:22 +08:00
Xubin Ren
a1241ee68c fix(mcp): clarify enabledTools filtering semantics
- support both raw and wrapped MCP tool names
- treat [\"*\"] as all tools and [] as no tools
- add warnings, tests, and README docs for enabledTools
2026-03-14 18:33:48 +08:00
lihua
40fad91ec2 注册mcp时,支持指定tool 2026-03-14 18:33:48 +08:00
lihua
4dde195a28 init 2026-03-14 18:33:48 +08:00
Xubin Ren
411b059dd2 refactor: replace <SILENT_OK> with structured post-run evaluation
- Add nanobot/utils/evaluator.py: lightweight LLM tool-call to decide notify/silent after background task execution
- Remove magic token injection from heartbeat and cron prompts
- Clean session history (no more <SILENT_OK> pollution)
- Add tests for evaluator and updated heartbeat three-phase flow
2026-03-14 17:41:08 +08:00
SJK-py
e6c1f520ac suppress unnecessary heartbeat notifications
Appends a strict instruction to background task prompts (cron and heartbeat) 
directing the agent to return a `<SILENT_OK>` token if there is nothing 
material to report. Adds conditional logic to intercept this token and 
suppress the outbound message to the user, preventing notification spam 
from autonomous background checks.
2026-03-14 17:41:08 +08:00
SJK-py
4990c7478b suppress unnecessary cron notifications
Appends a strict instruction to background task prompts (cron and heartbeat) 
directing the agent to return a `<SILENT_OK>` token if there is nothing 
material to report. Adds conditional logic to intercept this token and 
suppress the outbound message to the user, preventing notification spam 
from autonomous background checks.
2026-03-14 17:41:08 +08:00
Peixian Gong
58fc34d3f4 refactor: use shutil.which() instead of shell=True for npm calls
Replace platform-specific shell=True logic with shutil.which('npm') to
resolve the full path to the npm executable. This is cleaner because:

- No shell=True needed (safer, no shell injection risk)
- No platform-specific branching (sys.platform checks removed)
- Works identically on Windows, macOS, and Linux
- shutil.which() resolves npm.cmd on Windows automatically

The npm path check that already existed in _get_bridge_dir() is now
reused as the resolved path for subprocess calls. The same pattern is
applied to channels_login().
2026-03-14 17:19:01 +08:00
Peixian Gong
805228e91e fix: add shell=True for npm subprocess calls on Windows
On Windows, npm is installed as npm.cmd (a batch script), not a direct
executable. When subprocess.run() is called with a list like
['npm', 'install'] without shell=True, Python's CreateProcess cannot
locate npm.cmd, resulting in:

  FileNotFoundError: [WinError 2] The system cannot find the file specified

This fix adds a sys.platform == 'win32' check before each npm subprocess
call. On Windows, it uses shell=True with a string command so the shell
can resolve npm.cmd. On other platforms, the original list-based call is
preserved unchanged.

Affected locations:
- _get_bridge_dir(): npm install, npm run build
- channels_login(): npm start

No behavioral change on Linux/macOS.
2026-03-14 17:19:01 +08:00
Protocol Zero
c9cc160600 merge: resolve PR #1796 conflicts with main
Merge the latest main branch into the Telegram media filename fix and keep the file_unique_id-based download path on top of the refactored media handling and newer Telegram tests.

Made-with: Cursor
2026-03-14 08:33:56 +00:00
Xubin Ren
af65145bc8 fix(qq): add configurable message format and onboard backfill 2026-03-14 08:25:44 +00:00
chengyongru
91d95f139e fix: cross-platform test compatibility
- test_channel_plugins: fix assertion logic for discoverable channels
- test_filesystem_tools: normalize path separators for Windows
- test_tool_validation: use python to generate output, avoid cmd line limits
2026-03-14 16:13:38 +08:00
Xubin 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
Xubin Ren
58389766a7 Merge PR #1981: chore: bump wecom-aibot-sdk-python to >=0.1.5
chore: bump wecom-aibot-sdk-python to >=0.1.5
2026-03-13 23:42:43 +08:00
chengyongru
1e163d615d chore: bump wecom-aibot-sdk-python to >=0.1.5
- Includes bug fixes for duplicate recv loops
- Handles disconnected_event properly
- Fixes heartbeat timeout
2026-03-13 18:45:41 +08:00
nne998
a8fbea6a95 cleanup 2026-03-13 16:53:57 +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
2787523f49 fix: prevent empty </think> tags from appearing in messages
- Enhance _strip_think to handle stray tags:
  * Remove unmatched closing tags (</think>)
  * Remove incomplete blocks (<think> ... to end of string)
- Apply _strip_think to tool hint messages as well
- Prevents blank/parse errors from showing </think> in chat outputs

Fixes issue with empty </think> appearing in Feishu tool call cards and other messages.
2026-03-13 14:55:34 +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
Tony
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
Xubin Ren
65cbd7eb78 docs: update web search configuration instruction 2026-03-13 05:54:51 +00:00
Xubin Ren
3040102c02 Merge PR #398: multi-provider web search 2026-03-13 05:44:16 +00:00
Xubin Ren
ca5047b602 feat(web): multi-provider web search + Jina Reader fetch 2026-03-13 05:44:16 +00:00
Xubin Ren
511a335e82 Merge branch 'main' into pr-398 2026-03-13 05:12:10 +00:00
Xubin Ren
04b45e0e5c Merge PR #1920: langsmith integration 2026-03-13 04:54:22 +00:00
Xubin Ren
20b4fb3bff fix: langsmith callback 防覆盖 + 加 optional dep 2026-03-13 04:54:22 +00:00