From 4d482ed344bc0ab507841cfc5efc4cb6bc4cfd0e Mon Sep 17 00:00:00 2001 From: Mariano Nicolini Date: Fri, 28 Aug 2026 15:39:23 -0300 Subject: [PATCH] refactor(nous): trim comments and drop an unused field --- agent/auxiliary_client.py | 11 ++- agent/credits_tracker.py | 5 +- hermes_cli/auth.py | 5 +- hermes_cli/model_setup_flows.py | 5 +- hermes_cli/model_switch.py | 14 ++-- hermes_cli/models.py | 78 +++++++------------ hermes_cli/nous_account.py | 29 ++----- hermes_cli/web_server.py | 5 +- tests/hermes_cli/test_nous_policy_filter.py | 53 ++++--------- tests/hermes_cli/test_nous_policy_surfaces.py | 24 ++---- .../hermes_cli/test_pricing_cache_auth_key.py | 14 +--- 11 files changed, 76 insertions(+), 167 deletions(-) diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index 534b42184a..e3c87068f1 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -885,10 +885,9 @@ def _fast_model_from_catalog(provider_id: str) -> str: logger.debug("No credentials for %s catalog", provider_id, exc_info=True) if not api_key and provider_id.strip().lower() == "nous": - # Nous is OAuth, so the api-key resolver above raises for it. An - # anonymous read returns the full catalog rather than the one the - # org may reach, and a model picked from it is refused at request - # time with model_blocked_by_org_policy. + # Nous is OAuth, so the resolver above raises for it. An anonymous + # read returns the full catalog, and a model picked from it is + # refused at request time by the org's policy. try: from hermes_cli.models import _resolve_nous_pricing_credentials @@ -913,8 +912,8 @@ def _fast_model_from_catalog(provider_id: str) -> str: ids = sorted((str(m) for m in catalog), key=_model_recency_key, reverse=True) if provider_id.strip().lower() == "nous": - # The catalog's keys are a source of ids here, so the policy has to - # narrow them the same way it narrows the pickers' lists. + # The catalog's keys are a source of ids here, so the policy narrows + # them as it does the pickers' lists. try: from hermes_cli.models import ( nous_policy_allowed_ids, diff --git a/agent/credits_tracker.py b/agent/credits_tracker.py index 2d0873c563..82e2d53caa 100644 --- a/agent/credits_tracker.py +++ b/agent/credits_tracker.py @@ -254,10 +254,7 @@ def is_free_tier_model(model: str, base_url: str = "") -> bool: try: from hermes_cli.models import _is_model_free, peek_cached_pricing - # The agent's Nous base_url is /v1-suffixed - # (https://inference-api.nousresearch.com/v1) but the catalog fetchers - # key on the pre-/v1 root, and on auth state besides; peek_cached_pricing - # owns both details. + # peek_cached_pricing owns the /v1-suffix and auth-state key details. pricing = peek_cached_pricing(base_url) if not pricing: return False diff --git a/hermes_cli/auth.py b/hermes_cli/auth.py index c6a7330e29..6d5bfb8ae1 100644 --- a/hermes_cli/auth.py +++ b/hermes_cli/auth.py @@ -9428,9 +9428,8 @@ def _login_nous(args, pconfig: ProviderConfig) -> None: model_ids, pricing = union_with_portal_paid_recommendations( model_ids, pricing, _portal_for_recs, ) - # The curated list and the Portal's recommendations are both - # unauthenticated, so neither knows what the org may reach. - # Narrow both lists to the policy before they are shown. + # Neither the curated list nor the Portal's recommendations + # know what the org may reach. _policy_allowed = nous_policy_allowed_ids() model_ids = restrict_to_nous_policy( model_ids, _policy_allowed, rescue_empty=True, diff --git a/hermes_cli/model_setup_flows.py b/hermes_cli/model_setup_flows.py index c4b9dedfd7..90c9dd38d2 100644 --- a/hermes_cli/model_setup_flows.py +++ b/hermes_cli/model_setup_flows.py @@ -559,9 +559,8 @@ def _model_flow_nous(config, current_model="", args=None): model_ids, pricing, _nous_portal_url, ) - # The curated list and the Portal's recommendations are both - # unauthenticated, so neither knows what the org may reach. Narrow both - # lists to the policy before they are shown. + # Neither the curated list nor the Portal's recommendations know what the + # org may reach. from hermes_cli.models import nous_policy_allowed_ids, restrict_to_nous_policy _policy_allowed = nous_policy_allowed_ids() diff --git a/hermes_cli/model_switch.py b/hermes_cli/model_switch.py index fe18cb93a6..fa7f4c928f 100644 --- a/hermes_cli/model_switch.py +++ b/hermes_cli/model_switch.py @@ -2565,11 +2565,9 @@ def _collect_authed_provider_slugs( slugs.append(_cp.slug) seen.add(_cp.slug.lower()) - # Nous is deliberately excluded. Its picker branch builds from the curated - # list rather than cached_provider_model_ids, and nous cannot reach the - # api_key-only unified pathway, so a prefetched entry is written and never - # read — a live authenticated /v1/models round trip per picker open for - # nothing. + # Nous excluded: its picker branch builds from the curated list and it + # cannot reach the api_key-only pathway, so a prefetched entry is written + # and never read. return [s for s in slugs if s != "nous"] @@ -3101,10 +3099,8 @@ def list_authenticated_providers( # curated list alone (still correct, just may lag newly # launched models, exactly like an offline CLI run). pass - # Both the curated list and the Portal's recommendations are - # unauthenticated, so neither knows what the org may reach. Narrow - # to the policy outside the try, so a failed recommendation fetch - # still yields a filtered curated list. + # Outside the try above, so a failed recommendation fetch still + # yields a policy-filtered curated list. try: from hermes_cli.models import ( nous_policy_allowed_ids as _nous_policy, diff --git a/hermes_cli/models.py b/hermes_cli/models.py index 6662b9d3c8..9c81afb132 100644 --- a/hermes_cli/models.py +++ b/hermes_cli/models.py @@ -2255,18 +2255,16 @@ def _cache_catalog( return result -# A governed endpoint answers an authenticated read with a policy-filtered -# catalog and an anonymous read with the full one, so auth state is part of the -# cache identity. NUL cannot appear in a URL, so the suffix cannot collide with -# a base URL that happens to end this way. +# NUL cannot appear in a URL, so this cannot collide with a real base URL. _PRICING_AUTH_KEY_SUFFIX = "\x00auth" def _pricing_cache_key(url_root: str, api_key: str | None) -> str: - """The ``_pricing_cache`` key for a read of *url_root*. + """Cache key for a read of *url_root*. - Only *whether* a key was supplied participates — never its value, so no - secret reaches the cache key. + A governed endpoint answers an authenticated read with a policy-filtered + catalog and an anonymous one with the full catalog, so the two cannot share + an entry. Only whether a key was supplied participates, never its value. """ return url_root + _PRICING_AUTH_KEY_SUFFIX if api_key else url_root @@ -2274,9 +2272,8 @@ def _pricing_cache_key(url_root: str, api_key: str | None) -> str: def peek_cached_pricing(base_url: str) -> dict[str, dict[str, Any]]: """Pricing already cached for *base_url*, or ``{}``. Never fetches. - Accepts a ``/v1``-suffixed URL as well as the pre-``/v1`` root the - catalog fetchers key on. Prefers the authenticated catalog, which is the - one scoped to the caller's org. + Accepts a ``/v1``-suffixed URL as well as the pre-``/v1`` root the fetchers + key on, and prefers the authenticated catalog. """ root = (base_url or "").rstrip("/") if root.endswith("/v1"): @@ -2607,23 +2604,13 @@ def _resolve_nous_pricing_credentials() -> tuple[str, str]: def nous_policy_allowed_ids(*, force_refresh: bool = False) -> Optional[set[str]]: """The Nous model ids the caller's org may reach, or ``None`` to not filter. - The gateway filters ``GET /v1/models`` by the org's model policy for an - authenticated read, omitting blocked rows with no marker field, so the keys - of the authenticated pricing response are the reachable set. This reuses - that response rather than issuing a second round trip. + The gateway omits policy-blocked rows from an authenticated + ``GET /v1/models``, so that response's keys are the reachable set. - Returns ``None`` — meaning "leave the caller's list alone" — in three cases, - each of which would otherwise narrow a list on evidence that cannot support - it: - - * the org carries no policy, or the token is too old to say (see - :func:`~hermes_cli.nous_account.nous_policy_present`). Filtering an - unrestricted org's list buys nothing and risks dropping a model the - Portal recommends before the gateway catalog lists it. - * credential resolution failed, so the read is anonymous and therefore - unfiltered. A full catalog must not be mistaken for a policy-filtered one. - * the read came back empty, which is a fetch failure rather than an org - that may reach nothing. + ``None`` means "leave the caller's list alone", for the three states that + cannot support narrowing one: no policy (or a token too old to say), an + anonymous read whose catalog is unfiltered, and an empty read, which is a + fetch failure rather than an org that may reach nothing. """ try: from hermes_cli.nous_account import nous_policy_present @@ -2638,8 +2625,8 @@ def nous_policy_allowed_ids(*, force_refresh: bool = False) -> Optional[set[str] return None # Same arguments as get_pricing_for_provider's nous branch, so a caller - # that also asks for pricing shares this cache entry instead of paying for - # a second request. + # asking for pricing too shares this entry instead of paying for a second + # request. pricing = fetch_models_with_pricing( api_key=api_key, base_url=base_url, @@ -2649,10 +2636,8 @@ def nous_policy_allowed_ids(*, force_refresh: bool = False) -> Optional[set[str] return set(pricing) or None -# Above this many reachable models, an allowed set is treated as catalog-wide -# rather than as an allowlist worth showing in place of an empty picker. NAS -# caps an allowlist at 512, but a set this large is indistinguishable from the -# full catalog for display purposes. +# Past this size an allowed set reads as a whole catalog rather than an +# allowlist, and is not worth showing in place of an empty picker. _NOUS_POLICY_APPEND_MAX = 64 @@ -2664,14 +2649,12 @@ def restrict_to_nous_policy( ) -> list[str]: """*model_ids* narrowed to *allowed*, preserving the caller's order. - A ``None`` or empty *allowed* leaves the list untouched — see - :func:`nous_policy_allowed_ids` for when that happens. + A ``None`` or empty *allowed* leaves the list untouched. - A ``:free`` sibling is kept when its base model is reachable. The gateway - admits a row when any of its requestable ids passes, and treats anything - unknown as a keep on the grounds that over-listing costs a 403 from the - authoritative gate while hiding a row the gate would serve is unrecoverable - from the client. This mirrors that. + A ``:free`` sibling is kept when its base model is reachable, mirroring the + gateway, which admits a row when any of its requestable ids passes. Prefer + over-listing: that costs a 403 from the authoritative gate, while hiding a + row the gate would serve is unrecoverable from the client. """ if not allowed: return list(model_ids) @@ -2681,19 +2664,10 @@ def restrict_to_nous_policy( if mid in allowed or mid.split(":", 1)[0] in allowed ] - # An allowlist can admit only models the curated manifest has never heard - # of, leaving nothing to intersect and an empty picker — strictly worse than - # the unfiltered list, because the models the org may actually use are the - # ones dropped. *rescue_empty* falls back to the reachable set in exactly - # that case, and callers opt in per list: it is meaningful for the list a - # user picks from, and wrong for any list whose emptiness carries meaning. - # An unavailable/gated list is legitimately empty, and rescuing it would - # read that as "nothing survived" and fill it with the whole reachable set. - # - # Bounded, because a jurisdiction or provider policy narrows the catalog - # without shrinking it to an allowlist, and a large alphabetical dump buries - # the curated order the pickers show on purpose. Anything omitted stays - # reachable through the picker's custom-model entry. + # An allowlist can name only models the curated manifest lacks, leaving an + # empty picker — worse than no filter, since the models the org may use are + # the ones dropped. Opt-in per list: an already-empty list (a paid tier's + # gated models) means "nothing to gate", not "nothing survived". if rescue_empty and not kept and len(allowed) <= _NOUS_POLICY_APPEND_MAX: return sorted(allowed) return kept diff --git a/hermes_cli/nous_account.py b/hermes_cli/nous_account.py index c63d090fc4..6eba71c831 100644 --- a/hermes_cli/nous_account.py +++ b/hermes_cli/nous_account.py @@ -99,7 +99,6 @@ class NousPortalAccountInfo: subscription: Optional[NousPortalSubscriptionInfo] = None paid_service_access: Optional[bool] = None paid_service_access_info: Optional[NousPaidServiceAccessInfo] = None - policy_present: Optional[bool] = None tool_access: Optional[NousToolAccessInfo] = None raw_claims: Optional[dict[str, Any]] = None raw_account: Optional[dict[str, Any]] = None @@ -400,17 +399,12 @@ def get_nous_portal_account_info( def nous_policy_present() -> Optional[bool]: """Whether the caller's org carries a restrictive model/provider policy. - Read from the ``policy_present`` claim on the Nous OAuth access token, so - this costs no request. ``/api/oauth/account`` does not carry the claim, - which is why this reads the token directly rather than going through - :func:`get_nous_portal_account_info`. + Reads the ``policy_present`` claim off the access token, so it costs no + request; ``/api/oauth/account`` does not carry it. Stamped at mint time, so + it goes stale until the next token refresh. - ``None`` means unknown — an older mint, an unreadable token, or a - non-boolean claim. Unknown is NOT "no policy": callers must not report the - absence of the claim as the absence of a restriction. - - The claim is stamped at mint time, so it goes stale until the next token - refresh. + ``None`` is unknown — an older mint or an unreadable claim — and must not be + reported as the absence of a policy. """ try: from hermes_cli.auth import get_provider_auth_state, _decode_jwt_claims @@ -430,15 +424,9 @@ def nous_policy_present() -> Optional[bool]: def nous_policy_notice() -> str: """A one-line notice for an org that restricts model choice, else ``""``. - Under the gateway's policy filter a blocked model is omitted rather than - marked, which reads as "Hermes does not support this" instead of "your org - disallows it". This says which it is without enumerating anything: model - policy is an allowlist, so an org that admits a handful of models blocks - the whole rest of the catalog, and listing those would be a worse UI than - omitting them. - - Silent unless the claim is explicitly true — absent means an older mint, - not an unrestricted org. + A blocked model is omitted rather than marked, which reads as "Hermes does + not support this". This says which it is without enumerating the blocked + set, which under an allowlist is most of the catalog. """ if nous_policy_present() is not True: return "" @@ -694,7 +682,6 @@ def _info_from_valid_jwt( expires_at=datetime.fromtimestamp(exp, tz=timezone.utc), paid_service_access=paid_access, paid_service_access_info=access_info, - policy_present=_coerce_bool(claims.get("policy_present")), tool_access=_tool_access_from_value(claims.get("tool_access")), raw_claims=dict(claims), ) diff --git a/hermes_cli/web_server.py b/hermes_cli/web_server.py index 97c5dfe9e2..ec3aae53ec 100644 --- a/hermes_cli/web_server.py +++ b/hermes_cli/web_server.py @@ -7517,9 +7517,8 @@ def get_recommended_default_model(provider: str = ""): model_ids, pricing, portal_url ) - # Neither the curated list nor the Portal's recommendations know - # what the org may reach, and this endpoint picks the model a user - # lands on without choosing it. + # This endpoint picks the model a user lands on without choosing + # it, so an unreachable one here is worse than in a picker. model_ids = restrict_to_nous_policy( model_ids, nous_policy_allowed_ids(), rescue_empty=True, ) diff --git a/tests/hermes_cli/test_nous_policy_filter.py b/tests/hermes_cli/test_nous_policy_filter.py index b488ca2367..35a0de704e 100644 --- a/tests/hermes_cli/test_nous_policy_filter.py +++ b/tests/hermes_cli/test_nous_policy_filter.py @@ -1,10 +1,7 @@ """Narrowing the Nous model lists to an org's policy. -The inference gateway omits policy-blocked rows from an authenticated -``GET /v1/models`` with no marker field, so the keys of the authenticated -catalog read are the reachable set. These helpers turn that into a filter the -pickers can apply without a second round trip, and — just as importantly — -decline to filter when the evidence cannot support it. +The gateway omits policy-blocked rows from an authenticated ``GET /v1/models``, +so that response's keys are the reachable set. """ from __future__ import annotations @@ -44,15 +41,12 @@ class TestRestrictToNousPolicy: ) == ["a/one", "c/three"] def test_preserves_curated_order(self): - """The pickers show a curated order deliberately; filtering must not - reorder it into the catalog's alphabetical order.""" curated = ["z/last", "a/first", "m/middle"] allowed = {"a/first", "m/middle", "z/last"} assert restrict_to_nous_policy(curated, allowed) == curated def test_keeps_a_free_sibling_when_its_base_is_reachable(self): - """Portal free recommendations are ``:free`` ids; the gateway admits a - row when any of its requestable ids passes.""" + """Portal free recommendations are ``:free`` ids.""" assert restrict_to_nous_policy(["vendor/model:free"], {"vendor/model"}) == [ "vendor/model:free" ] @@ -115,8 +109,7 @@ class TestNousPolicyAllowedIds: assert calls == [] def test_declines_to_filter_on_an_anonymous_read(self, monkeypatch): - """An anonymous read returns the full catalog; treating it as the - policy-filtered set would silently widen the list to everything.""" + """An anonymous read returns the full, unfiltered catalog.""" self._patch(monkeypatch, policy_present=True, api_key="", pricing={"a/one": {}}) assert nous_policy_allowed_ids() is None @@ -146,7 +139,6 @@ class TestNousPolicyPresent: assert nous_policy_present() is None def test_non_boolean_claim_is_unknown(self, monkeypatch): - """The gateway refuses to read a corrupt claim as "no policy".""" self._patch_token(monkeypatch, _jwt({"policy_present": "yes"})) assert nous_policy_present() is None @@ -160,8 +152,6 @@ class TestNousPolicyPresent: class TestNousPolicyNotice: - """A governed org is told its choice is restricted, rather than left to - read an omitted model as one Hermes does not support.""" def _patch(self, monkeypatch, present): monkeypatch.setattr(account_mod, "nous_policy_present", lambda: present) @@ -172,14 +162,12 @@ class TestNousPolicyNotice: @pytest.mark.parametrize("present", [False, None]) def test_silent_otherwise(self, monkeypatch, present): - """Absent is an older mint, not an unrestricted org — either way there - is nothing truthful to say.""" + """Absent is an older mint, not an unrestricted org.""" self._patch(monkeypatch, present) assert account_mod.nous_policy_notice() == "" def test_names_no_models(self, monkeypatch): - """Policy is an allowlist, so the blocked set is most of the catalog; - the notice must not try to enumerate it.""" + """The blocked set is most of the catalog under an allowlist.""" self._patch(monkeypatch, True) notice = account_mod.nous_policy_notice() assert "/" not in notice, f"looks like it names a model: {notice}" @@ -187,12 +175,8 @@ class TestNousPolicyNotice: class TestAllowlistOutsideTheCuratedList: - """An allowlist can name a model the curated manifest has never heard of. - - Intersecting alone leaves the picker empty in that case — strictly worse - than showing an unfiltered list, because the one model the org may use is - the one that got dropped. - """ + """An allowlist can name only models the curated manifest lacks, which + intersecting alone turns into an empty picker.""" def test_surfaces_an_allowed_model_the_curated_list_lacks(self): assert restrict_to_nous_policy( @@ -200,9 +184,6 @@ class TestAllowlistOutsideTheCuratedList: ) == ["amazon/nova-2-lite-v1"] def test_does_not_append_when_the_curated_overlap_is_non_empty(self): - """A jurisdiction or provider policy narrows the catalog without - emptying the curated overlap. Appending its remainder would push - non-curated alphabetical ids into a deliberately curated order.""" kept = restrict_to_nous_policy( ["z/curated", "a/curated"], {"z/curated", "a/curated", "new/model"}, @@ -211,8 +192,8 @@ class TestAllowlistOutsideTheCuratedList: assert kept == ["z/curated", "a/curated"] def test_jurisdiction_policy_never_grows_the_list(self): - """Regression: a region filter leaves few enough models to slip under - the size cap, so a size-only guard let it append.""" + """A region filter can slip under the size cap, so the cap alone is not + enough of a guard.""" curated = ["vendor/one", "vendor/two", "vendor/three"] reachable = {"vendor/one", "vendor/two"} | {f"cn/model-{i}" for i in range(20)} assert restrict_to_nous_policy(curated, reachable, rescue_empty=True) == [ @@ -226,16 +207,13 @@ class TestAllowlistOutsideTheCuratedList: ) == ["vendor/m:free"] def test_a_provider_only_policy_does_not_bury_the_curated_order(self): - """Such a policy leaves the whole catalog reachable; appending it would - drop hundreds of alphabetical ids into the picker.""" curated = ["vendor/one", "vendor/two"] catalog = {f"vendor/model-{i}" for i in range(300)} | set(curated) assert restrict_to_nous_policy(curated, catalog, rescue_empty=True) == curated class TestRescueIsOptIn: - """The empty-intersection rescue is meaningful only for the list a user - picks from. Any list whose emptiness carries meaning must not get it.""" + """The rescue is meaningful only for the list a user picks from.""" def test_no_rescue_by_default(self): assert restrict_to_nous_policy([], {"a/one", "b/two"}) == [] @@ -246,15 +224,10 @@ class TestRescueIsOptIn: ) == ["a/one"] def test_an_already_empty_unavailable_list_is_never_filled(self): - """Regression: a paid-tier user has no gated models, so the - unavailable list is legitimately empty. Rescuing it read that as - "nothing survived" and pushed the whole reachable set into the picker's - unavailable block.""" + """A paid tier has no gated models, so this list is legitimately + empty — not a filter result to rescue.""" reachable = {f"cn/model-{i}" for i in range(42)} assert restrict_to_nous_policy([], reachable) == [] def test_rescue_does_not_resurrect_a_fully_blocked_list(self): - """A list whose every entry was blocked is a real filter result, not a - signal to show something else — unless the caller asked for the - rescue, which only the selectable list does.""" assert restrict_to_nous_policy(["x/blocked"], {"y/allowed"}) == [] diff --git a/tests/hermes_cli/test_nous_policy_surfaces.py b/tests/hermes_cli/test_nous_policy_surfaces.py index e59974c511..1fd43725d3 100644 --- a/tests/hermes_cli/test_nous_policy_surfaces.py +++ b/tests/hermes_cli/test_nous_policy_surfaces.py @@ -1,9 +1,7 @@ """Every Nous model list is narrowed to the org's policy before it is shown. -Four surfaces build a Nous list from the curated manifest unioned with the -Portal's ``recommended-models`` endpoint. Neither source is authenticated, so -without this filter an org's hidden model is offered to the user and then -refused at request time with ``model_blocked_by_org_policy``. +Four surfaces build their list from the curated manifest unioned with the +Portal's ``recommended-models`` endpoint; neither source is authenticated. """ from __future__ import annotations @@ -32,7 +30,6 @@ def no_policy(monkeypatch): class TestLoginNous: - """``_login_nous`` — the model picked at login is the model then used.""" def _run(self, monkeypatch, tmp_path): import hermes_cli.auth as auth_mod @@ -119,8 +116,7 @@ class TestModelSwitchPicker: assert set(CURATED) <= set(row["models"]) def test_filter_survives_a_failed_recommendation_fetch(self, monkeypatch, policy): - """The filter sits outside the try that wraps the Portal union, so a - Portal outage still yields a policy-filtered curated list.""" + """The filter sits outside the try wrapping the Portal union.""" def _boom(_p): raise RuntimeError("portal down") @@ -132,8 +128,7 @@ class TestModelSwitchPicker: class TestRecommendedDefaultEndpoint: - """``GET /api/model/recommended-default`` picks a model the user never sees - chosen, so an unreachable one there is worse than in a picker.""" + """This endpoint picks a model the user never sees chosen.""" def _call(self, monkeypatch): import hermes_cli.auth as auth_mod @@ -163,8 +158,7 @@ class TestRecommendedDefaultEndpoint: class TestAuxiliaryFastModel: - """``_fast_model_from_catalog`` treats the catalog's keys as a source of - ids, so an anonymous read there can select a model the gateway refuses.""" + """``_fast_model_from_catalog`` uses the catalog's keys as a source of ids.""" def _pick(self, monkeypatch, *, catalog): import agent.auxiliary_client as aux @@ -184,8 +178,7 @@ class TestAuxiliaryFastModel: return picked, seen def test_reads_the_catalog_with_nous_oauth_credentials(self, monkeypatch, no_policy): - """The api-key resolver raises for OAuth providers; without a fallback - the read goes out anonymous and returns the unfiltered catalog.""" + """The api-key resolver raises for OAuth providers.""" _, seen = self._pick(monkeypatch, catalog=["vendor/haiku-fast"]) assert seen["api_key"] == "sk-nous" @@ -204,8 +197,8 @@ class TestAuxiliaryFastModel: class TestNousPrefetch: - """The nous disk-cache entry is write-only: its picker branch builds from - the curated list, so prefetching it is a round trip for nothing.""" + """The nous disk-cache entry is write-only, so prefetching it is a round + trip for nothing.""" def test_nous_is_not_collected_for_prefetch(self, monkeypatch): import hermes_cli.auth as auth_mod @@ -220,7 +213,6 @@ class TestNousPrefetch: class TestPolicyNoticeIsShown: - """The notice reaches the two flows where a user picks a model.""" def test_login_prints_it(self, monkeypatch, tmp_path, policy, capsys): import hermes_cli.nous_account as account_mod diff --git a/tests/hermes_cli/test_pricing_cache_auth_key.py b/tests/hermes_cli/test_pricing_cache_auth_key.py index a1ae120365..d67c8d6e3a 100644 --- a/tests/hermes_cli/test_pricing_cache_auth_key.py +++ b/tests/hermes_cli/test_pricing_cache_auth_key.py @@ -1,10 +1,8 @@ """``_pricing_cache`` keys on auth state, not just the base URL. -A governed endpoint (Nous ``/v1/models`` filtered by an org's model policy) -answers an authenticated read with a narrower catalog than an anonymous one. -Keyed on the base URL alone, whichever read landed first in a process answered -every later one — so an authenticated caller could be handed the full, -unfiltered catalog without a request going out. +Nous ``/v1/models`` answers an authenticated read with a policy-filtered +catalog and an anonymous one with the full catalog, so the two must not share +a cache entry. """ from __future__ import annotations @@ -60,8 +58,6 @@ def catalog(monkeypatch): def test_authenticated_read_is_not_answered_by_an_anonymous_one(catalog): - """The bug: an anonymous read landing first must not answer the next - authenticated read out of cache.""" anon = fetch_models_with_pricing(api_key="", base_url=BASE) authed = fetch_models_with_pricing(api_key="sk-test", base_url=BASE) @@ -72,7 +68,6 @@ def test_authenticated_read_is_not_answered_by_an_anonymous_one(catalog): def test_anonymous_read_is_not_answered_by_an_authenticated_one(catalog): - """And the reverse direction, so neither entry can shadow the other.""" authed = fetch_models_with_pricing(api_key="sk-test", base_url=BASE) anon = fetch_models_with_pricing(api_key="", base_url=BASE) @@ -108,12 +103,11 @@ class TestPeekCachedPricing: assert peek_cached_pricing(BASE) == {} def test_accepts_a_v1_suffixed_url(self, catalog): - """The agent holds a /v1-suffixed base URL; the fetchers key on the root.""" + """The agent holds a /v1-suffixed base URL; fetchers key on the root.""" fetch_models_with_pricing(api_key="sk-test", base_url=BASE) assert sorted(peek_cached_pricing(BASE + "/v1")) == sorted(_FILTERED) def test_prefers_the_authenticated_catalog(self, catalog): - """It is the one scoped to the caller's org.""" fetch_models_with_pricing(api_key="", base_url=BASE) fetch_models_with_pricing(api_key="sk-test", base_url=BASE) assert sorted(peek_cached_pricing(BASE)) == sorted(_FILTERED)