fix: patch server-side tools showing up as interrupted (#441)

This commit is contained in:
Charles Packer
2025-12-31 17:39:26 -08:00
committed by GitHub
parent 26c7125ee3
commit 8f9eb5eec5
3 changed files with 13 additions and 1 deletions

View File

@@ -807,11 +807,18 @@ export default function App({
// Use a ref to track pending refresh
if (!buffersRef.current.pendingRefresh) {
buffersRef.current.pendingRefresh = true;
// Capture the current generation to detect if resume invalidates this refresh
const capturedGeneration = buffersRef.current.commitGeneration || 0;
setTimeout(() => {
buffersRef.current.pendingRefresh = false;
// Skip refresh if stream was interrupted - prevents stale updates appearing
// after user cancels. Normal stream completion still renders (interrupted=false).
if (!buffersRef.current.interrupted) {
// Also skip if commitGeneration changed - this means a resume is in progress and
// committing now would lock in the stale "Interrupted by user" state.
if (
!buffersRef.current.interrupted &&
(buffersRef.current.commitGeneration || 0) === capturedGeneration
) {
refreshDerived();
}
}, 16); // ~60fps

View File

@@ -72,6 +72,7 @@ export type Buffers = {
lastOtid: string | null; // Track the last otid to detect transitions
pendingRefresh?: boolean; // Track throttled refresh state
interrupted?: boolean; // Track if stream was interrupted by user (skip stale refreshes)
commitGeneration?: number; // Incremented when resuming from error to invalidate pending refreshes
usage: {
promptTokens: number;
completionTokens: number;
@@ -90,6 +91,7 @@ export function createBuffers(): Buffers {
pendingToolByRun: new Map(),
toolCallIdToLineId: new Map(),
lastOtid: null,
commitGeneration: 0,
usage: {
promptTokens: 0,
completionTokens: 0,

View File

@@ -336,6 +336,9 @@ export async function drainStreamWithResume(
// Reset interrupted flag so resumed chunks can be processed by onChunk.
// Without this, tool_return_message for server-side tools (web_search, fetch_webpage)
// would be silently ignored, showing "Interrupted by user" even on successful resume.
// Increment commitGeneration to invalidate any pending setTimeout refreshes that would
// commit the stale "Interrupted by user" state before the resume stream completes.
buffers.commitGeneration = (buffers.commitGeneration || 0) + 1;
buffers.interrupted = false;
// Resume from Redis where we left off