refactor(nous): trim comments and drop an unused field

This commit is contained in:
Mariano Nicolini
2026-08-28 15:39:23 -03:00
parent a51df3864e
commit 4d482ed344
11 changed files with 76 additions and 167 deletions
+5 -6
View File
@@ -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,
+1 -4
View File
@@ -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
+2 -3
View File
@@ -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,
+2 -3
View File
@@ -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()
+5 -9
View File
@@ -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,
+26 -52
View File
@@ -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
+8 -21
View File
@@ -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),
)
+2 -3
View File
@@ -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,
)
+13 -40
View File
@@ -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"}) == []
+8 -16
View File
@@ -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
@@ -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)