1092 Commits

Author SHA1 Message Date
chengyongru
af9f9ebfd7 fix: reject custom provider alias conflicts
maintainer edit: reject arbitrary custom provider keys that normalize to built-in provider names so runtime and WebUI settings cannot disagree about whether a provider is dynamic or built in.
2026-06-13 00:04:13 +08:00
chengyongru
b2d00a4ce0 fix: strip dynamic custom provider route prefixes
maintainer edit: preserve provider-prefix CLI routing for named custom providers by stripping only the matched dynamic route prefix before sending the model id to OpenAI-compatible endpoints. This keeps ordinary namespaced model ids intact when the provider is selected explicitly.
2026-06-13 00:04:13 +08:00
chengyongru
09d24e6c25 fix: validate named custom provider endpoints 2026-06-13 00:04:13 +08:00
chengyongru
57ced7930d refactor: simplify dynamic provider settings tests
maintainer edit: keep the WebUI dynamic-provider behavior unchanged while reducing repeated test setup and tightening the small dynamic-provider helper.
2026-06-13 00:04:13 +08:00
chengyongru
37ae655fa6 fix: expose dynamic custom providers in WebUI settings
maintainer edit: WebUI settings still treated non-registry custom providers as unknown, so users could not select them in model configurations or fetch their model list. Reuse dynamic provider specs for settings payloads, model-list requests, and provider updates.
2026-06-13 00:04:13 +08:00
chengyongru
68c6844c0b fix: preserve dynamic custom provider semantics
maintainer edit: treat arbitrary custom provider names as direct OpenAI-compatible providers, validate their api_type consistently, and avoid Pydantic instance-field warnings in fallback routing.
2026-06-13 00:04:13 +08:00
brendanlevy
2d9260cb9f feat(slack): add groupRequireMention for allowlist channels
Slack's groupPolicy could either restrict to specific channels
("allowlist") or require an @mention ("mention"), but not both: in
allowlist mode the bot replied to every message in approved channels.

Add a groupRequireMention flag so that, when groupPolicy is "allowlist",
the bot only responds in channels listed in groupAllowFrom AND only when
@mentioned. Mirrors Signal's group.requireMention. No effect for the
"mention"/"open" policies, so existing configs are unchanged.

Extract the mention check into _is_mention and reuse it from both the
mention and allowlist branches.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-12 00:23:27 +08:00
chengyongru
ffae1dca6d fix: keep Telegram streamed code blocks balanced
Maintainer edit: split final streamed Telegram markdown before rendering to HTML so long fenced code blocks do not produce unbalanced <pre><code> chunks while still respecting Telegram's rendered HTML limit.
2026-06-11 13:52:19 +08:00
axelray-dev
a5a816abaf fix(telegram): move fenced-code-block splitting into Telegram-specific helper
Move the fenced-code-block-aware splitting logic out of the shared
split_message helper (used by Signal, Slack, Discord, Weixin, etc.)
and into a Telegram-specific _split_telegram_markdown function.

The shared split_message remains a plain-text chunker. The Telegram
channel now uses _split_telegram_markdown for its raw Markdown paths
that feed _markdown_to_telegram_html, preventing broken HTML rendering
when splits fall inside fenced code blocks.

Also fixes a regression where content beginning with whitespace before
a fence could emit a whitespace-only chunk.

Addresses review feedback on #4257.
2026-06-11 13:52:19 +08:00
axelray-dev
131446fa61 fix(utils): make split_message fenced-code-block-aware
When split_message splits a long message, it now checks whether the
split point falls inside a fenced code block. If so, it either moves
the split to before the opening fence or closes/reopens the fence
across chunks, preventing broken HTML rendering.

Addresses #4250
2026-06-11 13:52:19 +08:00
Xubin Ren
b8a4ceb30c test(webui): cover siliconflow transcription settings 2026-06-10 23:05:12 +08:00
moran
9ed638ad70 feat(transcription): add SiliconFlow as transcription provider
- Register SiliconFlow in transcription registry with default model
  FunAudioLLM/SenseVoiceSmall and alias 'silicon'
- Reuse existing OpenAITranscriptionProvider adapter (Whisper-compatible)
- Add generic key/base resolution: fallback to registry env_key and
  default_api_base when provider config is absent
- Add tests for registry entry, alias, adapter, default model, and
  config resolution with env var fallback
