feat(tools): surface the free tool pool in entitlement + setup (#36153)

Read the Portal's tool_access claim (JWT + /api/oauth/account) into NousToolAccessInfo and gate managed Tool Gateway access on it: tool_gateway_entitled (paid OR live pool) and per-category tool_gateway_entitled_for(). The pool funds web/image/tts/browser but not video, so per-backend availability, the charge picker (ensure_nous_portal_access coverage_category), and managed defaults all respect coverage.

Setup: rebuild prompt_enable_tool_gateway as a per-tool checklist that renders whenever the pool is enabled, lists only pool-covered tools (video excluded for free-pool users), and is framed as the free tool pool for $0 subscribers rather than a paid subscription. get_gateway_eligible_tools now gates and filters off the entitlement snapshot.
This commit is contained in:
Siddharth Balyan
2026-06-01 06:32:48 +05:30
committed by GitHub
parent fa4ebaa8b5
commit e1c7a9aa7b
6 changed files with 449 additions and 123 deletions
+23 -6
View File
@@ -309,10 +309,28 @@ def test_model_flow_nous_prints_subscription_guidance_without_mutating_explicit_
def test_model_flow_nous_offers_tool_gateway_prompt_when_unconfigured(monkeypatch, capsys):
from hermes_cli.nous_account import NousPortalAccountInfo
# Entitled account (paid → all tools eligible) drives the offer; the prompt
# is a per-tool checklist now, so capture the call rather than scrape stdout.
monkeypatch.setattr(
"hermes_cli.nous_subscription.managed_nous_tools_enabled",
lambda *args, **kwargs: True,
"hermes_cli.nous_subscription.get_nous_portal_account_info",
lambda **kwargs: NousPortalAccountInfo(
logged_in=True,
source="account_api",
fresh=True,
paid_service_access=True,
),
)
captured = {}
def _fake_checklist(title, items, pre_selected=None):
captured["title"] = title
captured["items"] = list(items)
return [] # decline; we only assert the prompt was offered
monkeypatch.setattr("hermes_cli.setup.prompt_checklist", _fake_checklist, raising=False)
config = {
"model": {"provider": "nous", "default": "claude-opus-4-6"},
"tts": {"provider": "edge"},
@@ -338,10 +356,9 @@ def test_model_flow_nous_offers_tool_gateway_prompt_when_unconfigured(monkeypatc
monkeypatch.setattr("hermes_cli.auth._update_config_for_provider", lambda provider, url: None)
hermes_main._model_flow_nous(config, current_model="claude-opus-4-6")
out = capsys.readouterr().out
# Tool Gateway prompt should be shown (input() raises OSError in pytest
# which is caught, so the prompt text appears but nothing is applied)
assert "Tool Gateway" in out
# The per-tool Tool Gateway checklist was offered.
assert "title" in captured
assert "Tool Gateway" in captured["title"] or "tool pool" in captured["title"].lower()
def test_codex_provider_uses_config_model(monkeypatch):