agno 2.3.25__py3-none-any.whl → 2.4.0__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 (128) hide show
  1. agno/agent/__init__.py +4 -0
  2. agno/agent/agent.py +1428 -558
  3. agno/agent/remote.py +13 -0
  4. agno/db/base.py +339 -0
  5. agno/db/postgres/async_postgres.py +116 -12
  6. agno/db/postgres/postgres.py +1229 -25
  7. agno/db/postgres/schemas.py +48 -1
  8. agno/db/sqlite/async_sqlite.py +119 -4
  9. agno/db/sqlite/schemas.py +51 -0
  10. agno/db/sqlite/sqlite.py +1173 -13
  11. agno/db/utils.py +37 -1
  12. agno/knowledge/__init__.py +4 -0
  13. agno/knowledge/chunking/code.py +1 -1
  14. agno/knowledge/chunking/semantic.py +1 -1
  15. agno/knowledge/chunking/strategy.py +4 -0
  16. agno/knowledge/filesystem.py +412 -0
  17. agno/knowledge/knowledge.py +2767 -2254
  18. agno/knowledge/protocol.py +134 -0
  19. agno/knowledge/reader/arxiv_reader.py +2 -2
  20. agno/knowledge/reader/base.py +9 -7
  21. agno/knowledge/reader/csv_reader.py +5 -5
  22. agno/knowledge/reader/docx_reader.py +2 -2
  23. agno/knowledge/reader/field_labeled_csv_reader.py +2 -2
  24. agno/knowledge/reader/firecrawl_reader.py +2 -2
  25. agno/knowledge/reader/json_reader.py +2 -2
  26. agno/knowledge/reader/markdown_reader.py +2 -2
  27. agno/knowledge/reader/pdf_reader.py +5 -4
  28. agno/knowledge/reader/pptx_reader.py +2 -2
  29. agno/knowledge/reader/reader_factory.py +110 -0
  30. agno/knowledge/reader/s3_reader.py +2 -2
  31. agno/knowledge/reader/tavily_reader.py +2 -2
  32. agno/knowledge/reader/text_reader.py +2 -2
  33. agno/knowledge/reader/web_search_reader.py +2 -2
  34. agno/knowledge/reader/website_reader.py +5 -3
  35. agno/knowledge/reader/wikipedia_reader.py +2 -2
  36. agno/knowledge/reader/youtube_reader.py +2 -2
  37. agno/knowledge/utils.py +37 -29
  38. agno/learn/__init__.py +6 -0
  39. agno/learn/machine.py +35 -0
  40. agno/learn/schemas.py +82 -11
  41. agno/learn/stores/__init__.py +3 -0
  42. agno/learn/stores/decision_log.py +1156 -0
  43. agno/learn/stores/learned_knowledge.py +6 -6
  44. agno/models/anthropic/claude.py +24 -0
  45. agno/models/aws/bedrock.py +20 -0
  46. agno/models/base.py +48 -4
  47. agno/models/cohere/chat.py +25 -0
  48. agno/models/google/gemini.py +50 -5
  49. agno/models/litellm/chat.py +38 -0
  50. agno/models/openai/chat.py +7 -0
  51. agno/models/openrouter/openrouter.py +46 -0
  52. agno/models/response.py +16 -0
  53. agno/os/app.py +83 -44
  54. agno/os/middleware/__init__.py +2 -0
  55. agno/os/middleware/trailing_slash.py +27 -0
  56. agno/os/router.py +1 -0
  57. agno/os/routers/agents/router.py +29 -16
  58. agno/os/routers/agents/schema.py +6 -4
  59. agno/os/routers/components/__init__.py +3 -0
  60. agno/os/routers/components/components.py +466 -0
  61. agno/os/routers/evals/schemas.py +4 -3
  62. agno/os/routers/health.py +3 -3
  63. agno/os/routers/knowledge/knowledge.py +3 -3
  64. agno/os/routers/memory/schemas.py +4 -2
  65. agno/os/routers/metrics/metrics.py +9 -11
  66. agno/os/routers/metrics/schemas.py +10 -6
  67. agno/os/routers/registry/__init__.py +3 -0
  68. agno/os/routers/registry/registry.py +337 -0
  69. agno/os/routers/teams/router.py +20 -8
  70. agno/os/routers/teams/schema.py +6 -4
  71. agno/os/routers/traces/traces.py +5 -5
  72. agno/os/routers/workflows/router.py +38 -11
  73. agno/os/routers/workflows/schema.py +1 -1
  74. agno/os/schema.py +92 -26
  75. agno/os/utils.py +133 -16
  76. agno/reasoning/anthropic.py +2 -2
  77. agno/reasoning/azure_ai_foundry.py +2 -2
  78. agno/reasoning/deepseek.py +2 -2
  79. agno/reasoning/default.py +6 -7
  80. agno/reasoning/gemini.py +2 -2
  81. agno/reasoning/helpers.py +6 -7
  82. agno/reasoning/manager.py +4 -10
  83. agno/reasoning/ollama.py +2 -2
  84. agno/reasoning/openai.py +2 -2
  85. agno/reasoning/vertexai.py +2 -2
  86. agno/registry/__init__.py +3 -0
  87. agno/registry/registry.py +68 -0
  88. agno/run/agent.py +57 -0
  89. agno/run/base.py +7 -0
  90. agno/run/team.py +57 -0
  91. agno/skills/agent_skills.py +10 -3
  92. agno/team/__init__.py +3 -1
  93. agno/team/team.py +1276 -326
  94. agno/tools/duckduckgo.py +25 -71
  95. agno/tools/exa.py +0 -21
  96. agno/tools/function.py +35 -83
  97. agno/tools/knowledge.py +9 -4
  98. agno/tools/mem0.py +11 -10
  99. agno/tools/memory.py +47 -46
  100. agno/tools/parallel.py +0 -7
  101. agno/tools/reasoning.py +30 -23
  102. agno/tools/tavily.py +4 -1
  103. agno/tools/websearch.py +93 -0
  104. agno/tools/website.py +1 -1
  105. agno/tools/wikipedia.py +1 -1
  106. agno/tools/workflow.py +48 -47
  107. agno/utils/agent.py +42 -5
  108. agno/utils/events.py +160 -2
  109. agno/utils/print_response/agent.py +0 -31
  110. agno/utils/print_response/team.py +0 -2
  111. agno/utils/print_response/workflow.py +0 -2
  112. agno/utils/team.py +61 -11
  113. agno/vectordb/lancedb/lance_db.py +4 -1
  114. agno/vectordb/mongodb/mongodb.py +1 -1
  115. agno/vectordb/qdrant/qdrant.py +4 -4
  116. agno/workflow/__init__.py +3 -1
  117. agno/workflow/condition.py +0 -21
  118. agno/workflow/loop.py +0 -21
  119. agno/workflow/parallel.py +0 -21
  120. agno/workflow/router.py +0 -21
  121. agno/workflow/step.py +117 -24
  122. agno/workflow/steps.py +0 -21
  123. agno/workflow/workflow.py +625 -63
  124. {agno-2.3.25.dist-info → agno-2.4.0.dist-info}/METADATA +46 -76
  125. {agno-2.3.25.dist-info → agno-2.4.0.dist-info}/RECORD +128 -117
  126. {agno-2.3.25.dist-info → agno-2.4.0.dist-info}/WHEEL +0 -0
  127. {agno-2.3.25.dist-info → agno-2.4.0.dist-info}/licenses/LICENSE +0 -0
  128. {agno-2.3.25.dist-info → agno-2.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,68 @@
1
+ from dataclasses import dataclass, field
2
+ from functools import cached_property
3
+ from typing import Any, Callable, Dict, List, Optional, Type
4
+ from uuid import uuid4
5
+
6
+ from pydantic import BaseModel
7
+
8
+ from agno.db.base import BaseDb
9
+ from agno.models.base import Model
10
+ from agno.tools.function import Function
11
+ from agno.tools.toolkit import Toolkit
12
+ from agno.vectordb.base import VectorDb
13
+
14
+
15
+ @dataclass
16
+ class Registry:
17
+ """
18
+ Registry is used to manage non serializable objects like tools, models, databases and vector databases.
19
+ """
20
+
21
+ name: Optional[str] = None
22
+ description: Optional[str] = None
23
+ id: str = field(default_factory=lambda: str(uuid4()))
24
+ tools: List[Any] = field(default_factory=list)
25
+ models: List[Model] = field(default_factory=list)
26
+ dbs: List[BaseDb] = field(default_factory=list)
27
+ vector_dbs: List[VectorDb] = field(default_factory=list)
28
+ schemas: List[Type[BaseModel]] = field(default_factory=list)
29
+
30
+ @cached_property
31
+ def _entrypoint_lookup(self) -> Dict[str, Callable]:
32
+ lookup: Dict[str, Callable] = {}
33
+ for tool in self.tools:
34
+ if isinstance(tool, Toolkit):
35
+ for func in tool.functions.values():
36
+ if func.entrypoint is not None:
37
+ lookup[func.name] = func.entrypoint
38
+ elif isinstance(tool, Function):
39
+ if tool.entrypoint is not None:
40
+ lookup[tool.name] = tool.entrypoint
41
+ elif callable(tool):
42
+ lookup[tool.__name__] = tool
43
+ return lookup
44
+
45
+ def rehydrate_function(self, func_dict: Dict[str, Any]) -> Function:
46
+ """Reconstruct a Function from dict, reattaching its entrypoint."""
47
+ func = Function.from_dict(func_dict)
48
+ func.entrypoint = self._entrypoint_lookup.get(func.name)
49
+ return func
50
+
51
+ def get_schema(self, name: str) -> Optional[Type[BaseModel]]:
52
+ """Get a schema by name."""
53
+ if self.schemas:
54
+ return next((s for s in self.schemas if s.__name__ == name), None)
55
+ return None
56
+
57
+ def get_db(self, db_id: str) -> Optional[BaseDb]:
58
+ """Get a database by id from the registry.
59
+
60
+ Args:
61
+ db_id: The database id to look up
62
+
63
+ Returns:
64
+ The database instance if found, None otherwise
65
+ """
66
+ if self.dbs:
67
+ return next((db for db in self.dbs if db.id == db_id), None)
68
+ return None
agno/run/agent.py CHANGED
@@ -172,6 +172,12 @@ class RunEvent(str, Enum):
172
172
  output_model_response_started = "OutputModelResponseStarted"
173
173
  output_model_response_completed = "OutputModelResponseCompleted"
174
174
 
175
+ model_request_started = "ModelRequestStarted"
176
+ model_request_completed = "ModelRequestCompleted"
177
+
178
+ compression_started = "CompressionStarted"
179
+ compression_completed = "CompressionCompleted"
180
+
175
181
  custom_event = "CustomEvent"
176
182
 
177
183
 
@@ -349,6 +355,7 @@ class MemoryUpdateStartedEvent(BaseAgentRunEvent):
349
355
  @dataclass
350
356
  class MemoryUpdateCompletedEvent(BaseAgentRunEvent):
351
357
  event: str = RunEvent.memory_update_completed.value
358
+ memories: Optional[List[Any]] = None
352
359
 
353
360
 
354
361
  @dataclass
@@ -433,6 +440,48 @@ class OutputModelResponseCompletedEvent(BaseAgentRunEvent):
433
440
  event: str = RunEvent.output_model_response_completed.value
434
441
 
435
442
 
443
+ @dataclass
444
+ class ModelRequestStartedEvent(BaseAgentRunEvent):
445
+ """Event sent when a model request is about to be made"""
446
+
447
+ event: str = RunEvent.model_request_started.value
448
+ model: Optional[str] = None
449
+ model_provider: Optional[str] = None
450
+
451
+
452
+ @dataclass
453
+ class ModelRequestCompletedEvent(BaseAgentRunEvent):
454
+ """Event sent when a model request has completed"""
455
+
456
+ event: str = RunEvent.model_request_completed.value
457
+ model: Optional[str] = None
458
+ model_provider: Optional[str] = None
459
+ input_tokens: Optional[int] = None
460
+ output_tokens: Optional[int] = None
461
+ total_tokens: Optional[int] = None
462
+ time_to_first_token: Optional[float] = None
463
+ reasoning_tokens: Optional[int] = None
464
+ cache_read_tokens: Optional[int] = None
465
+ cache_write_tokens: Optional[int] = None
466
+
467
+
468
+ @dataclass
469
+ class CompressionStartedEvent(BaseAgentRunEvent):
470
+ """Event sent when tool result compression is about to start"""
471
+
472
+ event: str = RunEvent.compression_started.value
473
+
474
+
475
+ @dataclass
476
+ class CompressionCompletedEvent(BaseAgentRunEvent):
477
+ """Event sent when tool result compression has completed"""
478
+
479
+ event: str = RunEvent.compression_completed.value
480
+ tool_results_compressed: Optional[int] = None
481
+ original_size: Optional[int] = None
482
+ compressed_size: Optional[int] = None
483
+
484
+
436
485
  @dataclass
437
486
  class CustomEvent(BaseAgentRunEvent):
438
487
  event: str = RunEvent.custom_event.value
@@ -472,6 +521,10 @@ RunOutputEvent = Union[
472
521
  ParserModelResponseCompletedEvent,
473
522
  OutputModelResponseStartedEvent,
474
523
  OutputModelResponseCompletedEvent,
524
+ ModelRequestStartedEvent,
525
+ ModelRequestCompletedEvent,
526
+ CompressionStartedEvent,
527
+ CompressionCompletedEvent,
475
528
  CustomEvent,
476
529
  ]
477
530
 
@@ -506,6 +559,10 @@ RUN_EVENT_TYPE_REGISTRY = {
506
559
  RunEvent.parser_model_response_completed.value: ParserModelResponseCompletedEvent,
507
560
  RunEvent.output_model_response_started.value: OutputModelResponseStartedEvent,
508
561
  RunEvent.output_model_response_completed.value: OutputModelResponseCompletedEvent,
562
+ RunEvent.model_request_started.value: ModelRequestStartedEvent,
563
+ RunEvent.model_request_completed.value: ModelRequestCompletedEvent,
564
+ RunEvent.compression_started.value: CompressionStartedEvent,
565
+ RunEvent.compression_completed.value: CompressionCompletedEvent,
509
566
  RunEvent.custom_event.value: CustomEvent,
510
567
  }
511
568
 
agno/run/base.py CHANGED
@@ -18,6 +18,9 @@ class RunContext:
18
18
  session_id: str
19
19
  user_id: Optional[str] = None
20
20
 
21
+ workflow_id: Optional[str] = None
22
+ workflow_name: Optional[str] = None
23
+
21
24
  dependencies: Optional[Dict[str, Any]] = None
22
25
  knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
23
26
  metadata: Optional[Dict[str, Any]] = None
@@ -52,6 +55,7 @@ class BaseRunOutputEvent:
52
55
  "metrics",
53
56
  "run_input",
54
57
  "requirements",
58
+ "memories",
55
59
  ]
