• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

neuml / txtai / 15611849391

12 Jun 2025 01:26PM UTC coverage: 100.0%. Remained the same
15611849391

push

github

davidmezzetti
Update Slack link

8287 of 8287 relevant lines covered (100.0%)

2.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/python/txtai/agent/tool/factory.py
1
"""
2
Factory module
3
"""
4

5
import inspect
2✔
6

7
from types import FunctionType, MethodType
2✔
8

9
import mcpadapt.core
2✔
10

11
from mcpadapt.smolagents_adapter import SmolAgentsAdapter
2✔
12
from smolagents import PythonInterpreterTool, Tool, tool as CreateTool, VisitWebpageTool, WebSearchTool
2✔
13
from transformers.utils import chat_template_utils, TypeHintParsingException
2✔
14

15
from ...embeddings import Embeddings
2✔
16
from .embeddings import EmbeddingsTool
2✔
17
from .function import FunctionTool
2✔
18

19

20
class ToolFactory:
2✔
21
    """
22
    Methods to create tools.
23
    """
24

25
    # Default toolkit
26
    DEFAULTS = {"python": PythonInterpreterTool(), "websearch": WebSearchTool(), "webview": VisitWebpageTool()}
2✔
27

28
    @staticmethod
2✔
29
    def create(config):
2✔
30
        """
31
        Creates a new list of tools. This method iterates of the `tools` configuration option and creates a Tool instance
32
        for each entry. This supports the following:
33

34
          - Tool instance
35
          - Dictionary with `name`, `description`, `inputs`, `output` and `target` function configuration
36
          - String with a tool alias name
37

38
        Returns:
39
            list of tools
40
        """
41

42
        tools = []
2✔
43
        for tool in config.pop("tools", []):
2✔
44
            # Create tool from function and it's documentation
45
            if not isinstance(tool, Tool) and (isinstance(tool, (FunctionType, MethodType)) or hasattr(tool, "__call__")):
2✔
46
                tool = ToolFactory.createtool(tool)
2✔
47

48
            # Create tool from input dictionary
49
            elif isinstance(tool, dict):
2✔
50
                # Get target function
51
                target = tool.get("target")
2✔
52

53
                # Create tool from input dictionary
54
                tool = (
2✔
55
                    EmbeddingsTool(tool)
56
                    if isinstance(target, Embeddings) or any(x in tool for x in ["container", "path"])
57
                    else ToolFactory.createtool(target, tool)
58
                )
59

60
            # Get default tool, if applicable
61
            elif isinstance(tool, str) and tool in ToolFactory.DEFAULTS:
2✔
62
                tool = ToolFactory.DEFAULTS[tool]
2✔
63

64
            # Support importing MCP tool collections
65
            elif isinstance(tool, str) and tool.startswith("http"):
2✔
66
                tools.extend(mcpadapt.core.MCPAdapt({"url": tool}, SmolAgentsAdapter()).tools())
2✔
67
                tool = None
2✔
68

69
            # Add tool
70
            if tool:
2✔
71
                tools.append(tool)
2✔
72

73
        return tools
2✔
74

75
    @staticmethod
2✔
76
    def createtool(target, config=None):
2✔
77
        """
78
        Creates a new Tool.
79

80
        Args:
81
            target: target object or function
82
            config: optional tool configuration
83

84
        Returns:
85
            Tool
86
        """
87

88
        try:
2✔
89
            # Try to create using CreateTool function - this fails when no annotations are available
90
            return CreateTool(target)
2✔
91
        except (TypeHintParsingException, TypeError):
2✔
92
            return ToolFactory.fromdocs(target, config if config else {})
2✔
93

94
    @staticmethod
2✔
95
    def fromdocs(target, config):
2✔
96
        """
97
        Creates a tool from method documentation.
98

99
        Args:
100
            target: target object or function
101
            config: tool configuration
102

103
        Returns:
104
            Tool
105
        """
106

107
        # Get function name and target - use target if it's a function or method, else use target.__call__
108
        name = target.__name__ if isinstance(target, (FunctionType, MethodType)) or not hasattr(target, "__call__") else target.__class__.__name__
2✔
109
        target = target if isinstance(target, (FunctionType, MethodType)) or not hasattr(target, "__call__") else target.__call__
2✔
110

111
        # Extract target documentation
112
        doc = inspect.getdoc(target)
2✔
113
        description, parameters, _ = chat_template_utils.parse_google_format_docstring(doc.strip()) if doc else (None, {}, None)
2✔
114

115
        # Get list of required parameters
116
        signature = inspect.signature(target)
2✔
117
        inputs = {}
2✔
118
        for pname, param in signature.parameters.items():
2✔
119
            if param.default == inspect.Parameter.empty and pname in parameters:
2✔
120
                inputs[pname] = {"type": "any", "description": parameters[pname]}
2✔
121

122
        # Create function tool
123
        return FunctionTool(
2✔
124
            {
125
                "name": config.get("name", name.lower()),
126
                "description": config.get("description", description),
127
                "inputs": config.get("inputs", inputs),
128
                "target": config.get("target", target),
129
            }
130
        )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc