A dropped connection says so, instead of the generic error card
A user's run failed with the wizard's generic "check your Ollama settings" card and could not be replicated with the same key - because the key and model were never the problem: a raw error (a mid-run socket drop, a wifi/LTE switch, the app backgrounded by the phone OS) leaked out of the NDJSON reader as a DOMException, and the wizard can only show the generic card for unknown errors. The reader now classifies everything: abort -> "cancelled", stall -> "the model stopped responding", anything else on the wire -> "the connection dropped mid-run, try again". Pinned with a fetch stub that kills the stream mid-run in the wizard suite (95 checks). Contrast 0 findings, mobile 124/124, chat 101/101, regression 44/44, i18n 13/13, native 33/33. Version 0.4.1, SW -> freezmo-v70.
This commit is contained in:
parent
20bb08b0e7
commit
b70b0e83cf
6 changed files with 71 additions and 15 deletions
|
|
@ -76,21 +76,28 @@ export async function consumeNdjson(
|
|||
};
|
||||
while (true) {
|
||||
let chunk: ReadableStreamReadResult<Uint8Array>;
|
||||
if (stallMs > 0) {
|
||||
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||
const stalled = new Promise<never>((_, reject) => {
|
||||
timer = setTimeout(() => reject(new ApiError(t("api.stalled"), "timeout")), stallMs);
|
||||
});
|
||||
try {
|
||||
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||
try {
|
||||
if (stallMs > 0) {
|
||||
const stalled = new Promise<never>((_, reject) => {
|
||||
timer = setTimeout(() => reject(new ApiError(t("api.stalled"), "timeout")), stallMs);
|
||||
});
|
||||
chunk = await Promise.race([reader.read(), stalled]);
|
||||
} catch (error) {
|
||||
void reader.cancel().catch(() => {});
|
||||
throw error;
|
||||
} finally {
|
||||
if (timer) clearTimeout(timer);
|
||||
} else {
|
||||
chunk = await reader.read();
|
||||
}
|
||||
} else {
|
||||
chunk = await reader.read();
|
||||
} catch (error) {
|
||||
// A connection that dropped mid-run used to leak a raw DOMException, and
|
||||
// the wizard answered with its generic "check your Ollama settings"
|
||||
// card for what was really a network blip. Classify everything here.
|
||||
void reader.cancel().catch(() => {});
|
||||
if (error instanceof ApiError) throw error;
|
||||
if (error instanceof Error && error.name === "AbortError") {
|
||||
throw new ApiError(t("api.cancelled"), "aborted");
|
||||
}
|
||||
throw new ApiError(t("api.streamLost"), "network");
|
||||
} finally {
|
||||
if (timer) clearTimeout(timer);
|
||||
}
|
||||
if (chunk.done) break;
|
||||
buffer += decoder.decode(chunk.value, { stream: true });
|
||||
|
|
|
|||
|
|
@ -721,6 +721,7 @@ const en: Record<string, string> = {
|
|||
"api.httpError": "The server returned HTTP {status}.",
|
||||
"api.empty": "The server sent an empty response.",
|
||||
"api.stalled": "The model stopped responding. Check it and try again.",
|
||||
"api.streamLost": "The connection dropped mid-run. Check your connection and try again.",
|
||||
"api.almost": "Almost there…",
|
||||
"api.noDeck": "No deck came back from the server. Check your Ollama settings and try again.",
|
||||
"api.incomplete": "The server finished without sending a deck.",
|
||||
|
|
@ -1677,6 +1678,7 @@ const cs: Record<string, string> = {
|
|||
"api.httpError": "Server vrátil HTTP {status}.",
|
||||
"api.empty": "Server poslal prázdnou odpověď.",
|
||||
"api.stalled": "Model přestal odpovídat. Zkontrolujte ho a zkuste to znovu.",
|
||||
"api.streamLost": "Připojení se během generování přerušilo. Zkontrolujte připojení a zkuste to znovu.",
|
||||
"api.almost": "Už to bude…",
|
||||
"api.noDeck": "Ze serveru nepřišla žádná sada. Zkontroluj nastavení Ollamy a zkus to znovu.",
|
||||
"api.incomplete": "Server skončil, aniž by poslal sadu.",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue