Commit Graph

356 Commits

Author SHA1 Message Date
LIghtJUNction
68c01cfba4 Fix handling of cached_tokens in _extract_usage
Ensure cached_tokens is an integer and handle None safely.
2026-03-21 02:37:04 +08:00
LIghtJUNction
1b92c517e7 Merge branch 'master' into dev 2026-03-21 00:31:18 +08:00
Gargantua
dde02815c2 feat: add a toggle to disable thinking mode in Ollama (#5941)
* feat: add ollama thinking toggle

* fix: simplify hint for ollama_disable_thinking configuration

---------

Co-authored-by: Gargantua <22532097@zju.edu.cn>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-21 00:19:08 +08:00
LIghtJUNction
00c9388da3 重构:彻底放弃md5保存密码
main.py调整说明
修复一系列导入问题
修复一部分ruff check问题
2026-03-21 00:09:58 +08:00
LIghtJUNction
7445126057 Merge branch 'master' into dev 2026-03-20 22:40:32 +08:00
RichardLiu
a10ba4d641 feat: add xiaomi MiMo TTS & STT providers (#6643)
* feat: add mimo tts provider support

* fix: handle empty mimo tts choices

* feat: add mimo stt provider support
2026-03-20 20:52:21 +08:00
LIghtJUNction
4f04d39348 同步:同步主线 2026-03-20 16:59:43 +08:00
Soulter
6a42ad7934 fix(openai): improve logging for proxy and API base configuration (#6669)
fix: #6558
2026-03-20 13:42:58 +08:00
daniel5u
b07dbb3d26 feat: add Kimi Coding Plan provider with Anthropic API compatibility (#6559)
* Add Kimi Code provider

* Add icon mapping for Kimi Code provider

* Clarify Kimi CodingPlan provider labeling

* Refine Kimi Code header handling

* modified docker compose

* fix: correct Kimi Coding Plan label and update API base URL

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-20 13:32:06 +08:00
LIghtJUNction
ef5dac77a2 chore: fw2hw 2026-03-20 00:44:08 +08:00
LIghtJUNction
92bae1fdae docs: replace prints with logger in upload_doc_images_to_r2.py 2026-03-19 23:30:25 +08:00
LIghtJUNction
a3371ad6c8 core: refactor modules & fix typing/runtime issues 2026-03-19 23:06:27 +08:00
LIghtJUNction
d16f62423c Merge branch 'master' into dev 2026-03-19 19:25:47 +08:00
Soulter
5a90b56e45 fix(openai): Token usage not working when using MoonshotAI official API (#6618)
fixes: #6614
2026-03-19 19:04:24 +08:00
LIghtJUNction
14ec513b0d fix: clean lint suppressions and async route errors 2026-03-18 18:06:42 +08:00
LIghtJUNction
26d6d1b36f fix: resolve ruff check issues 2026-03-18 17:38:27 +08:00
LIghtJUNction
4bf2f0cb28 fix(dashboard): handle missing static assets gracefully and fix async/ruff issues
- Dashboard: Catch missing index.html error, log warning, and disable WebUI instead of crashing.
- Dashboard: Use anyio.Path for async file existence checks in SSL config.
- CLI/Backup: Replace blocking file operations with anyio async operations.
- Core: Replace blocking file operations with anyio in Coze/Dify clients and TTS simulation.
- Provider: Rename 'timeout' param to 'init_timeout'/'request_timeout' to fix ASYNC109 warnings.
- Ruff: Fix various ASYNC230/ASYNC240 errors across multiple files.
2026-03-18 16:46:22 +08:00
LIghtJUNction
b301ff21f2 feat(cli): enhance run/init/help cmds & service config support 2026-03-18 14:16:25 +08:00
LIghtJUNction
25f9effcc9 Merge branch 'master' into dev 2026-03-17 18:53:46 +08:00
jnMetaCode
dcffb5269a fix: only pass dimensions when explicitly configured in embedding config (#6432)
* fix: only pass dimensions param when explicitly configured

Models like bge-m3 don't support the dimensions parameter in the
embedding API, causing HTTP 400 errors. Previously dimensions was
always sent with a default value of 1024, even when the user never
configured it. Now dimensions is only included in the request when
embedding_dimensions is explicitly set in provider config.

Closes #6421

Signed-off-by: JiangNan <1394485448@qq.com>

* fix: handle invalid dimensions config and align get_dim return

- Add try-except around int() conversion in _embedding_kwargs to
  gracefully handle invalid embedding_dimensions config values
- Update get_dim() to return 0 when embedding_dimensions is not
  explicitly configured, so callers know dimensions weren't specified
  and can handle it accordingly
- Both methods now share consistent logic for reading the config

Signed-off-by: JiangNan <1394485448@qq.com>

* fix: improve logging for invalid embedding_dimensions configuration

---------

Signed-off-by: JiangNan <1394485448@qq.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-17 17:53:03 +08:00
LIghtJUNction
f6321be8c8 sync 2026-03-17 16:51:45 +08:00
Futureppo
c42ac87ee1 feat: Add OpenRouter chat completion provider adapter with custom headers. (#6436) 2026-03-16 19:11:43 +08:00
LIghtJUNction
3f24f82486 Merge branch 'master' into dev 2026-03-16 17:02:15 +08:00
Stable Genius
64e0183b55 fix: drop Groq reasoning_content from assistant history (#6065)
Co-authored-by: Stable Genius <259448942+stablegenius49@users.noreply.github.com>
2026-03-15 22:51:52 +08:00
Yufeng He
d87cf897da Fix TypeError when API returns null choices (#6313)
* Fix CreateSkillPayloadTool array schema missing items field

The payload parameter's anyOf array variant lacked an items field,
causing Gemini API to reject the tool declaration with 400 Bad Request:
'parameters.properties[payload].any_of[1].items: missing field.'

Add items: {type: object} to the array variant to satisfy the Gemini
API requirement for array type schemas.

Fixes #6279

* Fix TypeError when OpenAI-compatible API returns null choices

Some providers (e.g. OpenRouter) may return a completion where
choices is None rather than an empty list — for instance on rate
limiting, content filtering, or transient errors. The existing code
used len(completion.choices) which throws TypeError on None.

Replace all len(...choices) == 0 checks with 'not ... .choices' which
handles both None and empty list. Affects _query_stream, _parse_openai_completion,
and _extract_reasoning_content.

Fixes #6252
2026-03-15 22:28:26 +08:00
Rin
b0e10cf479 fix: add null check for delta in streaming mode to prevent AttributeError when tool calls are returned (#6365) 2026-03-15 22:17:12 +08:00
邹永赫
d7457f38d4 fix: handle webchat image outputs without streaming 2026-03-15 16:15:43 +09:00
eason
86ef758a9a fix: prevent ValueError when removing already-removed API key in retry loop (#6193)
In _handle_api_error(), when a 429 rate-limit is encountered, the code
calls available_api_keys.remove(chosen_key). If the same key was already
removed in a previous retry iteration (e.g. the key rotated back to the
same value), this raises ValueError which crashes the entire LLM request
with an opaque error instead of a proper retry/fallback.

Add a membership check before calling remove() to prevent the crash.

Co-authored-by: easonysliu <easonysliu@tencent.com>
2026-03-14 18:22:14 +08:00
ChuwuYo
66f5ccd902 fix: add file size validation to TTS provider test and MiniMax empty audio detection (#5999)
- Add audio data validation in MiniMax TTS get_audio() method to detect empty responses
- Validate generated audio file size in TTSProvider.test() to ensure valid output
- Provide detailed error messages guiding users to check group_id configuration
- Auto-cleanup test audio files after validation
- Fixes issue where 0KB audio files would pass TTS detection when group_id is not configured
2026-03-11 00:07:19 +08:00
lustresixx
23fffa95c8 fix(provider): support 84-char Azure TTS subscription keys (#5813)
* fix(provider): support 84-char Azure TTS subscription keys

* test(provider): add negative Azure TTS key validation cases

* chore: delete test

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-10 17:09:13 +08:00
Jason
a53a1ca49b fix(provider): handle MiniMax ThinkingBlock when max_tokens reached (#5913)
* fix(provider): handle MiniMax ThinkingBlock when max_tokens reached

Fixes #5912

Problem: MiniMax API returns ThinkingBlock when stop_reason='max_tokens',
but AstrBot throws 'completion 无法解析' exception because both
completion_text and tools_call_args are empty.

Root cause: The validation logic didn't consider ThinkingBlock
(reasoning_content) as valid content.

Fix: When completion_text and tools_call_args are empty but
reasoning_content is present, treat it as valid instead of throwing
exception. This happens when the model thinks but runs out of tokens
before generating the actual response.

Impact: MiniMax models now work correctly when responses are truncated
due to max_tokens limit.

* refactor: address review feedback

1. Use getattr for safe stop_reason access (prevent AttributeError)
2. Use ValueError instead of generic Exception for better error handling

Thanks @gemini-code-assist and @sourcery-ai for the review!

* refactor: flatten nested if/else with guard clause

Address Gemini Code Assist feedback:
- Use guard clause for early return
- Flattened nested conditional for better readability

Logic unchanged, just cleaner code structure.

* fix(provider): improve logging for ThinkingBlock completions in ProviderAnthropic

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-09 00:17:11 +08:00
whatevertogo
3fd6c4c8a6 fix: 修复 asyncio 事件循环相关问题 (#5774)
* fix: 修复 asyncio 事件循环相关的问题

1. components.py: 修复异常处理结构错误
   - 将 except Exception 移到正确的内部 try 块
   - 确保 _download_file() 异常能被正确捕获和记录

2. session_lock.py: 修复跨事件循环 Lock 绑定问题
   - 添加 _access_lock_loop_id 追踪事件循环
   - 当事件循环变化时重新创建 Lock

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 根据代码审查反馈修复问题

1. components.py: 移除 asyncio.set_event_loop() 调用
   - 创建临时 event loop 时不再设置为全局
   - 避免干扰其他 asyncio 使用

2. session_lock.py: 简化延迟初始化逻辑
   - 移除 loop-ID 追踪和 _get_lock 方法
   - 使用 setdefault 简化 session lock 创建
   - 保留延迟初始化行为

3. wecomai_queue_mgr.py: 使用 time.monotonic() 替代 loop.time()
   - 同步方法不再依赖活动的 event loop
   - 避免在非异步上下文中抛出 RuntimeError

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 优化 asyncio 事件循环管理,使用安全的方式创建和关闭事件循环

* fix: 根据代码审查反馈改进异常处理和事件循环使用

- main.py: 显式处理 check_dashboard_files() 返回 None 的情况
- components.py: 使用 logger.exception 保留异常堆栈信息
- star_manager.py: 添加 Future 异常回调处理 __del__ 执行异常
- bay_manager.py: 缓存事件循环引用避免重复调用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 简化 SessionLockManager 使用 defaultdict 和 setdefault

- 使用 defaultdict(asyncio.Lock) 简化锁的懒创建
- 使用 setdefault 简化 _get_loop_state 逻辑
- 减少 get + if 分支,提升可读性

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 降低 webui_dir 检查失败时的日志级别为 warning

改为警告而非退出,允许程序在无 WebUI 的情况下继续运行

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 重构事件循环锁管理,简化锁状态管理逻辑

* 新增对 SessionLockManager 的多事件循环隔离测试

* fix: 修复测试中的变量声明和断言,确保事件循环管理器的正确性

* fix: 修复插件删除时异常处理逻辑,确保正确记录错误信息

* fix: 新增针对多个事件循环的 OneBot 实例的测试,确保锁对象在不同事件循环间不共享

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 01:00:13 +09:00
exynos
69f2fb291a fix: cannot automatically get embedding dim when create embedding provider (#5442)
* fix(dashboard): 强化 API Key 复制临时节点清理逻辑

* fix(embedding): 自动检测改为探测 OpenAI embedding 最大可用维度

* fix: normalize openai embedding base url and add hint key

* i18n: add embedding_api_base hint translations

* i18n: localize provider embedding/proxy metadata hints

* fix: show provider-specific embedding API Base URL hint as field subtitle

* fix(embedding): cap OpenAI detect_dim probes with early short-circuit

* fix(dashboard): return generic error on provider adapter import failure

* 回退检测逻辑
2026-02-25 19:48:03 +08:00
氕氙
c81ef2672a fix: pass embedding dimensions to provider apis (#5411) 2026-02-24 22:09:44 +08:00
Soulter
dbeadb6833 refactor: remove Anthropic OAuth provider implementation and related metadata overrides 2026-02-21 23:40:04 +08:00
Minidoracat
7b302445c2 feat: add Anthropic Claude Code OAuth provider and adaptive thinking support (#5209)
* feat: add Anthropic Claude Code OAuth provider and adaptive thinking support

* fix: add defensive guard for metadata overrides and align budget condition with docs

* refactor: adopt sourcery-ai suggestions for OAuth provider

- Use use_api_key=False in OAuth subclass to avoid redundant
  API-key client construction before replacing with auth_token client
- Generalize metadata override helper to merge all dict keys
  instead of only handling 'limit', improving extensibility
2026-02-21 23:29:15 +08:00
Soulter
a4d37e2c20 chore: ruff format 2026-02-20 23:06:37 +08:00
Soulter
c599fb75ed feat: add OpenRouter provider support and icon 2026-02-20 22:57:20 +08:00
NayukiMeko
b30cb12133 fix(provider): 修复 dict 格式 content 导致的 JSON 残留问题 (#5250)
* fix(provider): 修复 dict 格式 content 导致的 JSON 残留问题

修复 _normalize_content 函数未处理 dict 类型 content 的问题。
当 LLM 返回 {"type": "text", "text": "..."} 格式的 content 时,
现在会正确提取 text 字段而非直接转为字符串。

同时改进 fallback 行为,对 None 值返回空字符串。

Fixes #5244

* Update warning message for unexpected dict format

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-20 13:48:41 +08:00
エイカク
9c691b2266 chore: remove Electron desktop pipeline and switch to tauri repo (#5226)
* ci: remove Electron desktop build from release pipeline

* chore: remove electron desktop and switch to tauri release trigger

* ci: remove desktop workflow dispatch trigger

* refactor: migrate data paths to astrbot_path helpers

* fix: point desktop update prompt to AstrBot-desktop releases
2026-02-19 23:04:18 +09:00
Soulter
0c0f8bf484 chore: ruff format 2026-02-18 18:22:06 +08:00
Soulter
3f4d7255a0 feat: supports aihubmix 2026-02-18 18:11:13 +08:00
NayukiMeko
79e239ad97 fix: handle list format content from OpenAI-compatible APIs (#5128)
* fix: handle list format content from OpenAI-compatible APIs

Some LLM providers (e.g., GLM-4.5V via SiliconFlow) return content as
list[dict] format like [{'type': 'text', 'text': '...'}] instead of
plain string. This causes the raw list representation to be displayed
to users.

Changes:
- Add _normalize_content() helper to extract text from various content formats
- Use json.loads instead of ast.literal_eval for safer parsing
- Add size limit check (8KB) before attempting JSON parsing
- Only convert lists that match OpenAI content-part schema (has 'type': 'text')
  to avoid collapsing legitimate list-literal replies like ['foo', 'bar']
- Add strip parameter to preserve whitespace in streaming chunks
- Clean up orphan </think> tags that may leak from some models

Fixes #5124

* fix: improve content normalization safety

- Try json.loads first, fallback to ast.literal_eval for single-quoted
  Python literals to avoid corrupting apostrophes (e.g., "don't")
- Coerce text values to str to handle null or non-string text fields
2026-02-15 23:30:47 +08:00
エイカク
4ff07e3c74 fix: 完善转发引用解析与图片回退并支持配置化控制 (#5054)
* feat: support fallback image parsing for quoted messages

* fix: fallback parse quoted images when reply chain has placeholders

* style: format network utils with ruff

* test: expand quoted parser coverage and improve fallback diagnostics

* fix: fallback to text-only retry when image requests fail

* fix: tighten image fallback and resolve nested quoted forwards

* refactor: simplify quoted message extraction and dedupe images

* fix: harden quoted parsing and openai error candidates

* fix: harden quoted image ref normalization

* refactor: organize quoted parser settings and logging

* fix: cap quoted fallback images and avoid retry loops

* refactor: split quoted message parser into focused modules

* refactor: share onebot segment parsing logic

* refactor: unify quoted message parsing flow

* feat: move quoted parser tuning to provider settings

* fix: add missing i18n metadata for quoted parser settings

* chore: refine forwarded message setting labels
2026-02-12 23:42:29 +09:00
Soulter
9d93bda3fe feat: temporary file handling and introduce TempDirCleaner (#5026)
* feat: temporary file handling and introduce TempDirCleaner

- Updated various modules to use `get_astrbot_temp_path()` instead of `get_astrbot_data_path()` for temporary file storage.
- Renamed temporary files for better identification and organization.
- Introduced `TempDirCleaner` to manage the size of the temporary directory, ensuring it does not exceed a specified limit by deleting the oldest files.
- Added configuration option for maximum temporary directory size in the dashboard.
- Implemented tests for `TempDirCleaner` to verify cleanup functionality and size management.

* ruff
2026-02-12 01:04:48 +08:00
Dt8333
7dd95d8a59 chore: auto ann fix by ruff (#4903)
* chore: auto fix by ruff

* refactor: 统一修正返回类型注解为 None/bool 以匹配实现

* refactor: 将 _get_next_page 改为异步并移除多余的请求错误抛出

* refactor: 将 get_client 的返回类型改为 object

* style: 为 LarkMessageEvent 的相关方法添加返回类型注解 None

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-09 00:22:24 +08:00
搁浅
30d1d55e3c feat: add provider-souce-level proxy (#4949)
* feat: 添加 Provider 级别代理支持及请求失败日志

* refactor: simplify provider source configuration structure

* refactor: move env proxy fallback logic to log_connection_failure

* refactor: update client proxy handling and add terminate method for cleanup

* refactor: update no_proxy configuration to remove redundant subnet

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-08 12:22:01 +08:00
Dt8333
f3397f6f08 fix: pyright lint (#4874)
* feat: 将 MessageSession 的 platform_id 改为 init=False,实例化时无需传入

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

* refactor: 将 isinstance 检查改为元组、将默认模型值设为空字符串、将类型注解改为 Any 并导入

* refactor: 为 _serialize_job 增加返回类型注解 dict

* fix: 使用 cast 获取百度 AIP 的 msg 并对 psutil_addr 引入 type: ignore

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

* refactor: 引入 _AddrWithPort 协议并替换 conn.laddr 的 cast

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

* fix: 在构建 AstrBotMessage 时对 ctx.channel 可能为 None 进行兜底处理

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

---------

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>
2026-02-05 21:54:12 +08:00
xunxiing
3765dd46f7 fix: gemini toolcall repetition call (#4686)
* 修复gemini toolcall 的名称导致的循环调用

* Apply suggestions from code review

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* Refactor function response creation for tool role

Refactor function response handling for tool role to ensure proper ID injection.

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2026-01-26 17:14:58 +08:00
Soulter
2b2edf4852 fix: genie tts config 2026-01-23 19:00:57 +08:00