agno 2.0.7__py3-none-any.whl → 2.0.9__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.
- agno/agent/agent.py +83 -51
- agno/db/base.py +14 -0
- agno/db/dynamo/dynamo.py +107 -27
- agno/db/firestore/firestore.py +109 -33
- agno/db/gcs_json/gcs_json_db.py +100 -20
- agno/db/in_memory/in_memory_db.py +95 -20
- agno/db/json/json_db.py +101 -21
- agno/db/migrations/v1_to_v2.py +322 -47
- agno/db/mongo/mongo.py +251 -26
- agno/db/mysql/mysql.py +307 -6
- agno/db/postgres/postgres.py +279 -33
- agno/db/redis/redis.py +99 -22
- agno/db/singlestore/singlestore.py +319 -38
- agno/db/sqlite/sqlite.py +339 -23
- agno/knowledge/embedder/sentence_transformer.py +3 -3
- agno/knowledge/knowledge.py +152 -31
- agno/knowledge/types.py +8 -0
- agno/models/anthropic/claude.py +0 -20
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/google/gemini.py +4 -8
- agno/models/huggingface/huggingface.py +2 -1
- agno/models/ollama/chat.py +52 -3
- agno/models/openai/chat.py +9 -7
- agno/models/openai/responses.py +21 -17
- agno/os/interfaces/agui/agui.py +2 -2
- agno/os/interfaces/agui/utils.py +81 -18
- agno/os/interfaces/base.py +2 -0
- agno/os/interfaces/slack/router.py +50 -10
- agno/os/interfaces/slack/slack.py +6 -4
- agno/os/interfaces/whatsapp/router.py +7 -4
- agno/os/interfaces/whatsapp/whatsapp.py +2 -2
- agno/os/router.py +18 -0
- agno/os/utils.py +10 -2
- agno/reasoning/azure_ai_foundry.py +2 -2
- agno/reasoning/deepseek.py +2 -2
- agno/reasoning/default.py +3 -1
- agno/reasoning/groq.py +2 -2
- agno/reasoning/ollama.py +2 -2
- agno/reasoning/openai.py +2 -2
- agno/run/base.py +15 -2
- agno/session/agent.py +8 -5
- agno/session/team.py +14 -10
- agno/team/team.py +218 -111
- agno/tools/function.py +43 -4
- agno/tools/mcp.py +60 -37
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/scrapegraph.py +58 -31
- agno/tools/whatsapp.py +1 -1
- agno/utils/gemini.py +147 -19
- agno/utils/models/claude.py +9 -0
- agno/utils/print_response/agent.py +18 -2
- agno/utils/print_response/team.py +22 -6
- agno/utils/reasoning.py +22 -1
- agno/utils/string.py +9 -0
- agno/vectordb/base.py +2 -2
- agno/vectordb/langchaindb/langchaindb.py +5 -7
- agno/vectordb/llamaindex/llamaindexdb.py +25 -6
- agno/workflow/workflow.py +30 -15
- {agno-2.0.7.dist-info → agno-2.0.9.dist-info}/METADATA +4 -1
- {agno-2.0.7.dist-info → agno-2.0.9.dist-info}/RECORD +64 -61
- {agno-2.0.7.dist-info → agno-2.0.9.dist-info}/WHEEL +0 -0
- {agno-2.0.7.dist-info → agno-2.0.9.dist-info}/licenses/LICENSE +0 -0
- {agno-2.0.7.dist-info → agno-2.0.9.dist-info}/top_level.txt +0 -0
agno/tools/scrapegraph.py
CHANGED
|
@@ -3,6 +3,7 @@ from os import getenv
|
|
|
3
3
|
from typing import Any, List, Optional
|
|
4
4
|
|
|
5
5
|
from agno.tools import Toolkit
|
|
6
|
+
from agno.utils.log import log_debug, log_error
|
|
6
7
|
|
|
7
8
|
try:
|
|
8
9
|
from scrapegraph_py import Client
|
|
@@ -23,11 +24,14 @@ class ScrapeGraphTools(Toolkit):
|
|
|
23
24
|
enable_crawl: bool = False,
|
|
24
25
|
enable_searchscraper: bool = False,
|
|
25
26
|
enable_agentic_crawler: bool = False,
|
|
27
|
+
enable_scrape: bool = False,
|
|
28
|
+
render_heavy_js: bool = False,
|
|
26
29
|
all: bool = False,
|
|
27
30
|
**kwargs,
|
|
28
31
|
):
|
|
29
32
|
self.api_key: Optional[str] = api_key or getenv("SGAI_API_KEY")
|
|
30
33
|
self.client = Client(api_key=self.api_key)
|
|
34
|
+
self.render_heavy_js = render_heavy_js
|
|
31
35
|
|
|
32
36
|
# Start with smartscraper by default
|
|
33
37
|
# Only enable markdownify if smartscraper is False
|
|
@@ -45,6 +49,8 @@ class ScrapeGraphTools(Toolkit):
|
|
|
45
49
|
tools.append(self.searchscraper)
|
|
46
50
|
if enable_agentic_crawler or all:
|
|
47
51
|
tools.append(self.agentic_crawler)
|
|
52
|
+
if enable_scrape or all:
|
|
53
|
+
tools.append(self.scrape)
|
|
48
54
|
|
|
49
55
|
super().__init__(name="scrapegraph_tools", tools=tools, **kwargs)
|
|
50
56
|
|
|
@@ -57,10 +63,13 @@ class ScrapeGraphTools(Toolkit):
|
|
|
57
63
|
The structured data extracted from the webpage
|
|
58
64
|
"""
|
|
59
65
|
try:
|
|
66
|
+
log_debug(f"ScrapeGraph smartscraper request for URL: {url}")
|
|
60
67
|
response = self.client.smartscraper(website_url=url, user_prompt=prompt)
|
|
61
68
|
return json.dumps(response["result"])
|
|
62
69
|
except Exception as e:
|
|
63
|
-
|
|
70
|
+
error_msg = f"Smartscraper failed: {str(e)}"
|
|
71
|
+
log_error(error_msg)
|
|
72
|
+
return f"Error: {error_msg}"
|
|
64
73
|
|
|
65
74
|
def markdownify(self, url: str) -> str:
|
|
66
75
|
"""Convert a webpage to markdown format.
|
|
@@ -70,10 +79,13 @@ class ScrapeGraphTools(Toolkit):
|
|
|
70
79
|
The markdown version of the webpage
|
|
71
80
|
"""
|
|
72
81
|
try:
|
|
82
|
+
log_debug(f"ScrapeGraph markdownify request for URL: {url}")
|
|
73
83
|
response = self.client.markdownify(website_url=url)
|
|
74
84
|
return response["result"]
|
|
75
85
|
except Exception as e:
|
|
76
|
-
|
|
86
|
+
error_msg = f"Markdownify failed: {str(e)}"
|
|
87
|
+
log_error(error_msg)
|
|
88
|
+
return f"Error: {error_msg}"
|
|
77
89
|
|
|
78
90
|
def crawl(
|
|
79
91
|
self,
|
|
@@ -100,10 +112,11 @@ class ScrapeGraphTools(Toolkit):
|
|
|
100
112
|
The structured data extracted from the website
|
|
101
113
|
"""
|
|
102
114
|
try:
|
|
115
|
+
log_debug(f"ScrapeGraph crawl request for URL: {url}")
|
|
103
116
|
response = self.client.crawl(
|
|
104
117
|
url=url,
|
|
105
118
|
prompt=prompt,
|
|
106
|
-
|
|
119
|
+
data_schema=schema,
|
|
107
120
|
cache_website=cache_website,
|
|
108
121
|
depth=depth,
|
|
109
122
|
max_pages=max_pages,
|
|
@@ -112,7 +125,9 @@ class ScrapeGraphTools(Toolkit):
|
|
|
112
125
|
)
|
|
113
126
|
return json.dumps(response, indent=2)
|
|
114
127
|
except Exception as e:
|
|
115
|
-
|
|
128
|
+
error_msg = f"Crawl failed: {str(e)}"
|
|
129
|
+
log_error(error_msg)
|
|
130
|
+
return f"Error: {error_msg}"
|
|
116
131
|
|
|
117
132
|
def agentic_crawler(
|
|
118
133
|
self,
|
|
@@ -143,21 +158,7 @@ class ScrapeGraphTools(Toolkit):
|
|
|
143
158
|
JSON string containing the scraping results, including request_id, status, and extracted data
|
|
144
159
|
"""
|
|
145
160
|
try:
|
|
146
|
-
|
|
147
|
-
if ai_extraction and not user_prompt:
|
|
148
|
-
return json.dumps({"error": "user_prompt is required when ai_extraction=True"})
|
|
149
|
-
|
|
150
|
-
# Validate URL format
|
|
151
|
-
if not url.strip():
|
|
152
|
-
return json.dumps({"error": "URL cannot be empty"})
|
|
153
|
-
if not (url.startswith("http://") or url.startswith("https://")):
|
|
154
|
-
return json.dumps({"error": "Invalid URL - must start with http:// or https://"})
|
|
155
|
-
|
|
156
|
-
# Validate steps
|
|
157
|
-
if not steps:
|
|
158
|
-
return json.dumps({"error": "Steps cannot be empty"})
|
|
159
|
-
if any(not step.strip() for step in steps):
|
|
160
|
-
return json.dumps({"error": "All steps must contain valid instructions"})
|
|
161
|
+
log_debug(f"ScrapeGraph agentic_crawler request for URL: {url}")
|
|
161
162
|
|
|
162
163
|
# Prepare parameters for the API call
|
|
163
164
|
params = {"url": url, "steps": steps, "use_session": use_session, "ai_extraction": ai_extraction}
|
|
@@ -170,26 +171,52 @@ class ScrapeGraphTools(Toolkit):
|
|
|
170
171
|
|
|
171
172
|
# Call the agentic scraper API
|
|
172
173
|
response = self.client.agenticscraper(**params)
|
|
173
|
-
|
|
174
174
|
return json.dumps(response, indent=2)
|
|
175
175
|
|
|
176
176
|
except Exception as e:
|
|
177
|
-
|
|
177
|
+
error_msg = f"Agentic crawler failed: {str(e)}"
|
|
178
|
+
log_error(error_msg)
|
|
179
|
+
return f"Error: {error_msg}"
|
|
178
180
|
|
|
179
|
-
def searchscraper(self,
|
|
181
|
+
def searchscraper(self, user_prompt: str) -> str:
|
|
180
182
|
"""Search the web and extract information from the web.
|
|
181
183
|
Args:
|
|
182
|
-
|
|
184
|
+
user_prompt (str): Search query
|
|
183
185
|
Returns:
|
|
184
186
|
JSON of the search results
|
|
185
187
|
"""
|
|
186
188
|
try:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
189
|
+
log_debug(f"ScrapeGraph searchscraper request with prompt: {user_prompt}")
|
|
190
|
+
response = self.client.searchscraper(user_prompt=user_prompt, render_heavy_js=self.render_heavy_js)
|
|
191
|
+
return json.dumps(response["result"])
|
|
192
|
+
except Exception as e:
|
|
193
|
+
error_msg = f"Searchscraper failed: {str(e)}"
|
|
194
|
+
log_error(error_msg)
|
|
195
|
+
return f"Error: {error_msg}"
|
|
196
|
+
|
|
197
|
+
def scrape(
|
|
198
|
+
self,
|
|
199
|
+
website_url: str,
|
|
200
|
+
headers: Optional[dict] = None,
|
|
201
|
+
) -> str:
|
|
202
|
+
"""Get raw HTML content from a website using the ScrapeGraphAI scrape API.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
website_url (str): The URL of the website to scrape
|
|
206
|
+
headers (Optional[dict]): Optional headers to send with the request
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
JSON string containing the HTML content and metadata
|
|
210
|
+
"""
|
|
211
|
+
try:
|
|
212
|
+
log_debug(f"ScrapeGraph scrape request for URL: {website_url}")
|
|
213
|
+
response = self.client.scrape(
|
|
214
|
+
website_url=website_url,
|
|
215
|
+
headers=headers,
|
|
216
|
+
render_heavy_js=self.render_heavy_js,
|
|
217
|
+
)
|
|
218
|
+
return json.dumps(response, indent=2)
|
|
194
219
|
except Exception as e:
|
|
195
|
-
|
|
220
|
+
error_msg = f"Scrape failed: {str(e)}"
|
|
221
|
+
log_error(error_msg)
|
|
222
|
+
return f"Error: {error_msg}"
|
agno/tools/whatsapp.py
CHANGED
agno/utils/gemini.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from typing import Any, Dict, List, Optional
|
|
2
|
+
from typing import Any, Dict, List, Optional, Type, Union
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
3
5
|
|
|
4
6
|
from agno.media import Image
|
|
5
7
|
from agno.utils.log import log_error, log_warning
|
|
@@ -9,12 +11,119 @@ try:
|
|
|
9
11
|
FunctionDeclaration,
|
|
10
12
|
Schema,
|
|
11
13
|
Tool,
|
|
12
|
-
|
|
14
|
+
)
|
|
15
|
+
from google.genai.types import (
|
|
16
|
+
Type as GeminiType,
|
|
13
17
|
)
|
|
14
18
|
except ImportError:
|
|
15
19
|
raise ImportError("`google-genai` not installed. Please install it using `pip install google-genai`")
|
|
16
20
|
|
|
17
21
|
|
|
22
|
+
def prepare_response_schema(pydantic_model: Type[BaseModel]) -> Union[Type[BaseModel], Schema]:
|
|
23
|
+
"""
|
|
24
|
+
Prepare a Pydantic model for use as Gemini response schema.
|
|
25
|
+
|
|
26
|
+
Returns the model directly if Gemini can handle it natively,
|
|
27
|
+
otherwise converts to Gemini's Schema format.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
pydantic_model: A Pydantic model class
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Either the original Pydantic model or a converted Schema object
|
|
34
|
+
"""
|
|
35
|
+
schema_dict = pydantic_model.model_json_schema()
|
|
36
|
+
|
|
37
|
+
# Convert to Gemini Schema if the model has problematic patterns
|
|
38
|
+
if needs_conversion(schema_dict):
|
|
39
|
+
try:
|
|
40
|
+
converted = convert_schema(schema_dict)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
log_warning(f"Failed to convert schema for {pydantic_model}: {e}")
|
|
43
|
+
converted = None
|
|
44
|
+
|
|
45
|
+
if converted is None:
|
|
46
|
+
# If conversion fails, let Gemini handle it directly
|
|
47
|
+
return pydantic_model
|
|
48
|
+
return converted
|
|
49
|
+
|
|
50
|
+
# Gemini can handle this model directly
|
|
51
|
+
return pydantic_model
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def needs_conversion(schema_dict: Dict[str, Any]) -> bool:
|
|
55
|
+
"""
|
|
56
|
+
Check if a schema needs conversion for Gemini.
|
|
57
|
+
|
|
58
|
+
Returns True if the schema has:
|
|
59
|
+
- Self-references or circular references
|
|
60
|
+
- Dict fields (additionalProperties) that Gemini doesn't handle well
|
|
61
|
+
- Empty object definitions that Gemini rejects
|
|
62
|
+
"""
|
|
63
|
+
# Check for dict fields (additionalProperties) anywhere in the schema
|
|
64
|
+
if has_additional_properties(schema_dict):
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
# Check if schema has $defs with circular references
|
|
68
|
+
if "$defs" in schema_dict:
|
|
69
|
+
defs = schema_dict["$defs"]
|
|
70
|
+
for def_name, def_schema in defs.items():
|
|
71
|
+
ref_path = f"#/$defs/{def_name}"
|
|
72
|
+
if has_self_reference(def_schema, ref_path):
|
|
73
|
+
return True
|
|
74
|
+
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def has_additional_properties(schema: Any) -> bool:
|
|
79
|
+
"""Check if schema has additionalProperties (Dict fields)"""
|
|
80
|
+
if isinstance(schema, dict):
|
|
81
|
+
# Direct check
|
|
82
|
+
if "additionalProperties" in schema:
|
|
83
|
+
return True
|
|
84
|
+
|
|
85
|
+
# Check properties recursively
|
|
86
|
+
if "properties" in schema:
|
|
87
|
+
for prop_schema in schema["properties"].values():
|
|
88
|
+
if has_additional_properties(prop_schema):
|
|
89
|
+
return True
|
|
90
|
+
|
|
91
|
+
# Check array items
|
|
92
|
+
if "items" in schema:
|
|
93
|
+
if has_additional_properties(schema["items"]):
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
return False
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def has_self_reference(schema: Dict, target_ref: str) -> bool:
|
|
100
|
+
"""Check if a schema references itself (directly or indirectly)"""
|
|
101
|
+
if isinstance(schema, dict):
|
|
102
|
+
# Direct self-reference
|
|
103
|
+
if schema.get("$ref") == target_ref:
|
|
104
|
+
return True
|
|
105
|
+
|
|
106
|
+
# Check properties
|
|
107
|
+
if "properties" in schema:
|
|
108
|
+
for prop_schema in schema["properties"].values():
|
|
109
|
+
if has_self_reference(prop_schema, target_ref):
|
|
110
|
+
return True
|
|
111
|
+
|
|
112
|
+
# Check array items
|
|
113
|
+
if "items" in schema:
|
|
114
|
+
if has_self_reference(schema["items"], target_ref):
|
|
115
|
+
return True
|
|
116
|
+
|
|
117
|
+
# Check anyOf/oneOf/allOf
|
|
118
|
+
for key in ["anyOf", "oneOf", "allOf"]:
|
|
119
|
+
if key in schema:
|
|
120
|
+
for sub_schema in schema[key]:
|
|
121
|
+
if has_self_reference(sub_schema, target_ref):
|
|
122
|
+
return True
|
|
123
|
+
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
|
|
18
127
|
def format_image_for_message(image: Image) -> Optional[Dict[str, Any]]:
|
|
19
128
|
# Case 1: Image is a URL
|
|
20
129
|
# Download the image from the URL and add it as base64 encoded data
|
|
@@ -66,7 +175,9 @@ def format_image_for_message(image: Image) -> Optional[Dict[str, Any]]:
|
|
|
66
175
|
return None
|
|
67
176
|
|
|
68
177
|
|
|
69
|
-
def convert_schema(
|
|
178
|
+
def convert_schema(
|
|
179
|
+
schema_dict: Dict[str, Any], root_schema: Optional[Dict[str, Any]] = None, visited_refs: Optional[set] = None
|
|
180
|
+
) -> Optional[Schema]:
|
|
70
181
|
"""
|
|
71
182
|
Recursively convert a JSON-like schema dictionary to a types.Schema object.
|
|
72
183
|
|
|
@@ -74,23 +185,39 @@ def convert_schema(schema_dict: Dict[str, Any], root_schema: Optional[Dict[str,
|
|
|
74
185
|
schema_dict (dict): The JSON schema dictionary with keys like "type", "description",
|
|
75
186
|
"properties", and "required".
|
|
76
187
|
root_schema (dict, optional): The root schema containing $defs for resolving $ref
|
|
188
|
+
visited_refs (set, optional): Set of visited $ref paths to detect circular references
|
|
77
189
|
|
|
78
190
|
Returns:
|
|
79
191
|
types.Schema: The converted schema.
|
|
80
192
|
"""
|
|
81
193
|
|
|
82
|
-
# If this is the initial call, set root_schema to self
|
|
194
|
+
# If this is the initial call, set root_schema to self and initialize visited_refs
|
|
83
195
|
if root_schema is None:
|
|
84
196
|
root_schema = schema_dict
|
|
197
|
+
if visited_refs is None:
|
|
198
|
+
visited_refs = set()
|
|
85
199
|
|
|
86
|
-
# Handle $ref references
|
|
200
|
+
# Handle $ref references with cycle detection
|
|
87
201
|
if "$ref" in schema_dict:
|
|
88
202
|
ref_path = schema_dict["$ref"]
|
|
203
|
+
|
|
204
|
+
# Check for circular reference
|
|
205
|
+
if ref_path in visited_refs:
|
|
206
|
+
# Return a basic object schema to break the cycle
|
|
207
|
+
return Schema(
|
|
208
|
+
type=GeminiType.OBJECT,
|
|
209
|
+
description=f"Circular reference to {ref_path}",
|
|
210
|
+
)
|
|
211
|
+
|
|
89
212
|
if ref_path.startswith("#/$defs/"):
|
|
90
213
|
def_name = ref_path.split("/")[-1]
|
|
91
214
|
if "$defs" in root_schema and def_name in root_schema["$defs"]:
|
|
215
|
+
# Add to visited set before recursing
|
|
216
|
+
new_visited = visited_refs.copy()
|
|
217
|
+
new_visited.add(ref_path)
|
|
218
|
+
|
|
92
219
|
referenced_schema = root_schema["$defs"][def_name]
|
|
93
|
-
return convert_schema(referenced_schema, root_schema)
|
|
220
|
+
return convert_schema(referenced_schema, root_schema, new_visited)
|
|
94
221
|
# If we can't resolve the reference, return None
|
|
95
222
|
return None
|
|
96
223
|
|
|
@@ -103,7 +230,7 @@ def convert_schema(schema_dict: Dict[str, Any], root_schema: Optional[Dict[str,
|
|
|
103
230
|
# Handle enum types
|
|
104
231
|
if "enum" in schema_dict:
|
|
105
232
|
enum_values = schema_dict["enum"]
|
|
106
|
-
return Schema(type=
|
|
233
|
+
return Schema(type=GeminiType.STRING, enum=enum_values, description=description, default=default)
|
|
107
234
|
|
|
108
235
|
if schema_type == "object":
|
|
109
236
|
# Handle regular objects with properties
|
|
@@ -117,8 +244,8 @@ def convert_schema(schema_dict: Dict[str, Any], root_schema: Optional[Dict[str,
|
|
|
117
244
|
prop_def["type"] = prop_type[0]
|
|
118
245
|
is_nullable = True
|
|
119
246
|
|
|
120
|
-
# Process property schema (pass root_schema for $ref resolution)
|
|
121
|
-
converted_schema = convert_schema(prop_def, root_schema)
|
|
247
|
+
# Process property schema (pass root_schema and visited_refs for $ref resolution)
|
|
248
|
+
converted_schema = convert_schema(prop_def, root_schema, visited_refs)
|
|
122
249
|
if converted_schema is not None:
|
|
123
250
|
if is_nullable:
|
|
124
251
|
converted_schema.nullable = True
|
|
@@ -128,14 +255,14 @@ def convert_schema(schema_dict: Dict[str, Any], root_schema: Optional[Dict[str,
|
|
|
128
255
|
|
|
129
256
|
if properties:
|
|
130
257
|
return Schema(
|
|
131
|
-
type=
|
|
258
|
+
type=GeminiType.OBJECT,
|
|
132
259
|
properties=properties,
|
|
133
260
|
required=required,
|
|
134
261
|
description=description,
|
|
135
262
|
default=default,
|
|
136
263
|
)
|
|
137
264
|
else:
|
|
138
|
-
return Schema(type=
|
|
265
|
+
return Schema(type=GeminiType.OBJECT, description=description, default=default)
|
|
139
266
|
|
|
140
267
|
# Handle Dict types (objects with additionalProperties but no properties)
|
|
141
268
|
elif "additionalProperties" in schema_dict:
|
|
@@ -170,7 +297,7 @@ def convert_schema(schema_dict: Dict[str, Any], root_schema: Optional[Dict[str,
|
|
|
170
297
|
placeholder_properties["example_key"].items = {} # type: ignore
|
|
171
298
|
|
|
172
299
|
return Schema(
|
|
173
|
-
type=
|
|
300
|
+
type=GeminiType.OBJECT,
|
|
174
301
|
properties=placeholder_properties,
|
|
175
302
|
description=description
|
|
176
303
|
or f"Dictionary with {value_type.lower()} values{type_description_suffix}. Can contain any number of key-value pairs.",
|
|
@@ -178,21 +305,22 @@ def convert_schema(schema_dict: Dict[str, Any], root_schema: Optional[Dict[str,
|
|
|
178
305
|
)
|
|
179
306
|
else:
|
|
180
307
|
# additionalProperties is false or true
|
|
181
|
-
return Schema(type=
|
|
308
|
+
return Schema(type=GeminiType.OBJECT, description=description, default=default)
|
|
182
309
|
|
|
183
310
|
# Handle empty objects
|
|
184
311
|
else:
|
|
185
|
-
return Schema(type=
|
|
312
|
+
return Schema(type=GeminiType.OBJECT, description=description, default=default)
|
|
186
313
|
|
|
187
314
|
elif schema_type == "array" and "items" in schema_dict:
|
|
188
315
|
if not schema_dict["items"]: # Handle empty {}
|
|
189
|
-
items = Schema(type=
|
|
316
|
+
items = Schema(type=GeminiType.STRING)
|
|
190
317
|
else:
|
|
191
|
-
|
|
318
|
+
converted_items = convert_schema(schema_dict["items"], root_schema, visited_refs)
|
|
319
|
+
items = converted_items if converted_items is not None else Schema(type=GeminiType.STRING)
|
|
192
320
|
min_items = schema_dict.get("minItems")
|
|
193
321
|
max_items = schema_dict.get("maxItems")
|
|
194
322
|
return Schema(
|
|
195
|
-
type=
|
|
323
|
+
type=GeminiType.ARRAY,
|
|
196
324
|
description=description,
|
|
197
325
|
items=items,
|
|
198
326
|
min_items=min_items,
|
|
@@ -201,7 +329,7 @@ def convert_schema(schema_dict: Dict[str, Any], root_schema: Optional[Dict[str,
|
|
|
201
329
|
|
|
202
330
|
elif schema_type == "string":
|
|
203
331
|
schema_kwargs = {
|
|
204
|
-
"type":
|
|
332
|
+
"type": GeminiType.STRING,
|
|
205
333
|
"description": description,
|
|
206
334
|
"default": default,
|
|
207
335
|
}
|
|
@@ -224,7 +352,7 @@ def convert_schema(schema_dict: Dict[str, Any], root_schema: Optional[Dict[str,
|
|
|
224
352
|
elif schema_type == "" and "anyOf" in schema_dict:
|
|
225
353
|
any_of = []
|
|
226
354
|
for sub_schema in schema_dict["anyOf"]:
|
|
227
|
-
sub_schema_converted = convert_schema(sub_schema, root_schema)
|
|
355
|
+
sub_schema_converted = convert_schema(sub_schema, root_schema, visited_refs)
|
|
228
356
|
any_of.append(sub_schema_converted)
|
|
229
357
|
|
|
230
358
|
is_nullable = False
|
agno/utils/models/claude.py
CHANGED
|
@@ -279,6 +279,15 @@ def format_messages(messages: List[Message]) -> Tuple[List[Dict[str, str]], str]
|
|
|
279
279
|
type="tool_use",
|
|
280
280
|
)
|
|
281
281
|
)
|
|
282
|
+
elif message.role == "tool":
|
|
283
|
+
content = []
|
|
284
|
+
content.append(
|
|
285
|
+
{
|
|
286
|
+
"type": "tool_result",
|
|
287
|
+
"tool_use_id": message.tool_call_id,
|
|
288
|
+
"content": str(message.content),
|
|
289
|
+
}
|
|
290
|
+
)
|
|
282
291
|
|
|
283
292
|
# Skip empty assistant responses
|
|
284
293
|
if message.role == "assistant" and not content:
|
|
@@ -44,6 +44,8 @@ def print_response_stream(
|
|
|
44
44
|
console: Optional[Any] = None,
|
|
45
45
|
add_history_to_context: Optional[bool] = None,
|
|
46
46
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
47
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
48
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
47
49
|
metadata: Optional[Dict[str, Any]] = None,
|
|
48
50
|
**kwargs: Any,
|
|
49
51
|
):
|
|
@@ -90,6 +92,8 @@ def print_response_stream(
|
|
|
90
92
|
knowledge_filters=knowledge_filters,
|
|
91
93
|
debug_mode=debug_mode,
|
|
92
94
|
add_history_to_context=add_history_to_context,
|
|
95
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
96
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
93
97
|
dependencies=dependencies,
|
|
94
98
|
metadata=metadata,
|
|
95
99
|
**kwargs,
|
|
@@ -223,6 +227,8 @@ async def aprint_response_stream(
|
|
|
223
227
|
console: Optional[Any] = None,
|
|
224
228
|
add_history_to_context: Optional[bool] = None,
|
|
225
229
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
230
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
231
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
226
232
|
metadata: Optional[Dict[str, Any]] = None,
|
|
227
233
|
**kwargs: Any,
|
|
228
234
|
):
|
|
@@ -269,6 +275,8 @@ async def aprint_response_stream(
|
|
|
269
275
|
knowledge_filters=knowledge_filters,
|
|
270
276
|
debug_mode=debug_mode,
|
|
271
277
|
add_history_to_context=add_history_to_context,
|
|
278
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
279
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
272
280
|
dependencies=dependencies,
|
|
273
281
|
metadata=metadata,
|
|
274
282
|
**kwargs,
|
|
@@ -415,7 +423,7 @@ def build_panels_stream(
|
|
|
415
423
|
reasoning_panel = create_panel(content=step_content, title=f"Reasoning step {i}", border_style="green")
|
|
416
424
|
panels.append(reasoning_panel)
|
|
417
425
|
|
|
418
|
-
if len(response_reasoning_content_buffer) > 0:
|
|
426
|
+
if len(response_reasoning_content_buffer) > 0 and show_reasoning:
|
|
419
427
|
# Create panel for thinking
|
|
420
428
|
thinking_panel = create_panel(
|
|
421
429
|
content=Text(response_reasoning_content_buffer),
|
|
@@ -490,6 +498,8 @@ def print_response(
|
|
|
490
498
|
console: Optional[Any] = None,
|
|
491
499
|
add_history_to_context: Optional[bool] = None,
|
|
492
500
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
501
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
502
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
493
503
|
metadata: Optional[Dict[str, Any]] = None,
|
|
494
504
|
**kwargs: Any,
|
|
495
505
|
):
|
|
@@ -527,6 +537,8 @@ def print_response(
|
|
|
527
537
|
knowledge_filters=knowledge_filters,
|
|
528
538
|
debug_mode=debug_mode,
|
|
529
539
|
add_history_to_context=add_history_to_context,
|
|
540
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
541
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
530
542
|
dependencies=dependencies,
|
|
531
543
|
metadata=metadata,
|
|
532
544
|
**kwargs,
|
|
@@ -590,6 +602,8 @@ async def aprint_response(
|
|
|
590
602
|
console: Optional[Any] = None,
|
|
591
603
|
add_history_to_context: Optional[bool] = None,
|
|
592
604
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
605
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
606
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
593
607
|
metadata: Optional[Dict[str, Any]] = None,
|
|
594
608
|
**kwargs: Any,
|
|
595
609
|
):
|
|
@@ -627,6 +641,8 @@ async def aprint_response(
|
|
|
627
641
|
knowledge_filters=knowledge_filters,
|
|
628
642
|
debug_mode=debug_mode,
|
|
629
643
|
add_history_to_context=add_history_to_context,
|
|
644
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
645
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
630
646
|
dependencies=dependencies,
|
|
631
647
|
metadata=metadata,
|
|
632
648
|
**kwargs,
|
|
@@ -711,7 +727,7 @@ def build_panels(
|
|
|
711
727
|
reasoning_panel = create_panel(content=step_content, title=f"Reasoning step {i}", border_style="green")
|
|
712
728
|
panels.append(reasoning_panel)
|
|
713
729
|
|
|
714
|
-
if isinstance(run_response, RunOutput) and run_response.reasoning_content is not None:
|
|
730
|
+
if isinstance(run_response, RunOutput) and run_response.reasoning_content is not None and show_reasoning:
|
|
715
731
|
# Create panel for thinking
|
|
716
732
|
thinking_panel = create_panel(
|
|
717
733
|
content=Text(run_response.reasoning_content),
|
|
@@ -36,6 +36,8 @@ def print_response(
|
|
|
36
36
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
37
37
|
add_history_to_context: Optional[bool] = None,
|
|
38
38
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
39
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
40
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
39
41
|
metadata: Optional[Dict[str, Any]] = None,
|
|
40
42
|
debug_mode: Optional[bool] = None,
|
|
41
43
|
**kwargs: Any,
|
|
@@ -88,6 +90,8 @@ def print_response(
|
|
|
88
90
|
knowledge_filters=knowledge_filters,
|
|
89
91
|
add_history_to_context=add_history_to_context,
|
|
90
92
|
dependencies=dependencies,
|
|
93
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
94
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
91
95
|
metadata=metadata,
|
|
92
96
|
debug_mode=debug_mode,
|
|
93
97
|
**kwargs,
|
|
@@ -121,7 +125,7 @@ def print_response(
|
|
|
121
125
|
panels.append(reasoning_panel)
|
|
122
126
|
live_console.update(Group(*panels))
|
|
123
127
|
|
|
124
|
-
if isinstance(run_response, TeamRunOutput) and run_response.reasoning_content is not None:
|
|
128
|
+
if isinstance(run_response, TeamRunOutput) and run_response.reasoning_content is not None and show_reasoning:
|
|
125
129
|
# Create panel for thinking
|
|
126
130
|
thinking_panel = create_panel(
|
|
127
131
|
content=Text(run_response.reasoning_content),
|
|
@@ -317,6 +321,8 @@ def print_response_stream(
|
|
|
317
321
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
318
322
|
add_history_to_context: Optional[bool] = None,
|
|
319
323
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
324
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
325
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
320
326
|
metadata: Optional[Dict[str, Any]] = None,
|
|
321
327
|
debug_mode: Optional[bool] = None,
|
|
322
328
|
**kwargs: Any,
|
|
@@ -386,6 +392,8 @@ def print_response_stream(
|
|
|
386
392
|
knowledge_filters=knowledge_filters,
|
|
387
393
|
add_history_to_context=add_history_to_context,
|
|
388
394
|
dependencies=dependencies,
|
|
395
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
396
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
389
397
|
metadata=metadata,
|
|
390
398
|
debug_mode=debug_mode,
|
|
391
399
|
yield_run_response=True,
|
|
@@ -489,7 +497,7 @@ def print_response_stream(
|
|
|
489
497
|
reasoning_panel = build_reasoning_step_panel(i, step, show_full_reasoning)
|
|
490
498
|
panels.append(reasoning_panel)
|
|
491
499
|
|
|
492
|
-
if len(_response_reasoning_content) > 0:
|
|
500
|
+
if len(_response_reasoning_content) > 0 and show_reasoning:
|
|
493
501
|
render = True
|
|
494
502
|
# Create panel for thinking
|
|
495
503
|
thinking_panel = create_panel(
|
|
@@ -671,7 +679,7 @@ def print_response_stream(
|
|
|
671
679
|
final_panels.append(reasoning_panel)
|
|
672
680
|
|
|
673
681
|
# Add thinking panel if available
|
|
674
|
-
if _response_reasoning_content:
|
|
682
|
+
if _response_reasoning_content and show_reasoning:
|
|
675
683
|
thinking_panel = create_panel(
|
|
676
684
|
content=Text(_response_reasoning_content),
|
|
677
685
|
title=f"Thinking ({response_timer.elapsed:.1f}s)",
|
|
@@ -841,6 +849,8 @@ async def aprint_response(
|
|
|
841
849
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
842
850
|
add_history_to_context: Optional[bool] = None,
|
|
843
851
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
852
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
853
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
844
854
|
metadata: Optional[Dict[str, Any]] = None,
|
|
845
855
|
debug_mode: Optional[bool] = None,
|
|
846
856
|
**kwargs: Any,
|
|
@@ -893,6 +903,8 @@ async def aprint_response(
|
|
|
893
903
|
knowledge_filters=knowledge_filters,
|
|
894
904
|
add_history_to_context=add_history_to_context,
|
|
895
905
|
dependencies=dependencies,
|
|
906
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
907
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
896
908
|
metadata=metadata,
|
|
897
909
|
debug_mode=debug_mode,
|
|
898
910
|
**kwargs,
|
|
@@ -926,7 +938,7 @@ async def aprint_response(
|
|
|
926
938
|
panels.append(reasoning_panel)
|
|
927
939
|
live_console.update(Group(*panels))
|
|
928
940
|
|
|
929
|
-
if isinstance(run_response, TeamRunOutput) and run_response.reasoning_content is not None:
|
|
941
|
+
if isinstance(run_response, TeamRunOutput) and run_response.reasoning_content is not None and show_reasoning:
|
|
930
942
|
# Create panel for thinking
|
|
931
943
|
thinking_panel = create_panel(
|
|
932
944
|
content=Text(run_response.reasoning_content),
|
|
@@ -1120,6 +1132,8 @@ async def aprint_response_stream(
|
|
|
1120
1132
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1121
1133
|
add_history_to_context: Optional[bool] = None,
|
|
1122
1134
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
1135
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
1136
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
1123
1137
|
metadata: Optional[Dict[str, Any]] = None,
|
|
1124
1138
|
debug_mode: Optional[bool] = None,
|
|
1125
1139
|
**kwargs: Any,
|
|
@@ -1196,6 +1210,8 @@ async def aprint_response_stream(
|
|
|
1196
1210
|
user_id=user_id,
|
|
1197
1211
|
knowledge_filters=knowledge_filters,
|
|
1198
1212
|
add_history_to_context=add_history_to_context,
|
|
1213
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
1214
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
1199
1215
|
dependencies=dependencies,
|
|
1200
1216
|
metadata=metadata,
|
|
1201
1217
|
debug_mode=debug_mode,
|
|
@@ -1290,7 +1306,7 @@ async def aprint_response_stream(
|
|
|
1290
1306
|
reasoning_panel = build_reasoning_step_panel(i, step, show_full_reasoning)
|
|
1291
1307
|
panels.append(reasoning_panel)
|
|
1292
1308
|
|
|
1293
|
-
if len(_response_reasoning_content) > 0:
|
|
1309
|
+
if len(_response_reasoning_content) > 0 and show_reasoning:
|
|
1294
1310
|
render = True
|
|
1295
1311
|
# Create panel for thinking
|
|
1296
1312
|
thinking_panel = create_panel(
|
|
@@ -1473,7 +1489,7 @@ async def aprint_response_stream(
|
|
|
1473
1489
|
final_panels.append(reasoning_panel)
|
|
1474
1490
|
|
|
1475
1491
|
# Add thinking panel if available
|
|
1476
|
-
if _response_reasoning_content:
|
|
1492
|
+
if _response_reasoning_content and show_reasoning:
|
|
1477
1493
|
thinking_panel = create_panel(
|
|
1478
1494
|
content=Text(_response_reasoning_content),
|
|
1479
1495
|
title=f"Thinking ({response_timer.elapsed:.1f}s)",
|