2766 Commits

Author SHA1 Message Date
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
chengyongru
1252550649 refactor: ChannelManager creates and injects GatewayHTTPHandler 2026-06-02 17:14:38 +08:00
chengyongru
e5eb08e3e5 refactor: WebSocketChannel accepts injected http_handler, update all tests 2026-06-02 17:14:38 +08:00
chengyongru
22673c2a27 refactor: update import paths after ws_http move to webui/ 2026-06-02 17:14:38 +08:00
chengyongru
ca139c7031 refactor: move ws_http.py from channels/ to webui/ 2026-06-02 17:14:38 +08:00
chengyongru
1a585288b2 refactor: extract GatewayHTTPHandler from WebSocketChannel
Extract all HTTP route handling (bootstrap, sessions, settings, media,
commands, sidebar state, static serving, token management) into a new
GatewayHTTPHandler class in nanobot/channels/ws_http.py.

WebSocketChannel is reduced from 1907 to 1372 lines (-28%), retaining
only WebSocket connection management and message dispatch.

No behavior change. 3730 tests pass, 0 failures.

Shared HTTP utility functions (path parsing, response builders, auth
helpers) now live in ws_http.py with websocket.py importing from there,
avoiding circular dependencies.

Backwards-compat property aliases on WebSocketChannel ensure existing
tests continue to work without modification.
2026-06-02 17:14:38 +08:00
Jasper
92fe40a690 fix(runner): prevent read_file offload loop 2026-06-02 17:06:37 +08:00
Xubin Ren
f382133bb4 refactor(webui): move media replay helpers out of websocket channel 2026-06-02 16:18:57 +08:00
Xubin Ren
7aa5e620be chore(webui): remove useless timezone assignment 2026-06-02 16:18:57 +08:00
Xubin Ren
8bc4a80035 fix(webui): suppress restart handshake noise 2026-06-02 16:18:57 +08:00
Xubin Ren
21c60b0c97 fix(webui): resign replayed assistant media 2026-06-02 16:18:57 +08:00
Xubin Ren
a371907809 fix(webui): keep tool activity in one thought block 2026-06-02 16:18:57 +08:00
Xubin Ren
fd61203be4 feat(webui): bucket dense prompt rails 2026-06-02 16:18:57 +08:00
Xubin Ren
1af2bc513f feat(webui): add prompt rail navigation 2026-06-02 16:18:57 +08:00
Xubin Ren
e8d4aff5be fix(webui): polish links and thought timing 2026-06-02 16:18:57 +08:00
chengyongru
d5692bf94c fix(napcat): harden async handlers and action errors
maintainer edit: track background handler tasks, surface failed OneBot actions, reject image redirects, and add focused unit coverage for group routing and edge cases.
2026-06-02 14:10:10 +08:00
LZDQ
0c3063b78c Fix deadlock: get_group_member_info blocks receive loop 2026-06-02 14:10:10 +08:00
LZDQ
b1a3053ceb Channel napcat by Claude 2026-06-02 14:10:10 +08:00
04cb
ac226d66f9 fix(memory): serialize cursor allocation in append_history (#4081) 2026-06-02 14:09:01 +08:00
chengyongru
3e98a03188 fix: support fallback copy for webui replies 2026-06-02 14:08:55 +08:00
chengyongru
1886d22352 fix webui refresh location routing 2026-06-02 14:08:47 +08:00
chengyongru
b2cabb2bd8 fix(webui): keep project heading singular
maintainer edit: render the Projects divider only before the first project group so Chats can sort between projects without duplicating the heading. Add middle and last ordering regression coverage.
2026-06-02 14:08:45 +08:00
chengyongru
a70871679c fix(webui): sort Chats group among projects by recency
In project-based sidebar grouping, the "Chats" section (non-project
conversations) was always appended at the end regardless of its most
recent updated_at. This meant the newest conversation could appear
below older project groups.

Move Chats group insertion before the global sort, compute its
updatedAt from its most recently updated session, and sort all groups
together by updatedAt descending.
2026-06-02 14:08:45 +08:00
Xubin Ren
edf34d857a search: add Volcengine web search provider 2026-06-02 13:55:12 +08:00
chengyongru
851150fcd8 docs: document DingTalk group user isolation 2026-06-01 23:01:19 +08:00
李明振
da0aafcfbd feat(dingtalk): add group_user_isolation to separate sessions per user in group chats
Add a new config option group_user_isolation (default: false) to the
DingTalk channel. When enabled, each user in a group chat gets their own
session while bot replies are still routed to the shared group chat.
2026-06-01 23:01:19 +08:00
chengyongru
0042f68f94 fix: close websocket turns after errors 2026-06-01 23:00:53 +08:00
chengyongru
ebc8c9faf9 chore: restore existing import order 2026-06-01 23:00:53 +08:00
chengyongru
d1b0fb6676 docs: clarify progress bus responsibility 2026-06-01 23:00:53 +08:00
chengyongru
f78700fe69 refactor: move runtime event publishing out of loop 2026-06-01 23:00:53 +08:00
chengyongru
81370565e0 refactor: subscribe to runtime event types 2026-06-01 23:00:53 +08:00
chengyongru
2f0e638bd1 refactor: route file edit progress via channel capability 2026-06-01 23:00:53 +08:00
chengyongru
8129c16b7d fix: tolerate missing runtime event state in direct loop tests 2026-06-01 23:00:53 +08:00
chengyongru
628b250e9a refactor: decouple webui runtime state via events 2026-06-01 23:00:53 +08:00
Xubin Ren
0c6ce80aeb docs: update README with release notes for v0.2.1, highlighting new features and improvements 2026-06-01 17:14:06 +08:00
Xubin Ren
f309982bb0 chore(release): update version to 0.2.1 v0.2.1 2026-06-01 16:51:24 +08:00
chengyongru
0e37024114 fix(session): archive actual idle compact drops 2026-06-01 16:07:08 +08:00
yorkhellen
baffd6ef92 fix(session): correct last_consolidated tracking in non-contiguous retention
The previous fix made retain_recent_legal_suffix return the actual dropped
message list, but already_consolidated was still computed with
min(before_last_consolidated, len(dropped)), which assumes dropped messages
are always a prefix. In the else branch (tail has no user messages), dropped
may include messages from after the consolidated prefix, causing
already_consolidated to skip too many and leaving tail messages neither
retained nor raw-archived.

Fix by having retain_recent_legal_suffix return (dropped,
already_consolidated_count) where already_consolidated_count is computed
against original message indices. Also fix last_consolidated update to count
how many retained messages were inside the old consolidated prefix.
2026-06-01 16:07:08 +08:00
yorkhellen
72fb642ef7 fix(session): prevent duplicate archive and message loss in enforce_file_cap
When retain_recent_legal_suffix hits the else branch (tail has no user
messages), it takes a non-contiguous slice from the middle of the session.
enforce_file_cap incorrectly assumed dropped messages were always a prefix
(before[:dropped_count]), causing user messages to be both archived and
retained, and some messages to silently disappear.

Fix by having retain_recent_legal_suffix return the actual dropped message
list using identity-based diff, so enforce_file_cap no longer needs to
guess which messages were removed.
2026-06-01 16:07:08 +08:00
Jasper
b886b4a566 docs: add AGENTS.md for Codex 2026-06-01 16:06:51 +08:00
Xubin Ren
a4bd4befd4 Fix thought activity ordering 2026-06-01 16:05:42 +08:00
Xubin Ren
9ecd25bca1 docs: update nanobot_webui.png for improved visuals 2026-06-01 06:07:10 +08:00
Xubin Ren
503fc83ce2 docs: rename README cover image 2026-06-01 05:47:14 +08:00