fix(coach): surface offline hint when network drops mid-stream

This commit is contained in:
Marc-André Bombeck committed 2026-05-21 22:32:02 +02:00
1 parent 13f4880f0c
commit 373515c1f1
8 files changed
+20 -2

No files matched your search

+1
View File
@@ -1064,6 +1064,7 @@
"refusalInjection": "In deiner Nachricht stehen Anweisungen, die meine Vorgaben überschreiben sollen. Ich bin der HealthLog-Coach und fasse ausschließlich deine eigenen Gesundheitsdaten zusammen — formuliere deine Frage bitte in diesem Rahmen neu.",
"errorBudget": "Du hast das heutige Coach-Limit erreicht. Das Budget setzt sich um Mitternacht (UTC) zurück.",
"errorProvider": "Der Coach konnte gerade keinen Auswertungs-Anbieter erreichen. Bitte versuche es in einem Moment erneut.",
"errorNetwork": "Keine Internetverbindung — versuche es erneut, sobald du online bist.",
"tagline": "Persönlicher Gesundheitscoach, auf deine Daten gestützt.",
"newChat": "Neuer Chat",
"send": "Senden",
+1
View File
@@ -1064,6 +1064,7 @@
"refusalInjection": "I noticed wording that tries to override my instructions. I am the HealthLog Coach and only summarise your own health data — please rephrase your question in those terms.",
"errorBudget": "You've reached today's Coach usage limit. The budget refreshes at midnight UTC.",
"errorProvider": "The Coach could not reach an Insights provider just now. Please try again in a moment.",
"errorNetwork": "No internet connection — try again once you're back online.",
"tagline": "Personal health coach, grounded in your data.",
"newChat": "New chat",
"send": "Send",
+1
View File
@@ -1064,6 +1064,7 @@
"refusalInjection": "Tu mensaje contiene instrucciones que pretenden sobrescribir mis indicaciones. Soy el coach de HealthLog y solo resumo tus propios datos de salud — reformula tu pregunta dentro de ese marco.",
"errorBudget": "Has alcanzado el límite diario del coach. El cupo se reinicia a medianoche (UTC).",
"errorProvider": "El coach no ha podido contactar con un proveedor de análisis ahora mismo. Inténtalo en un momento.",
"errorNetwork": "Sin conexión a Internet — inténtalo de nuevo cuando vuelvas a estar en línea.",
"tagline": "Coach personal de salud, apoyado en tus datos.",
"newChat": "Nueva conversación",
"send": "Enviar",
+1
View File
@@ -1064,6 +1064,7 @@
"refusalInjection": "Ton message contient des instructions qui cherchent à remplacer mes consignes. Je suis le coach HealthLog et je ne résume que tes propres données de santé — reformule ta question dans ce cadre.",
"errorBudget": "Tu as atteint la limite quotidienne du coach. Le quota se réinitialise à minuit (UTC).",
"errorProvider": "Le coach n’a pas pu joindre un fournisseur d’analyse maintenant. Réessaie dans un instant.",
"errorNetwork": "Pas de connexion Internet — réessaie une fois reconnecté.",
"tagline": "Coach personnel de santé, ancré sur tes données.",
"newChat": "Nouvelle conversation",
"send": "Envoyer",
+1
View File
@@ -1064,6 +1064,7 @@
"refusalInjection": "Nel tuo messaggio ci sono istruzioni che cercano di sovrascrivere le mie indicazioni. Sono il coach di HealthLog e riassumo solo i tuoi dati di salute — riformula la domanda in questo perimetro.",
"errorBudget": "Hai raggiunto il limite giornaliero del coach. Il budget si reimposta a mezzanotte (UTC).",
"errorProvider": "Il coach non è riuscito a contattare un provider di analisi ora. Riprova fra poco.",
"errorNetwork": "Nessuna connessione Internet — riprova quando sei di nuovo online.",
"tagline": "Coach personale di salute, basato sui tuoi dati.",
"newChat": "Nuova chat",
"send": "Invia",
+1
View File
@@ -1064,6 +1064,7 @@
"refusalInjection": "Twoja wiadomość zawiera instrukcje, które próbują nadpisać moje wytyczne. Jestem coachem HealthLog i podsumowuję wyłącznie twoje własne dane zdrowotne — przeformułuj pytanie w tych ramach.",
"errorBudget": "Osiągnięto dzienny limit coacha. Limit resetuje się o północy (UTC).",
"errorProvider": "Coach nie mógł teraz skontaktować się z dostawcą analizy. Spróbuj za chwilę.",
"errorNetwork": "Brak połączenia z Internetem — spróbuj ponownie, gdy wrócisz online.",
"tagline": "Osobisty coach zdrowia, oparty na twoich danych.",
"newChat": "Nowa rozmowa",
"send": "Wyślij",
@@ -528,13 +528,20 @@ describe("errorCodeToI18nKey", () => {
"coach.provider.unavailable",
"coach.provider.empty",
"coach.provider.none",
"coach.network",
"coach.stream",
]) {
expect(errorCodeToI18nKey(code)).toBe("insights.coach.errorProvider");
}
});
// v1.4.43 QoL (M6) — `coach.network` no longer collapses to the
// generic provider copy; the user needs the actionable offline hint.
it("maps coach.network to the dedicated offline key", () => {
expect(errorCodeToI18nKey("coach.network")).toBe(
"insights.coach.errorNetwork",
);
});
it("forward-compats unknown codes with the namespaced key", () => {
expect(errorCodeToI18nKey("errorProvider")).toBe(
"insights.coach.errorProvider",
@@ -82,10 +82,15 @@ export function errorCodeToI18nKey(code: string): string {
return "insights.coach.dailyLimitBody";
case "coach.provider.rate_limited":
return "insights.coach.providerRateLimitBody";
case "coach.network":
// v1.4.43 QoL (M6) — a dropped network is the user's local
// problem and needs a different next action ("come back online")
// than a provider failure ("try again in a moment"). Split out
// so the user sees the actionable copy in the offline branch.
return "insights.coach.errorNetwork";
case "coach.provider.unavailable":
case "coach.provider.empty":
case "coach.provider.none":
case "coach.network":
case "coach.stream":
return "insights.coach.errorProvider";
default: