agno 2.3.13__py3-none-any.whl → 2.3.14__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 (41) hide show
  1. agno/agent/agent.py +1131 -1402
  2. agno/eval/__init__.py +21 -8
  3. agno/knowledge/embedder/azure_openai.py +0 -1
  4. agno/knowledge/embedder/google.py +1 -1
  5. agno/models/anthropic/claude.py +4 -1
  6. agno/models/base.py +8 -4
  7. agno/models/openai/responses.py +2 -2
  8. agno/os/app.py +39 -0
  9. agno/os/interfaces/a2a/router.py +619 -9
  10. agno/os/interfaces/a2a/utils.py +31 -32
  11. agno/os/middleware/jwt.py +5 -5
  12. agno/os/routers/agents/schema.py +14 -1
  13. agno/os/routers/teams/schema.py +14 -1
  14. agno/os/utils.py +61 -53
  15. agno/reasoning/anthropic.py +85 -1
  16. agno/reasoning/azure_ai_foundry.py +93 -1
  17. agno/reasoning/deepseek.py +91 -1
  18. agno/reasoning/gemini.py +81 -1
  19. agno/reasoning/groq.py +103 -1
  20. agno/reasoning/manager.py +1244 -0
  21. agno/reasoning/ollama.py +93 -1
  22. agno/reasoning/openai.py +113 -1
  23. agno/reasoning/vertexai.py +85 -1
  24. agno/run/agent.py +11 -0
  25. agno/run/base.py +1 -1
  26. agno/run/team.py +11 -0
  27. agno/session/team.py +0 -3
  28. agno/team/team.py +1201 -1445
  29. agno/utils/events.py +69 -2
  30. agno/utils/hooks.py +4 -10
  31. agno/utils/print_response/agent.py +26 -0
  32. agno/utils/print_response/team.py +11 -0
  33. agno/utils/prompts.py +8 -6
  34. agno/utils/string.py +46 -0
  35. agno/utils/team.py +1 -1
  36. agno/vectordb/milvus/milvus.py +32 -3
  37. {agno-2.3.13.dist-info → agno-2.3.14.dist-info}/METADATA +3 -2
  38. {agno-2.3.13.dist-info → agno-2.3.14.dist-info}/RECORD +41 -40
  39. {agno-2.3.13.dist-info → agno-2.3.14.dist-info}/WHEEL +0 -0
  40. {agno-2.3.13.dist-info → agno-2.3.14.dist-info}/licenses/LICENSE +0 -0
  41. {agno-2.3.13.dist-info → agno-2.3.14.dist-info}/top_level.txt +0 -0
agno/eval/__init__.py CHANGED
@@ -1,12 +1,4 @@
1
- from agno.eval.accuracy import AccuracyAgentResponse, AccuracyEval, AccuracyEvaluation, AccuracyResult
2
- from agno.eval.agent_as_judge import (
3
- AgentAsJudgeEval,
4
- AgentAsJudgeEvaluation,
5
- AgentAsJudgeResult,
6
- )
7
1
  from agno.eval.base import BaseEval
8
- from agno.eval.performance import PerformanceEval, PerformanceResult
9
- from agno.eval.reliability import ReliabilityEval, ReliabilityResult
10
2
 
11
3
  __all__ = [
12
4
  "AccuracyAgentResponse",
@@ -22,3 +14,24 @@ __all__ = [
22
14
  "ReliabilityEval",
23
15
  "ReliabilityResult",
24
16
  ]
17
+
18
+
19
+ def __getattr__(name: str):
20
+ """Lazy import for eval implementations to avoid circular imports with Agent."""
21
+ if name in ("AccuracyAgentResponse", "AccuracyEval", "AccuracyEvaluation", "AccuracyResult"):
22
+ from agno.eval import accuracy
23
+
24
+ return getattr(accuracy, name)
25
+ elif name in ("AgentAsJudgeEval", "AgentAsJudgeEvaluation", "AgentAsJudgeResult"):
26
+ from agno.eval import agent_as_judge
27
+
28
+ return getattr(agent_as_judge, name)
29
+ elif name in ("PerformanceEval", "PerformanceResult"):
30
+ from agno.eval import performance
31
+
32
+ return getattr(performance, name)
33
+ elif name in ("ReliabilityEval", "ReliabilityResult"):
34
+ from agno.eval import reliability
35
+
36
+ return getattr(reliability, name)
37
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
@@ -18,7 +18,6 @@ except ImportError:
18
18
  @dataclass
19
19
  class AzureOpenAIEmbedder(Embedder):
20
20
  id: str = "text-embedding-3-small" # This has to match the model that you deployed at the provided URL
21
-
22
21
  dimensions: int = 1536
23
22
  encoding_format: Literal["float", "base64"] = "float"
24
23
  user: Optional[str] = None
@@ -15,7 +15,7 @@ except ImportError:
15
15
 
16
16
  @dataclass
17
17
  class GeminiEmbedder(Embedder):
18
- id: str = "gemini-embedding-exp-03-07"
18
+ id: str = "gemini-embedding-001"
19
19
  task_type: str = "RETRIEVAL_QUERY"
20
20
  title: Optional[str] = None
21
21
  dimensions: Optional[int] = 1536
@@ -320,8 +320,11 @@ class Claude(Model):
320
320
 
321
321
  return {"type": "json_schema", "schema": schema}
322
322
 
323
- # Handle dict format (already in correct structure)
323
+ # Handle dict format
324
324
  elif isinstance(response_format, dict):
325
+ # Claude only supports json_schema, not json_object
326
+ if response_format.get("type") == "json_object":
327
+ return None
325
328
  return response_format
326
329
 
327
330
  return None
agno/models/base.py CHANGED
@@ -196,7 +196,8 @@ class Model(ABC):
196
196
  )
