mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-08-18 14:28:14 +00:00
fix(models): tighten catalog evidence boundaries
This commit is contained in:
parent
639c440d6f
commit
a71661208a
4 changed files with 140 additions and 11 deletions
|
|
@ -171,7 +171,10 @@ def stable_model_id_for(vendor: Any, model_id: Any, *, endpoint_id: Any = "", ba
|
|||
|
||||
def model_id_from(raw: Mapping[str, Any], *keys: str) -> str:
|
||||
for key in keys:
|
||||
value = compact_str(raw.get(key))
|
||||
raw_value = raw.get(key)
|
||||
if not isinstance(raw_value, str):
|
||||
continue
|
||||
value = raw_value.strip()
|
||||
if value:
|
||||
return value.removeprefix("models/")
|
||||
return ""
|
||||
|
|
|
|||
|
|
@ -24,10 +24,7 @@ vendor = VENDOR_COPILOT
|
|||
|
||||
_SUPPORT_CAPABILITIES = {
|
||||
"tool_calls": mc.CAP_TOOL_CALL,
|
||||
"tools": mc.CAP_TOOL_CALL,
|
||||
"vision": mc.CAP_VISION,
|
||||
"reasoning": mc.CAP_REASONING,
|
||||
"structured_outputs": mc.CAP_STRUCTURED_OUTPUT,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -86,8 +86,8 @@ class ProviderCatalogShape:
|
|||
def item_matches(self, item: Mapping[str, Any]) -> bool:
|
||||
if self.identity_paths and not any(
|
||||
(value := _path_value(item, path)) is not _MISSING
|
||||
and value is not None
|
||||
and value != ""
|
||||
and isinstance(value, str)
|
||||
and bool(value.strip())
|
||||
for path in self.identity_paths
|
||||
):
|
||||
return False
|
||||
|
|
@ -120,7 +120,11 @@ class ProviderCatalogShape:
|
|||
if self.envelope == ENVELOPE_BARE_LIST:
|
||||
return [item]
|
||||
if self.envelope == ENVELOPE_SINGLE:
|
||||
return item
|
||||
return {
|
||||
key: value
|
||||
for key, value in item.items()
|
||||
if key not in {ENVELOPE_DATA, ENVELOPE_MODELS}
|
||||
}
|
||||
if isinstance(payload, Mapping):
|
||||
narrowed = {
|
||||
key: value
|
||||
|
|
@ -231,7 +235,10 @@ OLLAMA_TAGS_SHAPE = ProviderCatalogShape(
|
|||
envelope=ENVELOPE_MODELS,
|
||||
identity_paths=("model", "name"),
|
||||
required_item_any_paths=("digest", "details.family", "details.families"),
|
||||
detection_priority=90,
|
||||
# `name` plus a digest/details field is not globally provider-specific.
|
||||
# Configured provider context remains authoritative for local Ollama
|
||||
# inventories; payload-only detection would create false provider identity.
|
||||
detection_priority=0,
|
||||
)
|
||||
OLLAMA_SHOW_SHAPE = ProviderCatalogShape(
|
||||
shape_id="ollama.show.v1",
|
||||
|
|
@ -241,7 +248,11 @@ OLLAMA_SHOW_SHAPE = ProviderCatalogShape(
|
|||
required_item_paths=("capabilities",),
|
||||
required_item_any_paths=("model_info", "details", "template", "parameters"),
|
||||
item_types=(("capabilities", (list, tuple)),),
|
||||
detection_priority=100,
|
||||
# `/api/show` capability and parameter fields are not sufficiently unique
|
||||
# to identify an otherwise unknown provider. Local/default ports are also
|
||||
# deliberately non-authoritative, so require configured provider context
|
||||
# before interpreting this singleton response as Ollama-native metadata.
|
||||
detection_priority=0,
|
||||
)
|
||||
LMSTUDIO_MODELS_V1_SHAPE = ProviderCatalogShape(
|
||||
shape_id="lmstudio.models.native.v1",
|
||||
|
|
@ -610,7 +621,10 @@ def native_shape_for_payload(
|
|||
return None
|
||||
priority = max(shape.detection_priority for shape in matches)
|
||||
best = [shape for shape in matches if shape.detection_priority == priority]
|
||||
return sorted(best, key=lambda shape: shape.shape_id)[0]
|
||||
# Registry declaration order expresses preference between revisions of the
|
||||
# same provider shape (for example LM Studio v1 before v0). Alphabetical
|
||||
# shape ids invert that version preference for otherwise equal evidence.
|
||||
return best[0]
|
||||
|
||||
|
||||
def catalog_shape_for_id(shape_id: Any) -> ProviderCatalogShape | None:
|
||||
|
|
|
|||
|
|
@ -246,10 +246,13 @@ def test_native_catalog_shapes_resolve_with_required_provider_context():
|
|||
"huggingface",
|
||||
"lmstudio",
|
||||
"mistral",
|
||||
"ollama",
|
||||
}
|
||||
for payload, expected_provider, expected_shape in cases:
|
||||
explicit_provider = (
|
||||
expected_provider if expected_provider in explicit_context_providers else None
|
||||
expected_provider
|
||||
if expected_provider in explicit_context_providers
|
||||
else None
|
||||
)
|
||||
resolution = pcs.resolve_provider(payload, provider=explicit_provider)
|
||||
assert resolution.provider_id == expected_provider
|
||||
|
|
@ -262,6 +265,59 @@ def test_native_catalog_shapes_resolve_with_required_provider_context():
|
|||
assert resolution.fallback is False
|
||||
|
||||
|
||||
def test_generic_ollama_like_fields_require_provider_context():
|
||||
show_payload = {
|
||||
"name": "foreign-model",
|
||||
"capabilities": ["vision"],
|
||||
"parameters": {},
|
||||
}
|
||||
tags_payload = {"models": [{"name": "foreign-model", "digest": None}]}
|
||||
|
||||
inferred = pcs.resolve_provider(show_payload)
|
||||
contextual = pcs.resolve_provider(show_payload, provider="ollama")
|
||||
|
||||
assert inferred.provider_id == pcs.PROVIDER_UNKNOWN
|
||||
assert inferred.shape_id == ""
|
||||
assert inferred.fallback is False
|
||||
assert records_from_payload(show_payload) == ()
|
||||
assert contextual.provider_id == "ollama"
|
||||
assert contextual.shape_id == "ollama.show.v1"
|
||||
assert contextual.fallback is False
|
||||
contextual_record = records_from_payload(show_payload, vendor="ollama")[0]
|
||||
assert contextual_record.capability.capabilities == (mc.CAP_VISION,)
|
||||
|
||||
inferred_tags = pcs.resolve_provider(tags_payload)
|
||||
contextual_tags = pcs.resolve_provider(tags_payload, provider="ollama")
|
||||
assert inferred_tags.provider_id == pcs.PROVIDER_UNKNOWN
|
||||
assert inferred_tags.shape_id == "fallback.models.envelope.v1"
|
||||
assert inferred_tags.fallback is True
|
||||
assert contextual_tags.provider_id == "ollama"
|
||||
assert contextual_tags.shape_id == "ollama.tags.v1"
|
||||
assert contextual_tags.fallback is False
|
||||
|
||||
|
||||
def test_singleton_native_reader_ignores_competing_list_envelopes():
|
||||
record = records_from_payload(
|
||||
{
|
||||
"model": "show-model",
|
||||
"capabilities": ["completion", "vision"],
|
||||
"model_info": {"family.context_length": 4096},
|
||||
"models": [
|
||||
{
|
||||
"name": "shadow-model",
|
||||
"digest": "abc",
|
||||
"details": {"family": "shadow"},
|
||||
}
|
||||
],
|
||||
},
|
||||
vendor="ollama",
|
||||
)[0]
|
||||
|
||||
assert record.model_id == "show-model"
|
||||
assert record.catalog_shape_id == "ollama.show.v1"
|
||||
assert record.capability.capabilities == (mc.CAP_VISION,)
|
||||
|
||||
|
||||
def test_ambiguous_common_fields_do_not_infer_provider_from_payload_alone():
|
||||
cases = (
|
||||
({"data": [{"id": "generic", "architecture": {}}]}, "openrouter"),
|
||||
|
|
@ -436,6 +492,32 @@ def test_selected_native_envelope_ignores_an_unrelated_alternate_envelope():
|
|||
assert record.fallback is False
|
||||
|
||||
|
||||
def test_same_provider_shape_tie_prefers_declared_modern_envelope():
|
||||
record = records_from_payload(
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "legacy-v0-card",
|
||||
"type": "vlm",
|
||||
"arch": "legacy",
|
||||
}
|
||||
],
|
||||
"models": [
|
||||
{
|
||||
"key": "modern-v1-card",
|
||||
"type": "llm",
|
||||
"capabilities": {"vision": True},
|
||||
}
|
||||
],
|
||||
},
|
||||
vendor="lmstudio",
|
||||
)[0]
|
||||
|
||||
assert record.model_id == "modern-v1-card"
|
||||
assert record.catalog_shape_id == "lmstudio.models.native.v1"
|
||||
assert record.capability.capabilities == (mc.CAP_VISION,)
|
||||
|
||||
|
||||
def test_selected_fallback_envelope_is_not_shadowed_by_empty_data():
|
||||
record = records_from_payload(
|
||||
{
|
||||
|
|
@ -517,6 +599,15 @@ def test_fallback_reader_fails_soft_for_null_and_malformed_envelopes():
|
|||
assert generic_openai.records_from_payload(payload) == ()
|
||||
|
||||
|
||||
def test_structured_identity_values_are_not_stringified_into_fallback_records():
|
||||
for key in ("id", "name", "model", "key", "slug"):
|
||||
payload = [{key: {"nested": "model"}}]
|
||||
|
||||
assert pcs.resolve_provider(payload).shape_id == ""
|
||||
assert generic_openai.records_from_payload(payload) == ()
|
||||
assert records_from_payload(payload, vendor="future-provider") == ()
|
||||
|
||||
|
||||
def test_mistral_reader_maps_per_model_capabilities_without_provider_inheritance():
|
||||
records = mistral.records_from_payload(
|
||||
{
|
||||
|
|
@ -571,6 +662,30 @@ def test_copilot_reader_uses_picker_and_nested_supports_shape():
|
|||
assert dict(record.capability.limits) == {"input_tokens": 64000, "output_tokens": 8192}
|
||||
|
||||
|
||||
def test_copilot_reader_ignores_unverified_support_aliases():
|
||||
record = records_from_payload(
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "future-supports-model",
|
||||
"model_picker_enabled": True,
|
||||
"capabilities": {
|
||||
"supports": {
|
||||
"tools": True,
|
||||
"reasoning": True,
|
||||
"structured_outputs": True,
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
vendor="copilot",
|
||||
)[0]
|
||||
|
||||
assert record.capability.family == mc.FAMILY_CHAT
|
||||
assert record.capability.capabilities == ()
|
||||
|
||||
|
||||
def test_sglang_model_info_maps_native_generation_flags_only():
|
||||
generation = sglang.records_from_payload(
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue