fix: handle mid-stream errors properly using sdk typing (#54)

This commit is contained in:
Charles Packer
2025-11-02 20:36:05 -08:00
committed by GitHub
parent 998f24aaf5
commit f7cea4a830
4 changed files with 36 additions and 26 deletions

View File

@@ -197,26 +197,8 @@ function extractTextPart(v: unknown): string {
export function onChunk(b: Buffers, chunk: LettaStreamingResponse) {
// TODO remove once SDK v1 has proper typing for in-stream errors
// Check for streaming error objects (not typed in SDK but emitted by backend)
// These are emitted when LLM errors occur during streaming (rate limits, timeouts, etc.)
const chunkWithError = chunk as typeof chunk & {
error?: { message?: string; detail?: string };
};
if (chunkWithError.error && !chunk.message_type) {
const errorId = `err-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
const errorMsg = chunkWithError.error.message || "An error occurred";
const errorDetail = chunkWithError.error.detail || "";
const fullErrorText = errorDetail
? `${errorMsg}: ${errorDetail}`
: errorMsg;
b.byId.set(errorId, {
kind: "error",
id: errorId,
text: `${fullErrorText}`,
});
b.order.push(errorId);
return;
}
// Note: Error handling moved to catch blocks in App.tsx and headless.ts
// The SDK now throws APIError when it sees event: error, so chunks never have error property
switch (chunk.message_type) {
case "reasoning_message": {

View File

@@ -117,6 +117,11 @@ export async function drainStream(
stopReason = "error";
}
// Mark incomplete tool calls as cancelled if stream was cancelled
if (stopReason === "cancelled") {
markIncompleteToolsAsCancelled(buffers);
}
// Mark the final line as finished now that stream has ended
markCurrentLineAsFinished(buffers);
queueMicrotask(refresh);