-
Welcome to Hermes
+
Let's get you setup with Hermes Agent
Connect a model provider to start chatting. Most options take one click.
@@ -225,8 +235,31 @@ function Header() {
)
}
-function Picker({ ctx }: { ctx: OnboardingContext }) {
+const FEATURED_ID = 'nous'
+const FEATURED_PITCH = 'One subscription, 300+ frontier models — the recommended way to run Hermes'
+const SHOW_ALL_KEY = 'hermes-onboarding-show-all-v1'
+
+const readShowAll = () => {
+ try {
+ return window.localStorage.getItem(SHOW_ALL_KEY) === '1'
+ } catch {
+ return false
+ }
+}
+
+const persistShowAll = (value: boolean) => {
+ try {
+ window.localStorage.setItem(SHOW_ALL_KEY, value ? '1' : '0')
+ } catch {
+ // localStorage unavailable — degrade silently.
+ }
+
+ return value
+}
+
+export function Picker({ ctx }: { ctx: OnboardingContext }) {
const { mode, providers } = useStore($desktopOnboarding)
+ const [showAll, setShowAll] = useState(readShowAll)
const ordered = useMemo(() => (providers ? sortProviders(providers) : []), [providers])
const hasOauth = ordered.length > 0
@@ -234,42 +267,123 @@ function Picker({ ctx }: { ctx: OnboardingContext }) {
return
}
+ if (providers === null) {
+ return
Looking up providers...
+ }
+
+ const select = (p: OAuthProvider) => void startProviderOAuth(p, ctx)
+ const featured = ordered.find(p => p.id === FEATURED_ID) ?? null
+ const rest = featured ? ordered.filter(p => p.id !== FEATURED_ID) : ordered
+ // Collapse the secondary providers behind a disclosure only when Nous
+ // Portal is present to anchor the choice — otherwise show the full list.
+ const collapsible = Boolean(featured) && rest.length > 0
+ const showRest = !collapsible || showAll
+
return (
-
- {providers === null ? (
-
Looking up providers...
- ) : (
- ordered.map(provider => (
-
void startProviderOAuth(p, ctx)} provider={provider} />
- ))
- )}
- setOnboardingMode('apikey')}>I have an API key
+
+ {featured ?
: null}
+ {showRest ? (
+ <>
+ {rest.map(p => (
+
+ ))}
+
setOnboardingMode('apikey')} />
+ >
+ ) : null}
+ {collapsible ? (
+
+ ) : null}
+
+
+
)
}
-function FooterLink({ children, onClick }: { children: React.ReactNode; onClick: () => void }) {
+function FeaturedProviderRow({
+ onSelect,
+ provider
+}: {
+ onSelect: (provider: OAuthProvider) => void
+ provider: OAuthProvider
+}) {
+ const loggedIn = provider.status?.logged_in
+
return (
-
-
-
+
+ )
+}
+
+function ConnectedTag() {
+ return (
+
+
+ Connected
+
+ )
+}
+
+function KeyProviderRow({ onClick }: { onClick: () => void }) {
+ return (
+
)
}
function ProviderRow({ onSelect, provider }: { onSelect: (provider: OAuthProvider) => void; provider: OAuthProvider }) {
const loggedIn = provider.status?.logged_in
- const Trail = provider.flow === 'external' ? ExternalLink : ChevronRight
+ const Trail = provider.flow === 'external' ? Terminal : ChevronRight
return (