Repository navigation
feat(core): soft interrupts — steer a running turn without cancelling it (#377, 1/2) - #391
Merged
Merged
Conversation
🔍 Cora AI Code Review✅ No issues found. Code looks good! Review powered by cora-code · BYOK · MIT |
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.
What
Part 1 of 2 of soft interrupts: the core mechanism. Host entry points (serve REST, MCP tool) follow in part 2.
Why
#377. Cancel loses the turn's partial work; the owner needs to steer a running session at a safe point instead.
Changes
interrupt.rs(new): boundedInterruptQueue(16 pending, 8 KiB per message; blank or oversized text is refused, never truncated).cancel.rs: the queue rides on the session'sCancelToken(the per-session turn handle every host already shares), so no signature in the turn API changes and default tokens are unchanged.turn.rs: the loop drains the queue at its safe point (tool settled, next provider call not started) and commits each message as an attributed user-role entry (interrupt: true, attribution in the text). An interrupt that lands while a provider call is in flight supersedes that output before it takes effect: a final answer yields to any pending interrupt, a not-yet-started tool call only to anurgentone. The withdrawn output was never committed, so no intent is written and notool_useis left without itstool_result; a durablesuperseded by owner interrupterror entry records the drop.usage_reportturn stats,tole statusturn count).Design note
The loop issues one tool call per provider step, so there is no batch of remaining tools to skip: "urgent" withdraws the call the model just asked for, before its intent exists. An interrupt arriving after a turn's last safe point waits for the next turn's first.
Testing
Refs #377