1005 Commits

Author SHA1 Message Date
chengyongru
22673c2a27 refactor: update import paths after ws_http move 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
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
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
04cb
ac226d66f9 fix(memory): serialize cursor allocation in append_history (#4081) 2026-06-02 14:09:01 +08:00
Xubin Ren
edf34d857a search: add Volcengine web search provider 2026-06-02 13:55:12 +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
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
628b250e9a refactor: decouple webui runtime state via events 2026-06-01 23:00:53 +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
Xubin Ren
be2e0172d1 fix(agent): extend sustained goal iteration budget 2026-06-01 04:00:15 +08:00
hamb1y
a3241c33ba Require auth for WebSocket token issuance 2026-05-31 15:15:54 +08:00
chengyongru
15c2bd25b3 refactor(heartbeat): remove Completed section and tighten section gating
- Remove ## Completed section from HEARTBEAT.md template; completed
  tasks should be deleted, not accumulated
- Change in_active_section from tri-state (None/True/False) to bool
  (True/False) so stray text before any ## heading no longer triggers
  heartbeat
- Add test cases for stray pre-heading text and ## Notes section
- Update docs/chat-commands.md to reference ## Active Tasks
2026-05-31 15:15:37 +08:00
Xubin Ren
2671c8fe55 fix(heartbeat): ignore completed-only heartbeat entries 2026-05-31 15:15:37 +08:00
04cb
e3df310309 fix(heartbeat): skip when HEARTBEAT.md has no tasks and fail closed on delivery (#4111) 2026-05-31 15:15:37 +08:00
Xubin Ren
2b4c984e9a fix(matrix): align SAS verification message flow 2026-05-31 01:00:14 +08:00
mytechdream
68712fc489 fix(matrix): handle SAS device verification 2026-05-31 01:00:14 +08:00
Xubin Ren
0cc58a80a4 test(agent): cover process_direct session locking 2026-05-30 23:45:37 +08:00
04cb
e29c9c3906 fix(agent): acquire per-session lock in process_direct (#4080) 2026-05-30 23:45:37 +08:00
Xubin Ren
3dcf511c84
feat(webui): refine output timeline and model controls (#4108)
* feat(webui): refine output timeline and composer queue

* feat(webui): add provider model picker

* fix(webui): polish model settings and heartbeat checks

* chore: keep heartbeat changes out of webui pr

* refactor(webui): isolate settings routes

* fix(providers): align minimax anthropic test

* fix(providers): keep minimax anthropic base sdk-compatible

* fix(providers): normalize anthropic base urls
2026-05-30 23:45:26 +08:00
chengyongru
b2e43955e3 fix: add regression tests for bare-dict coercion, update stale comment 2026-05-30 15:35:04 +08:00
chengyongru
98be0de919 fix(test): increase yield_time_ms in test_write_stdin_can_close_stdin for Windows CI stability 2026-05-30 15:35:04 +08:00
chengyongru
288146315e fix(security): normalize IPv6-mapped IPv4 in loopback check, add tests
- Apply _normalize_addr in _is_allowed_loopback_target so
  ::ffff:127.0.0.1 is correctly identified as loopback
- Add test for contains_internal_url with IPv6-mapped addresses
- Add test for whitelist + IPv6-mapped CGNAT interaction
2026-05-30 15:34:49 +08:00
yorkhellen
13dec9d2c2 fix(security): normalize IPv6-mapped IPv4 addresses in SSRF checks
::ffff:127.0.0.1 and ::ffff:169.254.169.254 are IPv6Address objects
that match neither the IPv4 blocklists (127.0.0.0/8, 169.254.0.0/16)
nor the IPv6 ones (::1/128), allowing SSRF bypass via DNS responses
that return IPv6-mapped IPv4 addresses.

Add _normalize_addr() to convert ipv4_mapped IPv6 addresses to their
IPv4 form before blocklist/allowlist matching.
2026-05-30 15:34:49 +08:00
Xubin Ren
1d4000560d fix(matrix): reject boolean media sizes 2026-05-30 15:34:19 +08:00
hinotoi-agent
4dd89f4c46 fix(matrix): bound inbound media downloads 2026-05-30 15:34:19 +08:00
chengyongru
7c86223643 fix(exec): bypass cmd.exe for multi-line python -c commands on Windows
On Windows, cmd.exe /c treats newlines as command separators, silently
dropping code after the first line in `python -c "..."` commands. This
causes multi-line inline Python to produce no output with exit code 0.

Detect multi-line `python -c` commands on Windows, parse them into exec
args via `_split_python_c_args`, and use `create_subprocess_exec` to
bypass cmd.exe entirely. Same principle as Codex's Rust `Command::args()`.

Applied to both the direct execution path and the session spawn path.
Added unit tests for the parser and the exec-vs-shell branching logic.
2026-05-30 01:02:40 +08:00
Xubin Ren
9ed5643d93 refactor(webui): isolate signed media serving 2026-05-29 17:26:58 +08:00
Xubin Ren
4a0035ef8f fix(webui): support video byte ranges 2026-05-29 17:26:58 +08:00
Xubin Ren
a71e6a0ae8 fix(webui): persist markdown video previews 2026-05-29 17:26:58 +08:00
Xubin Ren
57563b671f fix(apps): recover stale npm installs 2026-05-29 17:26:58 +08:00
Xubin Ren
d7bc1bcfb5 fix(apps): use registry logos 2026-05-29 17:26:58 +08:00
Xubin Ren
c1357e86de feat(apps): add extension registry source 2026-05-29 17:26:58 +08:00
Xubin Ren
232df45126 fix(msteams): trust official Teams service hosts 2026-05-29 16:46:46 +08:00
hinotoi-agent
5734c17ee0 fix(msteams): trust service URLs before replies 2026-05-29 16:46:46 +08:00
04cb
9d3fe7c34b fix(providers): surface clear arrearage warning on quota/billing errors (#3006) 2026-05-29 15:31:17 +08:00
chengyongru
672fabe5be refactor(agent): move document media logic out of AgentLoop into document.py
Extract is_image_file() and reference_non_image_attachments() from
AgentLoop private static methods into nanobot/utils/document.py where
they belong alongside extract_documents(). Simplify config lookup by
removing dead isinstance(dict) branch.
2026-05-29 15:31:03 +08:00
hanyuanling
ec4f9e9857 Add document extraction channel toggle 2026-05-29 15:31:03 +08:00
Xubin Ren
404b68cdd4 feat(webui): add context window setting 2026-05-29 13:09:08 +08:00
Xubin Ren
3a420136bb
feat(webui): add project workspaces and access controls (#4007)
* feat(webui): add project workspaces and access controls

* feat(webui): add project workspaces and access controls

* refactor(tools): centralize workspace access resolution

* refactor(webui): remove unused workspace host state

* fix(webui): hide estimated file edit label

* fix(webui): clarify file edit deletion feedback

* fix(webui): label deleted file activity

* fix(webui): flatten file edit activity rows

* fix(core): remove path-only patch deletion

* fix(core): keep apply patch non-destructive

* refactor(webui): trim workspace host plumbing

* fix(tools): register exec with tools config
2026-05-29 03:42:53 +08:00
chengyongru
84428136e6 test: harden timing-fragile test and add cross-tool ContextVar isolation test
Replace asyncio.sleep(0.05) with an asyncio.Event + patched Lock.acquire
to guarantee the waiting task has reached the lock before asserting.  Add
a test confirming LongTaskTool and CompleteGoalTool ContextVars are
isolated, and document the design intent in _GoalToolsMixin.
2026-05-28 22:54:46 +08:00
hamb1y
0df60416ba fix(agent): address session and streaming concurrency bugs 2026-05-28 22:54:46 +08:00