You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ai-isolate-quickjs: let host-side waits (approvals, user input) not count against `timeout
#2121
createQuickJSIsolateDriver({ timeout }) gives each execution one wall-clock deadline. That
deadline bounds two different things at once:
a runaway guest, e.g. while (true) {}, which the interrupt handler must stop; and
time the guest spends awaiting a host binding that is itself waiting on a person: a tool
that needs approval, a form the user fills in, a choice in the chat.
The second kind has no natural bound. With timeout: 60_000, a script that calls an
approval-gated tool is killed with Code execution timed out if the user takes more than a
minute to click Approve, even though the guest has done no work in that minute. Raising timeout to cover a human wait also raises the bound on a runaway loop by the same amount, so
there is no setting that is right for both.
Proposal
An optional clock on the context config that reports how much wall time the host spent
waiting, which the driver subtracts from the deadline:
constdriver=createQuickJSIsolateDriver({timeout: 60_000})constcontext=awaitdriver.createContext({
bindings,// Total ms this context's bindings have spent waiting on a person. Monotonic.waitedMs: ()=>waits.total(),})
Semantics:
The wall deadline becomes start + timeout + waitedMs(), re-read whenever the deadline
timer fires rather than fixed at start, so a wait that begins mid-execution extends it.
A guest job that runs continuously (no await back to the host) still times out at timeout from when it started: waits extend the deadline only while the guest is parked
on a host promise. In our patch this is a separate jobDeadline, reset each time a binding
resolves, and the interrupt handler checks the earlier of the two.
Without waitedMs the behaviour is exactly today's.
A pause/resume pair (context.pauseDeadline() / resumeDeadline()) would serve equally well;
a clock is simpler for hosts that already track wait time across several concurrent
bindings, which is our case.
What we run today
A pnpm patch implementing the clock above against 1.1.0, touching src/isolate-context.ts
(awaitWithDeadline takes a deadline function instead of a number and re-arms its timer;
the cancel grace period subtracts waits) and src/isolate-driver.ts (QuickJSIsolateConfig
gains waitedMs; the interrupt handler checks min(deadline + waitedMs(), jobDeadline)).
It coexists with 1.1.0's signal. Happy to open it as a PR if the API shape works for you.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Problem
createQuickJSIsolateDriver({ timeout })gives each execution one wall-clock deadline. Thatdeadline bounds two different things at once:
while (true) {}, which the interrupt handler must stop; andthat needs approval, a form the user fills in, a choice in the chat.
The second kind has no natural bound. With
timeout: 60_000, a script that calls anapproval-gated tool is killed with
Code execution timed outif the user takes more than aminute to click Approve, even though the guest has done no work in that minute. Raising
timeoutto cover a human wait also raises the bound on a runaway loop by the same amount, sothere is no setting that is right for both.
Proposal
An optional clock on the context config that reports how much wall time the host spent
waiting, which the driver subtracts from the deadline:
Semantics:
start + timeout + waitedMs(), re-read whenever the deadlinetimer fires rather than fixed at start, so a wait that begins mid-execution extends it.
timeoutfrom when it started: waits extend the deadline only while the guest is parkedon a host promise. In our patch this is a separate
jobDeadline, reset each time a bindingresolves, and the interrupt handler checks the earlier of the two.
waitedMsthe behaviour is exactly today's.A pause/resume pair (
context.pauseDeadline()/resumeDeadline()) would serve equally well;a clock is simpler for hosts that already track wait time across several concurrent
bindings, which is our case.
What we run today
A pnpm patch implementing the clock above against 1.1.0, touching
src/isolate-context.ts(
awaitWithDeadlinetakes a deadline function instead of a number and re-arms its timer;the cancel grace period subtracts waits) and
src/isolate-driver.ts(QuickJSIsolateConfiggains
waitedMs; the interrupt handler checksmin(deadline + waitedMs(), jobDeadline)).It coexists with 1.1.0's
signal. Happy to open it as a PR if the API shape works for you.All reactions