- Use a local variable for the proxy URL instead of hardcoding it twice
- Pass proxy through the WebSearchTool constructor instead of mutating
after instantiation (matches real usage path)
- Add assertion that timeout is still forwarded correctly
- Use generic mock data instead of test-specific strings
The DuckDuckGo search provider instantiated DDGS(timeout=10) without
passing the configured proxy, making web_search unusable in environments
that require a proxy (e.g. behind GFW). DDGS supports a proxy parameter
and the proxy value is already available as self.proxy — it was simply
not forwarded.
Add a test verifying the proxy kwarg is forwarded to DDGS.
maintainer edit: derive thinking tag regexes and streaming partial prefixes from one tag list so future aliases only need one entry while preserving legacy self-closing think/thought behavior.
maintainer edit: native reasoning streams can split <thinking> wrapper tags across chunks. Buffer the stream and emit only cleaned incremental reasoning so raw partial tags do not reach WebUI.
Maintainer edit: add the provider reference row and a pasteable cookbook recipe so users know to select kimi_coding and set the required User-Agent header.
Add a dedicated provider entry for the Kimi Coding Plan endpoint
(api.kimi.com/coding) using the Anthropic Messages API transport.
- Register kimi_coding with backend=anthropic
- Use KIMI_CODING_API_KEY env key to avoid clashing with MOONSHOT_API_KEY
- Default api_base set to https://api.kimi.com/coding/v1 so that
AnthropicProvider._normalize_base_url() + the SDK produce the correct
/coding/v1/messages request path
- Keywords include kimi-coding, kimi_coding and kimi-for-coding
ClosesHKUDS/nanobot#4463
Maintainer edit: document OpenCode Zen and Go configuration, keep their registry entries with gateway providers, and add focused provider registration tests.
maintainer edit: move duplicate tool_use history repair out of AgentRunner and into Anthropic message conversion, reusing the OpenAI-compatible queue-mapping approach locally without broadening the shared runner path.
maintainer edit: remap duplicate tool_use/tool_call ids instead of dropping later calls, so Anthropic-compatible providers that reuse ids for distinct parallel tool calls keep all requested work while still sending unique ids.
Anthropic rejects any request where two tool_use blocks share an id
("messages.N.content.M: tool_use ids must be unique"). A mis-assembled
stream could surface the same tool_use block twice in one assistant turn;
the runner persisted it verbatim, so the malformed message was re-sent on
every subsequent turn and permanently bricked the session — the agent
silently stopped replying.
Fix at two layers:
- AnthropicProvider._parse_response: drop duplicate tool_use ids (keep
first) as the response enters nanobot, so corruption is never persisted.
- AgentRunner._dedup_tool_calls: a new context-governance pass that dedupes
assistant tool_calls and tool results by id before each send, healing any
history that was already corrupted.
Add regression tests covering both the dedup and the no-op fast path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When _stream_end fires and a streaming preview already exists, the
sendRichMessage path deletes the preview and sends a fresh message.
This causes line break loss and visible flickering. Gate the rich
path on not buf.message_id so existing previews use the legacy
edit_message_text path instead.
Replace the manual thread-based catalog refresh with an asyncio task and async HTTP catalog fetches so the Settings route stays within the async WebUI model.
maintainer edit: CLI Apps settings now treats optional catalog caches as refresh candidates without blocking the initial payload, and pending polling stops when refresh is throttled instead of running indefinitely.
maintainer edit: Empty cache-only CLI Apps payloads should still update the UI while the background catalog refresh is pending, otherwise cold catalog failures leave Settings stuck on the spinner.
maintainer edit: Settings reads local Codex token storage to avoid refresh work, so expired access tokens with refresh credentials still need to count as configured until real provider use refreshes them.