Commit Graph
1186 Commits
Author SHA1 Message Date
Xubin Ren d36117de7a feat(webui): support Firecrawl keyless MCP preset 2026-06-19 01:19:20 +08:00
chengyongruandXubin Ren 08a5f4cbbb fix: keep feishu login URL unmodified
maintainer edit: remove nonessential tracking parameters from the Feishu QR login URL after the author confirmed the flow works without them.
2026-06-18 22:38:06 +08:00
chengyongruandXubin Ren 5dfdd4f892 fix: handle feishu login network errors
maintainer edit: keep QR login network failures on the expected failure path instead of crashing the channels login command.
2026-06-18 22:38:06 +08:00
chengyongruandXubin Ren a56cd9710b fix: simplify feishu QR login 2026-06-18 22:38:06 +08:00
chengyongruandXubin Ren cd51654bf1 fix: keep channel login generic
maintainer edit: remove the Feishu-specific config-file guard from the shared CLI login command. Feishu now follows the Weixin pattern where channel.login owns its setup and persistence.
2026-06-18 22:38:06 +08:00
chengyongruandXubin Ren 3d386f7b7e fix: stabilize feishu login setup
maintainer edit: fix the lint failure, report the active config path, fail fast when the registration response lacks a login URL, and cover the new Feishu login writeback path.
2026-06-18 22:38:06 +08:00
d7280da17c fix(web): require API key for Keenable, fall back to DuckDuckGo
Manual testing against the live API showed the Keenable REST endpoint
(/v1/search) returns 401 without a key — the keyless "free tier" applies
only to the CLI, not the HTTP API. Treat Keenable like every other
key-based provider: fall back to DuckDuckGo when no key is configured,
and drop the now-inaccurate free-tier wording from the docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:08:52 +08:00
092b07c7aa feat(web): use shared user-agent and send X-Keenable-Title
Drop the bespoke nanobot/<version> User-Agent in favor of self.user_agent
for consistency with every other search provider, and add an
X-Keenable-Title: nanobot header so Keenable can attribute traffic.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:08:52 +08:00
83cb296cdc style(test): match existing single-line result-dict style
Keep the Keenable search test consistent with the surrounding mocks
(test_tavily/test_brave) rather than introducing a multi-line outlier.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:08:52 +08:00
fa3e902ee8 feat(web): register Keenable provider in WebUI, docs, and tests
Bring the Keenable search provider in line with the established
multi-file provider pattern so it surfaces everywhere the others do:

- settings_api.py: register in the web-search provider options so it
  appears in the WebUI settings dropdown (credential: api_key, optional).
- WebUI provider-brand: add keenable brand entry + brand test.
- docs/configuration.md: provider table row + config example.
- Harden _search_keenable: honor config.timeout and return explicit
  messages on HTTP status errors (429 / other), matching peer providers.
- Add env-key and HTTP-error tests; add the websocket settings whitelist
  assertion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:08:52 +08:00
4f6e5e9cb8 feat(web): send honest nanobot UA for Keenable
Keenable is a first-party API, so identify as nanobot/<version> instead
of the shared spoofed-browser User-Agent used by scraping providers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:08:52 +08:00
6fcf65a8e3 chore(web): drop redundant comments from Keenable provider
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:08:52 +08:00
a630a78941 feat(web): add Keenable search provider
Add Keenable (https://keenable.ai) as a web_search backend, modeled on
the existing httpx-based providers. Unlike key-gated providers, Keenable
has a no-login free tier, so it resolves to itself even without an API
key instead of falling back to DuckDuckGo; the X-API-Key header is only
sent when a key is configured (config api_key or KEENABLE_API_KEY env).

Maps result snippet (falling back to description) into the shared
content field. Covered by tests for keyed/anonymous search and the
no-fallback concurrency behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:08:52 +08:00
d5f5eb43e5 feat(providers): first-class Mistral support
Mistral's API constrains reasoning_effort to "high"/"none", rejects the
kwarg entirely for Magistral (reasoning is implicit), returns assistant
content as a mixed array of {type:"thinking",...}/{type:"text",...}
blocks, and 400s on the reasoning_content key in history.

- Remap user-supplied reasoning_effort (low/medium/minimal) onto Mistral's
  two-tier vocabulary; strip the kwarg for Magistral models
- Lift thinking blocks into reasoning_content for both batch and streaming
  responses; pass only text through on_content_delta callbacks
- Drop reasoning_content from outbound history when the spec asks for it
- Expose per-preset reasoning_effort_values so the UI can render the
  provider-specific option set

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 00:08:47 +08:00
chengyongruandXubin Ren 515e418eb4 fix: block exact-file allowlist link escapes
maintainer edit: compare exact-file allowlist entries using logical paths and require the resolved target to stay at that canonical path, so symlinks or junctions cannot redirect canonical memory files to an external write target.
2026-06-18 00:03:26 +08:00
chengyongruandXubin Ren 42ce294665 fix: preserve internal tool write scopes
Maintainer edit: keep capability-specific allowed_dir boundaries active even when the outer workspace scope is full access, and cover Dream plus ordinary full-access filesystem behavior.
2026-06-18 00:03:26 +08:00
chengyongruandXubin Ren 15f218e918 fix: enforce exact Dream memory file writes
maintainer edit: Dream write tools used file paths as directory roots, so a missing canonical memory file could be treated as a parent directory. Add exact-file allowlist support and keep skills/ as the only Dream write directory.
2026-06-18 00:03:26 +08:00
chengyongruandXubin Ren 732992df4f Clarify filesystem workspace write policy 2026-06-18 00:03:26 +08:00
chengyongruandXubin Ren fc635377bc fix: avoid replaying older long turns
Treat the current live user message as the replay boundary for normal user turns, while keeping user-turn extension for history and consolidation paths that need it. Add regression coverage for the user-triggered long tool-turn case.
2026-06-18 00:03:22 +08:00
Xubin Ren 09962895fb fix(session): preserve user turns in replay history 2026-06-18 00:03:22 +08:00
chengyongruandXubin Ren ef6da0a94e Fix my tool model preset switching 2026-06-18 00:03:13 +08:00
Xubin Ren bdf21c932b fix(anthropic): avoid sanitized tool id collisions 2026-06-18 00:03:08 +08:00
michaelxerandXubin Ren 0023f6d998 fix(providers): remove custom cloud httpx client, let SDK handle proxy defaults
chengyongru reviewed #4367 and identified that the cloud  branch
created a bare httpx.AsyncClient that lacked the SDK's default settings
(follow_redirects, connection pool limits). Since the SDK's
DefaultAsyncHttpxClient already has trust_env=True and proper defaults,
the simplest fix is to let http_client stay None for cloud endpoints.

Also updated the test to match the new behavior (http_client is None).
2026-06-18 00:03:03 +08:00
michaelxerandXubin Ren 72b8fc806f fix(providers): disable proxy for local endpoints, respect env proxy for cloud
When the host has HTTP_PROXY / HTTPS_PROXY / ALL_PROXY set, httpx routes
all traffic through the proxy — including requests to localhost or LAN
addresses that the proxy typically cannot reach.  This breaks local model
servers (Ollama, llama.cpp, vLLM) silently.

- Local endpoints: pass transport=httpx.AsyncHTTPTransport(proxy=None)
  so proxy env vars are ignored for local traffic.
- Cloud endpoints: pass trust_env=True so corporate/VPN proxies work
  without explicit configuration.

Fixes #4366
2026-06-18 00:03:03 +08:00
HaisamandXubin Ren bfe5b64022 fix: allow git commands in workspace subdirectories
The shell safety guard in _guard_command() checked extracted absolute
paths only against cwd_path (the command's working directory).  When
cwd was a subdirectory like ~/.nanobot/workspace/obsidian_notes, any
absolute path referencing the broader workspace (e.g. a sibling
directory or the workspace root itself) was incorrectly blocked with
"path outside working dir".

Fix: pass the workspace_root from _prepare_command() into
_guard_command() and check absolute paths against it as a fallback
when they are outside cwd_path.  Paths truly outside the workspace
root are still blocked.

Added tests:
- test_exec_allows_workspace_paths_from_subdirectory
- test_exec_blocks_outside_paths_from_subdirectory
2026-06-18 00:02:58 +08:00
chengyongruandXubin Ren 4219911423 fix: recover failed Feishu streaming updates
Feishu CardKit content updates can fail without raising, leaving a blank Generating card while the final streamed response skips normal send. Reopen streaming mode and retry once, close blank cards when the first update fails, and fall back to a regular card when final updates still fail.
2026-06-18 00:02:54 +08:00
chengyongruandXubin Ren 8ecc2d69c4 fix: log primary model error before fallback 2026-06-18 00:02:49 +08:00
chengyongruandXubin Ren 0d4af68e63 fix: silence unroutable cli progress noise 2026-06-18 00:02:45 +08:00
Xubin RenandGitHub c29601d303 Merge PR #4330: feat(webui): add automation management view
feat(webui): add automation management view
2026-06-17 01:55:39 +08:00
chengyongruandXubin Ren 4c5e340186 feat(memory): enable idle auto compact by default 2026-06-17 00:48:06 +08:00
chengyongruandXubin Ren dcf76117ab fix(command): explain empty dream runs 2026-06-17 00:47:59 +08:00
chengyongruandXubin Ren 072921893f fix: reuse token truncation helper
Maintainer edit: make token truncation include the suffix within the budget and route the consolidator through the shared helper so recent-history and archive truncation keep the same semantics.
2026-06-17 00:47:52 +08:00
w.antarandXubin Ren 21d9072190 fix(tests): update recent history truncation to use token limits 2026-06-17 00:47:52 +08:00
w.antarandXubin Ren 973a5ee507 fix(context): cap recent-history digest by tokens, not characters
The recent-history section injected into the system prompt was capped by character count (_MAX_HISTORY_CHARS = 32_000). Characters are a poor proxy for tokens: ~32k chars of English is ~8k tokens, but the same char count of CJK text or code can be far more, so the cap could let the section blow well past its intended size on non English/code-heavy histories.

Add a reusable truncate_text_to_tokens() helper (reusing the tiktoken
 cl100k_base encoder already used elsewhere, with a char-based fallback) and
  switch the digest cap to a token budget (_MAX_HISTORY_TOKENS = 8_000),
  matching the previous English-text size while holding regardless of
  content.
2026-06-17 00:47:52 +08:00
yu-xin-candXubin Ren 846410f936 fix(providers): validate stream idle timeout config 2026-06-17 00:47:44 +08:00
Xubin Ren 7bec0f6e01 fix(api): honor skip-user persist through save boundary 2026-06-16 21:31:26 +08:00
04cbandXubin Ren d75f80437c fix(api): don't re-persist user turn on empty-response retry (#4079)
The non-streaming retry called process_direct again with the same
content, persisting a duplicate user turn. Pass persist_user_message=False
so the retry recovers a response without re-recording the user message.
2026-06-16 21:31:26 +08:00
Xubin Ren 25a55fe1c7 fix(providers): enable thinking for Kimi K2.7 models 2026-06-16 17:44:22 +08:00
chengyongru 0263dbd1c3 chore: trim automation ui cleanup 2026-06-16 15:10:51 +08:00
chengyongru b24b5f19fc fix(cron): always require bound automation sessions 2026-06-16 14:16:12 +08:00
chengyongru 6239114c46 fix(cron): prevent unbound automation execution 2026-06-16 14:07:08 +08:00
chengyongruandXubin Ren 27d869d3cc fix(agent): refresh goal continuation context 2026-06-16 11:19:24 +08:00
chengyongru e6957de622 fix(webui): drop legacy automation setup state 2026-06-16 00:26:06 +08:00
chengyongruandXubin Ren 3ce0cd972e fix(session): keep auto compact suffix on user turn 2026-06-15 19:03:37 +08:00
chengyongru 03c79817ac test(websocket): expect session refresh after turn end 2026-06-15 18:25:00 +08:00
chengyongru 848378d0db Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	webui/src/components/settings/SettingsView.tsx
2026-06-15 18:11:22 +08:00
chengyongru 167a53dc45 fix(webui): sort sessions by transcript activity 2026-06-15 17:44:26 +08:00
chengyongru cbb4c0bad2 fix(webui): polish automation layout and session updates 2026-06-15 17:30:06 +08:00
chengyongru f8bf6aea51 fix(webui): encode automation update values 2026-06-15 15:14:24 +08:00
9814a3b9fe fix(api): forward real LLM usage in /v1/chat/completions response (#4310)
* fix(api): forward real LLM usage in /v1/chat/completions response

_chat_completion_response() hardcoded prompt_tokens/completion_tokens
to zero.  Now reads agent_loop._last_usage (set by process_direct
after every LLM call) and forwards the actual prompt/completion counts.

Streaming path is unchanged; usage is only surfaced in non-streaming
responses for now.

Fixes #4309

* fix: use defensive getattr for _last_usage and add it to all test mock agents

- Use getattr(agent_loop, '_last_usage', None) in server.py for safety
- Add _last_usage = {} to mock agents in test_api_attachment.py and test_api_stream.py
- Prevents AttributeError/500 when mock agents don't have the attribute

* fix(api): preserve provider total usage

---------

Co-authored-by: michaelxer <michaelxer@users.noreply.github.com>
Co-authored-by: Xubin Ren <52506698+Re-bin@users.noreply.github.com>
2026-06-15 15:13:11 +08:00