Skip to content

Fixes #397: Abort sandbox exec on turn cancellation - #407

Open
rohanmalhotracodes wants to merge 7 commits into
truefoundry:mainfrom
rohanmalhotracodes:fix-sandbox-exec-abort
Open

Fixes #397: Abort sandbox exec on turn cancellation#407
rohanmalhotracodes wants to merge 7 commits into
truefoundry:mainfrom
rohanmalhotracodes:fix-sandbox-exec-abort

Conversation

@rohanmalhotracodes

@rohanmalhotracodes rohanmalhotracodes commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #397

Fixes sandbox turn cancellation so an in-flight sandbox exec can stop promptly when the turn is cancelled, instead of waiting for the command timeout.

sanity check added a video

Screen.Recording.2026-08-22.at.8.07.24.PM.mov

Changes

  • Thread the turn AbortSignal into SandboxOptions and SandboxExecParams.
  • Pass the signal only on the user-facing sandbox exec path, not init, skills, mkdir, uploads, downloads, or general tool execution.
  • Make Daytona abort force-stop the sandbox with sandbox.stop(timeout, true) and avoid recovery/retry of the cancelled command.
  • Make TFY abort the /exec fetch when the turn signal aborts.
  • Make Local abort kill the active exec process tree through the existing killExecTree path without deleting the sandbox root.
  • Add focused coverage for exec signal propagation and TFY fetch abort behavior.
  • Add a changeset for @truefoundry/trueforge-core and @truefoundry/trueforge.

How was this tested?

  • git diff --check
  • pnpm --filter @truefoundry/trueforge-core test -- sandboxBridgeTimeout tfyLayout
  • pnpm --filter @truefoundry/trueforge-core typecheck
  • pnpm --filter @truefoundry/trueforge typecheck
  • pnpm --filter @truefoundry/trueforge test

Checklist

  • I have read the contributing guidelines
  • pnpm build, pnpm test, pnpm typecheck, pnpm lint:ci, and pnpm format:check pass locally
  • Tests added/updated where it makes sense
  • No hand-edits to generated code (packages/trueforge-sdk, .github/fern/openapi/openapi.json, docs/openapi.json) — fork PRs omit SDK regen; maintainers regenerate after merge
  • Docs / .env.example updated if configuration or behavior changed

Acceptance Critera

  • Client cancel during a long sandbox exec ends the turn without a wait for the full exec timeout. This applies to Daytona and Local.

  • After a Daytona cancel, executeWithSandboxRecovery must not start the sandbox and run the same cancelled command again on DaytonaError.

  • After a Daytona / Local stop, the next turn can reuse existingSandboxId. The sandbox starts. The filesystem is available. Any commands run successfully.

  • After a Daytona / Local stop, Code Mode works in the next turn.

  • After a Daytona / Local stop during Code Mode MCP use, the next turn recovers on-disk state without a hard failure.

  • If the mcp_client tools cache {server}.tools.json is corrupt or truncated, the client deletes it and refetches over NATS.

  • freezeTurn with reason cancelled-for-next-turn does not change.


Note

Medium Risk
Changes cancellation and teardown paths across Daytona, TFY, and local sandbox exec; incorrect signal scoping or recovery logic could leave sandboxes stuck or retry cancelled commands.

Overview
Fixes #397 by wiring the turn AbortSignal from turn creation into Sandbox and SandboxExecParams, so cancelling a turn can stop a long-running sandbox exec instead of waiting for the full command timeout.

The signal is passed only on the agent-facing exec tool path (including retry after recreate); sandbox init, skill setup, uploads, and downloads do not receive it. Providers return SANDBOX_EXEC_ABORTED when cancellation wins.

Daytona registers an abort handler that force-stops the sandbox (stop(..., true)), clears the cached SDK handle, and skips executeWithSandboxRecovery retry when the signal is aborted. TFY links the turn signal to the /exec fetch and maps turn-driven AbortError to the aborted result (distinct from timeout). Local kills the supervised process tree via killExecTree without removing the sandbox root, so existingSandboxId stays usable on the next turn.

