Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions templates/consumer-repo/tools/llm_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ def load_model_registry() -> list[ModelRegistryEntry]:
model=model,
blocked=bool(raw_entry.get("blocked", False)),
lifecycle=str(raw_entry.get("lifecycle", "unknown")).strip().lower(),
quality={},
)
)
return entries
Expand Down Expand Up @@ -434,12 +435,7 @@ def resolve_slots(
# Preserve an explicit runtime override as an emergency bootstrap when the
# registry file is unavailable. Empty models are never invoked directly;
# langchain_client skips them when the override cannot serve that provider.
Comment on lines 435 to 437
if (
not slots
and not os.environ.get(ENV_SLOT_CONFIG)
and not _slot_path().exists()
and os.environ.get(env_model_name)
):
if not slots and not os.environ.get(ENV_SLOT_CONFIG) and os.environ.get(env_model_name):
slots = [
SlotDefinition(name=f"slot{index}", provider=provider, model="")
for index, provider in enumerate(
Expand Down
4 changes: 2 additions & 2 deletions tests/tools/test_langchain_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ def test_load_model_registry_ignores_malformed_nested_values(
entries = llm_registry.load_model_registry()

assert len(entries) == 1
assert entries[0].quality is None
assert entries[0].quality == {}


def test_load_model_registry_rejects_non_list_models(
Expand Down Expand Up @@ -372,7 +372,7 @@ def test_load_model_registry_ignores_v1_quality_scores(

[entry] = llm_registry.load_model_registry()

assert entry.quality is None
assert entry.quality == {}


def test_load_slot_config_ignores_tier_slot_when_registry_invalid(
Expand Down
12 changes: 8 additions & 4 deletions tests/tools/test_llm_registry_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ def test_profile_selection_uses_explicit_decision_not_model_position(
assert registry.select_model_for_profile(provider="openai") == "model-balanced"


def test_loaded_registry_entries_keep_compatibility_quality_immutable(
def test_loaded_registry_entries_keep_empty_compatibility_quality(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
registry_path = tmp_path / "registry.json"
_write_registry(registry_path)
monkeypatch.setenv(registry.ENV_MODEL_REGISTRY_CONFIG, str(registry_path))

assert registry.load_model_registry()[0].quality is None
assert registry.load_model_registry()[0].quality == {}


def test_new_catalog_model_does_not_auto_promote(
Expand Down Expand Up @@ -207,7 +207,7 @@ def test_missing_explicit_slot_config_fails_closed(
assert registry.configured_model_for_provider("openai") == ""


def test_unusable_bundled_slot_config_does_not_bootstrap_env_model(
def test_unusable_bundled_slot_config_bootstraps_explicit_env_model(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
registry_path = tmp_path / "registry.json"
Expand All @@ -219,7 +219,11 @@ def test_unusable_bundled_slot_config_does_not_bootstrap_env_model(
monkeypatch.setattr(registry, "DEFAULT_SLOT_CONFIG_PATH", slots_path)
monkeypatch.setenv("LANGCHAIN_MODEL", "emergency-model")

assert registry.resolve_slots() == []
assert [slot.provider for slot in registry.resolve_slots()] == [
"openai",
"anthropic",
"github-models",
]


def test_invalid_registry_with_explicit_profile_slot_fails_closed(
Expand Down
8 changes: 2 additions & 6 deletions tools/llm_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ def load_model_registry() -> list[ModelRegistryEntry]:
model=model,
blocked=bool(raw_entry.get("blocked", False)),
lifecycle=str(raw_entry.get("lifecycle", "unknown")).strip().lower(),
quality={},
)
)
return entries
Expand Down Expand Up @@ -434,12 +435,7 @@ def resolve_slots(
# Preserve an explicit runtime override as an emergency bootstrap when the
# registry file is unavailable. Empty models are never invoked directly;
# langchain_client skips them when the override cannot serve that provider.
Comment on lines 435 to 437
if (
not slots
and not os.environ.get(ENV_SLOT_CONFIG)
and not _slot_path().exists()
and os.environ.get(env_model_name)
):
if not slots and not os.environ.get(ENV_SLOT_CONFIG) and os.environ.get(env_model_name):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the default slot allowlist during bootstrap

When a consumer has customized the create-only config/llm_slots.json at the default path so no slots are usable (for example an empty slot list or only disabled/unknown providers) while leaving LANGCHAIN_SLOT_CONFIG unset, this now expands that empty allowlist into OpenAI/Anthropic/GitHub whenever LANGCHAIN_MODEL is present. The synced agents-issue-optimizer.yml and agents-auto-pilot.yml workflows set LANGCHAIN_MODEL, so those repos can start invoking LLM clients despite their local default slot file intentionally restricting or disabling slots; keep the emergency bootstrap limited to a missing default slot file, or otherwise distinguish an intentionally empty default config from a missing registry.

Useful? React with 👍 / 👎.

slots = [
SlotDefinition(name=f"slot{index}", provider=provider, model="")
for index, provider in enumerate(
Expand Down
Loading