From 0c906a329bb31d5b7f61fa5b2f06c77aa0d00557 Mon Sep 17 00:00:00 2001 From: Alex Yaroshuk Date: Sun, 15 Feb 2026 04:56:57 +0800 Subject: [PATCH] feat(app): add localized FreeUsageLimitError handling with "Add credits" link --- packages/ui/src/components/session-turn.css | 6 ++++++ packages/ui/src/components/session-turn.tsx | 19 ++++++++++++++++++- packages/ui/src/i18n/ar.ts | 2 ++ packages/ui/src/i18n/br.ts | 2 ++ packages/ui/src/i18n/bs.ts | 2 ++ packages/ui/src/i18n/da.ts | 2 ++ packages/ui/src/i18n/de.ts | 2 ++ packages/ui/src/i18n/en.ts | 2 ++ packages/ui/src/i18n/es.ts | 2 ++ packages/ui/src/i18n/fr.ts | 2 ++ packages/ui/src/i18n/ja.ts | 2 ++ packages/ui/src/i18n/ko.ts | 2 ++ packages/ui/src/i18n/no.ts | 2 ++ packages/ui/src/i18n/pl.ts | 2 ++ packages/ui/src/i18n/ru.ts | 2 ++ packages/ui/src/i18n/th.ts | 2 ++ packages/ui/src/i18n/zh.ts | 2 ++ packages/ui/src/i18n/zht.ts | 2 ++ 18 files changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/components/session-turn.css b/packages/ui/src/components/session-turn.css index 9887ce2fc6a2..414e8a359009 100644 --- a/packages/ui/src/components/session-turn.css +++ b/packages/ui/src/components/session-turn.css @@ -560,6 +560,12 @@ overflow-y: auto; } + .retry-error-link, + .error-card-link { + color: var(--text-strong); + text-decoration: underline; + } + [data-slot="session-turn-collapsible-content-inner"] { width: 100%; min-width: 0; diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index 9ffa671e6985..c03622105916 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -436,6 +436,11 @@ export function SessionTurn( if (s.type !== "retry") return return s }) + const isRetryFreeUsageLimitError = createMemo(() => { + const r = retry() + if (!r) return false + return r.message.includes("Free usage exceeded") + }) const response = createMemo(() => lastTextPart()?.text) const responsePartId = createMemo(() => lastTextPart()?.id) @@ -691,10 +696,22 @@ export function SessionTurn( {(() => { const r = retry() if (!r) return "" - const msg = unwrap(r.message) + const msg = isRetryFreeUsageLimitError() + ? i18n.t("ui.sessionTurn.error.freeUsageExceeded") + : unwrap(r.message) return msg.length > 60 ? msg.slice(0, 60) + "..." : msg })()} + + + {i18n.t("ui.sessionTurn.error.addCredits")} + + · {i18n.t("ui.sessionTurn.retry.retrying")} {store.retrySeconds > 0 diff --git a/packages/ui/src/i18n/ar.ts b/packages/ui/src/i18n/ar.ts index 9a6c8dcbd050..4a1525d468c0 100644 --- a/packages/ui/src/i18n/ar.ts +++ b/packages/ui/src/i18n/ar.ts @@ -28,6 +28,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "إعادة المحاولة", "ui.sessionTurn.retry.inSeconds": "خلال {{seconds}} ثواني", + "ui.sessionTurn.error.freeUsageExceeded": "تم تجاوز حد الاستخدام المجاني", + "ui.sessionTurn.error.addCredits": "إضافة رصيد", "ui.sessionTurn.status.delegating": "تفويض العمل", "ui.sessionTurn.status.planning": "تخطيط الخطوات التالية", diff --git a/packages/ui/src/i18n/br.ts b/packages/ui/src/i18n/br.ts index 148b0ae17419..160d07aee217 100644 --- a/packages/ui/src/i18n/br.ts +++ b/packages/ui/src/i18n/br.ts @@ -28,6 +28,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "tentando novamente", "ui.sessionTurn.retry.inSeconds": "em {{seconds}}s", + "ui.sessionTurn.error.freeUsageExceeded": "Limite de uso gratuito excedido", + "ui.sessionTurn.error.addCredits": "Adicionar créditos", "ui.sessionTurn.status.delegating": "Delegando trabalho", "ui.sessionTurn.status.planning": "Planejando próximos passos", diff --git a/packages/ui/src/i18n/bs.ts b/packages/ui/src/i18n/bs.ts index 7614af087f90..9a049c14bc75 100644 --- a/packages/ui/src/i18n/bs.ts +++ b/packages/ui/src/i18n/bs.ts @@ -32,6 +32,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "ponovni pokušaj", "ui.sessionTurn.retry.inSeconds": "za {{seconds}}s", + "ui.sessionTurn.error.freeUsageExceeded": "Besplatna upotreba premašena", + "ui.sessionTurn.error.addCredits": "Dodaj kredite", "ui.sessionTurn.status.delegating": "Delegiranje posla", "ui.sessionTurn.status.planning": "Planiranje sljedećih koraka", diff --git a/packages/ui/src/i18n/da.ts b/packages/ui/src/i18n/da.ts index 2f49a94344cf..de0e854be9e7 100644 --- a/packages/ui/src/i18n/da.ts +++ b/packages/ui/src/i18n/da.ts @@ -27,6 +27,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "prøver igen", "ui.sessionTurn.retry.inSeconds": "om {{seconds}}s", + "ui.sessionTurn.error.freeUsageExceeded": "Gratis forbrug overskredet", + "ui.sessionTurn.error.addCredits": "Tilføj kreditter", "ui.sessionTurn.status.delegating": "Delegerer arbejde", "ui.sessionTurn.status.planning": "Planlægger næste trin", diff --git a/packages/ui/src/i18n/de.ts b/packages/ui/src/i18n/de.ts index 44090b7bdb8c..977065db4c88 100644 --- a/packages/ui/src/i18n/de.ts +++ b/packages/ui/src/i18n/de.ts @@ -31,6 +31,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "erneuter Versuch", "ui.sessionTurn.retry.inSeconds": "in {{seconds}}s", + "ui.sessionTurn.error.freeUsageExceeded": "Kostenloses Nutzungslimit überschritten", + "ui.sessionTurn.error.addCredits": "Guthaben aufladen", "ui.sessionTurn.status.delegating": "Arbeit delegieren", "ui.sessionTurn.status.planning": "Nächste Schritte planen", diff --git a/packages/ui/src/i18n/en.ts b/packages/ui/src/i18n/en.ts index 9b6ab0bd6d9e..59f08e48d399 100644 --- a/packages/ui/src/i18n/en.ts +++ b/packages/ui/src/i18n/en.ts @@ -28,6 +28,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "retrying", "ui.sessionTurn.retry.inSeconds": "in {{seconds}}s", + "ui.sessionTurn.error.freeUsageExceeded": "Free usage exceeded", + "ui.sessionTurn.error.addCredits": "Add credits", "ui.sessionTurn.status.delegating": "Delegating work", "ui.sessionTurn.status.planning": "Planning next steps", diff --git a/packages/ui/src/i18n/es.ts b/packages/ui/src/i18n/es.ts index c2f8ac3b9d5c..6706515ecb38 100644 --- a/packages/ui/src/i18n/es.ts +++ b/packages/ui/src/i18n/es.ts @@ -28,6 +28,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "reintentando", "ui.sessionTurn.retry.inSeconds": "en {{seconds}}s", + "ui.sessionTurn.error.freeUsageExceeded": "Límite de uso gratuito excedido", + "ui.sessionTurn.error.addCredits": "Añadir créditos", "ui.sessionTurn.status.delegating": "Delegando trabajo", "ui.sessionTurn.status.planning": "Planificando siguientes pasos", diff --git a/packages/ui/src/i18n/fr.ts b/packages/ui/src/i18n/fr.ts index 679d56fa76ff..68a687e840f4 100644 --- a/packages/ui/src/i18n/fr.ts +++ b/packages/ui/src/i18n/fr.ts @@ -28,6 +28,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "nouvelle tentative", "ui.sessionTurn.retry.inSeconds": "dans {{seconds}}s", + "ui.sessionTurn.error.freeUsageExceeded": "Limite d'utilisation gratuite dépassée", + "ui.sessionTurn.error.addCredits": "Ajouter des crédits", "ui.sessionTurn.status.delegating": "Délégation du travail", "ui.sessionTurn.status.planning": "Planification des prochaines étapes", diff --git a/packages/ui/src/i18n/ja.ts b/packages/ui/src/i18n/ja.ts index bf85807d0052..6fff28cff435 100644 --- a/packages/ui/src/i18n/ja.ts +++ b/packages/ui/src/i18n/ja.ts @@ -27,6 +27,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "再試行中", "ui.sessionTurn.retry.inSeconds": "{{seconds}}秒後", + "ui.sessionTurn.error.freeUsageExceeded": "無料使用制限に達しました", + "ui.sessionTurn.error.addCredits": "クレジットを追加", "ui.sessionTurn.status.delegating": "作業を委任中", "ui.sessionTurn.status.planning": "次のステップを計画中", diff --git a/packages/ui/src/i18n/ko.ts b/packages/ui/src/i18n/ko.ts index aba793a11b8d..6fac1590d794 100644 --- a/packages/ui/src/i18n/ko.ts +++ b/packages/ui/src/i18n/ko.ts @@ -28,6 +28,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "재시도 중", "ui.sessionTurn.retry.inSeconds": "{{seconds}}초 후", + "ui.sessionTurn.error.freeUsageExceeded": "무료 사용량 초과", + "ui.sessionTurn.error.addCredits": "크레딧 추가", "ui.sessionTurn.status.delegating": "작업 위임 중", "ui.sessionTurn.status.planning": "다음 단계 계획 중", diff --git a/packages/ui/src/i18n/no.ts b/packages/ui/src/i18n/no.ts index 7982b3ac75ed..160f26a5468a 100644 --- a/packages/ui/src/i18n/no.ts +++ b/packages/ui/src/i18n/no.ts @@ -31,6 +31,8 @@ export const dict: Record = { "ui.sessionTurn.retry.retrying": "Prøver igjen", "ui.sessionTurn.retry.inSeconds": "om {{seconds}}s", + "ui.sessionTurn.error.freeUsageExceeded": "Gratis bruk overskredet", + "ui.sessionTurn.error.addCredits": "Legg til kreditt", "ui.sessionTurn.status.delegating": "Delegerer arbeid", "ui.sessionTurn.status.planning": "Planlegger neste trinn", diff --git a/packages/ui/src/i18n/pl.ts b/packages/ui/src/i18n/pl.ts index 2489ac7f2ee4..4882ba034849 100644 --- a/packages/ui/src/i18n/pl.ts +++ b/packages/ui/src/i18n/pl.ts @@ -27,6 +27,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "ponawianie", "ui.sessionTurn.retry.inSeconds": "za {{seconds}}s", + "ui.sessionTurn.error.freeUsageExceeded": "Przekroczono limit darmowego użytkowania", + "ui.sessionTurn.error.addCredits": "Dodaj kredyty", "ui.sessionTurn.status.delegating": "Delegowanie pracy", "ui.sessionTurn.status.planning": "Planowanie kolejnych kroków", diff --git a/packages/ui/src/i18n/ru.ts b/packages/ui/src/i18n/ru.ts index 8e6bb678f249..93a9883d26a7 100644 --- a/packages/ui/src/i18n/ru.ts +++ b/packages/ui/src/i18n/ru.ts @@ -27,6 +27,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "повтор", "ui.sessionTurn.retry.inSeconds": "через {{seconds}}с", + "ui.sessionTurn.error.freeUsageExceeded": "Лимит бесплатного использования превышен", + "ui.sessionTurn.error.addCredits": "Добавить кредиты", "ui.sessionTurn.status.delegating": "Делегирование работы", "ui.sessionTurn.status.planning": "Планирование следующих шагов", diff --git a/packages/ui/src/i18n/th.ts b/packages/ui/src/i18n/th.ts index b036eca2e8ae..1a5438a2ae85 100644 --- a/packages/ui/src/i18n/th.ts +++ b/packages/ui/src/i18n/th.ts @@ -28,6 +28,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "กำลังลองใหม่", "ui.sessionTurn.retry.inSeconds": "ใน {{seconds}}วิ", + "ui.sessionTurn.error.freeUsageExceeded": "เกินขีดจำกัดการใช้งานฟรี", + "ui.sessionTurn.error.addCredits": "เพิ่มเครดิต", "ui.sessionTurn.status.delegating": "มอบหมายงาน", "ui.sessionTurn.status.planning": "วางแผนขั้นตอนถัดไป", diff --git a/packages/ui/src/i18n/zh.ts b/packages/ui/src/i18n/zh.ts index dcb8062a3365..dbebfb3f9f01 100644 --- a/packages/ui/src/i18n/zh.ts +++ b/packages/ui/src/i18n/zh.ts @@ -32,6 +32,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "重试中", "ui.sessionTurn.retry.inSeconds": "{{seconds}} 秒后", + "ui.sessionTurn.error.freeUsageExceeded": "免费使用额度已用完", + "ui.sessionTurn.error.addCredits": "添加积分", "ui.sessionTurn.status.delegating": "正在委派工作", "ui.sessionTurn.status.planning": "正在规划下一步", diff --git a/packages/ui/src/i18n/zht.ts b/packages/ui/src/i18n/zht.ts index 271a6ded3253..5cec9c399ef2 100644 --- a/packages/ui/src/i18n/zht.ts +++ b/packages/ui/src/i18n/zht.ts @@ -32,6 +32,8 @@ export const dict = { "ui.sessionTurn.retry.retrying": "重試中", "ui.sessionTurn.retry.inSeconds": "{{seconds}} 秒後", + "ui.sessionTurn.error.freeUsageExceeded": "免費使用額度已用完", + "ui.sessionTurn.error.addCredits": "新增點數", "ui.sessionTurn.status.delegating": "正在委派工作", "ui.sessionTurn.status.planning": "正在規劃下一步",