2026-06-10 23:05:12 +08:00
Xubin Ren
e1e643de2a refactor(webui): keep sidebar index out of session manager 2026-06-10 20:45:29 +08:00
Xubin Ren
999552b998 perf(webui): index session list metadata 2026-06-10 20:02:22 +08:00
Xubin Ren
603feef3aa Merge remote-tracking branch 'origin/main' into codex/webui-segmented-transcript-store 2026-06-10 19:11:37 +08:00
Xubin Ren
e168bb2754 feat(webui): segment transcript storage 2026-06-10 18:28:55 +08:00
chengyongru
bc4bb508a1 fix: continue recovered streams in a new segment
maintainer edit: streamed timeout recovery was returning the retried response internally while the channel still treated the final outbound as already streamed. End the current stream segment before retry/fallback recovery so subsequent deltas are delivered in a new segment.
2026-06-10 18:10:44 +08:00
aiguozhi123456
2c5a4e0703 fix(providers): allow retry and fallback on stream stalled timeout
When a stream stalls mid-response, both the retry layer and
FallbackProvider blocked recovery because content had already been
emitted via on_content_delta. This left users with truncated replies
and no automatic recovery.

For error_kind="timeout" specifically:
- _run_with_retry now suppresses delta callbacks and retries the same
  model instead of returning immediately
- FallbackProvider now allows failover to a different model with
  delta callbacks suppressed

Non-timeout errors retain the original "skip retry/failover after
streamed content" behavior to avoid duplicate output.
2026-06-10 18:10:44 +08:00
chengyongru
dadb35af49 feat(exec): add path prepend config 2026-06-10 18:09:57 +08:00
chengyongru
8c30dc5a57 Preserve session key when archiving new sessions 2026-06-10 18:09:45 +08:00
chengyongru
bfc6febddc Scope prompt recent history by session
Fixes #4259
2026-06-10 18:09:45 +08:00
chengyongru
aee656eb9f Fail fast on invalid config files 2026-06-10 18:09:36 +08:00
chengyongru
5d7f2e60c2 fix(feishu): lazy-load lark sdk during gateway startup 2026-06-10 18:09:27 +08:00
Xubin Ren
7186039be1 fix(websocket): limit final stream text to inline endings 2026-06-10 15:52:39 +08:00
Moran
9c492143b4 search: add Bocha web search provider 2026-06-10 15:51:15 +08:00
primit1v0
ce887772e9 fix(sandbox): set HOME inside bwrap 2026-06-10 15:50:53 +08:00
Xubin Ren
62a35c21b8 fix(asr): normalize StepFun transcription endpoint 2026-06-10 15:50:38 +08:00
moran
7930058348 feat(asr): add StepFun ASR SSE transcription provider
- Add StepFunTranscriptionProvider class in nanobot/providers/transcription.py
- New _post_stepfun_asr_with_retry() function handling SSE stream parsing
  (transcript.text.delta → transcript.text.done event sequence)
- Register 'stepfun' in transcription_registry.py with default model stepaudio-2.5-asr
- Reuse existing stepfun provider config (apiBase can point to Plan endpoint)
- Add 17 tests covering SSE parsing, retry contract, empty-text edge case, and registry integration
- Update docs/configuration.md with stepfun ASR documentation

