Commit Graph
179 Commits
Author SHA1 Message Date
sbyininandXubin Ren 6da56f3574 Fix OpenAI reference image home expansion test on Windows 2026-06-19 17:16:09 +08:00
sbyininandXubin Ren 44f7bbae50 fix openai image reference home paths 2026-06-19 17:16:09 +08:00
sbyininandXubin Ren adb737b614 fix openai image reference edits 2026-06-19 17:16:09 +08:00
Xubin Ren 58a14d18dd test: tighten image placeholder assertions 2026-06-19 14:59:52 +08:00
Xubin Ren de5e216583 test: fix image strip test formatting 2026-06-19 14:59:52 +08:00
michaelxerandXubin Ren 7917466f4e fix(tests): update image placeholder assertions for new non-descriptive text
The _strip_image_content methods now use a fixed non-descriptive
placeholder instead of path-derived text. Update the 3 existing
test_provider_retry assertions to match the new placeholder format.
2026-06-19 14:59:52 +08:00
michaelxerandXubin Ren 9ed3905a23 fix(providers): use non-descriptive placeholder when stripping images
The image-strip fallback (triggered when a model errors on image input)
replaced image_url blocks with [image: <path>] or [image omitted]. Both
read like a live, available image to the LLM, causing it to:

1. hallucinate about image contents it never received
2. attempt read_file on the leaked server path
3. expose internal file paths to the model

Replace with an explicit '[Image not delivered to model — do not describe
or reference it]' placeholder that tells the LLM the image was stripped.

Fixes #4345
2026-06-19 14:59: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
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
yu-xin-candXubin Ren 846410f936 fix(providers): validate stream idle timeout config 2026-06-17 00:47:44 +08:00
Xubin Ren 25a55fe1c7 fix(providers): enable thinking for Kimi K2.7 models 2026-06-16 17:44:22 +08:00
qcypggsandXubin Ren cb2620c877 Fix Codex image SSE handling 2026-06-14 12:52:40 +08:00
axelray-devandXubin Ren ad89cbb24f test(providers): use real Fable model ID claude-fable-5 in tests
Replace placeholder claude-fable-1 with the actual API model ID.
2026-06-14 12:52:07 +08:00
axelray-devandXubin Ren 29d7186853 fix(providers): widen omit_temperature to cover opus-4-8 and fable
The temperature suppression was hardcoded to only match opus-4-7. Newer
Anthropic models (opus-4-8, fable) also reject the parameter with a 400.

Normalize model_name to lowercase before matching so mixed-case configs
do not fall through.  Add tests for opus-4-8 and fable across adaptive,
enabled, and no-thinking paths, plus a negative test confirming ordinary
models still send temperature.

Fixes #4333
2026-06-14 12:52:07 +08:00
moranandXubin Ren 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
chengyongruandXubin Ren 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
aiguozhi123456andXubin Ren 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
Xubin Ren 62a35c21b8 fix(asr): normalize StepFun transcription endpoint 2026-06-10 15:50:38 +08:00
moranandXubin Ren 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
chengyongruandXubin Ren 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
04cbandXubin Ren a779e7c29e fix(providers): use max_completion_tokens for gpt-5/o-series on flagless specs (#4261) 2026-06-10 14:47:10 +08:00
chengyongruandGitHub 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
comadrejaandXubin Ren 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
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
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-devandXubin Ren 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 RenandGitHub 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
chengyongruandXubin Ren 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
michaelxerandXubin Ren 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
ab9f49970d feat(desktop): polish desktop shell and shared WebUI surfaces (#4195)
* feat(desktop): add native host scaffold

* feat(webui): track turns and usage in gateway

* feat(webui): polish desktop chat experience

* feat(apps): add ArcGIS and Joplin logos

* feat(desktop): polish shell and shared surfaces

* fix(webui): avoid preview chips for glob references

* test: align CI expectations for token fallback

* feat(webui): preview prompt rail entries

* feat(webui): add prompt navigator drawer

* style(webui): refine prompt navigator placement

* style(webui): align prompt navigator with header actions

* style(webui): simplify prompt navigator header

* refactor(webui): clean thread resource refresh

* feat(desktop): add native reply notifications

* fix(webui): preserve desktop restart and replay state

* fix(desktop): harden gateway proxy startup

* fix(web): fall back when readability is unavailable

* fix(desktop): hide window instead of closing on macos

* fix(webui): unify desktop header actions

* fix(webui): simplify prompt history rows

* fix(desktop): log notification delivery failures

* chore(desktop): clean source package artifacts

* fix(cron): support one-time relative reminders

* fix(webui): reveal scroll button in place

* Revert "fix(cron): support one-time relative reminders"

This reverts commit 4c4661da120a3c7283e0768412bae48604e7390b.

* refactor(webui): extract token usage heatmap

* docs(desktop): clarify contributor guides

---------

Co-authored-by: chengyongru <2755839590@qq.com>
2026-06-06 19:49:33 +08:00
Xubin Ren a1b9577224 test(image): cover dropping null OpenAI image params 2026-06-06 19:35:46 +08:00
chengyongruandXubin Ren d435cb0b21 fix: harden custom image provider compatibility
Maintainer edit: preserve provider-specific size hints for custom image generation endpoints while keeping the default 1K mapping compatible. Clarify the custom provider contract in docs and cover response_format/size overrides in tests.
2026-06-05 15:56:03 +08:00
chengyongruandXubin Ren ae17a79bdf fix: harden custom image generation config
Maintainer edit: require providers.custom.apiBase before making custom image requests and allow unauthenticated local endpoints by omitting Authorization when no apiKey is configured.
2026-06-05 15:56:03 +08:00
axelray-devandXubin Ren 748b28da01 feat(image): support custom image generation provider
Addresses #4132.

Add CustomImageGenerationClient for any OpenAI-compatible image generation
API (POST {apiBase}/images/generations). Uses the existing providers.custom
config slot. No schema changes required.

Tests: 54 passed, ruff clean.
Signed-off-by: axelray-dev <110029405+axelray-dev@users.noreply.github.com>
2026-06-05 15:56:03 +08:00
Kunal KarmakarandXubin Ren fa423dffbc Remove check from the test 2026-06-05 01:17:34 +08:00
Kunal KarmakarandXubin Ren c849ff6eec Address PR review comments 2026-06-05 01:17:34 +08:00
Kunal KarmakarandXubin Ren ba3fa38e97 Add support for Azure AAD based Auth 2026-06-05 01:17:34 +08:00
Xubin RenandGitHub 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
chengyongruandXubin Ren b2e43955e3 fix: add regression tests for bare-dict coercion, update stale comment 2026-05-30 15:35:04 +08:00
04cbandXubin Ren 9d3fe7c34b fix(providers): surface clear arrearage warning on quota/billing errors (#3006) 2026-05-29 15:31:17 +08:00
Xubin RenandGitHub 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
hamb1yandXubin Ren 0df60416ba fix(agent): address session and streaming concurrency bugs 2026-05-28 22:54:46 +08:00
yeounhyeokandXubin Ren ac8bef76f6 fix(provider): honor NANOBOT_STREAM_IDLE_TIMEOUT_S in Codex provider
Every other streaming provider (anthropic, bedrock, openai_compat,
litellm) reads NANOBOT_STREAM_IDLE_TIMEOUT_S with a 90s default. The
Codex provider hardcoded 60s in _request_codex, so it could not be
tuned the same way and aborted streams sooner than its peers.

Read the same env var with the same default and pass it as the httpx
client timeout. The variable name and int parsing match anthropic /
openai_compat / bedrock verbatim.

#4009 normalized the error response when the timeout fires; this PR
fixes the timeout knob itself.
2026-05-28 02:17:15 +08:00
EunHyunsuandXubin Ren 18567daaa0 Handle blank Codex transport errors 2026-05-27 03:01:32 +08:00
outlook84andXubin Ren 92f2ff3a33 test: Add test to ensure responses API is used regardless of circuit breaker state 2026-05-25 01:23:36 +08:00
outlook84andXubin Ren c433d60681 feat: Enhance OpenAI provider configuration with extraBody support and apiType validation 2026-05-25 01:23:36 +08:00
outlook84andXubin Ren d472595417 feat: Add OpenAI API type configuration and update provider settings 2026-05-25 01:23:36 +08:00
Yuxin LouandXubin Ren 3f0098839e fix(provider): preserve OpenAI-compatible tool call ids 2026-05-24 20:53:14 +08:00