feat: upstream forksync v3#10
Merged
Merged
Conversation
…n for consistency
- Add --dir parameter to specify custom base directory for config and workspace - Enables Multiple Instances initialization with isolated configurations - Config and workspace are created under the specified directory - Maintains backward compatibility with default ~/.nanobot/ - Updates help text and next steps with actual paths - Updates README.md with --dir usage examples for Multiple Instances Example usage: nanobot onboard --dir ~/.nanobot-A nanobot onboard --dir ~/.nanobot-B nanobot onboard # uses default ~/.nanobot/
- 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
Use file_unique_id when storing downloaded Telegram media so different uploads do not silently overwrite each other on disk.
Add multi-provider web search support: Brave (default), Tavily, DuckDuckGo, and SearXNG. Falls back to DuckDuckGo when provider credentials are missing. Providers are dispatched via a map with register_provider() for plugin extensibility. - WebSearchConfig with env-var resolution and from_legacy() bridge - Config migration for legacy flat keys (tavilyApiKey, searxngBaseUrl) - SearXNG URL validation, explicit error for unknown providers - ddgs package (replaces deprecated duckduckgo-search) - 16 tests covering all providers, fallback, env resolution, edge cases - docs/web-search.md with full config reference Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add `enable` flag to `ExecToolConfig` to conditionally register the tool. - Add `deny_patterns` to allow users to override the default command blacklist. - Remove `allow_patterns` (whitelist) to maintain tool flexibility. - Fix initialization logic to properly handle empty list (`[]`), allowing users to completely clear the default blacklist.
fix: wecom-aibot-sdk-python should use pypi version
…force save_memory in consolidation fix: raise tool result history limit to 16k and force save_memory in consolidation
Made-with: Cursor # Conflicts: # nanobot/agent/loop.py
… injection, attach reply media regardless of caption
Adjust the spawn tool description to keep the workspace-organizing hint while avoiding language that sounds like the system automatically assigns a dedicated working directory for subagents. Made-with: Cursor
- Add model_info.py module with litellm-based model lookup - Provide autocomplete suggestions for model names - Auto-fill context_window_tokens when model changes (only at default) - Add "Get recommended value" option for manual context lookup - Dynamically load provider keywords from registry (no hardcoding) Resolves HKUDS#2018
- Move onboard-related tests from test_commands.py and test_config_migration.py to new test_onboard_logic.py for better organization - Add comprehensive unit tests for: - _merge_missing_defaults recursive config merging - _get_field_type_info type extraction - _get_field_display_name human-readable name generation - _format_value display formatting - sync_workspace_templates file synchronization - Remove unused dev dependencies (matrix-nio, mistune, nh3) from pyproject.toml
- Add `_SELECT_FIELD_HINTS` for select fields with predefined choices (e.g., reasoning_effort: low/medium/high with hint text) - Add `_select_with_back()` using prompt_toolkit for custom key bindings - Support Escape and Left arrow keys to go back in menus - Apply to field config, provider selection, and channel selection menus
Tests for non-interactive onboard mode now explicitly use --no-interactive flag since the default changed to interactive mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
--workspace and --config now work as initial defaults in interactive mode: - The wizard starts with these values pre-filled - Users can view and modify them in the wizard - Final saved config reflects user's choices This makes the CLI args more useful for interactive sessions while still allowing full customization through the wizard.
Cherry-pick from d6acf1a with manual merge resolution. Keep onboarding edits in draft state until users choose Done or Save and Exit, so backing out or discarding the wizard no longer persists partial changes. Co-Authored-By: Jason Zhao <144443939+JasonZhaoWW@users.noreply.github.com>
…e repetition - Mask sensitive fields (api_key/token/secret/password) in all display surfaces, showing only the last 4 characters - Replace all emoji with pure ASCII labels for consistent cross-platform terminal rendering - Extract _print_summary_panel helper, eliminating 5x duplicate table construction in _show_summary - Replace 3 one-line wrapper functions with declarative _SETTINGS_SECTIONS dispatch tables and _MENU_DISPATCH in run_onboard - Extract _handle_model_field / _handle_context_window_field into a _FIELD_HANDLERS registry, shrinking _configure_pydantic_model - Return FieldTypeInfo NamedTuple from _get_field_type_info for clarity - Replace global mutable _PROVIDER_INFO / _CHANNEL_INFO with @lru_cache - Use vars() instead of dir() in _get_channel_info for reliable config class discovery - Defer litellm import in model_info.py so non-wizard CLI paths stay fast - Clarify README Quick Start wording (Add -> Configure)
When an OpenAI-compatible API returns a non-JSON response (e.g. plain text "unsupported model: xxx" with HTTP 200), the OpenAI SDK raises a JSONDecodeError whose message is the unhelpful "Expecting value: line 1 column 1 (char 0)". Extract the original response body from JSONDecodeError.doc (or APIError.response.text) so users see the actual error message from the API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Catch asyncio.CancelledError separately from generic exceptions - Re-raise CancelledError only when loop is shutting down (_running is False) - Continue processing messages if CancelledError occurs during normal operation - Prevents anyio/MCP cancel scopes from prematurely terminating the agent loop
Made-with: Cursor
- wire tools.exec.enable and deny_patterns into the current AgentLoop - preserve the current WebSearchTool config-based registration path - treat deny_patterns=[] as an explicit override instead of falling back to the default blacklist - add regression coverage for disabled exec registration and custom deny patterns Made-with: Cursor
Made-with: Cursor
Made-with: Cursor
feat(tools): enhance ExecTool with enable flag
Record run_at_ms, status, duration_ms and error for each execution, keeping the last 20 entries per job in jobs.json. Adds CronRunRecord dataclass, get_job() lookup, and four regression tests covering success, error, trimming and persistence. Closes HKUDS#1837 Made-with: Cursor
- Add openssh-client to apt dependencies for git operations - Configure git to use HTTPS instead of SSH for github.com to avoid SSH key requirements during Docker build Made-with: Cursor
Keep messages already collected in the current poll cycle when a stale IMAP connection dies mid-fetch, so retrying once does not drop emails that were already parsed and marked seen. Add a regression test covering a mid-cycle disconnect after the first message succeeds. Made-with: Cursor
Merged upstream/main into feature-forksync-v3. Protected file changes: - loop.py: upstream exec enable flag, WebSearchTool config param, current_role for system messages, archive_messages for /new. Keep: SysmonTool, NvidiaEscalateTool, @mention stripping, all custom !commands. - litellm_provider.py: add langsmith, tool_choice param, litellm_kwargs. Keep: suppressToolsParam, _extract_text_tool_calls, EOS token stripping. - context.py: keep build_messages_full + _TOOL_ARG_MAX_CHARS (Qwen compat). Add current_time_str import alongside logger. - web.py: adopt upstream multi-provider WebSearchTool (duckduckgo/tavily/ searxng/jina/brave). Keep max_chars=12000 for WebFetchTool. Add SSRF protection, _validate_url_safe. Retain searxng_url fallback in _search_searxng for backward config compat. - schema.py: channel configs moved to channel files (keep HttpConfig for http.py). AgentDefaults removes deprecated memory fields. allow_tools -> enabled_tools in MCPServerConfig. - mcp.py: keep MCPServerConnection + auto-reconnect (McpError 32600). Adopt upstream enabled_tools filtering (replaces allow_tools). - commands.py: onboard gets --workspace/--wizard. AgentLoop construction uses web_search_config. Remove deprecated memory/brave_api_key params. - context.py, memory.py, base.py, channels/base.py: non-conflicting upsteam improvements (tool_choice fallback, archive_messages, default_config). - discord.py: add allow_bots to local DiscordConfig (stash from pre-merge). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Server is EDT — explicit tz prevents drift if system timezone changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tests pass session directly; production uses MCPServerConnection.session. getattr fallback handles both without breaking reconnect logic. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
upstream/maininto fork — ~130 upstream commits since last sync (2026-03-12)Key decisions
SysmonTool,NvidiaEscalateTool,@mentionstripping, all!commands. Adopted upstreamexec_config.enableflag,web_search_configparam,current_rolefor system messages,archive_messagesfor/new.tool_choice+litellm_kwargsadditions merged cleanly alongside oursuppressToolsParam,_extract_text_tool_calls, EOS token stripping.build_messages_full(async, memory compaction) +_TOOL_ARG_MAX_CHARStruncation (Qwen Jinja compat). Addedcurrent_time_strimport from upstream.WebSearchTool. Keptmax_chars=12000forWebFetchTool. Addedsearxng_urlfallback in_search_searxngfor backward config compat.HttpConfigforhttp.py).allow_tools→enabled_toolsinMCPServerConfig.MCPServerConnection+ auto-reconnect (McpError 32600). Adopted upstreamenabled_toolsfiltering.allow_botsfield added to localDiscordConfig.Breaking change
allowToolsinmcpServersconfig renamed toenabledTools(default:["*"]= all tools). None of our current bot configs use this field so no action needed.Test plan
!ping,!status,/new,/helpcommandssearxngUrlconfig still works)nanobot onboard --helpto verify new--workspace/--wizardflags🤖 Generated with Claude Code