gofannon 0.25.14__tar.gz → 0.25.15__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {gofannon-0.25.14 → gofannon-0.25.15}/PKG-INFO +6 -5
  2. {gofannon-0.25.14 → gofannon-0.25.15}/README.md +1 -1
  3. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/base/__init__.py +14 -1
  4. gofannon-0.25.15/gofannon/base/langflow.py +111 -0
  5. gofannon-0.25.15/gofannon/base/mcp.py +6 -0
  6. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/config.py +2 -1
  7. gofannon-0.25.15/gofannon/nasa/apod.py +68 -0
  8. gofannon-0.25.15/gofannon/wikipedia/__init__.py +0 -0
  9. {gofannon-0.25.14 → gofannon-0.25.15}/pyproject.toml +13 -8
  10. {gofannon-0.25.14 → gofannon-0.25.15}/LICENSE +0 -0
  11. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/__init__.py +0 -0
  12. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/arxiv/__init__.py +0 -0
  13. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/arxiv/get_article.py +0 -0
  14. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/arxiv/search.py +0 -0
  15. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/base/bedrock.py +0 -0
  16. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/base/langchain.py +0 -0
  17. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/base/smol_agents.py +0 -0
  18. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/basic_math/__init__.py +0 -0
  19. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/basic_math/addition.py +0 -0
  20. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/basic_math/division.py +0 -0
  21. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/basic_math/exponents.py +0 -0
  22. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/basic_math/multiplication.py +0 -0
  23. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/basic_math/subtraction.py +0 -0
  24. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/cli.py +0 -0
  25. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/github/__init__.py +0 -0
  26. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/github/commit_file.py +0 -0
  27. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/github/commit_files.py +0 -0
  28. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/github/create_issue.py +0 -0
  29. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/github/get_repo_contents.py +0 -0
  30. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/github/pr_review_tool.py +0 -0
  31. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/github/read_issue.py +0 -0
  32. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/github/search.py +0 -0
  33. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/google_search/__init__.py +0 -0
  34. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/google_search/google_search.py +0 -0
  35. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/headless_browser/__init__.py +0 -0
  36. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/headless_browser/base.py +0 -0
  37. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/headless_browser/headless_browser_get.py +0 -0
  38. {gofannon-0.25.14/gofannon/reasoning → gofannon-0.25.15/gofannon/nasa}/__init__.py +0 -0
  39. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/nhsta/__init__.py +0 -0
  40. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/open_notify_space/__init__.py +0 -0
  41. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/open_notify_space/iss_locator.py +0 -0
  42. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/orchestration/__init__.py +0 -0
  43. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/orchestration/firebase_wrapper.py +0 -0
  44. {gofannon-0.25.14/gofannon/wikipedia → gofannon-0.25.15/gofannon/reasoning}/__init__.py +0 -0
  45. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/reasoning/base.py +0 -0
  46. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/reasoning/hierarchical_cot.py +0 -0
  47. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/reasoning/sequential_cot.py +0 -0
  48. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/reasoning/tree_of_thought.py +0 -0
  49. {gofannon-0.25.14 → gofannon-0.25.15}/gofannon/wikipedia/wikipedia_lookup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: gofannon
3
- Version: 0.25.14
3
+ Version: 0.25.15
4
4
  Summary: A collection of tools for LLMs
5
5
  License: ASFv2
6
6
  Author: Trevor Grant
@@ -16,17 +16,18 @@ Provides-Extra: aws
16
16
  Provides-Extra: google
17
17
  Provides-Extra: headless-browser
18
18
  Provides-Extra: langchain
19
+ Provides-Extra: langflow
19
20
  Provides-Extra: smolagents
20
21
  Provides-Extra: testing
21
22
  Requires-Dist: GitPython (>=3.1.43,<4.0.0)
22
23
  Requires-Dist: boto3 (>=1.34.97,<2.0.0) ; extra == "aws"
23
- Requires-Dist: google-api-python-client (>=2.161.0,<3.0.0) ; extra == "google"
24
+ Requires-Dist: google-api-python-client (>=2.154.0,<3.0.0) ; extra == "google"
24
25
  Requires-Dist: jsonschema (>=4.23.0,<5.0.0)
25
- Requires-Dist: langchain (>=0.3.16,<0.4.0) ; extra == "langchain"
26
+ Requires-Dist: langchain-core (>=0.3.16,<0.4.0) ; (python_version < "3.13") and (extra == "langchain")
26
27
  Requires-Dist: openai (>=1.60.2,<2.0.0)
27
28
  Requires-Dist: pydantic (>=2.10.6,<3.0.0) ; extra == "langchain"
28
29
  Requires-Dist: pygithub (>=2.6.1,<3.0.0)
29
- Requires-Dist: pytest (>=8.3.4,<9.0.0) ; extra == "testing"
30
+ Requires-Dist: pytest (>=8.3.5,<9.0.0) ; extra == "testing"
30
31
  Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
31
32
  Requires-Dist: requests (>=2.32.3,<3.0.0)
32
33
  Requires-Dist: requests-mock (>=1.12.1,<2.0.0) ; extra == "testing"
@@ -60,7 +61,7 @@ functionality for various tasks.
60
61
  3. New Contributor Friendly
61
62
  - [Curated contribution pathways](https://the-ai-alliance.github.io/gofannon/developers/)
62
63
  - [Gamified Contributor Process](https://the-ai-alliance.github.io/gofannon/leaderboard.html)
63
- ## 🎓🎓 Why the name `gofanon`? 🎓🎓
64
+ ## 🎓🎓 Why the name `gofannon`? 🎓🎓
64
65
 
65
66
  See [`why_the_name_gofannon`](https://the-ai-alliance.github.io/gofannon/about/the_name_gofannon/) for the rich story on why we chose to honor this Celtic Diety
66
67
 
@@ -24,7 +24,7 @@ functionality for various tasks.
24
24
  3. New Contributor Friendly
25
25
  - [Curated contribution pathways](https://the-ai-alliance.github.io/gofannon/developers/)
26
26
  - [Gamified Contributor Process](https://the-ai-alliance.github.io/gofannon/leaderboard.html)
27
- ## 🎓🎓 Why the name `gofanon`? 🎓🎓
27
+ ## 🎓🎓 Why the name `gofannon`? 🎓🎓
28
28
 
29
29
  See [`why_the_name_gofannon`](https://the-ai-alliance.github.io/gofannon/about/the_name_gofannon/) for the rich story on why we chose to honor this Celtic Diety
30
30
 
@@ -5,11 +5,16 @@ from typing import Any, Callable
5
5
  import json
6
6
  import logging
7
7
  from pathlib import Path
8
+
9
+ import anyio
10
+
8
11
  from ..config import ToolConfig
9
12
 
10
13
  from .smol_agents import SmolAgentsMixin
11
14
  from .langchain import LangchainMixin
12
15
  from .bedrock import BedrockMixin
16
+ from .langflow import LangflowMixin
17
+ from .mcp import MCPMixin
13
18
 
14
19
 
15
20
  @dataclass
@@ -62,7 +67,12 @@ class WorkflowContext:
62
67
  self.execution_log.append(entry)
63
68
 
64
69
 
65
- class BaseTool(SmolAgentsMixin, LangchainMixin, BedrockMixin, ABC):
70
+ class BaseTool(SmolAgentsMixin,
71
+ LangchainMixin,
72
+ BedrockMixin,
73
+ LangflowMixin,
74
+ MCPMixin,
75
+ ABC):
66
76
  def __init__(self, **kwargs):
67
77
  self.logger = logging.getLogger(
68
78
  f"{self.__class__.__module__}.{self.__class__.__name__}"
@@ -111,3 +121,6 @@ class BaseTool(SmolAgentsMixin, LangchainMixin, BedrockMixin, ABC):
111
121
  return ToolResult(success=True, output=result)
112
122
  except Exception as e:
113
123
  return ToolResult(success=False, output=None, error=str(e), retryable=True)
124
+
125
+ async def execute_async(self, arguments: dict):
126
+ return await anyio.to_thread.run_sync(self.fn, **arguments)
@@ -0,0 +1,111 @@
1
+ try:
2
+ from langflow.custom import Component
3
+ from langflow.io import MessageTextInput, IntInput, BoolInput, FloatInput, Output
4
+ from langflow.schema import Data
5
+
6
+ _HAS_LANGFLOW = True
7
+ except ImportError:
8
+ _HAS_LANGFLOW = False
9
+
10
+
11
+ class LangflowMixin:
12
+ def import_from_langflow(self, langflow_component):
13
+ """Adapt a Langflow component to a Gofannon tool"""
14
+ if not _HAS_LANGFLOW:
15
+ raise RuntimeError(
16
+ "langflow is not installed. Install with `pip install langflow`"
17
+ )
18
+
19
+ self.name = langflow_component.display_name.replace(" ", "_").lower()
20
+ self.description = langflow_component.description
21
+
22
+ # Extract parameters from component inputs
23
+ parameters = {
24
+ "type": "object",
25
+ "properties": {},
26
+ "required": []
27
+ }
28
+
29
+ for component_input in langflow_component.inputs:
30
+ if component_input.name in ["self", "context"]:
31
+ continue
32
+
33
+ param_type = "string"
34
+ if isinstance(component_input, (IntInput, FloatInput)):
35
+ param_type = "number"
36
+ elif isinstance(component_input, BoolInput):
37
+ param_type = "boolean"
38
+
39
+ parameters["properties"][component_input.name] = {
40
+ "type": param_type,
41
+ "description": component_input.info or ""
42
+ }
43
+
44
+ if component_input.required:
45
+ parameters["required"].append(component_input.name)
46
+
47
+ self.definition = {
48
+ "function": {
49
+ "name": self.name,
50
+ "description": self.description,
51
+ "parameters": parameters
52
+ }
53
+ }
54
+
55
+ # Create execution wrapper
56
+ def adapted_fn(**kwargs):
57
+ result = langflow_component.build()(**kwargs)
58
+ return result.data if isinstance(result, Data) else result
59
+
60
+ self.fn = adapted_fn
61
+
62
+ def export_to_langflow(self):
63
+ """Convert Gofannon tool to Langflow component"""
64
+ if not _HAS_LANGFLOW:
65
+ raise RuntimeError(
66
+ "langflow is not installed. Install with `pip install langflow`"
67
+ )
68
+
69
+ parameters = self.definition.get("function", {}).get("parameters", {})
70
+ param_properties = parameters.get("properties", {})
71
+ required_params = parameters.get("required", [])
72
+
73
+ # Create input fields
74
+ component_inputs = []
75
+ type_map = {
76
+ "string": MessageTextInput,
77
+ "number": FloatInput,
78
+ "integer": IntInput,
79
+ "boolean": BoolInput
80
+ }
81
+
82
+ for param_name, param_def in param_properties.items():
83
+ input_type = param_def.get("type", "string")
84
+ InputClass = type_map.get(input_type, MessageTextInput)
85
+
86
+ component_inputs.append(
87
+ InputClass(
88
+ name=param_name,
89
+ display_name=param_name.replace("_", " ").title(),
90
+ info=param_def.get("description", ""),
91
+ required=param_name in required_params,
92
+ tool_mode=True
93
+ )
94
+ )
95
+
96
+ # Define component class
97
+ class ExportedComponent(Component):
98
+ display_name = self.definition["function"]["name"].title()
99
+ description = self.definition["function"]["description"]
100
+ icon = "tool"
101
+
102
+ inputs = component_inputs
103
+ outputs = [Output(display_name="Result", name="result", method="run_tool")]
104
+
105
+ def run_tool(self, **kwargs):
106
+ result = self.tool.execute(context=None, **kwargs)
107
+ return Data(data=result.output)
108
+
109
+ # Attach tool instance to component class
110
+ ExportedComponent.tool = self
111
+ return ExportedComponent
@@ -0,0 +1,6 @@
1
+ from json import dumps
2
+
3
+ class MCPMixin:
4
+ def export_to_mcp(self, fast_mcp_server=None):
5
+ """Convert Gofannon tool definition to MCP Tool schema"""
6
+ fast_mcp_server.add_tool(fn=self.fn, name=self.name, description=dumps(self.definition))
@@ -13,7 +13,8 @@ class ToolConfig:
13
13
  'deepinfra_api_key': os.getenv('DEEPINFRA_API_KEY'),
14
14
  'arxiv_api_key': os.getenv('ARXIV_API_KEY'),
15
15
  'google_search_api_key': os.getenv('GOOGLE_SEARCH_API_KEY'),
16
- 'google_search_engine_id': os.getenv('GOOGLE_SEARCH_ENGINE_ID')
16
+ 'google_search_engine_id': os.getenv('GOOGLE_SEARCH_ENGINE_ID'),
17
+ 'nasa_apod_api_key': os.getenv('NASA_APOD_API_KEY'),
17
18
  }
18
19
 
19
20
  @classmethod
@@ -0,0 +1,68 @@
1
+ from ..base import BaseTool
2
+ from ..config import FunctionRegistry, ToolConfig
3
+ import logging
4
+ import requests
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ """Fetch the Astronomy Picture of the Day (APOD) from NASA's API.
9
+
10
+ This tool retrieves the daily astronomy image, including metadata such as the
11
+ title, explanation, date, and media type. It interacts with NASA's APOD API
12
+ and returns the data as a structured dictionary.
13
+
14
+ Authentication:
15
+ Requires an API key from NASA, available at https://api.nasa.gov/
16
+ The API key should be set in the environment as NASA_APOD_API_KEY
17
+ or passed as an argument during initialization.
18
+ """
19
+
20
+ @FunctionRegistry.register
21
+ class AstronomyPhotoOfTheDayTool(BaseTool):
22
+ def __init__(self, api_key=None ,name='apod'):
23
+ super().__init__()
24
+ self.name = name
25
+ self.api_key = api_key or ToolConfig.get("nasa_apod_api_key")
26
+
27
+ @property
28
+ def definition(self):
29
+ return {
30
+ "type": "function",
31
+ "function": {
32
+ "name": self.name,
33
+ "description": "Get the Astronomy Picture of the Day from NASA",
34
+ "parameters":{
35
+ "type": "object",
36
+ "properties": {},
37
+ "required": []
38
+ }
39
+ }
40
+ }
41
+
42
+ def fn(self):
43
+ logger.debug("Fetching NASA APOD data")
44
+ if not self.api_key:
45
+ logger.error("API key is missing. Cannot fetch APOD data.")
46
+ return {"error": "API key is missing. Please set it in the environment or pass it as an argument."}
47
+ url = "https://api.nasa.gov/planetary/apod"
48
+ params = {
49
+ "api_key": self.api_key
50
+ }
51
+
52
+ try:
53
+ response = requests.get(url, params=params)
54
+ response.raise_for_status()
55
+ data = response.json()
56
+
57
+ return{
58
+ "title": data.get("title", "No title available"),
59
+ "date": data.get("date", "No date available"),
60
+ "explanation": data.get("explanation", "No explanation available"),
61
+ "url": data.get("url", None),
62
+ "media_type": data.get("media_type", "unknown"),
63
+ }
64
+ except requests.exceptions.RequestException as e:
65
+ logger.error(f"Error fetching data from NASA APOD: {e}")
66
+ return {
67
+ "error": str(e)
68
+ }
File without changes
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "gofannon"
3
- version = "0.25.14"
3
+ version = "0.25.15"
4
4
  description = "A collection of tools for LLMs"
5
5
  authors = ["Trevor Grant <trevor.d.grant@gmail.com>"]
6
6
  license = "ASFv2"
@@ -8,7 +8,7 @@ readme = "README.md"
8
8
  packages = [{include = "gofannon"}]
9
9
 
10
10
  [tool.poetry.dependencies]
11
- python = "^3.10"
11
+ python = ">=3.10,<4.0"
12
12
  openai = "^1.60.2"
13
13
  requests = "^2.32.3"
14
14
  GitPython = "^3.1.43"
@@ -16,26 +16,31 @@ python-dotenv = "^1.0.1"
16
16
  jsonschema = "^4.23.0"
17
17
  pygithub = "^2.6.1"
18
18
 
19
- pytest = { version = "^8.3.4", optional = true }
20
- langchain = { version = "^0.3.16", optional = true }
19
+ # Optional dependencies
20
+ pytest = { version = "^8.3.5", optional = true }
21
+ langchain-core = { version = "^0.3.16", optional = true, python = "<3.13" }
21
22
  pydantic = { version = "^2.10.6", optional = true }
22
23
  smolagents = { version = "^1.6.0", optional = true }
23
24
  selenium = { version = "^4.10.0", optional = true }
24
- google-api-python-client = { version = "^2.161.0", optional = true}
25
- requests-mock = {version = "^1.12.1", optional = true}
25
+ google-api-python-client = { version = "^2.154.0", optional = true }
26
+ requests-mock = { version = "^1.12.1", optional = true }
26
27
  boto3 = { version = "^1.34.97", optional = true }
28
+ anyio = { version = "^4.9.0", optional = true}
27
29
 
28
30
  [tool.poetry.extras]
29
- testing = ["pytest","requests-mock"]
30
- langchain = ["langchain", "pydantic"]
31
+ testing = ["pytest", "requests-mock"]
32
+ langchain = ["langchain-core", "pydantic"]
31
33
  smolagents = ["smolagents"]
32
34
  headless_browser = ["selenium"]
33
35
  google = ["google-api-python-client"]
34
36
  aws = ["boto3"]
37
+ langflow = []
35
38
 
36
39
  [tool.poetry.group.dev.dependencies]
37
40
  pytest = "^8.3.5"
38
41
  responses = "^0.25.7"
42
+ pytest-asyncio = "0.26.0"
43
+ mcp = "1.5.0"
39
44
 
40
45
  [build-system]
41
46
  requires = ["poetry-core"]
File without changes
File without changes