fix(cli): reset interrupt timer on eager cancel (#984)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Charles Packer
2026-02-16 16:05:17 -08:00
committed by GitHub
parent 408bb8e81e
commit 2ac0b8b262
2 changed files with 57 additions and 0 deletions

View File

@@ -4809,6 +4809,7 @@ export default function App({
conversationIdRef.current;
userCancelledRef.current = true; // Prevent dequeue
setStreaming(false);
resetTrajectoryBases();
setIsExecutingTool(false);
toolResultsInFlightRef.current = false;
refreshDerived();
@@ -4887,6 +4888,7 @@ export default function App({
// Stop streaming and show error message (unless tool calls were cancelled,
// since the tool result will show "Interrupted by user")
setStreaming(false);
resetTrajectoryBases();
toolResultsInFlightRef.current = false;
if (!toolsCancelled) {
appendError(INTERRUPT_MESSAGE, true);
@@ -4988,6 +4990,7 @@ export default function App({
autoHandledResults,
autoDeniedApprovals,
queueApprovalResults,
resetTrajectoryBases,
]);
// Keep ref to latest processConversation to avoid circular deps in useEffect

View File

@@ -18,4 +18,58 @@ describe("interrupt recovery alert wiring", () => {
"pendingInterruptRecoveryConversationIdRef.current = null;",
);
});
test("resets trajectory bases in tool-interrupt eager-cancel branch", () => {
const appPath = fileURLToPath(
new URL("../../cli/App.tsx", import.meta.url),
);
const source = readFileSync(appPath, "utf-8");
const start = source.indexOf("if (\n isExecutingTool");
const end = source.indexOf("if (!streaming || interruptRequested)");
expect(start).toBeGreaterThan(-1);
expect(end).toBeGreaterThan(start);
const segment = source.slice(start, end);
expect(segment).toContain("setStreaming(false);");
expect(segment).toContain("resetTrajectoryBases();");
});
test("resets trajectory bases in regular eager-cancel branch", () => {
const appPath = fileURLToPath(
new URL("../../cli/App.tsx", import.meta.url),
);
const source = readFileSync(appPath, "utf-8");
const start = source.indexOf("if (EAGER_CANCEL) {");
const end = source.indexOf("} else {\n setInterruptRequested(true);");
expect(start).toBeGreaterThan(-1);
expect(end).toBeGreaterThan(start);
const segment = source.slice(start, end);
expect(segment).toContain("setStreaming(false);");
expect(segment).toContain("resetTrajectoryBases();");
});
test("includes resetTrajectoryBases in handleInterrupt dependency array", () => {
const appPath = fileURLToPath(
new URL("../../cli/App.tsx", import.meta.url),
);
const source = readFileSync(appPath, "utf-8");
const start = source.indexOf(
"const handleInterrupt = useCallback(async () => {",
);
const end = source.indexOf(
"const processConversationRef = useRef(processConversation);",
);
expect(start).toBeGreaterThan(-1);
expect(end).toBeGreaterThan(start);
const segment = source.slice(start, end);
expect(segment).toContain("resetTrajectoryBases,");
});
});