feat: cancel runs that time out, and send the prompt on stdin - #16
Closed
matt-wright-dev wants to merge 1 commit into
Closed
feat: cancel runs that time out, and send the prompt on stdin#16matt-wright-dev wants to merge 1 commit into
matt-wright-dev wants to merge 1 commit into
Conversation
Closes #11. Cancellation - Every `docker run` gets a unique `--name` (agent-gwt-<agent>-<hex>). - runDocker accepts `signal`, `stdin`, and `containerName`; on abort it force-removes the container synchronously (an async removal was cut short by worker teardown when the timed-out test was the last in its worker), kills the client, and rejects with the abort reason. Exit, SIGTERM and SIGINT handlers remove any still-tracked container, then re-raise. - RunAgentOptions gains `signal`; agent({ timeoutMs }) puts a deadline on the context and executing_the_agent aborts the run when it passes, throwing `agent run exceeded <n> ms`. - Under vitest, executing_the_agent also aborts when the test finishes first (its own timeout, a failure elsewhere), so the agent stops working and billing. vitest is loaded dynamically because it is an optional peer; other runners skip this. Prompt on stdin - Both bindings pass the prompt through `docker run -i` on stdin instead of argv. Linux caps one argument at 128 KB; stdin has no limit, and the prompt no longer shows in `ps` on the host. Verified against both CLIs. - buildClaudeDockerArgs / buildDockerArgs take an optional `containerName` instead of `prompt` (they build argv only). Tests - _runProcess.spec: stdin delivery, abort kills the child and rejects, already-aborted signal rejects at once (uses node as the child). - Specs for both bindings assert the name, `-i`, no prompt on argv, and that the runner receives stdin, containerName, and the signal. - executing_the_agent.spec: timeoutMs cancels and reports. - e2e/cancel.spec: against real docker, an aborted run rejects and its container is gone; a 300 KB stdin reaches the container intact. README: cancellation and timeouts section; stdin noted where the run commands are described.
Collaborator
Author
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.
Closes #11.
What changes
Runs can be cancelled, and cancelled runs leave nothing behind.
docker rungets a unique--name.runDockeraccepts anAbortSignal; on abort it force-removes the container, kills the client, and rejects with the reason.agent({ timeoutMs })sets a deadline;executing_the_agentcancels the run when it passes and throwsagent run exceeded <n> ms.executing_the_agentalso cancels when the test finishes first (its own timeout, or a failure elsewhere), so the agent stops working and billing. Vitest is loaded dynamically since it is an optional peer; other runners skip this part.forkspool.The prompt goes to the container on stdin, not argv.
argument list too long. stdin has no limit, and the prompt no longer appears inpson the host.buildClaudeDockerArgs/buildDockerArgsnow take an optionalcontainerNameinstead ofprompt, since they only build argv. Both are exported but undocumented; flagging in case anyone uses them directly.Checks
pnpm run lint && pnpm run test && pnpm run build: clean; 87 tests across 19 files._runProcess(stdin, abort kills and rejects, already-aborted), both bindings (name,-i, no prompt on argv, runner receives stdin/name/signal),executing_the_agent(timeoutMs cancels and reports),agent(timeoutMs on the context).e2e/cancel.spec.tsagainst real Docker: an aborted run rejects anddocker ps -ano longer lists it; a 300 KB stdin reaches the container intact. The existing agent e2e passes for both agents on the stdin path.timeoutMs: 8000is cancelled with the expected message and noagent-gwt-*container remains; the leak itself (only Vitest's test timeout, notimeoutMs) leaves no container behind either, checked immediately and 5 s after the run; prompts of 150 to 240 KB are delivered in full and answered correctly (Cursor in 32 s; Claude sonnet took 8 minutes and about $1.5 on 150 KB, which is the model's doing, not the transport).Notes
timeoutMsoption and a newsignalfield onRunAgentOptions.onTestFinished; it is wrapped so a missing or non-Vitest runtime is silently ignored.