mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
The daily briefing and the per-metric status assessments ignored the per-user response-timeout setting: they hardcoded their per-surface AI_BUDGETS default, so raising the timeout for a slow self-hosted or local backend had no effect and the surfaces still aborted early. Only the coach threaded the setting through. Resolve the effective timeout from User.aiResponseTimeoutSeconds in one shared helper and thread it onto every non-coach generation call: - runStatusCompletion is the single chokepoint every status / reference surface funnels through (per-metric cards, the batched assessment, the derived assessments, the period narratives), so resolving it there applies the setting to all of them at once — on both the upstream call's own timeout and the outer wall-clock cap that previously clipped a raised value at 60 s. - The comprehensive briefing generator and the user-initiated regenerate route thread it onto the main generation, the JSON retry, the grounding retry, and the paragraph re-roll. On a failed generation the briefing keeps its last good text — no cache row is written, so the previous payload stays intact — and records a dated, append-only failure marker (no migration; reuses the audit-log JSON pattern). The read path compares the marker against the last successful generation so it can tell a held briefing from a current one.
26 lines
1.2 KiB
TypeScript
26 lines
1.2 KiB
TypeScript
/**
|
||
* Resolve the upstream provider timeout (ms) for a non-chat generation surface.
|
||
*
|
||
* The per-user `User.aiResponseTimeoutSeconds` setting (Settings → AI) is the
|
||
* operator's lever for slow self-hosted / local backends whose first request
|
||
* loads the model. Coach already threads it onto its provider call; the
|
||
* generated-narrative surfaces (daily briefing, status cards, period
|
||
* narratives, …) historically hardcoded their per-surface `AI_BUDGETS.*`
|
||
* default and ignored the setting, so raising the timeout had no effect on
|
||
* them. This helper is the one place that converts the stored seconds into the
|
||
* milliseconds a `CompletionParams.timeoutMs` expects, falling back to the
|
||
* surface's budget default when the user has not set a value.
|
||
*
|
||
* Semantics mirror Coach: a positive stored value wins (seconds → ms), and any
|
||
* unset / non-positive value yields the surface default. The setting is bounded
|
||
* to 10–600 s at write-time, so no read-time clamp is needed here.
|
||
*/
|
||
export function resolveEffectiveTimeoutMs(
|
||
aiResponseTimeoutSeconds: number | null | undefined,
|
||
budgetDefaultMs: number,
|
||
): number {
|
||
return aiResponseTimeoutSeconds != null && aiResponseTimeoutSeconds > 0
|
||
? aiResponseTimeoutSeconds * 1000
|
||
: budgetDefaultMs;
|
||
}
|