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.
@@ -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}"