agno 2.4.6__py3-none-any.whl → 2.4.8__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.
Files changed (51) hide show
  1. agno/agent/agent.py +5 -1
  2. agno/db/base.py +2 -0
  3. agno/db/postgres/postgres.py +5 -5
  4. agno/db/singlestore/singlestore.py +4 -5
  5. agno/db/sqlite/sqlite.py +4 -4
  6. agno/knowledge/embedder/aws_bedrock.py +325 -106
  7. agno/knowledge/knowledge.py +83 -1853
  8. agno/knowledge/loaders/__init__.py +29 -0
  9. agno/knowledge/loaders/azure_blob.py +423 -0
  10. agno/knowledge/loaders/base.py +187 -0
  11. agno/knowledge/loaders/gcs.py +267 -0
  12. agno/knowledge/loaders/github.py +415 -0
  13. agno/knowledge/loaders/s3.py +281 -0
  14. agno/knowledge/loaders/sharepoint.py +439 -0
  15. agno/knowledge/reader/website_reader.py +2 -2
  16. agno/knowledge/remote_knowledge.py +151 -0
  17. agno/knowledge/reranker/aws_bedrock.py +299 -0
  18. agno/learn/machine.py +5 -6
  19. agno/learn/stores/session_context.py +10 -2
  20. agno/models/azure/openai_chat.py +6 -11
  21. agno/models/neosantara/__init__.py +5 -0
  22. agno/models/neosantara/neosantara.py +42 -0
  23. agno/models/utils.py +5 -0
  24. agno/os/app.py +4 -1
  25. agno/os/interfaces/agui/router.py +1 -1
  26. agno/os/routers/components/components.py +2 -0
  27. agno/os/routers/knowledge/knowledge.py +0 -1
  28. agno/os/routers/registry/registry.py +340 -192
  29. agno/os/routers/workflows/router.py +7 -1
  30. agno/os/schema.py +104 -0
  31. agno/registry/registry.py +4 -0
  32. agno/run/workflow.py +3 -0
  33. agno/session/workflow.py +1 -1
  34. agno/skills/utils.py +100 -2
  35. agno/team/team.py +6 -3
  36. agno/tools/mcp/mcp.py +26 -1
  37. agno/vectordb/lancedb/lance_db.py +22 -7
  38. agno/workflow/__init__.py +4 -0
  39. agno/workflow/cel.py +299 -0
  40. agno/workflow/condition.py +280 -58
  41. agno/workflow/loop.py +177 -46
  42. agno/workflow/parallel.py +75 -4
  43. agno/workflow/router.py +260 -44
  44. agno/workflow/step.py +14 -7
  45. agno/workflow/steps.py +43 -0
  46. agno/workflow/workflow.py +104 -46
  47. {agno-2.4.6.dist-info → agno-2.4.8.dist-info}/METADATA +25 -37
  48. {agno-2.4.6.dist-info → agno-2.4.8.dist-info}/RECORD +51 -39
  49. {agno-2.4.6.dist-info → agno-2.4.8.dist-info}/WHEEL +0 -0
  50. {agno-2.4.6.dist-info → agno-2.4.8.dist-info}/licenses/LICENSE +0 -0
  51. {agno-2.4.6.dist-info → agno-2.4.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,299 @@
1
+ from os import getenv
2
+ from typing import Any, Dict, List, Literal, Optional
3
+
4
+ from pydantic import ConfigDict, Field
5
+
6
+ from agno.knowledge.document import Document
7
+ from agno.knowledge.reranker.base import Reranker
8
+ from agno.utils.log import logger
9
+
10
+ try:
11
+ from boto3 import client as AwsClient
12
+ from boto3.session import Session
13
+ from botocore.exceptions import ClientError
14
+ except ImportError:
15
+ raise ImportError("`boto3` not installed. Please install it via `pip install boto3`.")
16
+
17
+
18
+ # Model ID constants
19
+ AMAZON_RERANK_V1 = "amazon.rerank-v1:0"
20
+ COHERE_RERANK_V3_5 = "cohere.rerank-v3-5:0"
21
+
22
+ # Type alias for supported models
23
+ RerankerModel = Literal["amazon.rerank-v1:0", "cohere.rerank-v3-5:0"]
24
+
25
+
26
+ class AwsBedrockReranker(Reranker):
27
+ """
28
+ AWS Bedrock reranker supporting Amazon Rerank 1.0 and Cohere Rerank 3.5 models.
29
+
30
+ This reranker uses the unified Bedrock Rerank API (bedrock-agent-runtime)
31
+ which provides a consistent interface for both model providers.
32
+
33
+ To use this reranker, you need to either:
34
+ 1. Set the following environment variables:
35
+ - AWS_ACCESS_KEY_ID
36
+ - AWS_SECRET_ACCESS_KEY
37
+ - AWS_REGION
38
+ 2. Or provide a boto3 Session object
39
+
40
+ Args:
41
+ model (str): The model ID to use. Options:
42
+ - 'amazon.rerank-v1:0' (Amazon Rerank 1.0)
43
+ - 'cohere.rerank-v3-5:0' (Cohere Rerank 3.5)
44
+ Default is 'cohere.rerank-v3-5:0'.
45
+ top_n (Optional[int]): Number of top results to return after reranking.
46
+ If None, returns all documents reranked.
47
+ aws_region (Optional[str]): The AWS region to use.
48
+ aws_access_key_id (Optional[str]): The AWS access key ID to use.
49
+ aws_secret_access_key (Optional[str]): The AWS secret access key to use.
50
+ session (Optional[Session]): A boto3 Session object for authentication.
51
+ additional_model_request_fields (Optional[Dict]): Additional model-specific
52
+ parameters to pass in the request (e.g., Cohere-specific options).
53
+
54
+ Example:
55
+ ```python
56
+ from agno.knowledge.reranker.aws_bedrock import AwsBedrockReranker
57
+
58
+ # Using Cohere Rerank 3.5 (default)
59
+ reranker = AwsBedrockReranker(
60
+ model="cohere.rerank-v3-5:0",
61
+ top_n=5,
62
+ aws_region="us-west-2",
63
+ )
64
+
65
+ # Using Amazon Rerank 1.0
66
+ reranker = AwsBedrockReranker(
67
+ model="amazon.rerank-v1:0",
68
+ top_n=10,
69
+ aws_region="us-west-2",
70
+ )
71
+
72
+ # Rerank documents
73
+ reranked_docs = reranker.rerank(query="What is machine learning?", documents=docs)
74
+ ```
75
+
76
+ Note:
77
+ - Amazon Rerank 1.0 is NOT available in us-east-1 (N. Virginia).
78
+ Use Cohere Rerank 3.5 in that region.
79
+ - Maximum 1000 documents per request.
80
+ """
81
+
82
+ model_config = ConfigDict(arbitrary_types_allowed=True, populate_by_name=True)
83
+
84
+ model: str = Field(default=COHERE_RERANK_V3_5, description="Reranker model ID")
85
+ top_n: Optional[int] = Field(default=None, description="Number of top results to return")
86
+
87
+ aws_region: Optional[str] = Field(default=None, description="AWS region")
88
+ aws_access_key_id: Optional[str] = Field(default=None, description="AWS access key ID")
89
+ aws_secret_access_key: Optional[str] = Field(default=None, description="AWS secret access key")
90
+ session: Optional[Session] = Field(default=None, description="Boto3 session", exclude=True)
91
+
92
+ additional_model_request_fields: Optional[Dict[str, Any]] = Field(
93
+ default=None,
94
+ description="Additional model-specific request parameters",
95
+ )
96
+
97
+ _client: Optional[AwsClient] = None
98
+
99
+ @property
100
+ def client(self) -> AwsClient:
101
+ """
102
+ Returns a bedrock-agent-runtime client for the Rerank API.
103
+
104
+ Returns:
105
+ AwsClient: An instance of the bedrock-agent-runtime client.
106
+ """
107
+ if self._client is not None:
108
+ return self._client
109
+
110
+ if self.session:
111
+ self._client = self.session.client("bedrock-agent-runtime")
112
+ return self._client
113
+
114
+ aws_access_key_id = self.aws_access_key_id or getenv("AWS_ACCESS_KEY_ID")
115
+ aws_secret_access_key = self.aws_secret_access_key or getenv("AWS_SECRET_ACCESS_KEY")
116
+ aws_region = self.aws_region or getenv("AWS_REGION")
117
+
118
+ if not aws_access_key_id or not aws_secret_access_key:
119
+ # Fall back to default credential chain
120
+ self._client = AwsClient(
121
+ service_name="bedrock-agent-runtime",
122
+ region_name=aws_region,
123
+ )
124
+ else:
125
+ self._client = AwsClient(
126
+ service_name="bedrock-agent-runtime",
127
+ region_name=aws_region,
128
+ aws_access_key_id=aws_access_key_id,
129
+ aws_secret_access_key=aws_secret_access_key,
130
+ )
131
+
132
+ return self._client
133
+
134
+ def _get_model_arn(self) -> str:
135
+ """
136
+ Constructs the full model ARN for the reranker model.
137
+
138
+ Returns:
139
+ str: The model ARN.
140
+ """
141
+ region = self.aws_region or getenv("AWS_REGION", "us-west-2")
142
+ return f"arn:aws:bedrock:{region}::foundation-model/{self.model}"
143
+
144
+ def _build_sources(self, documents: List[Document]) -> List[Dict[str, Any]]:
145
+ """
146
+ Convert Document objects to Bedrock Rerank API source format.
147
+
148
+ Args:
149
+ documents: List of Document objects to convert.
150
+
151
+ Returns:
152
+ List of RerankSource objects for the API.
153
+ """
154
+ sources = []
155
+ for doc in documents:
156
+ # Use text format for document content
157
+ source = {
158
+ "type": "INLINE",
159
+ "inlineDocumentSource": {
160
+ "type": "TEXT",
161
+ "textDocument": {
162
+ "text": doc.content,
163
+ },
164
+ },
165
+ }
166
+ sources.append(source)
167
+ return sources
168
+
169
+ def _rerank(self, query: str, documents: List[Document]) -> List[Document]:
170
+ """
171
+ Internal method to perform reranking via Bedrock Rerank API.
172
+
173
+ Args:
174
+ query: The query string to rank documents against.
175
+ documents: List of Document objects to rerank.
176
+
177
+ Returns:
178
+ List of Document objects sorted by relevance score.
179
+ """
180
+ if not documents:
181
+ return []
182
+
183
+ # Validate top_n
184
+ top_n = self.top_n
185
+ if top_n is not None and top_n <= 0:
186
+ logger.warning(f"top_n should be a positive integer, got {self.top_n}, setting top_n to None")
187
+ top_n = None
188
+
189
+ # Build the request
190
+ rerank_request: Dict[str, Any] = {
191
+ "queries": [
192
+ {
193
+ "type": "TEXT",
194
+ "textQuery": {
195
+ "text": query,
196
+ },
197
+ }
198
+ ],
199
+ "sources": self._build_sources(documents),
200
+ "rerankingConfiguration": {
201
+ "type": "BEDROCK_RERANKING_MODEL",
202
+ "bedrockRerankingConfiguration": {
203
+ "modelConfiguration": {
204
+ "modelArn": self._get_model_arn(),
205
+ },
206
+ },
207
+ },
208
+ }
209
+
210
+ # Add numberOfResults if top_n is specified
211
+ if top_n is not None:
212
+ rerank_request["rerankingConfiguration"]["bedrockRerankingConfiguration"]["numberOfResults"] = top_n
213
+
214
+ # Add additional model request fields if provided
215
+ if self.additional_model_request_fields:
216
+ rerank_request["rerankingConfiguration"]["bedrockRerankingConfiguration"]["modelConfiguration"][
217
+ "additionalModelRequestFields"
218
+ ] = self.additional_model_request_fields
219
+
220
+ # Call the Rerank API
221
+ response = self.client.rerank(**rerank_request)
222
+
223
+ # Process results
224
+ reranked_docs: List[Document] = []
225
+ results = response.get("results", [])
226
+
227
+ for result in results:
228
+ index = result.get("index")
229
+ relevance_score = result.get("relevanceScore")
230
+
231
+ if index is not None and index < len(documents):
232
+ doc = documents[index]
233
+ doc.reranking_score = relevance_score
234
+ reranked_docs.append(doc)
235
+
236
+ # Results from API are already sorted by relevance, but ensure sorting
237
+ reranked_docs.sort(
238
+ key=lambda x: x.reranking_score if x.reranking_score is not None else float("-inf"),
239
+ reverse=True,
240
+ )
241
+
242
+ return reranked_docs
243
+
244
+ def rerank(self, query: str, documents: List[Document]) -> List[Document]:
245
+ """
246
+ Rerank documents based on their relevance to a query.
247
+
248
+ Args:
249
+ query: The query string to rank documents against.
250
+ documents: List of Document objects to rerank.
251
+
252
+ Returns:
253
+ List of Document objects sorted by relevance score (highest first).
254
+ Each document will have its `reranking_score` attribute set.
255
+ """
256
+ try:
257
+ return self._rerank(query=query, documents=documents)
258
+ except ClientError as e:
259
+ error_code = e.response.get("Error", {}).get("Code", "Unknown")
260
+ error_message = e.response.get("Error", {}).get("Message", str(e))
261
+ logger.error(f"AWS Bedrock Rerank API error ({error_code}): {error_message}. Returning original documents.")
262
+ return documents
263
+ except Exception as e:
264
+ logger.error(f"Error reranking documents: {e}. Returning original documents.")
265
+ return documents
266
+
267
+
268
+ class CohereBedrockReranker(AwsBedrockReranker):
269
+ """
270
+ Convenience class for Cohere Rerank 3.5 on AWS Bedrock.
271
+
272
+ This is a pre-configured AwsBedrockReranker using the Cohere Rerank 3.5 model.
273
+
274
+ Example:
275
+ ```python
276
+ reranker = CohereBedrockReranker(top_n=5, aws_region="us-west-2")
277
+ reranked_docs = reranker.rerank(query="What is AI?", documents=docs)
278
+ ```
279
+ """
280
+
281
+ model: str = Field(default=COHERE_RERANK_V3_5)
282
+
283
+
284
+ class AmazonReranker(AwsBedrockReranker):
285
+ """
286
+ Convenience class for Amazon Rerank 1.0 on AWS Bedrock.
287
+
288
+ This is a pre-configured AwsBedrockReranker using the Amazon Rerank 1.0 model.
289
+
290
+ Note: Amazon Rerank 1.0 is NOT available in us-east-1 (N. Virginia).
291
+
292
+ Example:
293
+ ```python
294
+ reranker = AmazonReranker(top_n=5, aws_region="us-west-2")
295
+ reranked_docs = reranker.rerank(query="What is AI?", documents=docs)
296
+ ```
297
+ """
298
+
299
+ model: str = Field(default=AMAZON_RERANK_V1)
agno/learn/machine.py CHANGED
@@ -645,12 +645,11 @@ class LearningMachine:
645
645
  for name, store in self.stores.items():
646
646
  try:
647
647
  result = await store.arecall(**context)
648
- if result is not None:
649
- results[name] = result
650
- try:
651
- log_debug(f"Recalled from {name}: {result}")
652
- except Exception:
653
- pass
648
+ results[name] = result
649
+ try:
650
+ log_debug(f"Recalled from {name}: {result}")
651
+ except Exception:
652
+ pass
654
653
  except Exception as e:
655
654
  log_warning(f"Error recalling from {name}: {e}")
656
655
 
@@ -540,7 +540,11 @@ class SessionContextStore(LearningStore):
540
540
  existing_context=existing_context,
541
541
  )
