fix(server): graceful stream termination on cancellation (issue #847) (#850)

* fix(server): graceful stream termination on cancellation (issue #847)

* Update the code with review suggestion
This commit is contained in:
Willem Jiang
2026-02-06 23:41:23 +08:00
committed by GitHub
parent ec46937384
commit f21bc6b83f
6 changed files with 91 additions and 9 deletions

View File

@@ -84,6 +84,7 @@ export async function* chatStream(
});
for await (const event of stream) {
if (event.data == null) continue;
yield {
type: event.event,
data: JSON.parse(event.data),

View File

@@ -84,10 +84,20 @@ export interface CitationsEvent {
};
}
export interface ErrorEvent {
type: "error";
data: {
thread_id: string;
error: string;
reason?: "cancelled" | string;
};
}
export type ChatEvent =
| MessageChunkEvent
| ToolCallsEvent
| ToolCallChunksEvent
| ToolCallResultEvent
| InterruptEvent
| CitationsEvent;
| CitationsEvent
| ErrorEvent;

View File

@@ -53,7 +53,7 @@ export function mergeMessage(message: Message, event: ChatEvent) {
} else if (event.type === "interrupt") {
mergeInterruptMessage(message, event);
}
if (event.type !== "citations" && event.data.finish_reason) {
if (event.type !== "citations" && event.type !== "error" && event.data.finish_reason) {
message.finishReason = event.data.finish_reason;
message.isStreaming = false;
if (message.toolCalls) {

View File

@@ -155,7 +155,14 @@ export async function sendMessage(
for await (const event of stream) {
const { type, data } = event;
let message: Message | undefined;
if (type === "error") {
// Server sent an error event - check if it's user cancellation
if (data.reason !== "cancelled") {
toast(data.error || "An error occurred while generating the response.");
}
break;
}
// Handle citations event: store citations for the current research
if (type === "citations") {
const ongoingResearchId = useStore.getState().ongoingResearchId;
@@ -207,10 +214,12 @@ export async function sendMessage(
scheduleUpdate();
}
}
} catch {
toast("An error occurred while generating the response. Please try again.");
} catch (error) {
const isAborted = (error as Error).name === "AbortError";
if (!isAborted) {
toast("An error occurred while generating the response. Please try again.");
}
// Update message status.
// TODO: const isAborted = (error as Error).name === "AbortError";
if (messageId != null) {
const message = getMessage(messageId);
if (message?.isStreaming) {