-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
215 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
"""Extension system for loading MCP components from entry points.""" | ||
|
||
from llmling.extensions.base import BaseExtensionLoader | ||
from llmling.extensions.loaders import ToolsetLoader | ||
|
||
|
||
__all__ = [ | ||
"BaseExtensionLoader", | ||
"ToolsetLoader", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
"""Base class for extension loaders.""" | ||
|
||
from __future__ import annotations | ||
|
||
from typing import TYPE_CHECKING, Any, ClassVar, TypeVar | ||
|
||
from epregistry import EntryPointRegistry | ||
|
||
from llmling.core.log import get_logger | ||
|
||
|
||
if TYPE_CHECKING: | ||
from collections.abc import Callable | ||
|
||
|
||
logger = get_logger(__name__) | ||
T = TypeVar("T") | ||
|
||
|
||
class BaseExtensionLoader[T]: | ||
"""Base class for extension loaders. | ||
Entry points are expected to be registered under 'llmling' with their type | ||
as the entry point name, e.g.: | ||
[project.entry-points.llmling] | ||
tools = "my_module:get_mcp_tools" | ||
prompts = "my_module:get_mcp_prompts" | ||
""" | ||
|
||
component_type: ClassVar[str] | ||
converter: Callable[[Any], T] | ||
|
||
def __init__(self) -> None: | ||
"""Initialize loader.""" | ||
self.registry = EntryPointRegistry[Any]("llmling") | ||
|
||
def load_items(self, module_names: list[str]) -> dict[str, T]: | ||
"""Load items from specified modules.""" | ||
items = {} | ||
for module in module_names: | ||
try: | ||
# Just look for the component type entry point | ||
if entry_point := self.registry.get(self.component_type): | ||
get_items = entry_point.load() | ||
for item in get_items(): | ||
try: | ||
converted = self.converter(item) | ||
name = getattr(converted, "name", str(item)) | ||
items[name] = converted | ||
except Exception as exc: # noqa: BLE001 | ||
logger.warning( | ||
"Failed to load item from %s: %s", | ||
module, | ||
exc, | ||
) | ||
except Exception: | ||
logger.exception("Failed to load module %s", module) | ||
return items |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
"""Extension loaders for different MCP component types.""" | ||
|
||
from __future__ import annotations | ||
|
||
from llmling.extensions.base import BaseExtensionLoader | ||
from llmling.tools.base import LLMCallableTool | ||
|
||
|
||
class ToolsetLoader(BaseExtensionLoader[LLMCallableTool]): | ||
"""Loads tools from entry points. | ||
Entry points should return a list of callable objects: | ||
def get_mcp_tools() -> list[Callable[..., Any]]: | ||
return [function1, function2] | ||
""" | ||
|
||
component_type = "tools" | ||
converter = LLMCallableTool.from_callable |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from __future__ import annotations | ||
|
||
from llmling.extensions.loaders import ToolsetLoader | ||
|
||
|
||
def test_toolset_loader(): | ||
"""Test loading tools from entry points.""" | ||
loader = ToolsetLoader() | ||
tools = loader.load_items(["llmling"]) # just the package name | ||
assert "example_tool" in tools | ||
assert "analyze_ast" in tools |