* feat: add two-phase startup lifecycle
Allow the dashboard to become available before plugin bootstrap completes and surface runtime readiness and failure states to API callers.
Guard plugin-facing endpoints until runtime is ready and clean up provider and plugin runtime state safely across bootstrap failures, retries, stop, and restart flows.
* fix: harden runtime cleanup review fixes
Continue terminating remaining providers and disable MCP servers even if one provider terminate hook fails.
Also add InitialLoader failure-path coverage and extract guarded plugin routes into a shared constant for easier review and maintenance.
* fix: harden deferred startup recovery
* fix: streamline runtime guard handling
* fix: simplify runtime lifecycle coordination
* fix: restore orchestrator logger binding
The dev branch has astrbot/dashboard/dist as a symlink to
../../dashboard/dist, which is valid in the dev workspace but
becomes a broken symlink when cloned to /opt/astrbot for installation.
Fix the maturin build hook to:
- Remove broken symlinks before creating placeholder directories
- Handle symlink vs directory removal in copy_dashboard_dist()
- Always generate placeholder when dashboard build is skipped or fails
* fix(provider): add missing index field to streaming tool_call deltas
- Fix#6661: Streaming tool_call arguments lost when OpenAI-compatible proxy omits index field
- Gemini and some proxies (e.g. Continue) don't include index field in tool_call deltas
- Add default index=0 when missing to prevent ChatCompletionStreamState.handle_chunk() from rejecting chunks
Fixes#6661
* fix(provider): use enumerate for multi-tool-call index assignment
- Use enumerate() to assign correct index based on list position
- Iterate over all choices (not just the first) for completeness
- Addresses review feedback from sourcery-ai and gemini-code-assist
---------
Co-authored-by: Yaohua-Leo <3067173925@qq.com>
Co-authored-by: Soulter <905617992@qq.com>
Remove msg_id from payload to prevent errors with proactive tool-call path and avoid permission issues.
Co-authored-by: Naer <88199249+V-YOP@users.noreply.github.com>
* fix: auto-append /v1 to embedding_api_base in OpenAI embedding provider (#6855)
When users configure `embedding_api_base` without the `/v1` suffix,
the OpenAI SDK does not auto-complete it, causing request path errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: ensure API base URL for OpenAI embedding ends with /v1 or /v4
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Soulter <905617992@qq.com>
_BUNDLED_DIST may be a symlink pointing to the actual build output.
Using resolve() ensures the path is correctly resolved to the real
directory, allowing the dashboard frontend to load properly when
bundled as a symlink in the dev branch.
The run command should use the original InitialLoader-based startup,
not the new _internal/runtime bootstrap. Only the dev subcommand
uses the new architecture.
When ASTRBOT_BUILD_DASHBOARD is not set, the hatch build hook now
creates an empty target dir with a .placeholder file so the
artifacts glob matches and hatchling does not fail.
When clients disconnect abruptly, hypercorn raises
ssl.SSLError APPLICATION_DATA_AFTER_CLOSE_NOTIFY during SSL shutdown.
This is benign and expected behavior. Wrap serve() with
try/except to suppress these spurious errors.
Previously initialize_runtime_bootstrap() was called at module level,
causing it to run for ALL astrbot CLI commands (conf admin, etc).
Now it only runs when the 'run' command is executed.
The internal ToolSet (base.py) was missing add_tool() and merge()
methods that the agent code expects. When tmgr.get_full_tool_set()
returned a base.py ToolSet, calls to add_tool() and merge() failed.
Added:
- add_tool() as alias to add()
- merge() method to merge another ToolSet
This fixes runtime crash: AttributeError: 'ToolSet' object has no attribute 'add_tool'
- Add _message_count and _last_activity_timestamp to orchestrator
- Add record_activity() method to orchestrator
- Add name field to get_protocol_status returns
- Add total_messages and last_activity to get_stats
- Update tests to verify new fields