fix: display correct quota values in limit toast (#383)

- Parse JSON error response from server to get actual used/limit values
- Previously showed 0/0 due to race condition (config fetch vs error)
- AI SDK puts full response body in error.message for non-OK responses
- Updated all quota toasts (request, token, TPM) to use server values
This commit is contained in:
Dayuan Jiang
2025-12-23 21:08:21 +09:00
committed by GitHub
parent 72d647de7a
commit b2dfd5b890
2 changed files with 57 additions and 28 deletions

View File

@@ -557,12 +557,32 @@ Continue from EXACTLY where you stopped.`,
}, },
onError: (error) => { onError: (error) => {
// Handle server-side quota limit (429 response) // Handle server-side quota limit (429 response)
// AI SDK puts the full response body in error.message for non-OK responses
try {
const data = JSON.parse(error.message)
if (data.type === "request") {
quotaManager.showQuotaLimitToast(data.used, data.limit)
return
}
if (data.type === "token") {
quotaManager.showTokenLimitToast(data.used, data.limit)
return
}
if (data.type === "tpm") {
quotaManager.showTPMLimitToast(data.limit)
return
}
} catch {
// Not JSON, fall through to string matching for backwards compatibility
}
// Fallback to string matching
if (error.message.includes("Daily request limit")) { if (error.message.includes("Daily request limit")) {
quotaManager.showQuotaLimitToast() quotaManager.showQuotaLimitToast()
return return
} }
if (error.message.includes("Daily token limit")) { if (error.message.includes("Daily token limit")) {
quotaManager.showTokenLimitToast(dailyTokenLimit) quotaManager.showTokenLimitToast()
return return
} }
if ( if (

View File

@@ -18,36 +18,39 @@ export interface QuotaConfig {
* This hook only provides UI feedback when limits are exceeded. * This hook only provides UI feedback when limits are exceeded.
*/ */
export function useQuotaManager(config: QuotaConfig): { export function useQuotaManager(config: QuotaConfig): {
showQuotaLimitToast: () => void showQuotaLimitToast: (used?: number, limit?: number) => void
showTokenLimitToast: (used: number) => void showTokenLimitToast: (used?: number, limit?: number) => void
showTPMLimitToast: () => void showTPMLimitToast: (limit?: number) => void
} { } {
const { dailyRequestLimit, dailyTokenLimit, tpmLimit } = config const { dailyRequestLimit, dailyTokenLimit, tpmLimit } = config
const dict = useDictionary() const dict = useDictionary()
// Show quota limit toast (request-based) // Show quota limit toast (request-based)
const showQuotaLimitToast = useCallback(() => { const showQuotaLimitToast = useCallback(
toast.custom( (used?: number, limit?: number) => {
(t) => ( toast.custom(
<QuotaLimitToast (t) => (
used={dailyRequestLimit} <QuotaLimitToast
limit={dailyRequestLimit} used={used ?? dailyRequestLimit}
onDismiss={() => toast.dismiss(t)} limit={limit ?? dailyRequestLimit}
/> onDismiss={() => toast.dismiss(t)}
), />
{ duration: 15000 }, ),
) { duration: 15000 },
}, [dailyRequestLimit]) )
},
[dailyRequestLimit],
)
// Show token limit toast // Show token limit toast
const showTokenLimitToast = useCallback( const showTokenLimitToast = useCallback(
(used: number) => { (used?: number, limit?: number) => {
toast.custom( toast.custom(
(t) => ( (t) => (
<QuotaLimitToast <QuotaLimitToast
type="token" type="token"
used={used} used={used ?? dailyTokenLimit}
limit={dailyTokenLimit} limit={limit ?? dailyTokenLimit}
onDismiss={() => toast.dismiss(t)} onDismiss={() => toast.dismiss(t)}
/> />
), ),
@@ -58,15 +61,21 @@ export function useQuotaManager(config: QuotaConfig): {
) )
// Show TPM limit toast // Show TPM limit toast
const showTPMLimitToast = useCallback(() => { const showTPMLimitToast = useCallback(
const limitDisplay = (limit?: number) => {
tpmLimit >= 1000 ? `${tpmLimit / 1000}k` : String(tpmLimit) const effectiveLimit = limit ?? tpmLimit
const message = formatMessage(dict.quota.tpmMessageDetailed, { const limitDisplay =
limit: limitDisplay, effectiveLimit >= 1000
seconds: 60, ? `${effectiveLimit / 1000}k`
}) : String(effectiveLimit)
toast.error(message, { duration: 8000 }) const message = formatMessage(dict.quota.tpmMessageDetailed, {
}, [tpmLimit, dict]) limit: limitDisplay,
seconds: 60,
})
toast.error(message, { duration: 8000 })
},
[tpmLimit, dict],
)
return { return {
showQuotaLimitToast, showQuotaLimitToast,