56
60
  }
57
61
 
@@ -142,6 +146,9 @@ class BaseRunOutputEvent:
142
146
  if hasattr(self, "requirements") and self.requirements is not None:
143
147
  _dict["requirements"] = [req.to_dict() if hasattr(req, "to_dict") else req for req in self.requirements]
144
148
 
149
+ if hasattr(self, "memories") and self.memories is not None:
150
+ _dict["memories"] = [mem.to_dict() if hasattr(mem, "to_dict") else mem for mem in self.memories]
151
+
145
152
  return _dict
146
153
 
147
154
  def to_json(self, separators=(", ", ": "), indent: Optional[int] = 2) -> str:
agno/run/team.py CHANGED
@@ -165,6 +165,12 @@ class TeamRunEvent(str, Enum):
165
165
  output_model_response_started = "TeamOutputModelResponseStarted"
166
166
  output_model_response_completed = "TeamOutputModelResponseCompleted"
167
167
 
168
+ model_request_started = "TeamModelRequestStarted"
169
+ model_request_completed = "TeamModelRequestCompleted"
170
+
171
+ compression_started = "TeamCompressionStarted"
172
+ compression_completed = "TeamCompressionCompleted"
173
+
168
174
  custom_event = "CustomEvent"
169
175
 
170
176
 
@@ -322,6 +328,7 @@ class MemoryUpdateStartedEvent(BaseTeamRunEvent):
322
328
  @dataclass
323
329
  class MemoryUpdateCompletedEvent(BaseTeamRunEvent):
324
330
  event: str = TeamRunEvent.memory_update_completed.value
331
+ memories: Optional[List[Any]] = None
325
332
 
326
333
 
327
334
  @dataclass
@@ -406,6 +413,48 @@ class OutputModelResponseCompletedEvent(BaseTeamRunEvent):
406
413
  event: str = TeamRunEvent.output_model_response_completed.value
407
414
 
408
415
 
416
+ @dataclass
417
+ class ModelRequestStartedEvent(BaseTeamRunEvent):
418
+ """Event sent when a model request is about to be made"""
419
+
420
+ event: str = TeamRunEvent.model_request_started.value
421
+ model: Optional[str] = None
422
+ model_provider: Optional[str] = None
423
+
424
+
425
+ @dataclass
426
+ class ModelRequestCompletedEvent(BaseTeamRunEvent):
427
+ """Event sent when a model request has completed"""
428
+
429
+ event: str = TeamRunEvent.model_request_completed.value
430
+ model: Optional[str] = None
431
+ model_provider: Optional[str] = None
432
+ input_tokens: Optional[int] = None
433
+ output_tokens: Optional[int] = None
434
+ total_tokens: Optional[int] = None
435
+ time_to_first_token: Optional[float] = None
436
+ reasoning_tokens: Optional[int] = None
437
+ cache_read_tokens: Optional[int] = None
438
+ cache_write_tokens: Optional[int] = None
439
+
440
+
441
+ @dataclass
442
+ class CompressionStartedEvent(BaseTeamRunEvent):
443
+ """Event sent when tool result compression is about to start"""
444
+
445
+ event: str = TeamRunEvent.compression_started.value
446
+
447
+
448
+ @dataclass
449
+ class CompressionCompletedEvent(BaseTeamRunEvent):
450
+ """Event sent when tool result compression has completed"""
451
+
452
+ event: str = TeamRunEvent.compression_completed.value
453
+ tool_results_compressed: Optional[int] = None
454
+ original_size: Optional[int] = None
455
+ compressed_size: Optional[int] = None
456
+
457
+
409
458
  @dataclass
