Suspend sandbox execution deadlines while a tool dispatch awaits the host#1437
Merged
Merged
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-marketing | 076edba | Commit Preview URL Branch Preview URL |
Jul 20 2026, 08:34 AM |
Contributor
Cloudflare previewTorn down — the PR is closed. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-cloud | 076edba | Jul 20 2026, 08:35 AM |
@executor-js/cli
@executor-js/config
@executor-js/execution
@executor-js/sdk
@executor-js/codemode-core
@executor-js/runtime-quickjs
@executor-js/plugin-file-secrets
@executor-js/plugin-graphql
@executor-js/plugin-keychain
@executor-js/plugin-mcp
@executor-js/plugin-onepassword
@executor-js/plugin-openapi
executor
commit: |
RhysSullivan
marked this pull request as ready for review
July 20, 2026 09:01
This was referenced Jul 20, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Every sandbox runtime enforced its execution timeout as absolute wall-clock from execution start — including time spent paused for human approval. An approval-gated tool call is an in-flight tool dispatch awaiting the host, so a pause kept burning the 5-minute budget: when it expired mid-wait the fiber settled, the engine dropped the outstanding pause, and an approval granted inside the host's advertised approval window landed on a dead execution (
Execution timed out after 300000ms, thenPaused execution is unknownon retry).Reproduced on production cloud with two chained approval gates: the second approval, granted 1m50s inside its advertised 4-minute window, hit the already-expired sandbox. The first approved step's side effect had committed, so the execution died half-completed. Also reproduced on selfhost (QuickJS's fixed deadline).
The host-side watchdog in
runtime-dynamic-workeralready had the correct accounting: its reference point pins to now while a dispatch is in flight and advances when it returns, so only autonomous sandbox compute counts. This change adopts that same rule in the three sandbox-side timers.Fix
Uniform reference-point rule in all three runtimes — the deadline fires only after
timeoutMsof continuous autonomous compute; time while ≥1 tool dispatch awaits the host doesn't count, and each dispatch return grants a fresh budget:deadlineMs; the interrupt handler, job drain, and deferred waits all read it, and the tool bridge marks dispatch start/return. While a dispatch is in flight the deferred wait runs with no timer (a dispatch's deferred always settles, so this cannot hang).setTimeoutrace becomes a 1s-poll watchdog over in-flight/last-returned state, cleared in afinally. State lives insideevaluate()and the clock starts at evaluate entry.The engine's drop-pauses-on-settle behavior is unchanged — with the timers fixed, a paused execution no longer settles out from under its pause. A wedged sandbox still dies: autonomous compute exceeding the budget times out exactly as before, with the same messages, and cloud's host-side
timeoutMs + gracebackstop is untouched.Tests
tool-invokerdrop-on-settle test to an independently-failing executor fixture (the old fixture relied on QuickJS expiring during a pause — now dead behavior by design); the drop-on-settle assertion is unchanged and now exact-match.resume-after-sandbox-deadline.test.ts: one execution, two chained approval gates; the first approved at ~3.5 min (late in its window), the second at ~5.75 min after start — past the old absolute deadline, inside its own advertised window. Both approvals reach live pauses and both gated tools run. Passes on selfhost and on cloud when booted with a production-like paused-session idle window; skips (with reason) under the suite's default seconds-scale idle-teardown override, which would evict the paused session for unrelated reasons mid-journey.Gates: kernel suites (75/18/16), core/execution (53),
typecheck,lint,format:checkgreen. Changesets: patch for@executor-js/runtime-quickjs(published) and the two private runtimes.