Skip to content

feat(sandbox): wait for Shipyard Neo readiness#7779

Open
RhoninSeiei wants to merge 1 commit intoAstrBotDevs:masterfrom
RhoninSeiei:dev/fix-shipyard-neo-ready
Open

feat(sandbox): wait for Shipyard Neo readiness#7779
RhoninSeiei wants to merge 1 commit intoAstrBotDevs:masterfrom
RhoninSeiei:dev/fix-shipyard-neo-ready

Conversation

@RhoninSeiei
Copy link
Copy Markdown
Contributor

@RhoninSeiei RhoninSeiei commented Apr 24, 2026

Fixes #7777

Modifications / 改动点

本 PR 修复 Shipyard Neo 冷启动期间首次 sandbox 工具调用容易因 httpx.ReadTimeout 返回空 error: 的问题。

  • ShipyardNeoBooter.boot() 中,create_sandbox() 成功后增加 shell 就绪探测,遇到冷启动阶段的临时超时会等待并重试,直到 shell 可执行后再进入后续 skills 同步与工具调用。

  • readiness 等待保留 90 秒总上限,超过上限时抛出包含 sandbox id、profile 和最后错误原因的 TimeoutError,避免长时间无响应。

  • 增加通用异常文本格式化函数,当异常字符串为空时使用异常类型名,例如 ReadTimeoutTimeoutError,避免工具侧只显示空错误。

  • shell、python、Shipyard Neo browser 相关工具复用该异常文本格式化逻辑。

  • 增加单元测试覆盖冷启动第一次超时后重试成功,以及空 TimeoutError 能正确显示异常类型。

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

已执行以下验证:

python -m pytest tests/test_profile_aware_tools.py tests/test_computer_skill_sync.py -q
.......................                                                  [100%]
23 passed in 8.30s
python -m ruff format --check astrbot/core/computer/booters/shipyard_neo.py astrbot/core/tools/computer_tools/util.py astrbot/core/tools/computer_tools/shell.py astrbot/core/tools/computer_tools/python.py astrbot/core/tools/computer_tools/shipyard_neo/browser.py tests/test_profile_aware_tools.py
6 files already formatted
python -m ruff check astrbot/core/computer/booters/shipyard_neo.py astrbot/core/tools/computer_tools/util.py astrbot/core/tools/computer_tools/shell.py astrbot/core/tools/computer_tools/python.py astrbot/core/tools/computer_tools/shipyard_neo/browser.py tests/test_profile_aware_tools.py
All checks passed!

真实 Shipyard Neo 环境验证:冷启动后 readiness 探测先捕获 ReadTimeout,随后第 3 次探测成功,后续 shell 与 python 调用均成功:

[Computer] Waiting for Shipyard Neo sandbox shell readiness: id=sandbox-e4906bdb5926, profile=browser-python, timeout=90s
[Computer] Shipyard Neo sandbox shell not ready yet: id=sandbox-e4906bdb5926, attempt=1, last_error=ReadTimeout
[Computer] Shipyard Neo sandbox shell not ready yet: id=sandbox-e4906bdb5926, attempt=2, last_error=ReadTimeout
[Computer] Shipyard Neo sandbox shell is ready: id=sandbox-e4906bdb5926, attempts=3
{
  "shell": {
    "stdout": "prod14-ready\n/workspace",
    "stderr": "",
    "exit_code": 0,
    "success": true
  },
  "python": {
    "success": true,
    "output": "17",
    "error": ""
  }
}

Checklist / 检查清单

  • 😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
    / 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。

  • 👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
    / 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”

  • 🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
    / 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。

  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

Summary by Sourcery

Add readiness checks for Shipyard Neo sandboxes and improve error reporting for computer tools.

New Features:

  • Add a shell readiness check in ShipyardNeoBooter that waits for the sandbox shell to become executable before proceeding with skill sync and tool usage.

Bug Fixes:

  • Ensure timeouts and other exceptions during sandbox cold start surface meaningful error messages instead of empty error strings in computer tools.

Enhancements:

  • Introduce shared helpers to format exception messages and shell execution results for clearer logs and tool outputs.
  • Log clearer diagnostics and bounded timeout behavior when Shipyard Neo shell readiness is not achieved within a configured window.

