feat(setup): add recommendation badges to tool provider selection (#9929)

New users don't know which tool providers to pick during setup.
Add [badge] labels to each provider in the selection menu:

  - [★ recommended · free] for best default choices (Edge TTS, Local Browser)
  - [★ recommended] for top-tier paid options (Firecrawl Cloud)
  - [paid] for options requiring an API key
  - [free tier] for services with a free tier (Tavily)
  - [free · self-hosted] / [free · local] for self-run options
  - [subscription] for Nous subscription-managed options

Also improves vague tag descriptions — e.g. 'AI-native search and
contents' becomes 'Neural search with semantic understanding' and
Tavily gets '1000 free searches/mo'.

Both hermes setup and hermes tools share the same rendering path,
so badges appear in both flows.

Addresses user feedback about setup being confusing for newcomers.
fix/verification-admin-route-recovery
Teknium 2026-04-14 16:58:10 -07:00 committed by GitHub
parent e7475b1582
commit a9c78d0eb0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 37 additions and 16 deletions

View File

@ -121,6 +121,7 @@ TOOL_CATEGORIES = {
"providers": [
{
"name": "Nous Subscription",
"badge": "subscription",
"tag": "Managed OpenAI TTS billed to your subscription",
"env_vars": [],
"tts_provider": "openai",
@ -130,13 +131,15 @@ TOOL_CATEGORIES = {
},
{
"name": "Microsoft Edge TTS",
"tag": "Free - no API key needed",
"badge": "★ recommended · free",
"tag": "Good quality, no API key needed",
"env_vars": [],
"tts_provider": "edge",
},
{
"name": "OpenAI TTS",
"tag": "Premium - high quality voices",
"badge": "paid",
"tag": "High quality voices",
"env_vars": [
{"key": "VOICE_TOOLS_OPENAI_KEY", "prompt": "OpenAI API key", "url": "https://platform.openai.com/api-keys"},
],
@ -144,7 +147,8 @@ TOOL_CATEGORIES = {
},
{
"name": "ElevenLabs",
"tag": "Premium - most natural voices",
"badge": "paid",
"tag": "Most natural voices",
"env_vars": [
{"key": "ELEVENLABS_API_KEY", "prompt": "ElevenLabs API key", "url": "https://elevenlabs.io/app/settings/api-keys"},
],
@ -152,7 +156,8 @@ TOOL_CATEGORIES = {
},
{
"name": "Mistral (Voxtral TTS)",
"tag": "Multilingual, native Opus, needs MISTRAL_API_KEY",
"badge": "paid",
"tag": "Multilingual, native Opus",
"env_vars": [
{"key": "MISTRAL_API_KEY", "prompt": "Mistral API key", "url": "https://console.mistral.ai/"},
],
@ -168,6 +173,7 @@ TOOL_CATEGORIES = {
"providers": [
{
"name": "Nous Subscription",
"badge": "subscription",
"tag": "Managed Firecrawl billed to your subscription",
"web_backend": "firecrawl",
"env_vars": [],
@ -177,7 +183,8 @@ TOOL_CATEGORIES = {
},
{
"name": "Firecrawl Cloud",
"tag": "Hosted service - search, extract, and crawl",
"badge": "★ recommended",
"tag": "Full-featured search, extract, and crawl",
"web_backend": "firecrawl",
"env_vars": [
{"key": "FIRECRAWL_API_KEY", "prompt": "Firecrawl API key", "url": "https://firecrawl.dev"},
@ -185,7 +192,8 @@ TOOL_CATEGORIES = {
},
{
"name": "Exa",
"tag": "AI-native search and contents",
"badge": "paid",
"tag": "Neural search with semantic understanding",
"web_backend": "exa",
"env_vars": [
{"key": "EXA_API_KEY", "prompt": "Exa API key", "url": "https://exa.ai"},
@ -193,7 +201,8 @@ TOOL_CATEGORIES = {
},
{
"name": "Parallel",
"tag": "AI-native search and extract",
"badge": "paid",
"tag": "AI-powered search and extract",
"web_backend": "parallel",
"env_vars": [
{"key": "PARALLEL_API_KEY", "prompt": "Parallel API key", "url": "https://parallel.ai"},
@ -201,7 +210,8 @@ TOOL_CATEGORIES = {
},
{
"name": "Tavily",
"tag": "AI-native search, extract, and crawl",
"badge": "free tier",
"tag": "Search, extract, and crawl — 1000 free searches/mo",
"web_backend": "tavily",
"env_vars": [
{"key": "TAVILY_API_KEY", "prompt": "Tavily API key", "url": "https://app.tavily.com/home"},
@ -209,7 +219,8 @@ TOOL_CATEGORIES = {
},
{
"name": "Firecrawl Self-Hosted",
"tag": "Free - run your own instance",
"badge": "free · self-hosted",
"tag": "Run your own Firecrawl instance (Docker)",
"web_backend": "firecrawl",
"env_vars": [
{"key": "FIRECRAWL_API_URL", "prompt": "Your Firecrawl instance URL (e.g., http://localhost:3002)"},
@ -223,6 +234,7 @@ TOOL_CATEGORIES = {
"providers": [
{
"name": "Nous Subscription",
"badge": "subscription",
"tag": "Managed FAL image generation billed to your subscription",
"env_vars": [],
"requires_nous_auth": True,
@ -231,6 +243,7 @@ TOOL_CATEGORIES = {
},
{
"name": "FAL.ai",
"badge": "paid",
"tag": "FLUX 2 Pro with auto-upscaling",
"env_vars": [
{"key": "FAL_KEY", "prompt": "FAL API key", "url": "https://fal.ai/dashboard/keys"},
@ -244,6 +257,7 @@ TOOL_CATEGORIES = {
"providers": [
{
"name": "Nous Subscription (Browser Use cloud)",
"badge": "subscription",
"tag": "Managed Browser Use billed to your subscription",
"env_vars": [],
"browser_provider": "browser-use",
@ -254,14 +268,16 @@ TOOL_CATEGORIES = {
},
{
"name": "Local Browser",
"tag": "Free headless Chromium (no API key needed)",
"badge": "★ recommended · free",
"tag": "Headless Chromium, no API key needed",
"env_vars": [],
"browser_provider": "local",
"post_setup": "agent_browser",
},
{
"name": "Browserbase",
"tag": "Cloud browser with stealth & proxies",
"badge": "paid",
"tag": "Cloud browser with stealth and proxies",
"env_vars": [
{"key": "BROWSERBASE_API_KEY", "prompt": "Browserbase API key", "url": "https://browserbase.com"},
{"key": "BROWSERBASE_PROJECT_ID", "prompt": "Browserbase project ID"},
@ -271,6 +287,7 @@ TOOL_CATEGORIES = {
},
{
"name": "Browser Use",
"badge": "paid",
"tag": "Cloud browser with remote execution",
"env_vars": [
{"key": "BROWSER_USE_API_KEY", "prompt": "Browser Use API key", "url": "https://browser-use.com"},
@ -280,6 +297,7 @@ TOOL_CATEGORIES = {
},
{
"name": "Firecrawl",
"badge": "paid",
"tag": "Cloud browser with remote execution",
"env_vars": [
{"key": "FIRECRAWL_API_KEY", "prompt": "Firecrawl API key", "url": "https://firecrawl.dev"},
@ -289,7 +307,8 @@ TOOL_CATEGORIES = {
},
{
"name": "Camofox",
"tag": "Local anti-detection browser (Firefox/Camoufox)",
"badge": "free · local",
"tag": "Anti-detection browser (Firefox/Camoufox)",
"env_vars": [
{"key": "CAMOFOX_URL", "prompt": "Camofox server URL", "default": "http://localhost:9377",
"url": "https://github.com/jo-inc/camofox-browser"},
@ -838,7 +857,8 @@ def _configure_tool_category(ts_key: str, cat: dict, config: dict):
# Plain text labels only (no ANSI codes in menu items)
provider_choices = []
for p in providers:
tag = f" ({p['tag']})" if p.get("tag") else ""
badge = f" [{p['badge']}]" if p.get("badge") else ""
tag = f"{p['tag']}" if p.get("tag") else ""
configured = ""
env_vars = p.get("env_vars", [])
if not env_vars or all(get_env_value(v["key"]) for v in env_vars):
@ -848,7 +868,7 @@ def _configure_tool_category(ts_key: str, cat: dict, config: dict):
configured = ""
else:
configured = " [configured]"
provider_choices.append(f"{p['name']}{tag}{configured}")
provider_choices.append(f"{p['name']}{badge}{tag}{configured}")
# Add skip option
provider_choices.append("Skip — keep defaults / configure later")
@ -1104,7 +1124,8 @@ def _configure_tool_category_for_reconfig(ts_key: str, cat: dict, config: dict):
provider_choices = []
for p in providers:
tag = f" ({p['tag']})" if p.get("tag") else ""
badge = f" [{p['badge']}]" if p.get("badge") else ""
tag = f"{p['tag']}" if p.get("tag") else ""
configured = ""
env_vars = p.get("env_vars", [])
if not env_vars or all(get_env_value(v["key"]) for v in env_vars):
@ -1114,7 +1135,7 @@ def _configure_tool_category_for_reconfig(ts_key: str, cat: dict, config: dict):
configured = ""
else:
configured = " [configured]"
provider_choices.append(f"{p['name']}{tag}{configured}")
provider_choices.append(f"{p['name']}{badge}{tag}{configured}")
default_idx = _detect_active_provider_index(providers, config)