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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ version = "0.17.0"
description = "Orchestrate a cluster of containerized local LLMs (via Ollama), each with a specific persona and role, that collaborate to solve a goal."
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.9"
requires-python = ">=3.10"
authors = [{ name = "Fabio Cumbo" }]
keywords = ["llm", "ollama", "multi-agent", "orchestration", "docker", "agents"]
classifiers = [
Expand Down
17 changes: 7 additions & 10 deletions team/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,16 +170,13 @@ def _load_plugin_commands() -> None:
Errors loading individual plugins are logged and skipped so one bad plugin
does not prevent ``team`` from starting.
"""
try:
for ep in entry_points(group="team.commands"):
try:
cmd = ep.load()
cli.add_command(cmd, name=ep.name)
log.debug("cli: loaded plugin command %r from %s", ep.name, ep.value)
except Exception as exc: # noqa: BLE001
log.warning("cli: failed to load plugin command %r: %s", ep.name, exc)
except Exception: # noqa: BLE001
pass # importlib.metadata not available in very old environments
for ep in entry_points(group="team.commands"):
try:
cmd = ep.load()
cli.add_command(cmd, name=ep.name)
log.debug("cli: loaded plugin command %r from %s", ep.name, ep.value)
except Exception as exc: # noqa: BLE001
log.warning("cli: failed to load plugin command %r: %s", ep.name, exc)


_load_plugin_commands()
Expand Down
25 changes: 11 additions & 14 deletions team/persona_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,17 @@ def _persona_dirs() -> list[tuple[Path, str]]:
dirs.append((custom, "env (TEAM_PERSONA_DIR)"))

# 2. Entry-point registered persona directories.
try:
known_paths = {p for p, _ in dirs}
for ep in entry_points(group="team.persona_dirs"):
try:
fn = ep.load()
p = Path(fn()).expanduser().resolve()
if p.is_dir() and p not in known_paths:
dirs.append((p, ep.name))
known_paths.add(p)
log.debug("persona_library: loaded persona dir from plugin %r: %s", ep.name, p)
except Exception as exc: # noqa: BLE001
log.warning("persona_library: failed to load persona dir from plugin %r: %s", ep.name, exc)
except Exception: # noqa: BLE001
pass # importlib.metadata not available in very old environments
known_paths = {p for p, _ in dirs}
for ep in entry_points(group="team.persona_dirs"):
try:
fn = ep.load()
p = Path(fn()).expanduser().resolve()
if p.is_dir() and p not in known_paths:
dirs.append((p, ep.name))
known_paths.add(p)
log.debug("persona_library: loaded persona dir from plugin %r: %s", ep.name, p)
except Exception as exc: # noqa: BLE001
log.warning("persona_library: failed to load persona dir from plugin %r: %s", ep.name, exc)

# 3. Built-in directory — lowest priority.
if _BUILTIN_DIR.is_dir():
Expand Down
9 changes: 3 additions & 6 deletions team/skills.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,9 @@ def _load_skill_registry() -> dict[str, str]:
return _SKILL_REGISTRY

registry: dict[str, str] = {}
try:
for ep in entry_points(group="team.skills"):
registry[ep.name] = ep.value
log.debug("skill registry: registered %r → %s", ep.name, ep.value)
except Exception: # noqa: BLE001
pass # importlib.metadata not available in very old environments
for ep in entry_points(group="team.skills"):
registry[ep.name] = ep.value
log.debug("skill registry: registered %r → %s", ep.name, ep.value)

_SKILL_REGISTRY = registry
return _SKILL_REGISTRY
Expand Down
6 changes: 0 additions & 6 deletions tests/test_plugin_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,6 @@ def test_result_is_cached(self):
skills_mod._load_skill_registry()
assert m.call_count == 1 # entry_points only called once

def test_importlib_error_yields_empty(self):
# If importlib.metadata raises, we get an empty dict (graceful degradation).
with patch("team.skills.entry_points", side_effect=RuntimeError("no metadata")):
registry = skills_mod._load_skill_registry()
assert registry == {}


# --------------------------------------------------------------------------- #
# _load_skill_by_name
Expand Down
Loading