2808 Commits

Author SHA1 Message Date
chengyongru
7510918610 fix(webui): align token usage heatmap 2026-06-08 16:02:12 +08:00
chengyongru
631fdb4a46 test: cover empty reasoning_content history preservation
maintainer edit: add SDK-object and tool-call history regressions so the empty-string reasoning_content fix is covered across both parse branches and the sanitized request path.
2026-06-08 01:08:27 +08:00
michaelxer
05de864f5b fix: preserve empty-string reasoning_content instead of coercing to None
Custom providers (e.g. DeepSeek) may return reasoning_content as an
empty string "" to explicitly indicate no reasoning occurred. The
previous truthiness checks (, ) treated "" as falsy
and converted it to None, which caused the field to be dropped from
the message history entirely. Providers that require reasoning_content
on all assistant messages then rejected subsequent requests.

Replace truthiness checks with identity checks () so that
empty-string reasoning_content is preserved as-is. The streaming path
is unchanged since an empty join genuinely means no chunks received.

Fixes #4105
2026-06-08 01:08:27 +08:00
dvp
4f5f965f09
fix(whatsapp): handle LID group mentions (#2663)
Co-authored-by: Xubin Ren <52506698+Re-bin@users.noreply.github.com>
2026-06-07 18:02:39 +08:00
Xubin Ren
ab9f49970d
feat(desktop): polish desktop shell and shared WebUI surfaces (#4195)
* feat(desktop): add native host scaffold

* feat(webui): track turns and usage in gateway

* feat(webui): polish desktop chat experience

* feat(apps): add ArcGIS and Joplin logos

* feat(desktop): polish shell and shared surfaces

* fix(webui): avoid preview chips for glob references

* test: align CI expectations for token fallback

* feat(webui): preview prompt rail entries

* feat(webui): add prompt navigator drawer

* style(webui): refine prompt navigator placement

* style(webui): align prompt navigator with header actions

* style(webui): simplify prompt navigator header

* refactor(webui): clean thread resource refresh

* feat(desktop): add native reply notifications

* fix(webui): preserve desktop restart and replay state

* fix(desktop): harden gateway proxy startup

* fix(web): fall back when readability is unavailable

* fix(desktop): hide window instead of closing on macos

* fix(webui): unify desktop header actions

* fix(webui): simplify prompt history rows

* fix(desktop): log notification delivery failures

* chore(desktop): clean source package artifacts

* fix(cron): support one-time relative reminders

* fix(webui): reveal scroll button in place

* Revert "fix(cron): support one-time relative reminders"

This reverts commit 4c4661da120a3c7283e0768412bae48604e7390b.

* refactor(webui): extract token usage heatmap

* docs(desktop): clarify contributor guides

---------

Co-authored-by: chengyongru <2755839590@qq.com>
2026-06-06 19:49:33 +08:00
Xubin Ren
a1b9577224 test(image): cover dropping null OpenAI image params 2026-06-06 19:35:46 +08:00
04cb
a4cf0f9514 fix(providers): allow dropping default OpenAI image params via null extraBody (#4167) 2026-06-06 19:35:46 +08:00
Xubin Ren
73353785a0 docs(sdk): document Nanobot teardown 2026-06-06 15:35:28 +08:00
axelray-dev
57fa37dcfe fix(sdk): close MCP connections from Nanobot facade
The SDK opened MCP connections through AgentLoop.process_direct but
never called close_mcp, leaving stdio MCP generators to be finalized
during asyncio shutdown from a different task, producing a RuntimeError
about exiting a cancel scope in a different task.

Add aclose() that delegates to AgentLoop.close_mcp (which already
drains background tasks and closes MCP stacks), plus __aenter__ and
__aexit__ so the SDK works as an async context manager.

Fixes #4211
2026-06-06 15:35:28 +08:00
Xubin Ren
6a0368b32f fix(telegram): route /skill command 2026-06-05 18:48:51 +08:00
Xubin Ren
935a37182d docs(command): document /skill command 2026-06-05 18:48:51 +08:00
EndeavourYuan
6b6be20f32 feat(command): add /skill slash command to list enabled skills
- Register /skill in BUILTIN_COMMAND_SPECS with wrench icon
- Add cmd_skill handler that lists skill names and descriptions
- Disabled skills are excluded from the output
- Add 6 tests covering empty list, names/descriptions, disabled
  filtering, fallback description, markdown output, and router
  registration
2026-06-05 18:48:51 +08:00
chengyongru
710d00a179 fix(webui): persist user messages for refresh 2026-06-05 16:13:51 +08:00
chengyongru
3da68ac7fe Fix pairing for Weixin and Telegram DMs 2026-06-05 16:13:31 +08:00
chengyongru
d435cb0b21 fix: harden custom image provider compatibility
Maintainer edit: preserve provider-specific size hints for custom image generation endpoints while keeping the default 1K mapping compatible. Clarify the custom provider contract in docs and cover response_format/size overrides in tests.
2026-06-05 15:56:03 +08:00
chengyongru
ae17a79bdf fix: harden custom image generation config
Maintainer edit: require providers.custom.apiBase before making custom image requests and allow unauthenticated local endpoints by omitting Authorization when no apiKey is configured.
2026-06-05 15:56:03 +08:00
axelray-dev
748b28da01 feat(image): support custom image generation provider
Addresses #4132.

Add CustomImageGenerationClient for any OpenAI-compatible image generation
API (POST {apiBase}/images/generations). Uses the existing providers.custom
config slot. No schema changes required.

Tests: 54 passed, ruff clean.
Signed-off-by: axelray-dev <110029405+axelray-dev@users.noreply.github.com>
2026-06-05 15:56:03 +08:00
chengyongru
c574b028c1 fix(feishu): allow punctuation after mention placeholders
maintainer edit: Keep the shared-prefix guard for Feishu numbered mention keys while still resolving placeholders followed by punctuation, matching the previous user-visible mention behavior.
2026-06-05 15:55:53 +08:00
Xubin Ren
894811db8b fix(feishu): strip leading bot mention before commands 2026-06-05 15:55:53 +08:00
Kunal Karmakar
fa423dffbc Remove check from the test 2026-06-05 01:17:34 +08:00
Kunal Karmakar
9fdc6f892a Fix test 2026-06-05 01:17:34 +08:00
Kunal Karmakar
c849ff6eec Address PR review comments 2026-06-05 01:17:34 +08:00
Kunal Karmakar
ba3fa38e97 Add support for Azure AAD based Auth 2026-06-05 01:17:34 +08:00
chengyongru
39454534d4 fix: isolate run-level hook snapshots 2026-06-05 01:09:45 +08:00
chengyongru
8933da1ec5 fix: harden run-level hook lifecycle
maintainer edit: keep cancellation out of on_error so shutdown paths do not look like run failures, and let the SDK capture hook use the authoritative after_run snapshot.
2026-06-05 01:09:45 +08:00
chengyongru
2ea226055e feat: add run-level agent hook lifecycle 2026-06-05 01:09:45 +08:00
chengyongru
c77ca16d91 fix: preserve uv pip update reinstall semantics
Maintainer edit: the uv fallback for CLI app updates now keeps the force-reinstall behavior from the python -m pip path by using uv pip install --reinstall, with unit coverage for the generated argv.
2026-06-04 19:41:51 +08:00
axelray-dev
c2e9064b35 fix: remove unsupported -y flag from uv pip uninstall fallback
uv pip uninstall does not support the -y (assume-yes) flag. Remove it
from the uv fallback argv while keeping it for the python -m pip
uninstall path.

Reported-by: chengyongru
2026-06-04 19:41:51 +08:00
axelray-dev
6d827efb0e test: explicitly stub _pip_available in pip-path tests
CI's uv-managed Python does not have pip importable, so the runtime
falls back to uv pip. Four tests that verify the python -m pip path
were failing because _pip_available() returned False in CI.

Monkeypatch _pip_available to True in tests that intentionally verify
the pip code path, so they pass regardless of the CI Python
environment.
2026-06-04 19:41:51 +08:00
axelray-dev
a37e58a29e fix(cli): fall back to uv pip when pip is unavailable
When nanobot is installed via uv tool install, sys.executable points to
a Python that does not have pip available as a module. _pip_install_argv
and _pip_uninstall_argv always used [sys.executable, -m, pip, ...]
which fails in that environment.

Add _pip_available() helper that checks importlib.util.find_spec('pip').
When pip is not available and uv is on PATH, fall back to:
  uv pip install --python <sys.executable> ...
  uv pip uninstall --python <sys.executable> -y ...
If neither pip nor uv is available, raise CliAppError.

Fixes #4158
2026-06-04 19:41:51 +08:00
chengyongru
24e56fcf07 test: improve deterministic unit test coverage 2026-06-04 19:41:32 +08:00
Xubin Ren
87bd56468c fix(webui): show platform-specific new chat shortcut 2026-06-04 14:01:21 +08:00
chengyongru
54d8d3010b fix: close search when starting new chats
maintainer edit: Close the session search dialog when the global new-chat shortcut navigates to the blank chat route, and expose the new shortcut through the sidebar button title so the shortcut is discoverable.
2026-06-04 14:01:21 +08:00
axelray-dev
4275678b43 feat(webui): add new chat keyboard shortcut
Add Cmd/Ctrl+Shift+O shortcut to start a new chat, matching the
convention used by ChatGPT, Claude.ai, and Gemini.

Addresses #4178

Signed-off-by: axelray-dev <110029405+axelray-dev@users.noreply.github.com>
2026-06-04 14:01:21 +08:00
chengyongru
d0eba7cd9d fix: cover MCP reconnect edge cases
maintainer edit: handle prompt sessions that report Connection closed outside McpError, and match reconnect registration prefixes with the same sanitization used by MCP wrapper names.
2026-06-04 10:43:09 +08:00
chengyongru
e9145b7acd fix(mcp): reconnect terminated sessions 2026-06-04 10:43:09 +08:00
yorkhellen
7c3808327f fix(qq): send pairing codes for unauthorized C2C users 2026-06-04 10:42:51 +08:00
chengyongru
facdc41a16 fix: restore top-level import order 2026-06-03 16:57:29 +08:00
chengyongru
3b46386887 test(email): cover progress message suppression
Maintainer edit: add a regression test for the email channel fix so progress/tool-event messages return before SMTP is opened instead of sending empty emails.
2026-06-03 15:01:47 +08:00
Nicolas Blondiau
cbf1ede179 fix(email): skip progress messages to prevent empty emails after tool calls 2026-06-03 15:01:47 +08:00
chengyongru
13178f3eaa fix(session): reject non-integer consolidated offsets
maintainer edit: corrupt session metadata can contain JSON strings, nulls, floats, or booleans. Reset non-integer offsets before range checks so recovery keeps valid messages visible instead of falling back to an empty session.
2026-06-03 15:01:29 +08:00
04cb
0307ee6b73 fix(session): reset out-of-range last_consolidated to recover hidden history (#4066) 2026-06-03 15:01:29 +08:00
chengyongru
d1a94dae8a
refactor(dream): replace two-phase Dream class with simple cron + process_direct (#3990)
* refactor(dream): replace two-phase Dream class with simple cron + process_direct

- Remove the heavyweight Dream class (AgentRunner-based two-phase system)
  from nanobot/agent/memory.py
- Delete dream_phase1.md and dream_phase2.md templates
- New dream.md template serves as the consolidation prompt
- Cron callback uses agent.process_direct(prompt, session_key=\"dream\")
  instead of agent.dream.run()
- Always performs git auto_commit after execution
- /dream command updated to use process_direct + git commit
- DreamConfig kept for backward compatibility; deprecated fields
  (model_override, max_batch_size, max_iterations, annotate_line_ages)
  are ignored but accepted in config
- interval_h remains configurable via agents.defaults.dream.interval_h
- Update tests and webui settings to match new architecture

* feat(loop): add ephemeral mode to process_direct, skip history writes for Dream

When ephemeral=True, _state_save skips enforce_file_cap (which calls
raw_archive -> append_history) and consolidator.maybe_consolidate_by_tokens.
This prevents Dream sessions from creating a positive feedback loop where
they process their own output. The session IS still saved to disk.

* fix(loop): skip extra hooks for ephemeral sessions (Dream)

* feat(dream): per-run timestamped sessions with rotation for WebUI

* test(config): restore DreamConfig schedule and alias tests

* fix(dream): include LLM response summary in git auto-commit message

The old two-phase Dream class included the Phase 1 analysis in the git
commit message body. The new single-phase version lost this. Restore it
by extracting resp.content from the process_direct return value and
appending it to the commit message in both the cron handler and the
/dream command.

* fix(test): accept ephemeral kwarg in test_openai_api fake_process

* refactor(dream): merge dream_session.py into MemoryStore

The standalone dream_session.py module only contained three small helpers
that all revolve around MemoryStore concerns (session keys, commit messages,
file pruning). Fold them into MemoryStore as @staticmethod to reduce
indirection and avoid a 35-line module with no independent reason to exist.

* fix(test): address code review — patch correct instance, use actual function

- Fix test_ephemeral_skips_raw_archive to patch loop.context.memory
  instead of the fixture's separate MemoryStore instance
- Fix TestDreamCommitMessage to call MemoryStore.build_dream_commit_message
  instead of reimplementing the logic inline
- Move Dream helpers in memory.py above the Consolidator section comment
  to avoid misleading visual boundary

* fix(dream): gate cursor advancement and restrict tools

maintainer edit: Dream now processes backlog from the oldest unprocessed entries, only advances the cursor after a completed ephemeral run, and uses a restricted file-only tool registry for background consolidation.

* fix(dream): skip idle compact for dream sessions

Dream runs use internal dream:* sessions that are pruned by Dream retention. Exclude them from AutoCompact scheduling, archive execution, and summary injection so idle-session compaction cannot truncate Dream transcripts.

* fix(dream): keep batched history isolated

* feat(dream): tag archived memory for single-phase Dream

---------

Co-authored-by: Xubin Ren <52506698+Re-bin@users.noreply.github.com>
2026-06-02 22:46:47 +08:00
chengyongru
b2ae5d936f fix(email): bound outbound attachment handling
maintainer edit: apply the existing email attachment count and size limits to outbound media, and include visible fallback notes when an attachment cannot be sent.
2026-06-02 21:17:31 +08:00
Pringlas
82a3fd03b1 test(email): cover agent-initiated file attachments in outbound messages 2026-06-02 21:17:31 +08:00
Pringlas
25bb053206 feat(email): attach media files to outbound SMTP messages 2026-06-02 21:17:31 +08:00
chengyongru
456ed77e79 fix(webui): bound startup fetch waits 2026-06-02 18:47:34 +08:00
chengyongru
2a98360105 refactor: split WebUI gateway dependencies
Maintainer edit for PR 4115: rebase onto origin/main and split gateway HTTP routing from token, media, and workspace services so WebSocketChannel depends on explicit gateway services instead of GatewayHTTPHandler internals.

Preserve file edit channel capabilities and restore tools.restrict_to_workspace wiring through ChannelManager.
2026-06-02 17:14:38 +08:00
chengyongru
2420826e05 fix: handler token issue also checks static token as fallback 2026-06-02 17:14:38 +08:00
chengyongru
0acf7cd373 refactor: remove gateway-specific kwargs from WebSocketChannel 2026-06-02 17:14:38 +08:00