410
459
  class CustomEvent(BaseTeamRunEvent):
411
460
  event: str = TeamRunEvent.custom_event.value
@@ -441,6 +490,10 @@ TeamRunOutputEvent = Union[
441
490
  ParserModelResponseCompletedEvent,
442
491
  OutputModelResponseStartedEvent,
443
492
  OutputModelResponseCompletedEvent,
493
+ ModelRequestStartedEvent,
494
+ ModelRequestCompletedEvent,
495
+ CompressionStartedEvent,
496
+ CompressionCompletedEvent,
444
497
  CustomEvent,
445
498
  ]
446
499
 
@@ -472,6 +525,10 @@ TEAM_RUN_EVENT_TYPE_REGISTRY = {
472
525
  TeamRunEvent.parser_model_response_completed.value: ParserModelResponseCompletedEvent,
473
526
  TeamRunEvent.output_model_response_started.value: OutputModelResponseStartedEvent,
474
527
  TeamRunEvent.output_model_response_completed.value: OutputModelResponseCompletedEvent,
528
+ TeamRunEvent.model_request_started.value: ModelRequestStartedEvent,
529
+ TeamRunEvent.model_request_completed.value: ModelRequestCompletedEvent,
530
+ TeamRunEvent.compression_started.value: CompressionStartedEvent,
531
+ TeamRunEvent.compression_completed.value: CompressionCompletedEvent,
475
532
  TeamRunEvent.custom_event.value: CustomEvent,
476
533
  }
