Skip to content

feat: upstream forksync v3#10

Merged
kmbandy merged 203 commits into
mainfrom
feature-forksync-v3
Mar 20, 2026
Merged

feat: upstream forksync v3#10
kmbandy merged 203 commits into
mainfrom
feature-forksync-v3

Conversation

@kmbandy
Copy link
Copy Markdown
Owner

@kmbandy kmbandy commented Mar 20, 2026

Summary

  • Merged upstream/main into fork — ~130 upstream commits since last sync (2026-03-12)
  • All 11 protected files touched; all custom patches preserved
  • Full multi-provider web search (duckduckgo/tavily/searxng/jina/brave) from upstream
  • Upstream SSRF protection, LangSmith integration, MCP enabledTools filtering, onboard wizard

Key decisions

  • loop.py: Kept SysmonTool, NvidiaEscalateTool, @mention stripping, all !commands. Adopted upstream exec_config.enable flag, web_search_config param, current_role for system messages, archive_messages for /new.
  • litellm_provider.py: Upstream LangSmith + tool_choice + litellm_kwargs additions merged cleanly alongside our suppressToolsParam, _extract_text_tool_calls, EOS token stripping.
  • context.py: Kept our build_messages_full (async, memory compaction) + _TOOL_ARG_MAX_CHARS truncation (Qwen Jinja compat). Added current_time_str import from upstream.
  • web.py: Adopted upstream multi-provider WebSearchTool. Kept max_chars=12000 for WebFetchTool. Added searxng_url fallback in _search_searxng for backward config compat.
  • schema.py: Channel configs moved to channel files (kept HttpConfig for http.py). allow_toolsenabled_tools in MCPServerConfig.
  • mcp.py: Kept MCPServerConnection + auto-reconnect (McpError 32600). Adopted upstream enabled_tools filtering.
  • discord.py: allow_bots field added to local DiscordConfig.

Breaking change

  • allowTools in mcpServers config renamed to enabledTools (default: ["*"] = all tools). None of our current bot configs use this field so no action needed.

Test plan

  • Start eng-1 and verify Discord connection
  • Test !ping, !status, /new, /help commands
  • Verify MCP memory tools connect (mad-lab-memory)
  • Test web search via SearXNG (verify searxngUrl config still works)
  • Run nanobot onboard --help to verify new --workspace/--wizard flags

🤖 Generated with Claude Code

danielyangfei and others added 30 commits February 25, 2026 01:40
- 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
Re-bin and others added 28 commits March 20, 2026 13:30
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
- 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
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>
@kmbandy kmbandy merged commit 4492b59 into main Mar 20, 2026
1 check failed
@kmbandy kmbandy deleted the feature-forksync-v3 branch March 20, 2026 22:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.