197
197
  sleep(delay)
198
198
  else:
199
- log_error(f"Model provider error after {self.retries + 1} attempts: {e}")
199
+ if self.retries > 0:
200
+ log_error(f"Model provider error after {self.retries + 1} attempts: {e}")
200
201
  except RetryableModelProviderError as e:
201
202
  current_count = retries_with_guidance_count
202
203
  if current_count >= self.retry_with_guidance_limit:
@@ -238,7 +239,8 @@ class Model(ABC):
238
239
  )
239
240
  await asyncio.sleep(delay)
240
241
  else:
241
- log_error(f"Model provider error after {self.retries + 1} attempts: {e}")
242
+ if self.retries > 0:
243
+ log_error(f"Model provider error after {self.retries + 1} attempts: {e}")
242
244
  except RetryableModelProviderError as e:
243
245
  current_count = retries_with_guidance_count
244
246
  if current_count >= self.retry_with_guidance_limit:
@@ -283,7 +285,8 @@ class Model(ABC):
283
285
  )
284
286
  sleep(delay)
285
287
  else:
286
- log_error(f"Model provider error after {self.retries + 1} attempts: {e}")
288
+ if self.retries > 0:
289
+ log_error(f"Model provider error after {self.retries + 1} attempts: {e}")
287
290
  except RetryableModelProviderError as e:
288
291
  current_count = retries_with_guidance_count
289
292
  if current_count >= self.retry_with_guidance_limit:
@@ -330,7 +333,8 @@ class Model(ABC):
330
333
  )
331
334
  await asyncio.sleep(delay)
332
335
  else:
333
- log_error(f"Model provider error after {self.retries + 1} attempts: {e}")
336
+ if self.retries > 0:
337
+ log_error(f"Model provider error after {self.retries + 1} attempts: {e}")
334
338
  except RetryableModelProviderError as e:
335
339
  current_count = retries_with_guidance_count
336
340
  if current_count >= self.retry_with_guidance_limit:
@@ -234,8 +234,8 @@ class OpenAIResponses(Model):
234
234
  "strict": self.strict_output,
235
235
  }
236
236
  else:
237
- # JSON mode
238
- text_params["format"] = {"type": "json_object"}
237
+ # Pass through directly, user handles everything
238
+ text_params["format"] = response_format
239
239
 
240
240
  # Add text parameter if there are any text-level params
241
241
  if text_params:
agno/os/app.py CHANGED
@@ -225,6 +225,9 @@ class AgentOS:
225
225
  self._initialize_teams()
226
226
  self._initialize_workflows()
227
227
 
228
+ # Check for duplicate IDs
229
+ self._raise_if_duplicate_ids()
230
+
228
231
  if self.tracing:
229
232
  self._setup_tracing()
230
233
 
@@ -266,6 +269,9 @@ class AgentOS:
266
269
  self._initialize_agents()
267
270
  self._initialize_teams()
268
271
  self._initialize_workflows()
272
+
273
+ # Check for duplicate IDs
274
+ self._raise_if_duplicate_ids()
269
275
  self._auto_discover_databases()
270
276
  self._auto_discover_knowledge_instances()
271
277
 
@@ -334,6 +340,31 @@ class AgentOS:
334
340
  self.interfaces.append(a2a_interface)
335
341
  self._add_router(app, a2a_interface.get_router())
336
342
 
343
+ def _raise_if_duplicate_ids(self) -> None:
344
+ """Check for duplicate IDs within each entity type.
345
+
346
+ Raises:
347
+ ValueError: If duplicate IDs are found within the same entity type
348
+ """
349
+ duplicate_ids: List[str] = []
350
+
351
+ for entities in [self.agents, self.teams, self.workflows]:
352
+ if not entities:
353
+ continue
354
+ seen_ids: set[str] = set()
355
+ for entity in entities:
356
+ entity_id = entity.id
357
+ if entity_id is None:
358
+ continue
359
+ if entity_id in seen_ids:
360
+ if entity_id not in duplicate_ids:
361
+ duplicate_ids.append(entity_id)
362
+ else:
363
+ seen_ids.add(entity_id)
364
+
365
+ if duplicate_ids:
366
+ raise ValueError(f"Duplicate IDs found in AgentOS: {', '.join(repr(id_) for id_ in duplicate_ids)}")
367
+
337
368
  def _make_app(self, lifespan: Optional[Any] = None) -> FastAPI:
338
369
  # Adjust the FastAPI app lifespan to handle MCP connections if relevant
339
370
  app_lifespan = lifespan
@@ -981,6 +1012,8 @@ class AgentOS:
981
1012
  host: str = "localhost",
982
1013
  port: int = 7777,
983
1014
  reload: bool = False,
1015
+ reload_includes: Optional[List[str]] = None,
1016
+ reload_excludes: Optional[List[str]] = None,
984
1017
  workers: Optional[int] = None,
985
1018
  access_log: bool = False,
986
1019
  **kwargs,
@@ -1015,11 +1048,17 @@ class AgentOS:
1015
1048
  )
1016
1049
  )
1017
1050
 
1051
+ # Adding *.yaml to reload_includes to reload the app when the yaml config file changes.
1052
+ if reload and reload_includes is not None:
1053
+ reload_includes = ["*.yaml", "*.yml"]
1054
+
1018
1055
  uvicorn.run(
1019
1056
  app=app,
1020
1057
  host=host,
1021
1058
  port=port,
1022
1059
  reload=reload,
1060
+ reload_includes=reload_includes,
1061
+ reload_excludes=reload_excludes,
1023
1062
  workers=workers,
1024
1063
  access_log=access_log,
1025
1064
  lifespan="on",