Skip to content

Add cancellable SDK run controller - #850

Closed
victorxheng wants to merge 7285 commits into
mainfrom
fix/stop-running-cloud-jobs-2026070707
Closed

Add cancellable SDK run controller#850
victorxheng wants to merge 7285 commits into
mainfrom
fix/stop-running-cloud-jobs-2026070707

Conversation

@victorxheng

Copy link
Copy Markdown

User request

A Freebuff cloud user reported that long-running terminal commands or autonomous agent work can get stuck for 20+ minutes, and requested a user-controlled way to terminate the running work.

Implementation

  • Added CodebuffRunController and createRunController() in the SDK.
  • Added CodebuffClient.runCancellable(), which returns { id, controller, signal, result, cancel } for hosts to keep in an in-flight run registry and call from a Stop/Terminate UI or API action.
  • The cancel path composes with any caller-provided AbortSignal, then flows through the existing runtime cancellation path used by LLM streams, subagents, tool execution, and terminal commands.
  • Exported the new controller and CancellableRun type from the SDK entrypoint.
  • Added tests proving cancel() aborts an already-running agent signal and that external caller signals still abort the same run.

Confidence / verification

Ready to merge with high confidence for the SDK/runtime control surface. Verified locally:

  • bun test sdk/src/__tests__/client-cancellable-run.test.ts sdk/src/__tests__/run-cancellation.test.ts
  • cd sdk && bun run typecheck
  • cd sdk && bun run build

Note: this public snapshot does not include the tracked cloud web route/component code for the Stop button itself; this PR provides the production SDK primitive that the cloud host can wire to its stop endpoint/UI without bypassing existing runtime cancellation semantics.

codebuff public sync bot added 30 commits June 25, 2026 18:59
Source: CodebuffAI/freebuff-private@7f1d70af4e776d7ca837d7cb5c4e144a23ddcc35
Source: CodebuffAI/freebuff-private@2a4ce121534d4962c6b1aecf9fb9b0e7db676cbf
Source: CodebuffAI/freebuff-private@e3f83e2a565d9b0f880a0e20e33b8fc3c67874dc
Source: CodebuffAI/freebuff-private@d311d21df4a5c6c6beee5a761d9b3f2e9a41687e
Source: CodebuffAI/freebuff-private@5e5f3fa8a90f5d9fadc5fef83bb4b9bf25aa7b19
Source: CodebuffAI/freebuff-private@db30dde41695e7506515e1a3cd115257128b2087
Source: CodebuffAI/freebuff-private@85fd8a382965b0a6af6a93c4e66a733a5720eabb
Source: CodebuffAI/freebuff-private@32ba6455530dd0e4e7cb84b35d2bdf2882f1ff66
Source: CodebuffAI/freebuff-private@c317c1eddb42a42b2999e81edfbfa0cb863fe797
Source: CodebuffAI/freebuff-private@d66c763e6b432b12597cc95cf927ff8490ae054f
Source: CodebuffAI/freebuff-private@3368e13128b758b628c6923bc8e8865c834391c9
Source: CodebuffAI/freebuff-private@818bb0d9d2b516e746a384c98754b11a873be0c2
Source: CodebuffAI/freebuff-private@c848c2f6ce0a42722b012b007d0c9be8f3933017
Source: CodebuffAI/freebuff-private@824c84eb0adc55779f41cc019b4bf691ec12678d
Source: CodebuffAI/freebuff-private@9a4a6b206b498fb202cd577f15e40d432b93b282
Source: CodebuffAI/freebuff-private@4d935832dfa467d4795da8d0e28e1c43aab03dce
Source: CodebuffAI/freebuff-private@b3bad5da17411f2d5ca51653d9894f8020bc2abb
Source: CodebuffAI/freebuff-private@a190d0d480750846d5f306d4099877c7919c5f82
Source: CodebuffAI/freebuff-private@179f3d4196720acecb35e092156eca05a4ff52b0
Source: CodebuffAI/freebuff-private@b0e1320bae24697b020ad17a5bd013d6d4dfddcd
Source: CodebuffAI/freebuff-private@7b23e5a807dade38436c0a465c9df6e8fb0a855e
Source: CodebuffAI/freebuff-private@728acb920c3b8d689c4a05041a0ad7b80f7c31a6
Source: CodebuffAI/freebuff-private@8565c60947d9d508fbac7cb77940d025061ec594
Source: CodebuffAI/freebuff-private@d69513cebf2af01b54e89eb2fb6f3208966397aa
Source: CodebuffAI/freebuff-private@7582f22e2967b584d392c626ca1214877e6b6bf1
Source: CodebuffAI/freebuff-private@e4121caddf33e6884fb43bd312e5577843597fe3
Source: CodebuffAI/freebuff-private@e5715cf275e056f9c785ae08268c377749466383
Source: CodebuffAI/freebuff-private@39ed4a1dc71e88bcc612c6f1cd1b1a5d500f4f48
Source: CodebuffAI/freebuff-private@abc76d5ca43d3b19b6ffa6128d9e38e3085c7afb
Source: CodebuffAI/freebuff-private@b82cf0008c9b7d85b64751f00a2dc89320add8ac
codebuff public sync bot and others added 24 commits July 6, 2026 06:08
Source: CodebuffAI/freebuff-private@5e536272ee4cb2fedc20afabd21a811dd5762362
Source: CodebuffAI/freebuff-private@a197a4ff94dda8b4640fff2daac358b143ab22d3
Source: CodebuffAI/freebuff-private@3f892919d2b3ed8b094ac58b76014de866dcb53c
Source: CodebuffAI/freebuff-private@74b2c92cd472e9f3a84dcd9d3561c004a768b587
Source: CodebuffAI/freebuff-private@8cf795e3c9e8aa0da338b1627b093382a0feaadc
Source: CodebuffAI/freebuff-private@77458ab0309efd10e18cb01a37328601feb95a88
Source: CodebuffAI/freebuff-private@5646debd58f97075ed7e1d53f9a674d9466a59c7
Source: CodebuffAI/freebuff-private@9e01e7011c9c542d8c85721ec291798a05c24e35
Source: CodebuffAI/freebuff-private@0669c61ade7029dde749db61cc214e8318c4f81b
Source: CodebuffAI/freebuff-private@86cac0782092c1d63e77d466ec41088fe3c97969
Source: CodebuffAI/freebuff-private@705296f9e77fcef899a4bddd8cb3855fb1cee953
Source: CodebuffAI/freebuff-private@1144dfe0f0150febe6bb967de7cd38143f544679
Source: CodebuffAI/freebuff-private@3bd49f9d53f469d83a242737d93a5910b0387109
Source: CodebuffAI/freebuff-private@5bd6c589fe161009af6dfb616486dddb43c20b5a
Source: CodebuffAI/freebuff-private@9e8f0855e648612535468840bd5ed807760005ce
Source: CodebuffAI/freebuff-private@8006d6117836c15c941ba76c85c5caefdb513dd0
Source: CodebuffAI/freebuff-private@38861bf75a94cca0e2cda0170a2647bd91eec46f
Source: CodebuffAI/freebuff-private@b6739ce9b785e2116be5892ba3d4aa911dc0217e
Source: CodebuffAI/freebuff-private@6d15b69643a19f8b2fc880b58f380e3f2f7f0055
Source: CodebuffAI/freebuff-private@08432bee1b090e5d12cb46995196a338d5f78efa
@codebuff-team

