aiqtoolkit-agno 1.2.0a20250707__py3-none-any.whl → 1.2.0a20250730__py3-none-any.whl
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.
Potentially problematic release.
This version of aiqtoolkit-agno might be problematic. Click here for more details.
- aiq/plugins/agno/llm.py +30 -7
- aiq/plugins/agno/tools/serp_api_tool.py +28 -51
- {aiqtoolkit_agno-1.2.0a20250707.dist-info → aiqtoolkit_agno-1.2.0a20250730.dist-info}/METADATA +2 -2
- {aiqtoolkit_agno-1.2.0a20250707.dist-info → aiqtoolkit_agno-1.2.0a20250730.dist-info}/RECORD +7 -7
- {aiqtoolkit_agno-1.2.0a20250707.dist-info → aiqtoolkit_agno-1.2.0a20250730.dist-info}/WHEEL +0 -0
- {aiqtoolkit_agno-1.2.0a20250707.dist-info → aiqtoolkit_agno-1.2.0a20250730.dist-info}/entry_points.txt +0 -0
- {aiqtoolkit_agno-1.2.0a20250707.dist-info → aiqtoolkit_agno-1.2.0a20250730.dist-info}/top_level.txt +0 -0
aiq/plugins/agno/llm.py
CHANGED
|
@@ -18,8 +18,10 @@ import os
|
|
|
18
18
|
from aiq.builder.builder import Builder
|
|
19
19
|
from aiq.builder.framework_enum import LLMFrameworkEnum
|
|
20
20
|
from aiq.cli.register_workflow import register_llm_client
|
|
21
|
+
from aiq.data_models.retry_mixin import RetryMixin
|
|
21
22
|
from aiq.llm.nim_llm import NIMModelConfig
|
|
22
23
|
from aiq.llm.openai_llm import OpenAIModelConfig
|
|
24
|
+
from aiq.utils.exception_handlers.automatic_retries import patch_with_retry
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
@register_llm_client(config_type=NIMModelConfig, wrapper_type=LLMFrameworkEnum.AGNO)
|
|
@@ -46,10 +48,20 @@ async def nim_agno(llm_config: NIMModelConfig, builder: Builder):
|
|
|
46
48
|
os.environ["NVIDIA_API_KEY"] = nvidai_api_key
|
|
47
49
|
|
|
48
50
|
# Create Nvidia instance with conditional base_url
|
|
49
|
-
|
|
51
|
+
kwargs = {"id": config_obj.get("id")}
|
|
50
52
|
if "base_url" in config_obj and config_obj.get("base_url") is not None:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
kwargs["base_url"] = config_obj.get("base_url")
|
|
54
|
+
|
|
55
|
+
client = Nvidia(**kwargs) # type: ignore[arg-type]
|
|
56
|
+
|
|
57
|
+
if isinstance(client, RetryMixin):
|
|
58
|
+
|
|
59
|
+
client = patch_with_retry(client,
|
|
60
|
+
retries=llm_config.num_retries,
|
|
61
|
+
retry_codes=llm_config.retry_on_status_codes,
|
|
62
|
+
retry_on_messages=llm_config.retry_on_errors)
|
|
63
|
+
|
|
64
|
+
yield client
|
|
53
65
|
|
|
54
66
|
|
|
55
67
|
@register_llm_client(config_type=OpenAIModelConfig, wrapper_type=LLMFrameworkEnum.AGNO)
|
|
@@ -57,8 +69,19 @@ async def openai_agno(llm_config: OpenAIModelConfig, builder: Builder):
|
|
|
57
69
|
|
|
58
70
|
from agno.models.openai import OpenAIChat
|
|
59
71
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
72
|
+
# Use model_dump to get the proper field values with correct types
|
|
73
|
+
kwargs = llm_config.model_dump(exclude={"type"}, by_alias=True)
|
|
74
|
+
|
|
75
|
+
# AGNO uses 'id' instead of 'model' for the model name
|
|
76
|
+
if "model" in kwargs:
|
|
77
|
+
kwargs["id"] = kwargs.pop("model")
|
|
78
|
+
|
|
79
|
+
client = OpenAIChat(**kwargs)
|
|
80
|
+
|
|
81
|
+
if isinstance(llm_config, RetryMixin):
|
|
82
|
+
client = patch_with_retry(client,
|
|
83
|
+
retries=llm_config.num_retries,
|
|
84
|
+
retry_codes=llm_config.retry_on_status_codes,
|
|
85
|
+
retry_on_messages=llm_config.retry_on_errors)
|
|
63
86
|
|
|
64
|
-
yield
|
|
87
|
+
yield client
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
import logging
|
|
17
17
|
import os
|
|
18
18
|
|
|
19
|
+
from pydantic import Field
|
|
20
|
+
|
|
19
21
|
from aiq.builder.builder import Builder
|
|
20
22
|
from aiq.builder.framework_enum import LLMFrameworkEnum
|
|
21
23
|
from aiq.builder.function_info import FunctionInfo
|
|
@@ -24,38 +26,31 @@ from aiq.data_models.function import FunctionBaseConfig
|
|
|
24
26
|
|
|
25
27
|
logger = logging.getLogger(__name__)
|
|
26
28
|
|
|
27
|
-
# Module level variable to track empty query handling
|
|
28
|
-
_empty_query_handled = False
|
|
29
|
-
|
|
30
29
|
|
|
31
30
|
class SerpApiToolConfig(FunctionBaseConfig, name="serp_api_tool"):
|
|
32
31
|
"""
|
|
33
32
|
Tool that retrieves search results from the web using SerpAPI.
|
|
34
33
|
Requires a SERP_API_KEY.
|
|
35
34
|
"""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
max_results: int = 5
|
|
35
|
+
api_key: str | None = Field(default=None, description="The API key for the SerpAPI service.")
|
|
36
|
+
max_results: int = Field(default=5, description="The maximum number of results to return.")
|
|
39
37
|
|
|
40
38
|
|
|
41
39
|
@register_function(config_type=SerpApiToolConfig, framework_wrappers=[LLMFrameworkEnum.AGNO])
|
|
42
40
|
async def serp_api_tool(tool_config: SerpApiToolConfig, builder: Builder):
|
|
43
|
-
"""
|
|
44
|
-
Create a SerpAPI search tool for use with Agno.
|
|
41
|
+
"""Create a SerpAPI search tool for use with Agno.
|
|
45
42
|
|
|
46
43
|
This creates a search function that uses SerpAPI to search the web.
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
Configuration for the SerpAPI tool
|
|
52
|
-
builder : Builder
|
|
53
|
-
The AIQ Toolkit builder instance
|
|
45
|
+
Args:
|
|
46
|
+
tool_config (SerpApiToolConfig): Configuration for the SerpAPI tool.
|
|
47
|
+
builder (Builder): The AIQ Toolkit builder instance.
|
|
54
48
|
|
|
55
|
-
Returns
|
|
56
|
-
|
|
57
|
-
A FunctionInfo object wrapping the SerpAPI search functionality
|
|
49
|
+
Returns:
|
|
50
|
+
FunctionInfo: A FunctionInfo object wrapping the SerpAPI search functionality.
|
|
58
51
|
"""
|
|
52
|
+
import json
|
|
53
|
+
|
|
59
54
|
from agno.tools.serpapi import SerpApiTools
|
|
60
55
|
|
|
61
56
|
if (not tool_config.api_key):
|
|
@@ -69,43 +64,35 @@ async def serp_api_tool(tool_config: SerpApiToolConfig, builder: Builder):
|
|
|
69
64
|
search_tool = SerpApiTools(api_key=tool_config.api_key)
|
|
70
65
|
|
|
71
66
|
# Simple search function with a single string parameter
|
|
72
|
-
async def _serp_api_search(query: str
|
|
67
|
+
async def _serp_api_search(query: str) -> str:
|
|
73
68
|
"""
|
|
74
69
|
Search the web using SerpAPI.
|
|
75
70
|
|
|
76
71
|
Args:
|
|
77
|
-
query: The search query to perform. If empty, returns initialization message.
|
|
72
|
+
query (str): The search query to perform. If empty, returns initialization message.
|
|
78
73
|
|
|
79
74
|
Returns:
|
|
80
|
-
Formatted search results or initialization message
|
|
75
|
+
str: Formatted search results or initialization message.
|
|
81
76
|
"""
|
|
82
|
-
# Use the module-level variable for tracking
|
|
83
|
-
global _empty_query_handled
|
|
84
77
|
|
|
85
|
-
# Handle the case where no query is provided
|
|
86
78
|
if not query or query.strip() == "":
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
else:
|
|
93
|
-
logger.warning("Empty query provided again, returning error message to stop looping")
|
|
94
|
-
return "ERROR: Search query cannot be empty. Please provide a specific search term to continue."
|
|
95
|
-
else:
|
|
96
|
-
# Reset the empty query flag when we get a valid query
|
|
97
|
-
_empty_query_handled = False
|
|
98
|
-
|
|
99
|
-
logger.info(f"Searching SerpAPI with query: '{query}', max_results: {tool_config.max_results}")
|
|
79
|
+
exception_msg = "Search query cannot be empty. Please provide a specific search term to continue."
|
|
80
|
+
logger.warning(exception_msg)
|
|
81
|
+
return exception_msg
|
|
82
|
+
|
|
83
|
+
logger.info("Searching SerpAPI with query: '%s', max_results: %s", query, tool_config.max_results)
|
|
100
84
|
|
|
101
85
|
try:
|
|
102
86
|
# Perform the search
|
|
103
|
-
|
|
104
|
-
|
|
87
|
+
raw_all_results: str = search_tool.search_google(query=query, num_results=tool_config.max_results)
|
|
88
|
+
all_results: dict = json.loads(raw_all_results)
|
|
89
|
+
search_results = all_results.get('search_results', [])
|
|
90
|
+
|
|
91
|
+
logger.info("SerpAPI returned %s results", len(search_results))
|
|
105
92
|
|
|
106
93
|
# Format the results as a string
|
|
107
94
|
formatted_results = []
|
|
108
|
-
for
|
|
95
|
+
for result in search_results:
|
|
109
96
|
title = result.get('title', 'No Title')
|
|
110
97
|
link = result.get('link', 'No Link')
|
|
111
98
|
snippet = result.get('snippet', 'No Snippet')
|
|
@@ -118,21 +105,11 @@ async def serp_api_tool(tool_config: SerpApiToolConfig, builder: Builder):
|
|
|
118
105
|
|
|
119
106
|
return "\n\n---\n\n".join(formatted_results)
|
|
120
107
|
except Exception as e:
|
|
121
|
-
logger.exception(
|
|
108
|
+
logger.exception("Error searching with SerpAPI: %s", e)
|
|
122
109
|
return f"Error performing search: {str(e)}"
|
|
123
110
|
|
|
124
|
-
# Create a FunctionInfo object with simple string parameter
|
|
125
111
|
fn_info = FunctionInfo.from_fn(
|
|
126
112
|
_serp_api_search,
|
|
127
|
-
description="""
|
|
128
|
-
This tool searches the web using SerpAPI and returns relevant results for the given query.
|
|
129
|
-
|
|
130
|
-
Args:
|
|
131
|
-
query (str, optional): The search query to perform. A valid search query is required.
|
|
132
|
-
|
|
133
|
-
Returns:
|
|
134
|
-
str: Formatted search results or error message if query is empty.
|
|
135
|
-
""",
|
|
136
|
-
)
|
|
113
|
+
description="""This tool searches the web using SerpAPI and returns relevant results for the given query.""")
|
|
137
114
|
|
|
138
115
|
yield fn_info
|
{aiqtoolkit_agno-1.2.0a20250707.dist-info → aiqtoolkit_agno-1.2.0a20250730.dist-info}/METADATA
RENAMED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aiqtoolkit-agno
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.0a20250730
|
|
4
4
|
Summary: Subpackage for Agno integration in AIQtoolkit
|
|
5
5
|
Keywords: ai,rag,agents
|
|
6
6
|
Classifier: Programming Language :: Python
|
|
7
7
|
Requires-Python: <3.13,>=3.11
|
|
8
8
|
Description-Content-Type: text/markdown
|
|
9
|
-
Requires-Dist: aiqtoolkit==v1.2.
|
|
9
|
+
Requires-Dist: aiqtoolkit==v1.2.0a20250730
|
|
10
10
|
Requires-Dist: agno~=1.2.3
|
|
11
11
|
Requires-Dist: openai~=1.66
|
|
12
12
|
Requires-Dist: google-search-results~=2.4.2
|
{aiqtoolkit_agno-1.2.0a20250707.dist-info → aiqtoolkit_agno-1.2.0a20250730.dist-info}/RECORD
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
aiq/meta/pypi.md,sha256=N2ermX9UkrluhitorV664jAxkwiT_gmbMyDHyZhb8N4,1174
|
|
2
2
|
aiq/plugins/agno/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
aiq/plugins/agno/llm.py,sha256=
|
|
3
|
+
aiq/plugins/agno/llm.py,sha256=d08EfB4xOFwNh6cgaAoFPBiXVSofazd_puZRK1oO8Zg,3434
|
|
4
4
|
aiq/plugins/agno/register.py,sha256=6vC1TjMxo3igqTnEtVFgLEf_jgLYkBfBZxjwqxGng6w,820
|
|
5
5
|
aiq/plugins/agno/tool_wrapper.py,sha256=bWsCdx6IkzOZbvBYC30N5mvGnHNVBScdHji6Mj9amB0,15939
|
|
6
6
|
aiq/plugins/agno/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
aiq/plugins/agno/tools/register.py,sha256=OCmzR03CHmQHm34ZEascM1dRVh-ALMs2mafDcqLDz6s,775
|
|
8
|
-
aiq/plugins/agno/tools/serp_api_tool.py,sha256=
|
|
9
|
-
aiqtoolkit_agno-1.2.
|
|
10
|
-
aiqtoolkit_agno-1.2.
|
|
11
|
-
aiqtoolkit_agno-1.2.
|
|
12
|
-
aiqtoolkit_agno-1.2.
|
|
13
|
-
aiqtoolkit_agno-1.2.
|
|
8
|
+
aiq/plugins/agno/tools/serp_api_tool.py,sha256=gTLWwsDmkzmJ6Zp-OzupbwA6t_neSCGrzKdrGQcpIkg,4450
|
|
9
|
+
aiqtoolkit_agno-1.2.0a20250730.dist-info/METADATA,sha256=cRelDOqeF8WgnLbEBEBGEZQshqFMbf3VPofjyN5LPe0,1577
|
|
10
|
+
aiqtoolkit_agno-1.2.0a20250730.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
+
aiqtoolkit_agno-1.2.0a20250730.dist-info/entry_points.txt,sha256=iMjZt0Aziz5vGiuTfSNjy1gWeOj2URFhhKt-gti-9sY,103
|
|
12
|
+
aiqtoolkit_agno-1.2.0a20250730.dist-info/top_level.txt,sha256=fo7AzYcNhZ_tRWrhGumtxwnxMew4xrT1iwouDy_f0Kc,4
|
|
13
|
+
aiqtoolkit_agno-1.2.0a20250730.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{aiqtoolkit_agno-1.2.0a20250707.dist-info → aiqtoolkit_agno-1.2.0a20250730.dist-info}/top_level.txt
RENAMED
|
File without changes
|