aiqtoolkit-agno 1.2.0a20250706__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 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
- nvidia_args = {"id": config_obj.get("id")}
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
- nvidia_args["base_url"] = config_obj.get("base_url")
52
- yield Nvidia(**nvidia_args)
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
- config_obj = {
61
- **llm_config.model_dump(exclude={"type"}, by_alias=True),
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 OpenAIChat(**config_obj)
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
- _type: str = "serp_api_tool" # Flat type name without namespacing
37
- api_key: str | None = None
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
- Parameters
49
- ----------
50
- tool_config : SerpApiToolConfig
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 = "") -> 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
- # Only provide initialization message once, then provide a more direct error
88
- if not _empty_query_handled:
89
- _empty_query_handled = True
90
- logger.info("Empty query provided, returning initialization message (first time)")
91
- return "SerpAPI Tool is initialized and ready for use. Please provide a search query."
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
- results = await search_tool.search_google(query=query, num_results=tool_config.max_results)
104
- logger.info(f"SerpAPI returned {len(results)} results")
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 i, result in enumerate(results, 1):
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(f"Error searching with SerpAPI: {e}")
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
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiqtoolkit-agno
3
- Version: 1.2.0a20250706
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.0a20250706
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
@@ -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=KvtcyBCKzN1gEVet8RORjjYh1dctazzC8V2xZhwCSgc,2459
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=93Rnj9tmK8N4hVWzXHMflcTOrj8YLNiY9b2jT_K72d8,5303
9
- aiqtoolkit_agno-1.2.0a20250706.dist-info/METADATA,sha256=9XLDipRQ9fel_cN-iCai1jNMWigptxMthYBavUC4D7s,1577
10
- aiqtoolkit_agno-1.2.0a20250706.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
- aiqtoolkit_agno-1.2.0a20250706.dist-info/entry_points.txt,sha256=iMjZt0Aziz5vGiuTfSNjy1gWeOj2URFhhKt-gti-9sY,103
12
- aiqtoolkit_agno-1.2.0a20250706.dist-info/top_level.txt,sha256=fo7AzYcNhZ_tRWrhGumtxwnxMew4xrT1iwouDy_f0Kc,4
13
- aiqtoolkit_agno-1.2.0a20250706.dist-info/RECORD,,
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,,