fix: cache provider plugin directory stamps

(cherry picked from commit 75aaf1458fbcb7d9de335740aec87a1354118f8a)
This commit is contained in:
KoNit-K
2026-09-23 14:52:23 +08:00
committed by kshitij
parent b3a1900e72
commit 8605ca5919
2 changed files with 53 additions and 6 deletions

View File

@@ -41,6 +41,7 @@ import logging
import os
import sys
import threading
import time
from contextvars import ContextVar
from dataclasses import dataclass, field
from pathlib import Path
@@ -59,6 +60,7 @@ _current_source: str | None = None
_PROVIDER_LIST_CACHE: list[ProviderProfile] | None = None
_discovered = False
_discovering = False
_PLUGIN_DIR_STAMP_TTL_SECONDS = 1.0
@dataclass
@@ -75,6 +77,7 @@ class _HomeLayer:
registry: dict[str, ProviderProfile] = field(default_factory=dict)
aliases: dict[str, str] = field(default_factory=dict)
stamps: tuple = ()
stamp_checked_at: float | None = None
_HOME_LAYERS: dict[str, _HomeLayer] = {}
@@ -158,6 +161,13 @@ def get_provider_profile(name: str) -> ProviderProfile | None:
layer = _home_layer()
canonical = layer.aliases.get(name) or _ALIASES.get(name, name)
profile = layer.registry.get(canonical) or _REGISTRY.get(canonical)
# A newly installed provider is normally first requested by its new name.
# Refresh that miss immediately so installs remain usable without waiting
# for the periodic stamp check, while known-provider lookups stay hot.
if profile is None:
layer = _home_layer(force_stamp_check=True)
canonical = layer.aliases.get(name) or _ALIASES.get(name, name)
profile = layer.registry.get(canonical) or _REGISTRY.get(canonical)
# Named custom routes share the generic wire policy unless a plugin
# explicitly registered that route. Other names retain exact lookup.
if profile is None and isinstance(name, str) and name.lower().startswith("custom:"):
@@ -213,7 +223,7 @@ def list_providers() -> list[ProviderProfile]:
return result
def _home_layer() -> _HomeLayer:
def _home_layer(*, force_stamp_check: bool = False) -> _HomeLayer:
"""The layer for the home bound right now, importing plugin dirs it has not seen yet."""
try:
from hermes_constants import get_hermes_home, hermes_home_key
@@ -226,11 +236,23 @@ def _home_layer() -> _HomeLayer:
layer = _HOME_LAYERS.get(key)
if layer is None:
layer = _HOME_LAYERS[key] = _HomeLayer()
# Stamps are read before the scan: a plugin that lands mid-scan changes them and the next lookup
# picks it up. Two threads scanning the same home at once only re-import idempotently.
if home is not None and (stamps := _plugin_dir_stamps(home)) != layer.stamps:
_scan_home_layer(layer, key)
layer.stamps = stamps
# Stamps are read before the scan: a plugin that lands mid-scan changes them and the next
# check picks it up. Checking on a short cadence keeps a newly installed plugin discoverable
# without making every model lookup perform two filesystem stats.
now = time.monotonic()
if (
home is not None
and (
force_stamp_check
or layer.stamp_checked_at is None
or now - layer.stamp_checked_at >= _PLUGIN_DIR_STAMP_TTL_SECONDS
)
):
stamps = _plugin_dir_stamps(home)
if stamps != layer.stamps:
_scan_home_layer(layer, key)
layer.stamps = stamps
layer.stamp_checked_at = now
return layer

View File

@@ -64,3 +64,28 @@ def test_list_providers_dedupes_aliases_in_cached_snapshot():
assert providers.get_provider_profile("moonshot") is profile
assert providers.list_providers() == [profile]
def test_provider_lookups_reuse_the_home_plugin_stamp_within_its_ttl(tmp_path, monkeypatch):
"""The model-picker hot path must not stat plugin directories per lookup (#119950)."""
_reset_registry()
profile = _profile("known")
providers.register_provider(profile)
stamp_calls = 0
original_stamps = providers._plugin_dir_stamps
def count_stamps(home):
nonlocal stamp_calls
stamp_calls += 1
return original_stamps(home)
monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
monkeypatch.setattr(providers, "_HOME_LAYERS", {})
monkeypatch.setattr(providers, "_plugin_dir_stamps", count_stamps)
monkeypatch.setattr(providers, "_scan_home_layer", lambda *_: None)
assert providers.get_provider_profile("known") is profile
assert providers.list_providers() == [profile]
assert providers.get_provider_profile("known") is profile
assert stamp_calls == 1