* 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>
* fix: 修改 register_agent 以避免运行时导入 AstrAgentContext
* test: improve register_agent test robustness
- Add fixture for llm_tools cleanup to avoid test interference
- Use multiple import patterns to make guard more robust to refactors
- Add assertion to verify decorated coroutine is wired as handoff handler
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* 删除测试文件: 移除 register_agent 装饰器的运行时行为测试
---------
Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Soulter <905617992@qq.com>
* fix: resolve subagent persona lookup for 'default' and unify resolution logic
- Add PersonaManager.get_persona_v3_by_id() to centralize v3 persona resolution
- Handle 'default' persona_id mapping to DEFAULT_PERSONALITY in subagent orchestrator
- Fix HandoffTool.default_description using agent_name parameter correctly
- Add tests for default persona in subagent config and tool deduplication
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: simplify get_default_persona_v3 using get_persona_v3_by_id
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
There is an issue with reading the skill directory on the Windows system, which results in a high probability of files under the skill directory being unrecognizable, now fix it.
The async engine is created without a busy timeout, so concurrent
writes (agent responses, metrics, session updates) fail instantly
with 'database is locked' instead of waiting for the lock.
Add connect_args={'timeout': 30} for SQLite engines so the driver
waits up to 30 seconds for the write lock. Combined with the existing
WAL journal mode, this handles the typical concurrent write bursts
from agent + metrics + session operations.
Fixes#6443
Fixes#6283
When adding a new embedding provider, the knowledge base creation page
did not show the new provider until restart.
Root cause: create_provider() did not update self.providers_config,
which is used by get_provider_config_list() to return provider lists.
This fix syncs the in-memory config after loading the new provider,
consistent with how reload() handles config updates.
Co-authored-by: ccsang <ccsang@users.noreply.github.com>
* 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
Fixes#6294
QQ official bot receives emoji/sticker messages as raw XML-like tags:
`<faceType=4,faceId="",ext="eyJ0ZXh0IjoiW+a7oeWktOmXruWPt10ifQ==">`
This made the LLM unable to understand the emoji content.
Changes:
- Added `_parse_face_message()` method to parse face message format
- Decode base64 `ext` field to get emoji description text
- Replace face tags with `[表情:描述]` format for readability
Example:
- Input: `<faceType=4,faceId="",ext="eyJ0ZXh0IjoiW+a7oeWktOmXruWPt10ifQ==">`
- Output: `[表情:[满头问号]]`
Co-authored-by: ccsang <ccsang@users.noreply.github.com>
1. Fix missing spaces in cron job wake prompt string concatenation.
Python implicit string concatenation produced:
"...scheduled taskProceed..." and "...conversation.After..."
which sent garbled instructions to the LLM agent, causing unreliable
cron job execution.
2. Replace deprecated datetime.utcnow() with
datetime.now(datetime.timezone.utc) in JWT generation.
utcnow() is deprecated since Python 3.12 and returns naive datetime
which can cause incorrect token expiry on non-UTC systems.
Closes#6103Closes#6165
Co-authored-by: easonysliu <easonysliu@tencent.com>
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>
* fix(qqofficial): fix streaming message delivery for C2C
* fix(qqofficial): rewrite send_streaming for C2C vs non-C2C split
* fix(qqofficial): add _extract_response_message_id for safe id extraction
* fix(qqofficial): flush stream segment on tool-call break signal
* fix(qqofficial): downgrade rich-media to non-stream send in C2C
* fix(qqofficial): auto-append \n to final stream chunk (state=10)
* fix(qqofficial): propagate stream param to all _send_with_markdown_fallback call sites
* fix(qqofficial): retry on STREAM_MARKDOWN_NEWLINE_ERROR with newline fix
* fix(qqofficial): handle None/non-dict response in post_c2c_message gracefully
* fix(qqofficial): remove msg_id from video/file media payloads in send_by_session
QQ API rejects msg_id on proactive media (video/file, msg_type=7) messages
sent via the tool-call path, returning "请求参数msg_id无效或越权". The
msg_id passive-reply credential is consumed by the first send and cannot be
reused for subsequent media uploads in the same session.
Remove msg_id from the payload after setting msg_type=7 for video and file
sends, for both FRIEND_MESSAGE (C2C) and GROUP_MESSAGE paths.
* fix(qqofficial): replace deprecated get_event_loop() with get_running_loop()
asyncio.get_event_loop() is deprecated since Python 3.10 and raises a
DeprecationWarning (or errors) when called from inside a running coroutine
without a current event loop set on the thread. Replace both call-sites
in the streaming throttle logic with asyncio.get_running_loop(), which is
the correct API to use inside an already-running async context.
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
---------
Co-authored-by: 2ndelement <2ndelement@users.noreply.github.com>
Co-authored-by: Claude Sonnet <noreply@anthropic.com>
* feat: add video message support and enhance message type descriptions in SendMessageToUserTool
* feat: add error handling for disabled sandbox runtime in get_booter function
- 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
* feat(extension): add PluginSortControl reusable component for sorting
* i18n: add i18n keys for plugin sorting and filtering features
* feat(extension): add sorting and status filtering for installed plugins
Backend changes (plugin.py):
- Add _resolve_plugin_dir method to resolve plugin directory path
- Add _get_plugin_installed_at method to get installation time from file mtime
- Add installed_at field to plugin API response
Frontend changes (InstalledPluginsTab.vue):
- Import PluginSortControl component
- Add status filter toggle (all/enabled/disabled) using v-btn-toggle
- Integrate PluginSortControl for sorting options
- Add toolbar layout with actions and controls sections
Frontend changes (MarketPluginsTab.vue):
- Import PluginSortControl component
- Replace v-select + v-btn combination with unified PluginSortControl
Frontend changes (useExtensionPage.js):
- Add installedStatusFilter, installedSortBy, installedSortOrder refs
- Add installedSortItems and installedSortUsesOrder computed properties
- Add sortInstalledPlugins function with multi-criteria support
- Support sorting by install time, name, author, and update status
- Add status filtering in filteredPlugins computed property
- Disable default table sorting by setting sortable: false
* test: add tests for installed_at field in plugin API
- Assert all plugins have installed_at field in get_plugins response
- Assert installed_at is not null after plugin installation
* fix(extension): add explicit fallbacks for installed plugin sort comparisons
* i18n(extension): rename install time label to last modified
* fix(extension): cache installed_at parsing and validate timestamp format in tests
* test(dashboard): strengthen installed_at coverage for plugin API