mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
fix(pm): judge a build's hermes-agent markers on its own interpreter
Round-3 P3 (marker environment): the gate evaluated requirement markers with default_environment() of the calling process, while the build's own marker evaluation asks the generation's interpreter (_target_environment), because PM can run under a bootstrap Python. A build now passes its interpreter, so it leaves out exactly what the loader (running in the generation) skips. Callers outside a build keep this process's markers: no probe at loader start.
This commit is contained in:
1 parent
6eea8ca0c3
commit
c314285f07
2 files changed
+20
-14
No files matched your search
+2
-1
@@ -534,7 +534,8 @@ class Venv(StatePackage):
|
||||
# An update does evict them, loudly: it must not fail on another profile's config.
|
||||
from pm.plugins_state import enabled_plugins_ordered
|
||||
enabled_plugins_ordered(skip_invalid_secondary=skip_invalid_secondary)
|
||||
members = [] if repair else (build_member_dirs(extras) if plugin_dirs is None else plugin_dirs)
|
||||
members = [] if repair else (build_member_dirs(extras, environment.python) if plugin_dirs is None
|
||||
else plugin_dirs)
|
||||
try:
|
||||
generation.mkdir(parents=True)
|
||||
(generation / ".lease-managed").touch()
|
||||
|
||||
+18
-13
@@ -315,12 +315,15 @@ def enabled_member_dirs(*, proposed_home=None, enabled=None, disabled=None) -> l
|
||||
return members
|
||||
|
||||
|
||||
def build_member_dirs(extras: Iterable[str]) -> list[Path]:
|
||||
def build_member_dirs(extras: Iterable[str], python: Path | None = None) -> list[Path]:
|
||||
"""``enabled_member_dirs`` for a build selecting core *extras*: a plugin extra they select
|
||||
can add a ``hermes-agent`` requirement the running Hermes misses, which sits out too."""
|
||||
extras = list(extras)
|
||||
return [path for path in enabled_member_dirs()
|
||||
if not core_requirement_error(read_python_declaration(path), extras)]
|
||||
can add a ``hermes-agent`` requirement the running Hermes misses, which sits out too.
|
||||
A build passes its interpreter *python*, whose markers the generation (and so the loader)
|
||||
sees; PM itself may run under a bootstrap Python."""
|
||||
extras, members = list(extras), enabled_member_dirs()
|
||||
target = _target_environment(python) if members and python is not None else None
|
||||
return [path for path in members
|
||||
if not core_requirement_error(read_python_declaration(path), extras, target)]
|
||||
|
||||
|
||||
def _member_key(identity: Path) -> str:
|
||||
@@ -539,16 +542,18 @@ def _recorded_extras() -> list[str]:
|
||||
return [extra for extra in extras if isinstance(extra, str)] if isinstance(extras, list) else []
|
||||
|
||||
|
||||
def core_requirement_error(declaration, extras: Iterable[str] | None = None) -> Optional[str]:
|
||||
def core_requirement_error(declaration, extras: Iterable[str] | None = None,
|
||||
target: Mapping[str, str] | None = None) -> Optional[str]:
|
||||
"""Why the plugin's applicable requirement on ``hermes-agent`` rejects the running Hermes.
|
||||
|
||||
PM satisfies ``hermes-agent`` from the checkout itself: a runtime requirement naming it is
|
||||
dropped, and a selected extra naming it binds to the workspace root, where uv ignores the
|
||||
specifier. So the specifier is judged here, PEP 440 like any requirement, under *extras*
|
||||
(the core extras the build selects; ``None`` reads the recorded selection) and this host's
|
||||
markers. The identity is the one ``requires_hermes`` reads (the committed pyproject
|
||||
version is a placeholder); with none (``unknown``) nothing is judged. It is read only for
|
||||
a plugin that names core: the read walks git, and every plugin passes here at startup.
|
||||
(the core extras the build selects; ``None`` reads the recorded selection) and the markers
|
||||
of *target* (the installing interpreter; ``None`` is this process, which the loader runs
|
||||
in). The identity is the one ``requires_hermes`` reads (the committed pyproject version is
|
||||
a placeholder); with none (``unknown``) nothing is judged. It is read only for a plugin
|
||||
that names core: the read walks git, and every plugin passes here at startup.
|
||||
"""
|
||||
import tomllib
|
||||
|
||||
@@ -560,15 +565,15 @@ def core_requirement_error(declaration, extras: Iterable[str] | None = None) ->
|
||||
|
||||
if declaration.external:
|
||||
return None
|
||||
target = default_environment()
|
||||
environment = default_environment() if target is None else target
|
||||
specs, installed = list(declaration.requirements), set()
|
||||
if declaration.pyproject is not None:
|
||||
document = tomllib.loads(declaration.pyproject.read_text(encoding="utf-8-sig"))
|
||||
installed = _selected_member_extras(document, _recorded_extras() if extras is None else extras, target)[0]
|
||||
installed = _selected_member_extras(document, _recorded_extras() if extras is None else extras, environment)[0]
|
||||
specs += [spec for name, values in document["project"].get("optional-dependencies", {}).items()
|
||||
if _extra_key(name) in installed for spec in values]
|
||||
pins = [requirement for requirement in _self_references(specs, "hermes-agent")
|
||||
if requirement.specifier and _reference_active(requirement, ("", *sorted(installed)), target)]
|
||||
if requirement.specifier and _reference_active(requirement, ("", *sorted(installed)), environment)]
|
||||
if not pins:
|
||||
return None
|
||||
current = running_hermes_version()
|
||||
|
||||
Reference in new issue
Block a user