onSignalAbort now returns a disposer; isSignalAborted is exported. Tests cover signal scoping, TFY fetch abort, Daytona no-recovery-on-abort, and local smoke abort behavior.

Reviewed by Cursor Bugbot for commit b476ce4. Bugbot is set up for automated code reviews on this repo. Configure here.

@changeset-bot

changeset-bot Bot commented Aug 22, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b476ce4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@truefoundry/trueforge-core Patch
@truefoundry/trueforge Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@debajyoti-truefoundry

Copy link
Copy Markdown
Contributor

@rohanmalhotracodes

Thanks for your contribution.

Can you attach a video that showcases

  1. Ask the agent to execute sleep 120.
  2. You click cancel on the UI, and the turn cancels promptly.

Please add a before-and-after video by changing the branch in between.

@chiragjn chiragjn added the core label Aug 24, 2026
@debajyoti-truefoundry

Copy link
Copy Markdown
Contributor

@rohanmalhotracodes

Please also confirm that you have covered all Acceptance Criteria present on #397

Feel free to copy them into this PR description.

@rohanmalhotracodes

Copy link
Copy Markdown
Contributor Author

@rohanmalhotracodes

Thanks for your contribution.

Can you attach a video that showcases

  1. Ask the agent to execute sleep 120.
  2. You click cancel on the UI, and the turn cancels promptly.

Please add a before-and-after video by changing the branch in between.

Before

Screen.Recording.2026-08-24.at.5.33.37.PM.mov

After

Screen.Recording.2026-08-24.at.5.45.34.PM.mov

@thesujai thesujai left a comment

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.

The video you uploaded is not very satisfactory.

For instance - From the video it is not very clear that next turn can be created after the cancellation or not(using the same sandbox, or code mode works etc)

You should test the acceptance criteria mention in the Issue

Comment thread packages/trueforge/src/sandbox/local/core/hostRun.ts Outdated
Comment thread packages/trueforge-core/src/core/sandbox/provider/DaytonaProvider.ts Outdated
@rohanmalhotracodes

Copy link
Copy Markdown
Contributor Author

Added coverage for the

  • Daytona: aborting an exec does not trigger sandbox recovery/restart or retry the cancelled command on DaytonaError.
  • Local: aborting a long exec returns promptly, then the same existingSandboxId can run another command and read the existing filesystem state.

I also reran pnpm smoke:local-sandbox, which passes and covers Local sandbox reuse plus Code Mode UDS behavior.

@thesujai

thesujai commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Just a note: #409 also adds signal to download method

@rohanmalhotracodes

Copy link
Copy Markdown
Contributor Author

Before

Screen.Recording.2026-08-25.at.1.03.35.PM.mov

After

Screen.Recording.2026-08-25.at.1.07.47.PM.mov
Screen.Recording.2026-08-25.at.1.08.14.PM.mov

@debajyoti-truefoundry @thesujai PTAL

@rohanmalhotracodes

Copy link
Copy Markdown
Contributor Author

Thanks for the heads-up. I kept this PR scoped to #397 and only pass the turn abort signal through the sandbox exec path. I did not add/forward the turn signal to downloadFile, since the issue explicitly says to support abort on exec only and not other sandbox operations.

@rohanmalhotracodes

Copy link
Copy Markdown
Contributor Author

sorry to bother here can I get more issues assigned please I cannot see help wanted issues as the newer issues have not yet been approved @govindavashishtha @debajyoti-truefoundry, I have got the chat deletion issue merged so I do have time to work on more

@thesujai

thesujai commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

@thesujai thesujai left a comment

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.

LGTM

@thesujai

Copy link
Copy Markdown
Contributor

This looks good.
Only thing is when cancelling a sandbox when it is initializing(in the first turn), it takes time because we are not passing the cancel signal to the initialization methods, but this is out of scope for this PR, will track that in a followup issue.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stop the sandbox when the cancel API cancels a turn

4 participants