mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-30 05:24:50 +02:00
[eric] subscriptions: confirm active node before Connected (claude+codex), re-check on run-fail, honest copy
(cherry picked from commit 3ce44f314b3b51e48692d5f47df38d5bc43ec0f6)
This commit is contained in:
@@ -23,6 +23,7 @@ import { estimateRenderedTextHeight, oversizedCharThreshold, RECHECK_VISIBILITY_
|
||||
import { THINKING_LABELS } from '../thinkingLabels';
|
||||
import { AgentMessage, retryLastUserMessage } from '@/shared/state/agentsSlice';
|
||||
import { openSettingsModal } from '@/shared/state/settingsSlice';
|
||||
import { fetchSubscriptionStatus } from '@/shared/state/subscriptionsSlice';
|
||||
import { shallowEqual } from 'react-redux';
|
||||
import { useAppDispatch, useAppSelector } from '@/shared/hooks';
|
||||
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
|
||||
@@ -209,8 +210,8 @@ function parseOpenSwarmError(text: string, ctx?: OverflowContext): OpenSwarmErro
|
||||
if (/No active subscription|Subscription canceled|Subscription past_due|Invalid.*token|Missing bearer token/i.test(text)) {
|
||||
return {
|
||||
kind: 'auth',
|
||||
title: 'Subscription issue',
|
||||
detail: "We can't find an active OpenSwarm subscription. Check your billing status.",
|
||||
title: 'Connection needs a refresh',
|
||||
detail: "This model's account isn't active right now. Reconnect it in Settings, or switch to a different model.",
|
||||
ctaLabel: 'Open Settings',
|
||||
ctaAction: 'settings',
|
||||
};
|
||||
@@ -1050,6 +1051,15 @@ const MessageBubble: React.FC<Props> = React.memo(({ message, editing = false, o
|
||||
}
|
||||
}, [message.id, openswarmError?.kind]);
|
||||
|
||||
// A run that failed on a subscription/connection error means the card may be
|
||||
// showing a stale "Connected" (the optimistic mark, or a token that went stale
|
||||
// mid-session); re-pull the real 9Router/cloud status so it flips to Reconnect.
|
||||
React.useEffect(() => {
|
||||
if (openswarmError?.kind === 'auth') {
|
||||
dispatch(fetchSubscriptionStatus());
|
||||
}
|
||||
}, [message.id, openswarmError?.kind, dispatch]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (editing) setEditText(rawText);
|
||||
}, [editing, rawText]);
|
||||
|
||||
@@ -197,9 +197,26 @@ function runAuthCodeFlow(ctx: ConnectCtx) {
|
||||
try { body = await r.json(); } catch {}
|
||||
succeeded = r.ok && !!body?.success;
|
||||
} catch {}
|
||||
// 9Router /providers lags /exchange; an immediate fetchStatus would clobber the UI.
|
||||
if (succeeded) markConnected(providerId);
|
||||
// /providers lags /exchange by a few seconds, so confirm an actually-active
|
||||
// node within a short window instead of trusting bare HTTP success. A handoff
|
||||
// that returns success but never lands a usable node must NOT show "Connected"
|
||||
// (that was the card-says-connected-but-every-run-fails bug); it resets so the
|
||||
// user sees Connect/retry.
|
||||
let confirmed = false;
|
||||
if (succeeded) {
|
||||
for (let i = 0; i < 6 && !confirmed; i++) {
|
||||
try {
|
||||
const sr = await fetch(`${API_BASE}/agents/subscriptions/status`);
|
||||
const sd = await sr.json();
|
||||
const connections = sd.providers?.connections || [];
|
||||
confirmed = connections.some((p: any) => p.provider === providerId && (p.isActive || p.testStatus === 'active'));
|
||||
} catch {}
|
||||
if (!confirmed) await new Promise((r) => setTimeout(r, 1500));
|
||||
}
|
||||
}
|
||||
if (confirmed) markConnected(providerId);
|
||||
setConnecting(null);
|
||||
fetchStatus();
|
||||
refreshPickerModels();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user