477
534
 
@@ -106,10 +106,17 @@ class Skills:
106
106
  "- **Scripts**: Executable code templates you can use or adapt",
107
107
  "- **References**: Supporting documentation (guides, cheatsheets, examples)",
108
108
  "",
109
- "## Progressive Discovery",
110
- "Skill information is designed to be loaded on-demand to keep your context focused:",
109
+ "## IMPORTANT: How to Use Skills",
110
+ "**Skill names are NOT callable functions.** You cannot call a skill directly by its name.",
111
+ "Instead, you MUST use the provided skill access tools:",
112
+ "",
113
+ "1. `get_skill_instructions(skill_name)` - Load the full instructions for a skill",
114
+ "2. `get_skill_reference(skill_name, reference_path)` - Access specific documentation",
115
+ "3. `get_skill_script(skill_name, script_path, execute=False)` - Read or run scripts",
116
+ "",
117
+ "## Progressive Discovery Workflow",
111
118
  "1. **Browse**: Review the skill summaries below to understand what's available",
112
- "2. **Load**: When a task matches a skill, use `get_skill_instructions` to load full guidance",
119
+ "2. **Load**: When a task matches a skill, call `get_skill_instructions(skill_name)` first",
113
120
  "3. **Reference**: Use `get_skill_reference` to access specific documentation as needed",
114
121
  "4. **Scripts**: Use `get_skill_script` to read or execute scripts from a skill",
115
122
  "",
agno/team/__init__.py CHANGED
@@ -16,7 +16,7 @@ from agno.run.team import (
16
16
  ToolCallStartedEvent,
17
17
  )
18
18
  from agno.team.remote import RemoteTeam
19
- from agno.team.team import Team
19
+ from agno.team.team import Team, get_team_by_id, get_teams
20
20
 
21
21
  __all__ = [
22
22
  "Team",
@@ -36,4 +36,6 @@ __all__ = [
36
36
  "ReasoningCompletedEvent",
37
37
  "ToolCallStartedEvent",
38
38
  "ToolCallCompletedEvent",
39
+ "get_team_by_id",
40
+ "get_teams",
39
41
  ]