542
542
 
543
- messages_for_model = [system_message]
543
+ messages_for_model = [
544
+ system_message,
545
+ # For models that require a non-system message
546
+ Message(role="user", content="Please analyze the conversation and update the session context using the available tools."),
547
+ ]
544
548
 
545
549
  model_copy = deepcopy(self.model)
546
550
  response = model_copy.response(
@@ -596,7 +600,11 @@ class SessionContextStore(LearningStore):
596
600
  existing_context=existing_context,
597
601
  )
598
602
 
599
- messages_for_model = [system_message]
603
+ messages_for_model = [
604
+ system_message,
605
+ # For models that require a non-system message
606
+ Message(role="user", content="Please analyze the conversation and update the session context using the available tools."),
607
+ ]
600
608
 
601
609
  model_copy = deepcopy(self.model)
602
610
  response = await model_copy.aresponse(
@@ -65,17 +65,12 @@ class AzureOpenAI(OpenAILike):
65
65
  self.azure_endpoint = self.azure_endpoint or getenv("AZURE_OPENAI_ENDPOINT")
66
66
  self.azure_deployment = self.azure_deployment or getenv("AZURE_OPENAI_DEPLOYMENT")
67
67
 
68
- if not (self.api_key or self.azure_ad_token):
69
- if not self.api_key:
70
- raise ModelAuthenticationError(
71
- message="AZURE_OPENAI_API_KEY not set. Please set the AZURE_OPENAI_API_KEY environment variable.",
72
- model_name=self.name,
73
- )
74
- if not self.azure_ad_token:
75
- raise ModelAuthenticationError(
76
- message="AZURE_AD_TOKEN not set. Please set the AZURE_AD_TOKEN environment variable.",
77
- model_name=self.name,
78
- )
68
+ if not (self.api_key or self.azure_ad_token or self.azure_ad_token_provider):
69
+ raise ModelAuthenticationError(
70
+ message="Azure OpenAI authentication not configured. Please provide one of:"
71
+ "AZURE_OPENAI_API_KEY environment variable, azure_ad_token, or azure_ad_token_provider",
72
+ model_name=self.name,
73
+ )
79
74
 
80
75
  params_mapping = {
81
76
  "api_key": self.api_key,
@@ -0,0 +1,5 @@
1
+ from agno.models.neosantara.neosantara import Neosantara
2
+
3
+ __all__ = [
4
+ "Neosantara",
5
+ ]
@@ -0,0 +1,42 @@
1
+ from dataclasses import dataclass
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 Neosantara(OpenAILike):
11
+ """
12
+ A class for interacting with Neosantara API.
13
+
14
+ Attributes:
15
+ id (str): The id of the Neosantara model to use. Default is "grok-4.1-fast-non-reasoning".
16
+ name (str): The name of this chat model instance. Default is "Neosantara"
17
+ provider (str): The provider of the model. Default is "Neosantara".
18
+ api_key (str): The api key to authorize request to Neosantara.
19
+ base_url (str): The base url to which the requests are sent. Defaults to "https://api.neosantara.xyz/v1".
20
+ """
21
+
22
+ id: str = "grok-4.1-fast-non-reasoning"
23
+ name: str = "Neosantara"
24
+ provider: str = "Neosantara"
25
+ api_key: Optional[str] = None
26
+ base_url: str = "https://api.neosantara.xyz/v1"
27
+
28
+ def _get_client_params(self) -> Dict[str, Any]:
29
+ """
30
+ Returns client parameters for API requests, checking for NEOSANTARA_API_KEY.
31
+
32
+ Returns:
33
+ Dict[str, Any]: A dictionary of client parameters for API requests.
34
+ """
35
+ if not self.api_key:
36
+ self.api_key = getenv("NEOSANTARA_API_KEY")
37
+ if not self.api_key:
38
+ raise ModelAuthenticationError(
39
+ message="NEOSANTARA_API_KEY not set. Please set the NEOSANTARA_API_KEY environment variable.",
40
+ model_name=self.name,
41
+ )
42
+ return super()._get_client_params()
agno/models/utils.py CHANGED
@@ -149,6 +149,11 @@ def _get_model_class(model_id: str, model_provider: str) -> Model:
149
149
 
150
150
  return Nebius(id=model_id)
151
151
 
152
+ elif model_provider == "neosantara":
153
+ from agno.models.neosantara import Neosantara
154
+
155
+ return Neosantara(id=model_id)
156
+
152
157
  elif model_provider == "nexus":
153
158
  from agno.models.nexus import Nexus
154
159
 
agno/os/app.py CHANGED
@@ -1056,12 +1056,15 @@ class AgentOS:
1056
1056
  dbs_with_specific_config = [db.db_id for db in knowledge_config.dbs]
1057
1057
 
1058
1058
  # Only add databases that are actually used for knowledge contents
1059
- for db_id in self.knowledge_dbs.keys():
1059
+ for db_id, dbs in self.knowledge_dbs.items():
1060
1060
  if db_id not in dbs_with_specific_config:
1061
+ # Collect unique table names from all databases with the same id
1062
+ unique_tables = list(set(db.knowledge_table_name for db in dbs))
1061
1063
  knowledge_config.dbs.append(
1062
1064
  DatabaseConfig(
1063
1065
  db_id=db_id,
1064
1066
  domain_config=KnowledgeDomainConfig(display_name=db_id),
1067
+ tables=unique_tables,
1065
1068
  )
1066
1069
  )
1067
1070
 
@@ -14,7 +14,7 @@ try:
14
14
  )
15
15
  from ag_ui.encoder import EventEncoder
16
16
  except ImportError as e:
17
- raise ImportError("`ag_ui` not installed. Please install it with `pip install -U ag-ui`") from e
17
+ raise ImportError("`ag_ui` not installed. Please install it with `pip install -U ag-ui-protocol`") from e
18
18
 
19
19
  from fastapi import APIRouter
20
20
  from fastapi.responses import StreamingResponse
@@ -243,6 +243,8 @@ def attach_routes(
243
243
  update_kwargs["description"] = body.description
244
244
  if body.metadata is not None:
245
245
  update_kwargs["metadata"] = body.metadata
246
+ if body.current_version is not None:
247
+ update_kwargs["current_version"] = body.current_version
246
248
  if body.component_type is not None:
247
249
  update_kwargs["component_type"] = DbComponentType(body.component_type)
248
250
 
@@ -215,7 +215,6 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Union[Knowledge,
215
215
  description=(
216
216
  "Upload content from a remote source (S3, GCS, SharePoint, GitHub) to the knowledge base. "
217
217
  "Content is processed asynchronously in the background. "
218
- "Use the /knowledge/config endpoint to see available remote content sources."
219
218
  ),
220
219
  responses={
221
220
  202: {