fix(relay): handle dead connections and preserve usage on refresh failure

Use received frames for peer liveness and reject new requests after terminal relay failures. Keep authoritative usage snapshots separate from refresh errors, bound request lifetime, and guard concurrent refreshes and runtime switches.

Add regression coverage for relay liveness, terminal rejections, quota failures, cancellation and request deadlines. Validated with 51 focused tests, workspace type-check and lint, web build and mobile assets.
This commit is contained in:
Bohdan Triapitsyn
2026-09-09 17:41:14 +03:00
parent 0841ccdd57
commit cc25e58b55
23 changed files with 414 additions and 88 deletions
@@ -47,6 +47,7 @@ export const UsagePage: React.FC = () => {
const isLoading = useQuotaStore((state) => state.isLoading);
const lastUpdated = useQuotaStore((state) => state.lastUpdated);
const error = useQuotaStore((state) => state.error);
const refreshErrors = useQuotaStore((state) => state.refreshErrors);
const dropdownProviderIds = useQuotaStore((state) => state.dropdownProviderIds);
const setDropdownProviderIds = useQuotaStore((state) => state.setDropdownProviderIds);
const selectedModels = useQuotaStore((state) => state.selectedModels);
@@ -76,9 +77,14 @@ export const UsagePage: React.FC = () => {
const providerMeta = QUOTA_PROVIDERS.find((provider) => provider.id === selectedProviderId);
const providerName = providerMeta?.name ?? selectedProviderId ?? t('settings.usage.sidebar.title');
const usage = selectedResult?.usage;
const selectedProviderError = selectedResult?.configured && !selectedResult.ok
? selectedResult.error
: null;
const refreshError = selectedProviderId ? refreshErrors[selectedProviderId] : undefined;
const selectedProviderError = refreshError
? usage
? t('header.services.usageRefreshFailedStale', { error: refreshError })
: refreshError
: selectedResult?.configured && !selectedResult.ok
? selectedResult.error
: null;
const showInDropdown = selectedProviderId ? dropdownProviderIds.includes(selectedProviderId) : false;
const hasCredentialsForm = selectedProviderId === 'exe-dev' || selectedProviderId === 'ollama-cloud' || selectedProviderId === 'cursor';
const handleDropdownToggle = React.useCallback((enabled: boolean) => {
@@ -190,7 +196,7 @@ export const UsagePage: React.FC = () => {
{(error || selectedProviderError) && (
<div className="mb-8 rounded-lg border border-[var(--status-error-border)] bg-[var(--status-error-background)] px-4 py-3">
<p className="typography-ui-label font-medium text-[var(--status-error)]">{t('settings.usage.page.state.refreshFailedTitle')}</p>
<p className="typography-meta text-[var(--status-error)]/80 mt-1">{error ?? selectedProviderError}</p>
<p className="typography-meta text-[var(--status-error)]/80 mt-1">{selectedProviderError ?? error}</p>
</div>
)}
@@ -98,7 +98,7 @@ export const UsageSidebar: React.FC<UsageSidebarProps> = ({ onItemSelect }) => {
const percent = getUsagePercent(result?.usage);
const tone = resolveUsageTone(percent);
const isSelected = provider.id === selectedProviderId;
const configured = result?.configured ?? false;
const configured = result?.configured;
const statusStyle = !configured
? { backgroundColor: 'var(--surface-muted-foreground)', opacity: 0.4 }
@@ -129,7 +129,7 @@ export const UsageSidebar: React.FC<UsageSidebarProps> = ({ onItemSelect }) => {
<span className="typography-ui-label font-normal truncate flex-1 min-w-0 text-foreground">
{provider.name}
</span>
{!configured && (
{configured === false && (
<span className="typography-micro text-muted-foreground/60 flex-shrink-0">{t('settings.usage.sidebar.status.notSet')}</span>
)}
</button>