agno 2.4.3__py3-none-any.whl → 2.4.5__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 +45 -38
- agno/db/firestore/firestore.py +53 -30
- agno/db/surrealdb/models.py +5 -5
- agno/db/surrealdb/surrealdb.py +13 -1
- agno/knowledge/chunking/markdown.py +112 -11
- agno/knowledge/knowledge.py +8 -10
- agno/models/base.py +6 -0
- agno/models/moonshot/__init__.py +3 -0
- agno/models/moonshot/moonshot.py +57 -0
- agno/models/response.py +4 -0
- agno/models/utils.py +5 -0
- agno/team/team.py +27 -20
- agno/tools/decorator.py +3 -0
- agno/tools/function.py +3 -0
- agno/tools/seltz.py +134 -0
- agno/tools/unsplash.py +341 -0
- agno/utils/print_response/agent.py +8 -5
- agno/utils/response.py +38 -28
- agno/vectordb/lancedb/lance_db.py +29 -7
- agno/workflow/workflow.py +8 -0
- {agno-2.4.3.dist-info → agno-2.4.5.dist-info}/METADATA +5 -2
- {agno-2.4.3.dist-info → agno-2.4.5.dist-info}/RECORD +25 -21
- {agno-2.4.3.dist-info → agno-2.4.5.dist-info}/WHEEL +1 -1
- {agno-2.4.3.dist-info → agno-2.4.5.dist-info}/licenses/LICENSE +0 -0
- {agno-2.4.3.dist-info → agno-2.4.5.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from os import getenv
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
from agno.exceptions import ModelAuthenticationError
|
|
6
|
+
from agno.models.openai.like import OpenAILike
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class MoonShot(OpenAILike):
|
|
11
|
+
"""
|
|
12
|
+
A class for interacting with MoonShot models.
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
id (str): The model id. Defaults to "kimi-k2-thinking".
|
|
16
|
+
name (str): The model name. Defaults to "Moonshot".
|
|
17
|
+
provider (str): The provider name. Defaults to "Moonshot".
|
|
18
|
+
api_key (Optional[str]): The API key.
|
|
19
|
+
base_url (str): The base URL. Defaults to "https://api.moonshot.ai/v1".
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
id: str = "kimi-k2-thinking"
|
|
23
|
+
name: str = "Moonshot"
|
|
24
|
+
provider: str = "Moonshot"
|
|
25
|
+
|
|
26
|
+
api_key: Optional[str] = field(default_factory=lambda: getenv("MOONSHOT_API_KEY"))
|
|
27
|
+
base_url: str = "https://api.moonshot.ai/v1"
|
|
28
|
+
|
|
29
|
+
def _get_client_params(self) -> Dict[str, Any]:
|
|
30
|
+
# Fetch API key from env if not already set
|
|
31
|
+
if not self.api_key:
|
|
32
|
+
self.api_key = getenv("MOONSHOT_API_KEY")
|
|
33
|
+
if not self.api_key:
|
|
34
|
+
# Raise error immediately if key is missing
|
|
35
|
+
raise ModelAuthenticationError(
|
|
36
|
+
message="MOONSHOT_API_KEY not set. Please set the MOONSHOT_API_KEY environment variable.",
|
|
37
|
+
model_name=self.name,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Define base client params
|
|
41
|
+
base_params = {
|
|
42
|
+
"api_key": self.api_key,
|
|
43
|
+
"organization": self.organization,
|
|
44
|
+
"base_url": self.base_url,
|
|
45
|
+
"timeout": self.timeout,
|
|
46
|
+
"max_retries": self.max_retries,
|
|
47
|
+
"default_headers": self.default_headers,
|
|
48
|
+
"default_query": self.default_query,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Create client_params dict with non-None values
|
|
52
|
+
client_params = {k: v for k, v in base_params.items() if v is not None}
|
|
53
|
+
|
|
54
|
+
# Add additional client params if provided
|
|
55
|
+
if self.client_params:
|
|
56
|
+
client_params.update(self.client_params)
|
|
57
|
+
return client_params
|
agno/models/response.py
CHANGED
|
@@ -52,6 +52,9 @@ class ToolExecution:
|
|
|
52
52
|
|
|
53
53
|
external_execution_required: Optional[bool] = None
|
|
54
54
|
|
|
55
|
+
# If True (and external_execution_required=True), suppresses verbose paused messages
|
|
56
|
+
external_execution_silent: Optional[bool] = None
|
|
57
|
+
|
|
55
58
|
@property
|
|
56
59
|
def is_paused(self) -> bool:
|
|
57
60
|
return bool(self.requires_confirmation or self.requires_user_input or self.external_execution_required)
|
|
@@ -84,6 +87,7 @@ class ToolExecution:
|
|
|
84
87
|
if "user_input_schema" in data
|
|
85
88
|
else None,
|
|
86
89
|
external_execution_required=data.get("external_execution_required"),
|
|
90
|
+
external_execution_silent=data.get("external_execution_silent"),
|
|
87
91
|
metrics=Metrics(**(data.get("metrics", {}) or {})),
|
|
88
92
|
**{"created_at": data["created_at"]} if "created_at" in data else {},
|
|
89
93
|
)
|
agno/models/utils.py
CHANGED
|
@@ -139,6 +139,11 @@ def _get_model_class(model_id: str, model_provider: str) -> Model:
|
|
|
139
139
|
|
|
140
140
|
return MistralChat(id=model_id)
|
|
141
141
|
|
|
142
|
+
elif model_provider == "moonshot":
|
|
143
|
+
from agno.models.moonshot import MoonShot
|
|
144
|
+
|
|
145
|
+
return MoonShot(id=model_id)
|
|
146
|
+
|
|
142
147
|
elif model_provider == "nebius":
|
|
143
148
|
from agno.models.nebius import Nebius
|
|
144
149
|
|
agno/team/team.py
CHANGED
|
@@ -343,6 +343,8 @@ class Team:
|
|
|
343
343
|
# Add a tool to search the knowledge base (aka Agentic RAG)
|
|
344
344
|
# Only added if knowledge is provided.
|
|
345
345
|
search_knowledge: bool = True
|
|
346
|
+
# If True, add search_knowledge instructions to the system prompt
|
|
347
|
+
add_search_knowledge_instructions: bool = True
|
|
346
348
|
|
|
347
349
|
# If False, media (images, videos, audio, files) is only available to tools and not sent to the LLM
|
|
348
350
|
send_media_to_model: bool = True
|
|
@@ -530,6 +532,7 @@ class Team:
|
|
|
530
532
|
share_member_interactions: bool = False,
|
|
531
533
|
get_member_information_tool: bool = False,
|
|
532
534
|
search_knowledge: bool = True,
|
|
535
|
+
add_search_knowledge_instructions: bool = True,
|
|
533
536
|
read_chat_history: bool = False,
|
|
534
537
|
store_media: bool = True,
|
|
535
538
|
store_tool_messages: bool = True,
|
|
@@ -653,6 +656,7 @@ class Team:
|
|
|
653
656
|
self.share_member_interactions = share_member_interactions
|
|
654
657
|
self.get_member_information_tool = get_member_information_tool
|
|
655
658
|
self.search_knowledge = search_knowledge
|
|
659
|
+
self.add_search_knowledge_instructions = add_search_knowledge_instructions
|
|
656
660
|
self.read_chat_history = read_chat_history
|
|
657
661
|
|
|
658
662
|
self.store_media = store_media
|
|
@@ -5675,16 +5679,6 @@ class Team:
|
|
|
5675
5679
|
if self.name is not None and self.add_name_to_context:
|
|
5676
5680
|
additional_information.append(f"Your name is: {self.name}.")
|
|
5677
5681
|
|
|
5678
|
-
# Add knowledge context using protocol's build_context
|
|
5679
|
-
if self.knowledge is not None:
|
|
5680
|
-
build_context_fn = getattr(self.knowledge, "build_context", None)
|
|
5681
|
-
if callable(build_context_fn):
|
|
5682
|
-
knowledge_context = build_context_fn(
|
|
5683
|
-
enable_agentic_filters=self.enable_agentic_knowledge_filters,
|
|
5684
|
-
)
|
|
5685
|
-
if knowledge_context:
|
|
5686
|
-
additional_information.append(knowledge_context)
|
|
5687
|
-
|
|
5688
5682
|
# 2 Build the default system message for the Agent.
|
|
5689
5683
|
system_message_content: str = ""
|
|
5690
5684
|
if self.members is not None and len(self.members) > 0:
|
|
@@ -5788,6 +5782,16 @@ class Team:
|
|
|
5788
5782
|
"You should ALWAYS prefer information from this conversation over the past summary.\n\n"
|
|
5789
5783
|
)
|
|
5790
5784
|
|
|
5785
|
+
# Add search_knowledge instructions to the system prompt
|
|
5786
|
+
if self.knowledge is not None and self.search_knowledge and self.add_search_knowledge_instructions:
|
|
5787
|
+
build_context_fn = getattr(self.knowledge, "build_context", None)
|
|
5788
|
+
if callable(build_context_fn):
|
|
5789
|
+
knowledge_context = build_context_fn(
|
|
5790
|
+
enable_agentic_filters=self.enable_agentic_knowledge_filters,
|
|
5791
|
+
)
|
|
5792
|
+
if knowledge_context:
|
|
5793
|
+
system_message_content += knowledge_context + "\n"
|
|
5794
|
+
|
|
5791
5795
|
if self.description is not None:
|
|
5792
5796
|
system_message_content += f"<description>\n{self.description}\n</description>\n\n"
|
|
5793
5797
|
|
|
@@ -5971,16 +5975,6 @@ class Team:
|
|
|
5971
5975
|
if self.name is not None and self.add_name_to_context:
|
|
5972
5976
|
additional_information.append(f"Your name is: {self.name}.")
|
|
5973
5977
|
|
|
5974
|
-
# Add knowledge context using protocol's build_context
|
|
5975
|
-
if self.knowledge is not None:
|
|
5976
|
-
build_context_fn = getattr(self.knowledge, "build_context", None)
|
|
5977
|
-
if callable(build_context_fn):
|
|
5978
|
-
knowledge_context = build_context_fn(
|
|
5979
|
-
enable_agentic_filters=self.enable_agentic_knowledge_filters,
|
|
5980
|
-
)
|
|
5981
|
-
if knowledge_context:
|
|
5982
|
-
additional_information.append(knowledge_context)
|
|
5983
|
-
|
|
5984
5978
|
# 2 Build the default system message for the Agent.
|
|
5985
5979
|
system_message_content: str = ""
|
|
5986
5980
|
system_message_content += "You are the leader of a team and sub-teams of AI Agents.\n"
|
|
@@ -6089,6 +6083,16 @@ class Team:
|
|
|
6089
6083
|
"You should ALWAYS prefer information from this conversation over the past summary.\n\n"
|
|
6090
6084
|
)
|
|
6091
6085
|
|
|
6086
|
+
# Add search_knowledge instructions to the system prompt
|
|
6087
|
+
if self.knowledge is not None and self.search_knowledge and self.add_search_knowledge_instructions:
|
|
6088
|
+
build_context_fn = getattr(self.knowledge, "build_context", None)
|
|
6089
|
+
if callable(build_context_fn):
|
|
6090
|
+
knowledge_context = build_context_fn(
|
|
6091
|
+
enable_agentic_filters=self.enable_agentic_knowledge_filters,
|
|
6092
|
+
)
|
|
6093
|
+
if knowledge_context:
|
|
6094
|
+
system_message_content += knowledge_context + "\n"
|
|
6095
|
+
|
|
6092
6096
|
if self.description is not None:
|
|
6093
6097
|
system_message_content += f"<description>\n{self.description}\n</description>\n\n"
|
|
6094
6098
|
|
|
@@ -8359,6 +8363,8 @@ class Team:
|
|
|
8359
8363
|
config["add_knowledge_to_context"] = self.add_knowledge_to_context
|
|
8360
8364
|
if not self.search_knowledge: # default is True
|
|
8361
8365
|
config["search_knowledge"] = self.search_knowledge
|
|
8366
|
+
if self.add_search_knowledge_instructions:
|
|
8367
|
+
config["add_search_knowledge_instructions"] = self.add_search_knowledge_instructions
|
|
8362
8368
|
if self.references_format != "json": # default is "json"
|
|
8363
8369
|
config["references_format"] = self.references_format
|
|
8364
8370
|
|
|
@@ -8717,6 +8723,7 @@ class Team:
|
|
|
8717
8723
|
add_knowledge_to_context=config.get("add_knowledge_to_context", False),
|
|
8718
8724
|
update_knowledge=config.get("update_knowledge", False),
|
|
8719
8725
|
search_knowledge=config.get("search_knowledge", True),
|
|
8726
|
+
add_search_knowledge_instructions=config.get("add_search_knowledge_instructions", True),
|
|
8720
8727
|
references_format=config.get("references_format", "json"),
|
|
8721
8728
|
# --- Tools ---
|
|
8722
8729
|
tools=config.get("tools"),
|
agno/tools/decorator.py
CHANGED
|
@@ -70,6 +70,7 @@ def tool(
|
|
|
70
70
|
requires_user_input: Optional[bool] = None,
|
|
71
71
|
user_input_fields: Optional[List[str]] = None,
|
|
72
72
|
external_execution: Optional[bool] = None,
|
|
73
|
+
external_execution_silent: Optional[bool] = None,
|
|
73
74
|
pre_hook: Optional[Callable] = None,
|
|
74
75
|
post_hook: Optional[Callable] = None,
|
|
75
76
|
tool_hooks: Optional[List[Callable]] = None,
|
|
@@ -98,6 +99,7 @@ def tool(*args, **kwargs) -> Union[Function, Callable[[F], Function]]:
|
|
|
98
99
|
requires_user_input: Optional[bool] - If True, the function will require user input before execution
|
|
99
100
|
user_input_fields: Optional[List[str]] - List of fields that will be provided to the function as user input
|
|
100
101
|
external_execution: Optional[bool] - If True, the function will be executed outside of the agent's context
|
|
102
|
+
external_execution_silent: Optional[bool] - If True (and external_execution=True), suppresses verbose paused messages (e.g., "I have tools to execute...")
|
|
101
103
|
pre_hook: Optional[Callable] - Hook that runs before the function is executed.
|
|
102
104
|
post_hook: Optional[Callable] - Hook that runs after the function is executed.
|
|
103
105
|
tool_hooks: Optional[List[Callable]] - List of hooks that run before and after the function is executed.
|
|
@@ -135,6 +137,7 @@ def tool(*args, **kwargs) -> Union[Function, Callable[[F], Function]]:
|
|
|
135
137
|
"requires_user_input",
|
|
136
138
|
"user_input_fields",
|
|
137
139
|
"external_execution",
|
|
140
|
+
"external_execution_silent",
|
|
138
141
|
"pre_hook",
|
|
139
142
|
"post_hook",
|
|
140
143
|
"tool_hooks",
|
agno/tools/function.py
CHANGED
|
@@ -121,6 +121,9 @@ class Function(BaseModel):
|
|
|
121
121
|
# If True, the function will be executed outside the agent's control.
|
|
122
122
|
external_execution: Optional[bool] = None
|
|
123
123
|
|
|
124
|
+
# If True (and external_execution=True), the function will not produce verbose paused messages (e.g., "I have tools to execute...")
|
|
125
|
+
external_execution_silent: Optional[bool] = None
|
|
126
|
+
|
|
124
127
|
# Caching configuration
|
|
125
128
|
cache_results: bool = False
|
|
126
129
|
cache_dir: Optional[str] = None
|
agno/tools/seltz.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from os import getenv
|
|
3
|
+
from typing import Any, List, Optional
|
|
4
|
+
|
|
5
|
+
from agno.tools import Toolkit
|
|
6
|
+
from agno.utils.log import log_info, logger
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from seltz import Seltz
|
|
10
|
+
from seltz.exceptions import (
|
|
11
|
+
SeltzAPIError,
|
|
12
|
+
SeltzAuthenticationError,
|
|
13
|
+
SeltzConfigurationError,
|
|
14
|
+
SeltzConnectionError,
|
|
15
|
+
SeltzError,
|
|
16
|
+
SeltzRateLimitError,
|
|
17
|
+
SeltzTimeoutError,
|
|
18
|
+
)
|
|
19
|
+
except ImportError as exc:
|
|
20
|
+
raise ImportError("`seltz` not installed. Please install using `pip install seltz`") from exc
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SeltzTools(Toolkit):
|
|
24
|
+
"""Toolkit for interacting with the Seltz AI-powered search API.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
api_key: Seltz API key. If not provided, uses the `SELTZ_API_KEY` env var.
|
|
28
|
+
endpoint: Optional Seltz gRPC endpoint. If not provided, uses SDK default.
|
|
29
|
+
insecure: Use an insecure gRPC channel. Defaults to False.
|
|
30
|
+
max_documents: Default maximum number of documents to return per search.
|
|
31
|
+
show_results: Log search results for debugging.
|
|
32
|
+
enable_search: Enable search tool functionality. Defaults to True.
|
|
33
|
+
all: Enable all tools. Overrides individual flags when True. Defaults to False.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
api_key: Optional[str] = None,
|
|
39
|
+
endpoint: Optional[str] = None,
|
|
40
|
+
insecure: bool = False,
|
|
41
|
+
max_documents: int = 10,
|
|
42
|
+
show_results: bool = False,
|
|
43
|
+
enable_search: bool = True,
|
|
44
|
+
all: bool = False,
|
|
45
|
+
**kwargs: Any,
|
|
46
|
+
):
|
|
47
|
+
if max_documents <= 0:
|
|
48
|
+
raise ValueError("max_documents must be greater than 0")
|
|
49
|
+
|
|
50
|
+
self.api_key = api_key or getenv("SELTZ_API_KEY")
|
|
51
|
+
if not self.api_key:
|
|
52
|
+
logger.error("SELTZ_API_KEY not set. Please set the SELTZ_API_KEY environment variable.")
|
|
53
|
+
|
|
54
|
+
self.endpoint = endpoint
|
|
55
|
+
self.insecure = insecure
|
|
56
|
+
self.max_documents = max_documents
|
|
57
|
+
self.show_results = show_results
|
|
58
|
+
|
|
59
|
+
self.client: Optional[Seltz] = None
|
|
60
|
+
if self.api_key:
|
|
61
|
+
client_kwargs: dict[str, Any] = {"api_key": self.api_key}
|
|
62
|
+
if self.endpoint:
|
|
63
|
+
client_kwargs["endpoint"] = self.endpoint
|
|
64
|
+
if self.insecure:
|
|
65
|
+
client_kwargs["insecure"] = self.insecure
|
|
66
|
+
self.client = Seltz(**client_kwargs)
|
|
67
|
+
|
|
68
|
+
tools: List[Any] = []
|
|
69
|
+
if all or enable_search:
|
|
70
|
+
tools.append(self.search_seltz)
|
|
71
|
+
|
|
72
|
+
super().__init__(name="seltz", tools=tools, **kwargs)
|
|
73
|
+
|
|
74
|
+
def _parse_documents(self, documents: Any) -> str:
|
|
75
|
+
"""Convert Seltz documents into JSON for the agent."""
|
|
76
|
+
parsed: List[dict[str, Any]] = []
|
|
77
|
+
for doc in documents or []:
|
|
78
|
+
doc_dict: dict[str, Any] = {}
|
|
79
|
+
url = getattr(doc, "url", None)
|
|
80
|
+
content = getattr(doc, "content", None)
|
|
81
|
+
|
|
82
|
+
if url is not None:
|
|
83
|
+
doc_dict["url"] = url
|
|
84
|
+
if content:
|
|
85
|
+
doc_dict["content"] = content
|
|
86
|
+
if doc_dict:
|
|
87
|
+
parsed.append(doc_dict)
|
|
88
|
+
return json.dumps(parsed, indent=4, ensure_ascii=False)
|
|
89
|
+
|
|
90
|
+
def search_seltz(self, query: str, max_documents: Optional[int] = None) -> str:
|
|
91
|
+
"""Use this function to search Seltz for a query.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
query: The query to search for.
|
|
95
|
+
max_documents: Maximum number of documents to return. Defaults to toolkit `max_documents`.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
str: Search results in JSON format.
|
|
99
|
+
"""
|
|
100
|
+
if not query:
|
|
101
|
+
return "Error: Please provide a query to search for."
|
|
102
|
+
|
|
103
|
+
if not self.client:
|
|
104
|
+
return "Error: SELTZ_API_KEY not set. Please set the SELTZ_API_KEY environment variable."
|
|
105
|
+
|
|
106
|
+
limit = max_documents if max_documents is not None else self.max_documents
|
|
107
|
+
if limit <= 0:
|
|
108
|
+
return "Error: max_documents must be greater than 0."
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
if self.show_results:
|
|
112
|
+
log_info(f"Searching Seltz for: {query}")
|
|
113
|
+
|
|
114
|
+
response = self.client.search(query, max_documents=limit)
|
|
115
|
+
result = self._parse_documents(getattr(response, "documents", []))
|
|
116
|
+
|
|
117
|
+
if self.show_results:
|
|
118
|
+
log_info(result)
|
|
119
|
+
|
|
120
|
+
return result
|
|
121
|
+
except (
|
|
122
|
+
SeltzConfigurationError,
|
|
123
|
+
SeltzAuthenticationError,
|
|
124
|
+
SeltzConnectionError,
|
|
125
|
+
SeltzTimeoutError,
|
|
126
|
+
SeltzRateLimitError,
|
|
127
|
+
SeltzAPIError,
|
|
128
|
+
SeltzError,
|
|
129
|
+
) as exc:
|
|
130
|
+
logger.error(f"Seltz error: {exc}")
|
|
131
|
+
return f"Error: {exc}"
|
|
132
|
+
except Exception as exc:
|
|
133
|
+
logger.error(f"Failed to search Seltz: {exc}")
|
|
134
|
+
return f"Error: {exc}"
|