Two changes to make the tool schema sent to the LLM deterministic:
1. ToolSet.normalize() — sort tools by name before serialization.
Called at the end of build_main_agent() after all injection passes.
Eliminates ordering drift from plugin load order, MCP reconnection,
and persona tool list differences.
2. Always inject full sandbox tool set — ComputerToolProvider now
returns get_default_sandbox_tools() unconditionally, regardless of
sandbox boot state. Browser tools are always in the schema even if
the sandbox profile lacks browser capability. The executor rejects
calls to unavailable browser tools with a descriptive error instead
of silently omitting them from the schema.
This eliminates the pre-boot/post-boot tool set jump that caused
prefix cache misses on the second request of a conversation.
- Add get_default_tools/get_tools/get_system_prompt_parts to ComputerBooter base
- Each booter subclass (ShipyardNeo, Shipyard, Boxlite) declares its own tools
- ComputerToolProvider now delegates to booter API via computer_client helpers
- Add unified query API: get_sandbox_tools, get_default_sandbox_tools, etc.
- Extract Neo prompts to dedicated computer/prompts.py module
- Add booter type constants (booters/constants.py)
- Fix subagent tool path to pass sandbox_cfg and session_id
- Fix Sourcery issues: shell injection in send_message, typo in prompts,
internal tools bypass inactivated_llm_tools check
Add explicit Neo lifecycle instructions to the main agent prompt so
skill creation and updates follow payload -> candidate -> promotion
instead of direct local folder writes.
Clarify lifecycle tool descriptions and parameter semantics, including
skill_key/source_execution_ids usage and stable release sync_to_local
behavior, to reduce ambiguity and improve consistent skill publishing.
- Resolve skills root via Path.resolve() so LLM prompts always
reference absolute paths regardless of sandbox cwd
- Use resolved path in skill metadata for reliable cat/head commands
- Add DRY cross-reference comment for frontmatter parser
- Remove dead skills_root_abs field from JSON output (no consumer)
- Remove unnecessary os import and fake resolve/abspath branch
Add capabilities property to ComputerBooter base class (returns None)
and ShipyardNeoBooter (returns immutable tuple from sandbox).
- Extract DEFAULT_PROFILE class constant to replace scattered magic string
- Use tuple[str, ...] for immutability (no defensive copy needed)
- Add _resolve_profile() for smart profile selection:
- honour user-specified profile
- query Bay API, prefer browser-capable profiles
- re-raise auth errors (401/403), fallback on transient failures
- Conditionally create NeoBrowserComponent only when profile has browser
- Log resolved profile and capabilities at boot
Add BayContainerManager to manage Bay container lifecycle via Docker
Engine API, similar to how BoxliteBooter manages Ship containers.
When ShipyardNeoBooter endpoint is empty or set to '__auto__', Bay is
automatically pulled, started, health-checked, and credentials are
read from the container.
- New bay_manager.py: ensure_running, wait_healthy, read_credentials
- Integrate auto-start into ShipyardNeoBooter boot/shutdown
- Reuse Bay container across sessions (unless-stopped policy)
- Friendly error messages for Docker and credential failures
separate sandbox skill syncing into distinct apply and scan steps
while keeping the legacy combined command for compatibility
improve observability by adding phase-based logs and richer shell
error details that include exit code, stderr, and stdout tail
reuse a shared python-exec command builder to reduce duplication
and keep command generation consistent
extract shared promote/sync orchestration into `NeoSkillSyncManager` so
computer tools and dashboard routes use the same rollback and error logic
add a reusable neo tool base runner to remove duplicated admin checks and
try/catch handling across skill-related tools, keeping responses consistent
factor sync result serialization into a single helper and reuse it where
stable release sync output is returned
set the base booter browser property to return None instead of
raising NotImplementedError so callers can handle missing browser
support through capability checks
When shipyard_neo_access_token is not configured, _discover_bay_credentials()
searches for Bay's credentials.json in:
1. BAY_DATA_DIR env var
2. Mono-repo relative path ../pkgs/bay/
3. Current working directory
Enables zero-config dev mode when Bay runs locally alongside AstrBot.
* 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
* feat: support anthropic skills
closes: #4687
* chore: ruff
* feat: implement skills management and selection in persona configuration
* feat: enhance skills management with local environment tools and permissions