Tests:

  • Add async tests covering successful retry after initial shell timeout and timeout reporting that includes the exception type for Shipyard Neo boot readiness.

@auto-assign auto-assign Bot requested review from Soulter and anka-afk April 24, 2026 16:33
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. area:core The bug / feature is about astrbot's core, backend labels Apr 24, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • There are now two very similar helpers for exception formatting (_format_exception_detail in shipyard_neo.py and format_exception_message in computer_tools/util.py); consider consolidating them into a single shared utility to avoid divergence in behavior.
  • In _wait_until_shell_ready you catch a broad Exception from self._shell.exec; if there are known non-retryable error types (e.g., auth or 4xx/5xx errors from the backend), it may be worth distinguishing them to fail fast rather than continuing to poll.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- There are now two very similar helpers for exception formatting (`_format_exception_detail` in `shipyard_neo.py` and `format_exception_message` in `computer_tools/util.py`); consider consolidating them into a single shared utility to avoid divergence in behavior.
- In `_wait_until_shell_ready` you catch a broad `Exception` from `self._shell.exec`; if there are known non-retryable error types (e.g., auth or 4xx/5xx errors from the backend), it may be worth distinguishing them to fail fast rather than continuing to poll.

## Individual Comments

### Comment 1
<location path="astrbot/core/computer/booters/shipyard_neo.py" line_range="39-41" />
<code_context>
     return {}


+def _format_exception_detail(exc: BaseException) -> str:
+    message = str(exc).strip()
+    return message or exc.__class__.__name__
+
+
</code_context>
<issue_to_address>
**suggestion:** Avoid duplicating exception-formatting logic that already exists in `computer_tools.util.format_exception_message`.

This helper duplicates `format_exception_message` in `computer_tools/util.py`. Prefer reusing that utility (or moving this logic there) so exception formatting stays consistent and only needs to be updated in one place.

Suggested implementation:

```python
from astrbot.api import logger
from computer_tools.util import format_exception_message
    return {}

```

1. Remove the `_format_exception_detail` definition from `astrbot/core/computer/booters/shipyard_neo.py`:
   - Delete:

   ```python
   def _format_exception_detail(exc: BaseException) -> str:
       message = str(exc).strip()
       return message or exc.__class__.__name__
   ```

2. Replace any calls to `_format_exception_detail(exc)` in this file with `format_exception_message(exc)`:
   - For example, change:

   ```python
   detail = _format_exception_detail(exc)
   ```

   to:

   ```python
   detail = format_exception_message(exc)
   ```

3. If there are other modules that copied this helper, they should similarly import and use `format_exception_message` from `computer_tools.util` to keep exception formatting consistent project-wide.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +39 to +41
def _format_exception_detail(exc: BaseException) -> str:
message = str(exc).strip()
return message or exc.__class__.__name__
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Avoid duplicating exception-formatting logic that already exists in computer_tools.util.format_exception_message.

This helper duplicates format_exception_message in computer_tools/util.py. Prefer reusing that utility (or moving this logic there) so exception formatting stays consistent and only needs to be updated in one place.

Suggested implementation:

from astrbot.api import logger
from computer_tools.util import format_exception_message
    return {}
  1. Remove the _format_exception_detail definition from astrbot/core/computer/booters/shipyard_neo.py:

    • Delete:
    def _format_exception_detail(exc: BaseException) -> str:
        message = str(exc).strip()
        return message or exc.__class__.__name__
  2. Replace any calls to _format_exception_detail(exc) in this file with format_exception_message(exc):

    • For example, change:
    detail = _format_exception_detail(exc)

    to:

    detail = format_exception_message(exc)
  3. If there are other modules that copied this helper, they should similarly import and use format_exception_message from computer_tools.util to keep exception formatting consistent project-wide.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a shell readiness check for the Shipyard Neo booter, ensuring that the shell is available before proceeding with tool synchronization. It adds utility functions for formatting exception and shell result details, which are now used across various computer tools to provide more informative error messages. Additionally, new unit tests have been added to verify the shell readiness retry logic and timeout behavior. I have no feedback to provide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Shipyard Neo 冷启动期间首次 sandbox 工具调用可能因 ReadTimeout 返回空 error

1 participant