StepFun ASR uses a dedicated SSE endpoint (/v1/audio/asr/sse) rather
than the chat-completions or Whisper multipart formats used by other
providers. Users on Step Plan can set apiBase to the Plan endpoint.
2026-06-10 15:50:38 +08:00
erikmackinnon
31bfec58d0 Add Exa web search provider 2026-06-10 15:02:07 +08:00
chengyongru
5d91d59cf7 fix(agent): finalize max-iteration turns without tools 2026-06-10 14:47:20 +08:00
chengyongru
99f7f371fa fix: cover o1 max-completion token fallback
Maintainer edit: keep the GPT-5/o-series fallback on slug-boundary matching so unrelated model names are not caught by substring checks, and include o1 alongside o3/o4 because it is also an o-series chat model.
2026-06-10 14:47:10 +08:00
04cb
a779e7c29e fix(providers): use max_completion_tokens for gpt-5/o-series on flagless specs (#4261) 2026-06-10 14:47:10 +08:00
yu-xin-c
fd9fc38f41 fix(tools): keep apply_patch additions line-separated 2026-06-10 14:47:01 +08:00
Xubin Ren
916525f94a refactor(webui): shrink fork implementation 2026-06-10 04:26:06 +08:00
Xubin Ren
73d4b1cb2f feat(webui): persist fork boundary metadata 2026-06-10 04:26:06 +08:00
Bayern4ever-dot
03bca4c0a9 feat(webui): add assistant reply fork-from-here 2026-06-10 04:26:06 +08:00
Flávio Veloso Soares
0580c186c1 test(email): update tests for postActionExpunge option 2026-06-09 14:50:59 +08:00
Flávio Veloso Soares
4369eb20fc feat(email): support IMAP MOVE and UID expunge fallbacks 2026-06-09 14:50:59 +08:00
Flávio Veloso Soares
ec5460d23e feat(email): add configurable post-action handling 2026-06-09 14:50:59 +08:00
chengyongru
0a396aa6e2
Improve tool call validation strictness (#4190)
* Improve tool call validation strictness

Reject near-miss tool names without executing suggested tools. Require object-shaped tool parameters while preserving only lossless JSON wire-shape normalization.

* Tighten tool call argument validation

* Simplify tool argument validation tests

* Improve tool name suggestions

* Simplify tool suggestion helpers

* Limit tool suggestions to canonical matches

* Allow repair only for tool history replay

* Clarify non-object tool argument errors

* Inline replay tool argument normalization

* Track only successful tool executions

* Reject JSON null tool arguments
2026-06-09 14:50:40 +08:00
comadreja
f3eb2aa08b feat(transcription): add AssemblyAI as transcription provider
Add AssemblyAI as a third transcription provider option alongside
OpenAI and Groq. AssemblyAI offers better accuracy for certain
audio types (distant voices, noisy environments) and serves as a
reliable fallback when other providers struggle.

Changes:
- Add AssemblyAITranscriptionProvider class in providers/transcription.py
- Add 'assemblyai' option in base channel's transcribe_audio()
- Per-channel configuration via transcriptionProvider in config

Usage:
  Set transcriptionProvider: 'assemblyai' and provide an AssemblyAI
  API key via transcriptionApiKey in the channel config.
2026-06-09 05:33:18 +08:00
NanoBot
c20ecc52d7 feat(transcription): add Xiaomi MiMo ASR provider (mimo-v2.5-asr)
Add support for Xiaomi MiMo ASR as a third transcription backend alongside
Groq and OpenAI Whisper. Xiaomi ASR uses the /v1/chat/completions endpoint
with base64-encoded audio input, rather than the standard Whisper multipart
upload format.

Co-Authored-By:连 <lian@tangping.homes>
2026-06-09 04:29:09 +08:00
Ilia Breitburg
0eb3010e40 feat(transcription): configurable STT model + OpenRouter provider
Add a `transcriptionModel` channel setting and an OpenRouter transcription
backend so voice messages can be transcribed through OpenRouter's
speech-to-text endpoint (e.g. nvidia/parakeet-tdt-0.6b-v3, openai/whisper-1),
alongside the existing Groq/OpenAI Whisper providers.

- schema: add channels.transcriptionModel (None = provider default)
- providers/transcription: extract a shared POST/retry skeleton; add a
  JSON+base64 OpenRouterTranscriptionProvider; make the STT model a
  constructor param on all providers instead of hardcoding it
- channels: route transcriptionProvider="openrouter" and thread the model
  through the manager to each channel
- docs + tests

Only dedicated STT models work on OpenRouter's transcription endpoint;
chat LLMs (e.g. google/gemini-3.5-flash) are rejected there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 04:01:37 +08:00
axelray-dev
28f3a20d64 feat(providers): add extra_query config for OpenAI-compatible providers
Adds ProviderConfig.extra_query, threaded into AsyncOpenAI(default_query)
so that Azure-style gateways requiring query params like api-version can
be configured without URL hacks.

Also updates provider_signature to track extra_query changes so per-turn
refresh rebuilds the provider when the value changes.

Addresses the extra_query portion of #4204. The max_completion_tokens
model-awareness enhancement is intentionally left separate.
2026-06-09 03:18:14 +08:00
Xubin Ren
9c81280300
feat(transcription): add shared voice input support (#4232)
* feat(webui): add voice transcription input

* feat(webui): render ANSI output in code blocks

* refactor(webui): isolate voice recorder logic

* refactor(transcription): keep websocket ingress thin

* refactor(transcription): resolve channel audio settings on demand

* style(webui): neutralize voice waveform color

* feat(webui): add voice input tooltip

* feat(webui): add voice input keyboard shortcut

* fix(webui): distinguish voice shortcut platforms

* fix(webui): place voice button after model selector

* refactor(webui): share voice hold recording helpers

* fix(desktop): allow microphone voice input

* fix(webui): stabilize token usage month labels

* feat(webui): show voice input on settings overview

* fix(webui): label voice capability as recognition

* fix(webui): align capability overview status

* refactor(webui): isolate transcription socket handling

* fix(webui): soften silent voice waveform

* refactor(audio): clarify transcription service location

* docs(transcription): clarify audio and provider boundaries

* fix(exec): reduce session output polling flake
2026-06-09 01:08:49 +08:00
chengyongru
06d454a225 test: cover MCP redirect guard wiring
Maintainer edit: make the unsafe redirect regression go through connect_mcp_servers so both SSE and streamable HTTP prove that the request hook is attached to the MCP clients before redirects are followed.
2026-06-08 16:03:57 +08:00
Stellar鱼
ed0aeb1ea9 fix(mcp): reject unsafe HTTP URLs before probe 2026-06-08 16:03:57 +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