From d968df4612ff42eb5286a54b898c80b706994066 Mon Sep 17 00:00:00 2001 From: Phantom Date: Sun, 30 Nov 2025 18:34:56 +0800 Subject: [PATCH] fix(ApiService): properly handle and throw stream errors in API check (#11577) * fix(ApiService): handle stream errors properly in checkApi Ensure stream errors are properly caught and thrown when checking API availability * docs(types): add type safety comment for ResponseError Add FIXME comment highlighting weak type safety in ResponseError type --- src/renderer/src/services/ApiService.ts | 11 +++++------ src/renderer/src/types/newMessage.ts | 1 + 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/services/ApiService.ts b/src/renderer/src/services/ApiService.ts index 1b2bf0433f..d265d5cb48 100644 --- a/src/renderer/src/services/ApiService.ts +++ b/src/renderer/src/services/ApiService.ts @@ -12,7 +12,7 @@ import type { FetchChatCompletionParams } from '@renderer/types' import type { Assistant, MCPServer, MCPTool, Model, Provider } from '@renderer/types' import type { StreamTextParams } from '@renderer/types/aiCoreTypes' import { type Chunk, ChunkType } from '@renderer/types/chunk' -import type { Message } from '@renderer/types/newMessage' +import type { Message, ResponseError } from '@renderer/types/newMessage' import type { SdkModel } from '@renderer/types/sdk' import { removeSpecialCharactersForTopicName, uuid } from '@renderer/utils' import { abortCompletion, readyToAbort } from '@renderer/utils/abortController' @@ -476,7 +476,7 @@ export async function checkApi(provider: Provider, model: Model, timeout = 15000 } else { const abortId = uuid() const signal = readyToAbort(abortId) - let chunkError + let streamError: ResponseError | undefined const params: StreamTextParams = { system: assistant.prompt, prompt: 'hi', @@ -495,19 +495,18 @@ export async function checkApi(provider: Provider, model: Model, timeout = 15000 callType: 'check', onChunk: (chunk: Chunk) => { if (chunk.type === ChunkType.ERROR) { - chunkError = chunk.error + streamError = chunk.error } else { abortCompletion(abortId) } } } - // Try streaming check try { await ai.completions(model.id, params, config) } catch (e) { - if (!isAbortError(e) && !isAbortError(chunkError)) { - throw e + if (!isAbortError(e) && !isAbortError(streamError)) { + throw streamError ?? e } } } diff --git a/src/renderer/src/types/newMessage.ts b/src/renderer/src/types/newMessage.ts index 5ce96e4ec7..ef7179527d 100644 --- a/src/renderer/src/types/newMessage.ts +++ b/src/renderer/src/types/newMessage.ts @@ -234,6 +234,7 @@ export interface Response { error?: ResponseError } +// FIXME: Weak type safety. It may be a specific class instance which inherits Error in runtime. export type ResponseError = Record export interface MessageInputBaseParams {