mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
Merge v1.25.3: v1253-briefing-timeout
This commit is contained in:
commit
d3057e4a92
18 files changed
+426
-41
No files matched your search
@@ -36,6 +36,7 @@ import type {
|
||||
DailyBriefingKeyFinding,
|
||||
DailyBriefingSignal,
|
||||
} from "@/lib/ai/schema";
|
||||
import type { BriefingFailureClass } from "@/lib/insights/briefing-failure-marker";
|
||||
|
||||
/**
|
||||
* v1.4.27 MB7 / CF-68 — per-metric routing target for the briefing
|
||||
@@ -127,6 +128,13 @@ interface DailyBriefingProps {
|
||||
* generic empty state for a "couldn't generate" one whose CTA retries.
|
||||
*/
|
||||
generationFailed?: boolean;
|
||||
/**
|
||||
* v1.25.3 — coarse class of the most recent failure. When the empty state is
|
||||
* shown ("couldn't generate"), it lets the hint point at the right lever:
|
||||
* `timeout` → raise the AI response timeout, `auth` → re-check the provider.
|
||||
* Absent / null → the generic failed-description holds.
|
||||
*/
|
||||
generationFailureClass?: BriefingFailureClass | null;
|
||||
/**
|
||||
* Optional slot for a meta control mounted in the card header — the
|
||||
* comparison toggle migrates here from the hero in commit 5.
|
||||
@@ -358,6 +366,7 @@ export function DailyBriefing({
|
||||
noProvider = false,
|
||||
noProviderStale = false,
|
||||
generationFailed = false,
|
||||
generationFailureClass = null,
|
||||
metaSlot,
|
||||
memory = null,
|
||||
}: DailyBriefingProps) {
|
||||
@@ -365,6 +374,20 @@ export function DailyBriefing({
|
||||
const fmt = useFormatters();
|
||||
const { user } = useAuth();
|
||||
|
||||
// v1.25.3 — when there is no last good text and the last attempt failed,
|
||||
// point the hint at the lever that matches the failure class. A timeout (the
|
||||
// dominant failure on a slow self-hosted model) → raise the AI response
|
||||
// timeout; an auth / config rejection → re-check the provider in Settings.
|
||||
// Anything else keeps the calmer generic line. Non-alarming by design.
|
||||
const failedDescriptionKey =
|
||||
generationFailureClass === "timeout"
|
||||
? "insights.dailyBriefing.failedDescriptionTimeout"
|
||||
: generationFailureClass === "auth"
|
||||
? "insights.dailyBriefing.failedDescriptionProvider"
|
||||
: generationFailureClass === "rate-limit"
|
||||
? "insights.dailyBriefing.failedDescriptionRateLimit"
|
||||
: "insights.dailyBriefing.failedDescription";
|
||||
|
||||
return (
|
||||
// v1.13.1 — heading-above-card pattern. The "Tagesbriefing" title
|
||||
// moves OUT of the card into an `<h2>` above it (mirroring the
|
||||
@@ -588,7 +611,7 @@ export function DailyBriefing({
|
||||
}
|
||||
description={
|
||||
generationFailed
|
||||
? t("insights.dailyBriefing.failedDescription")
|
||||
? t(failedDescriptionKey)
|
||||
: t("insights.dailyBriefing.emptyDescription")
|
||||
}
|
||||
action={
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
} from "@/lib/ai/schema";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
import { apiFetchRaw } from "@/lib/api/api-fetch";
|
||||
import type { BriefingFailureClass } from "@/lib/insights/briefing-failure-marker";
|
||||
|
||||
/**
|
||||
* v1.4.16 phase D reconcile (CRITICAL C1 + C2) — shared TanStack Query
|
||||
@@ -80,6 +81,13 @@ export interface InsightAdvisorPayload {
|
||||
* Absent on a pre-field cached payload → treated as "not failed" (no hint).
|
||||
*/
|
||||
generationFailed?: boolean;
|
||||
/**
|
||||
* v1.25.3 — coarse class of the most recent failure (`timeout`, `auth`,
|
||||
* `rate-limit`, `provider`, `format`, `unknown`), so the empty state can
|
||||
* point its hint at the right lever. Null / absent → no specific hint, the
|
||||
* generic failed-description holds.
|
||||
*/
|
||||
generationFailureClass?: BriefingFailureClass | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,8 +107,7 @@ const ADVISOR_TIMEOUT_MS = 8_000;
|
||||
* discarded a slow-but-successful generation — the abort returned a null
|
||||
* payload, the mutation only invalidated (re-reading the OLD cache), yet
|
||||
* the server had often already written the fresh briefing. Give the force
|
||||
* branch the same 45 s budget the out-of-band warm job uses
|
||||
* (`COMPREHENSIVE_WARM_TIMEOUT_MS`) so a slow success is kept, not
|
||||
* branch a generous 45 s client budget so a slow success is kept, not
|
||||
* dropped. The READ path stays fast at 8 s — only the explicit user tap
|
||||
* may wait. Per `.planning/v1.15.18-daily-briefing-audit.md` Fix 1b.
|
||||
*/
|
||||
@@ -291,6 +298,12 @@ export interface UseInsightsAdvisorResult {
|
||||
* when there is no last good text. Defaults false (no hint) when absent.
|
||||
*/
|
||||
generationFailed: boolean;
|
||||
/**
|
||||
* v1.25.3 — coarse class of the most recent failure, so the empty state can
|
||||
* point its hint at the right lever. Null when the last attempt succeeded or
|
||||
* the payload predates the field.
|
||||
*/
|
||||
generationFailureClass: BriefingFailureClass | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -379,5 +392,7 @@ export function useInsightsAdvisorQuery(
|
||||
// Absent (pre-field cached payload or unsettled query) → not failed, so a
|
||||
// transient unknown never flashes a false "couldn't refresh" hint.
|
||||
generationFailed: query.data?.payload?.generationFailed ?? false,
|
||||
// Absent → no specific lever hint; the generic failed-description holds.
|
||||
generationFailureClass: query.data?.payload?.generationFailureClass ?? null,
|
||||
};
|
||||
}
|
||||
@@ -7,7 +7,8 @@
|
||||
* call (`CompletionParams.timeoutMs`). Surfaced here mainly for local /
|
||||
* self-hosted backends: an MLX/exo server can take >60 s on the first request
|
||||
* while it loads the model, which the legacy 60 s default timed out before the
|
||||
* first token landed. Empty = the generous built-in default (~180 s).
|
||||
* first token landed. Empty = the built-in comprehensive-briefing default
|
||||
* (~120 s, `AI_BUDGETS.comprehensive.timeoutMs`).
|
||||
* ──────────────────────────────────────────────────────────────── */
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
Reference in new issue
Block a user