ghost commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This is a clean, focused addition to sdk/src/run-controller.ts. A few positives:

  • CodebuffRunController and createRunController() are small, single-purpose primitives that compose naturally with existing AbortSignal-based cancellation already used for LLM streams/subagents/terminal commands (per client.ts's run({ ...options, signal })), rather than introducing a parallel cancellation mechanism.
  • anySignal() correctly handles the 0/1/N signal cases and falls back to manual event listeners when AbortSignal.any isn't available - good defensive coding for older runtimes.
  • The tests in client-cancellable-run.test.ts are solid: one verifies controller.cancel() propagates through to the runtime's signal, the other verifies an externally-supplied signal still aborts the same run and that the controller itself remains uncancelled in that case. Both assert on the resulting RunState.output shape, which matches how this repo already tests cancellation elsewhere.
  • Public API surface (CodebuffClient.runCancellable, exports from index.ts) is minimal and additive - no existing behavior changes.

A couple of things worth double-checking before porting:

  • cancel()'s default reason wraps a string into new Error(reason) - worth confirming downstream consumers (UI, logging) expect an Error here rather than a raw string, since the existing run() signal-abort path may format reasons differently.
  • No changes to SDK docs/README describing the new runCancellable entrypoint - minor, but worth adding given this is a public API addition.

Overall this looks like a real, well-scoped fix for the reported 20+ minute stuck-run problem, and the test coverage gives confidence it behaves correctly under both self-initiated and caller-initiated cancellation.

@codebuff-team codebuff-team added bot:triaged Classified by the community triage bot pr:port-candidate Worth porting into the private source tree labels Aug 20, 2026
@victorxheng
victorxheng force-pushed the fix/stop-running-cloud-jobs-2026070707 branch from 4afa1e7 to fa7d100 Compare August 31, 2026 21:01
@victorxheng

ghost commented Aug 31, 2026

Copy link
Copy Markdown
Author

Apologies — this PR was auto-closed by GitHub when we force-pushed a history rewrite of this repository (repository maintenance; every commit SHA changed). That was not a judgment on this PR, and GitHub does not allow us to reopen it because the commits it was based on no longer exist in the new history.

If you'd like to continue with this change: rebase your branch onto the new main (or recreate it from a fresh clone) and open a new PR — feel free to link back to this one for context, and we'll pick up the review there.

Sorry for the churn, and thanks for contributing.

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

Labels

bot:triaged Classified by the community triage bot pr:port-candidate Worth porting into the private source tree

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants