agno 2.3.26__py3-none-any.whl → 2.4.1__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/__init__.py +4 -0
- agno/agent/agent.py +1368 -541
- agno/agent/remote.py +13 -0
- agno/db/base.py +339 -0
- agno/db/postgres/async_postgres.py +116 -12
- agno/db/postgres/postgres.py +1242 -25
- agno/db/postgres/schemas.py +48 -1
- agno/db/sqlite/async_sqlite.py +119 -4
- agno/db/sqlite/schemas.py +51 -0
- agno/db/sqlite/sqlite.py +1186 -13
- agno/db/utils.py +37 -1
- agno/integrations/discord/client.py +12 -1
- agno/knowledge/__init__.py +4 -0
- agno/knowledge/chunking/code.py +1 -1
- agno/knowledge/chunking/semantic.py +1 -1
- agno/knowledge/chunking/strategy.py +4 -0
- agno/knowledge/filesystem.py +412 -0
- agno/knowledge/knowledge.py +3722 -2182
- agno/knowledge/protocol.py +134 -0
- agno/knowledge/reader/arxiv_reader.py +2 -2
- agno/knowledge/reader/base.py +9 -7
- agno/knowledge/reader/csv_reader.py +236 -13
- agno/knowledge/reader/docx_reader.py +2 -2
- agno/knowledge/reader/field_labeled_csv_reader.py +169 -5
- agno/knowledge/reader/firecrawl_reader.py +2 -2
- agno/knowledge/reader/json_reader.py +2 -2
- agno/knowledge/reader/markdown_reader.py +2 -2
- agno/knowledge/reader/pdf_reader.py +5 -4
- agno/knowledge/reader/pptx_reader.py +2 -2
- agno/knowledge/reader/reader_factory.py +118 -1
- agno/knowledge/reader/s3_reader.py +2 -2
- agno/knowledge/reader/tavily_reader.py +2 -2
- agno/knowledge/reader/text_reader.py +2 -2
- agno/knowledge/reader/web_search_reader.py +2 -2
- agno/knowledge/reader/website_reader.py +5 -3
- agno/knowledge/reader/wikipedia_reader.py +2 -2
- agno/knowledge/reader/youtube_reader.py +2 -2
- agno/knowledge/remote_content/__init__.py +29 -0
- agno/knowledge/remote_content/config.py +204 -0
- agno/knowledge/remote_content/remote_content.py +74 -17
- agno/knowledge/utils.py +37 -29
- agno/learn/__init__.py +6 -0
- agno/learn/machine.py +35 -0
- agno/learn/schemas.py +82 -11
- agno/learn/stores/__init__.py +3 -0
- agno/learn/stores/decision_log.py +1156 -0
- agno/learn/stores/learned_knowledge.py +6 -6
- agno/models/anthropic/claude.py +24 -0
- agno/models/aws/bedrock.py +20 -0
- agno/models/base.py +60 -6
- agno/models/cerebras/cerebras.py +34 -2
- agno/models/cohere/chat.py +25 -0
- agno/models/google/gemini.py +50 -5
- agno/models/litellm/chat.py +38 -0
- agno/models/n1n/__init__.py +3 -0
- agno/models/n1n/n1n.py +57 -0
- agno/models/openai/chat.py +25 -1
- agno/models/openrouter/openrouter.py +46 -0
- agno/models/perplexity/perplexity.py +2 -0
- agno/models/response.py +16 -0
- agno/os/app.py +83 -44
- agno/os/interfaces/slack/router.py +10 -1
- agno/os/interfaces/whatsapp/router.py +6 -0
- agno/os/middleware/__init__.py +2 -0
- agno/os/middleware/trailing_slash.py +27 -0
- agno/os/router.py +1 -0
- agno/os/routers/agents/router.py +29 -16
- agno/os/routers/agents/schema.py +6 -4
- agno/os/routers/components/__init__.py +3 -0
- agno/os/routers/components/components.py +475 -0
- agno/os/routers/evals/schemas.py +4 -3
- agno/os/routers/health.py +3 -3
- agno/os/routers/knowledge/knowledge.py +128 -3
- agno/os/routers/knowledge/schemas.py +12 -0
- agno/os/routers/memory/schemas.py +4 -2
- agno/os/routers/metrics/metrics.py +9 -11
- agno/os/routers/metrics/schemas.py +10 -6
- agno/os/routers/registry/__init__.py +3 -0
- agno/os/routers/registry/registry.py +337 -0
- agno/os/routers/teams/router.py +20 -8
- agno/os/routers/teams/schema.py +6 -4
- agno/os/routers/traces/traces.py +5 -5
- agno/os/routers/workflows/router.py +38 -11
- agno/os/routers/workflows/schema.py +1 -1
- agno/os/schema.py +92 -26
- agno/os/utils.py +84 -19
- agno/reasoning/anthropic.py +2 -2
- agno/reasoning/azure_ai_foundry.py +2 -2
- agno/reasoning/deepseek.py +2 -2
- agno/reasoning/default.py +6 -7
- agno/reasoning/gemini.py +2 -2
- agno/reasoning/helpers.py +6 -7
- agno/reasoning/manager.py +4 -10
- agno/reasoning/ollama.py +2 -2
- agno/reasoning/openai.py +2 -2
- agno/reasoning/vertexai.py +2 -2
- agno/registry/__init__.py +3 -0
- agno/registry/registry.py +68 -0
- agno/run/agent.py +59 -0
- agno/run/base.py +7 -0
- agno/run/team.py +57 -0
- agno/skills/agent_skills.py +10 -3
- agno/team/__init__.py +3 -1
- agno/team/team.py +1165 -330
- agno/tools/duckduckgo.py +25 -71
- agno/tools/exa.py +0 -21
- agno/tools/function.py +35 -83
- agno/tools/knowledge.py +9 -4
- agno/tools/mem0.py +11 -10
- agno/tools/memory.py +47 -46
- agno/tools/parallel.py +0 -7
- agno/tools/reasoning.py +30 -23
- agno/tools/tavily.py +4 -1
- agno/tools/websearch.py +93 -0
- agno/tools/website.py +1 -1
- agno/tools/wikipedia.py +1 -1
- agno/tools/workflow.py +48 -47
- agno/utils/agent.py +42 -5
- agno/utils/events.py +160 -2
- agno/utils/print_response/agent.py +0 -31
- agno/utils/print_response/team.py +0 -2
- agno/utils/print_response/workflow.py +0 -2
- agno/utils/team.py +61 -11
- agno/vectordb/lancedb/lance_db.py +4 -1
- agno/vectordb/mongodb/mongodb.py +1 -1
- agno/vectordb/pgvector/pgvector.py +3 -3
- agno/vectordb/qdrant/qdrant.py +4 -4
- agno/workflow/__init__.py +3 -1
- agno/workflow/condition.py +0 -21
- agno/workflow/loop.py +0 -21
- agno/workflow/parallel.py +0 -21
- agno/workflow/router.py +0 -21
- agno/workflow/step.py +117 -24
- agno/workflow/steps.py +0 -21
- agno/workflow/workflow.py +427 -63
- {agno-2.3.26.dist-info → agno-2.4.1.dist-info}/METADATA +49 -76
- {agno-2.3.26.dist-info → agno-2.4.1.dist-info}/RECORD +140 -126
- {agno-2.3.26.dist-info → agno-2.4.1.dist-info}/WHEEL +1 -1
- {agno-2.3.26.dist-info → agno-2.4.1.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.26.dist-info → agno-2.4.1.dist-info}/top_level.txt +0 -0
agno/utils/team.py
CHANGED
|
@@ -73,14 +73,40 @@ def add_interaction_to_team_run_context(
|
|
|
73
73
|
log_debug(f"Updated team run context with member name: {member_name}")
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
def get_team_member_interactions_str(
|
|
76
|
+
def get_team_member_interactions_str(
|
|
77
|
+
team_run_context: Dict[str, Any],
|
|
78
|
+
max_interactions: Optional[int] = None,
|
|
79
|
+
) -> str:
|
|
80
|
+
"""
|
|
81
|
+
Build a string representation of member interactions from the team run context.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
team_run_context: The context containing member responses
|
|
85
|
+
max_interactions: Maximum number of recent interactions to include.
|
|
86
|
+
None means include all interactions.
|
|
87
|
+
If set, only the most recent N interactions are included.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
A formatted string with member interactions
|
|
91
|
+
"""
|
|
77
92
|
if not team_run_context:
|
|
78
93
|
return ""
|
|
79
94
|
team_member_interactions_str = ""
|
|
80
95
|
if "member_responses" in team_run_context:
|
|
81
|
-
|
|
96
|
+
member_responses = team_run_context["member_responses"]
|
|
97
|
+
|
|
98
|
+
# If max_interactions is set, only include the most recent N interactions
|
|
99
|
+
if max_interactions is not None and len(member_responses) > max_interactions:
|
|
100
|
+
member_responses = member_responses[-max_interactions:]
|
|
82
101
|
|
|
83
|
-
|
|
102
|
+
if not member_responses:
|
|
103
|
+
return ""
|
|
104
|
+
|
|
105
|
+
team_member_interactions_str += (
|
|
106
|
+
"<member_interaction_context>\nSee below interactions with other team members.\n"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
for interaction in member_responses:
|
|
84
110
|
response_dict = interaction["run_response"].to_dict()
|
|
85
111
|
response_content = (
|
|
86
112
|
response_dict.get("content")
|
|
@@ -95,45 +121,69 @@ def get_team_member_interactions_str(team_run_context: Dict[str, Any]) -> str:
|
|
|
95
121
|
return team_member_interactions_str
|
|
96
122
|
|
|
97
123
|
|
|
98
|
-
def get_team_run_context_images(
|
|
124
|
+
def get_team_run_context_images(
|
|
125
|
+
team_run_context: Dict[str, Any],
|
|
126
|
+
max_interactions: Optional[int] = None,
|
|
127
|
+
) -> List[Image]:
|
|
99
128
|
if not team_run_context:
|
|
100
129
|
return []
|
|
101
130
|
images = []
|
|
102
131
|
if "member_responses" in team_run_context:
|
|
103
|
-
|
|
132
|
+
member_responses = team_run_context["member_responses"]
|
|
133
|
+
if max_interactions is not None and len(member_responses) > max_interactions:
|
|
134
|
+
member_responses = member_responses[-max_interactions:]
|
|
135
|
+
for interaction in member_responses:
|
|
104
136
|
if interaction["run_response"].images:
|
|
105
137
|
images.extend(interaction["run_response"].images)
|
|
106
138
|
return images
|
|
107
139
|
|
|
108
140
|
|
|
109
|
-
def get_team_run_context_videos(
|
|
141
|
+
def get_team_run_context_videos(
|
|
142
|
+
team_run_context: Dict[str, Any],
|
|
143
|
+
max_interactions: Optional[int] = None,
|
|
144
|
+
) -> List[Video]:
|
|
110
145
|
if not team_run_context:
|
|
111
146
|
return []
|
|
112
147
|
videos = []
|
|
113
148
|
if "member_responses" in team_run_context:
|
|
114
|
-
|
|
149
|
+
member_responses = team_run_context["member_responses"]
|
|
150
|
+
if max_interactions is not None and len(member_responses) > max_interactions:
|
|
151
|
+
member_responses = member_responses[-max_interactions:]
|
|
152
|
+
for interaction in member_responses:
|
|
115
153
|
if interaction["run_response"].videos:
|
|
116
154
|
videos.extend(interaction["run_response"].videos)
|
|
117
155
|
return videos
|
|
118
156
|
|
|
119
157
|
|
|
120
|
-
def get_team_run_context_audio(
|
|
158
|
+
def get_team_run_context_audio(
|
|
159
|
+
team_run_context: Dict[str, Any],
|
|
160
|
+
max_interactions: Optional[int] = None,
|
|
161
|
+
) -> List[Audio]:
|
|
121
162
|
if not team_run_context:
|
|
122
163
|
return []
|
|
123
164
|
audio = []
|
|
124
165
|
if "member_responses" in team_run_context:
|
|
125
|
-
|
|
166
|
+
member_responses = team_run_context["member_responses"]
|
|
167
|
+
if max_interactions is not None and len(member_responses) > max_interactions:
|
|
168
|
+
member_responses = member_responses[-max_interactions:]
|
|
169
|
+
for interaction in member_responses:
|
|
126
170
|
if interaction["run_response"].audio:
|
|
127
171
|
audio.extend(interaction["run_response"].audio)
|
|
128
172
|
return audio
|
|
129
173
|
|
|
130
174
|
|
|
131
|
-
def get_team_run_context_files(
|
|
175
|
+
def get_team_run_context_files(
|
|
176
|
+
team_run_context: Dict[str, Any],
|
|
177
|
+
max_interactions: Optional[int] = None,
|
|
178
|
+
) -> List[File]:
|
|
132
179
|
if not team_run_context:
|
|
133
180
|
return []
|
|
134
181
|
files = []
|
|
135
182
|
if "member_responses" in team_run_context:
|
|
136
|
-
|
|
183
|
+
member_responses = team_run_context["member_responses"]
|
|
184
|
+
if max_interactions is not None and len(member_responses) > max_interactions:
|
|
185
|
+
member_responses = member_responses[-max_interactions:]
|
|
186
|
+
for interaction in member_responses:
|
|
137
187
|
if interaction["run_response"].files:
|
|
138
188
|
files.extend(interaction["run_response"].files)
|
|
139
189
|
return files
|
|
@@ -282,7 +282,10 @@ class LanceDb(VectorDb):
|
|
|
282
282
|
meta_data.update(filters)
|
|
283
283
|
document.meta_data = meta_data
|
|
284
284
|
|
|
285
|
-
document
|
|
285
|
+
# Only embed if the document doesn't already have an embedding
|
|
286
|
+
# This prevents duplicate embedding when called from async_insert or async_upsert
|
|
287
|
+
if document.embedding is None:
|
|
288
|
+
document.embed(embedder=self.embedder)
|
|
286
289
|
cleaned_content = document.content.replace("\x00", "\ufffd")
|
|
287
290
|
# Include content_hash in ID to ensure uniqueness across different content hashes
|
|
288
291
|
base_id = document.id or md5(cleaned_content.encode()).hexdigest()
|
agno/vectordb/mongodb/mongodb.py
CHANGED
|
@@ -1150,7 +1150,7 @@ class MongoDb(VectorDb):
|
|
|
1150
1150
|
if isinstance(filters, List):
|
|
1151
1151
|
log_warning("Filters Expressions are not supported in MongoDB. No filters will be applied.")
|
|
1152
1152
|
filters = None
|
|
1153
|
-
query_embedding = self.embedder.
|
|
1153
|
+
query_embedding = await self.embedder.async_get_embedding(query)
|
|
1154
1154
|
if query_embedding is None:
|
|
1155
1155
|
logger.error(f"Failed to generate embedding for query: {query}")
|
|
1156
1156
|
return []
|
|
@@ -379,7 +379,7 @@ class PgVector(VectorDb):
|
|
|
379
379
|
record = {
|
|
380
380
|
"id": record_id,
|
|
381
381
|
"name": doc.name,
|
|
382
|
-
"meta_data":
|
|
382
|
+
"meta_data": meta_data,
|
|
383
383
|
"filters": filters,
|
|
384
384
|
"content": cleaned_content,
|
|
385
385
|
"embedding": doc.embedding,
|
|
@@ -514,7 +514,7 @@ class PgVector(VectorDb):
|
|
|
514
514
|
return {
|
|
515
515
|
"id": record_id,
|
|
516
516
|
"name": doc.name,
|
|
517
|
-
"meta_data":
|
|
517
|
+
"meta_data": meta_data,
|
|
518
518
|
"filters": filters,
|
|
519
519
|
"content": cleaned_content,
|
|
520
520
|
"embedding": doc.embedding,
|
|
@@ -664,7 +664,7 @@ class PgVector(VectorDb):
|
|
|
664
664
|
record = {
|
|
665
665
|
"id": record_id, # use record_id as a reproducible id to avoid duplicates while upsert
|
|
666
666
|
"name": doc.name,
|
|
667
|
-
"meta_data":
|
|
667
|
+
"meta_data": meta_data,
|
|
668
668
|
"filters": filters,
|
|
669
669
|
"content": cleaned_content,
|
|
670
670
|
"embedding": doc.embedding,
|
agno/vectordb/qdrant/qdrant.py
CHANGED
|
@@ -423,12 +423,12 @@ class Qdrant(VectorDb):
|
|
|
423
423
|
# Fall back to individual embedding
|
|
424
424
|
for doc in documents:
|
|
425
425
|
if self.search_type in [SearchType.vector, SearchType.hybrid]:
|
|
426
|
-
doc.
|
|
426
|
+
await doc.async_embed(embedder=self.embedder)
|
|
427
427
|
else:
|
|
428
428
|
# Use individual embedding
|
|
429
429
|
for doc in documents:
|
|
430
430
|
if self.search_type in [SearchType.vector, SearchType.hybrid]:
|
|
431
|
-
doc.
|
|
431
|
+
await doc.async_embed(embedder=self.embedder)
|
|
432
432
|
|
|
433
433
|
async def process_document(document):
|
|
434
434
|
cleaned_content = document.content.replace("\x00", "\ufffd")
|
|
@@ -634,7 +634,7 @@ class Qdrant(VectorDb):
|
|
|
634
634
|
limit: int,
|
|
635
635
|
formatted_filters: Optional[models.Filter],
|
|
636
636
|
) -> List[models.ScoredPoint]:
|
|
637
|
-
dense_embedding = self.embedder.
|
|
637
|
+
dense_embedding = await self.embedder.async_get_embedding(query)
|
|
638
638
|
|
|
639
639
|
# TODO(v2.0.0): Remove this conditional and always use named vectors
|
|
640
640
|
if self.use_named_vectors:
|
|
@@ -683,7 +683,7 @@ class Qdrant(VectorDb):
|
|
|
683
683
|
limit: int,
|
|
684
684
|
formatted_filters: Optional[models.Filter],
|
|
685
685
|
) -> List[models.ScoredPoint]:
|
|
686
|
-
dense_embedding = self.embedder.
|
|
686
|
+
dense_embedding = await self.embedder.async_get_embedding(query)
|
|
687
687
|
sparse_embedding = next(iter(self.sparse_encoder.embed([query]))).as_object()
|
|
688
688
|
call = await self.async_client.query_points(
|
|
689
689
|
collection_name=self.collection,
|
agno/workflow/__init__.py
CHANGED
|
@@ -7,7 +7,7 @@ from agno.workflow.router import Router
|
|
|
7
7
|
from agno.workflow.step import Step
|
|
8
8
|
from agno.workflow.steps import Steps
|
|
9
9
|
from agno.workflow.types import StepInput, StepOutput, WorkflowExecutionInput
|
|
10
|
-
from agno.workflow.workflow import Workflow
|
|
10
|
+
from agno.workflow.workflow import Workflow, get_workflow_by_id, get_workflows
|
|
11
11
|
|
|
12
12
|
__all__ = [
|
|
13
13
|
"Workflow",
|
|
@@ -22,4 +22,6 @@ __all__ = [
|
|
|
22
22
|
"WorkflowExecutionInput",
|
|
23
23
|
"StepInput",
|
|
24
24
|
"StepOutput",
|
|
25
|
+
"get_workflow_by_id",
|
|
26
|
+
"get_workflows",
|
|
25
27
|
]
|
agno/workflow/condition.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import inspect
|
|
2
|
-
import warnings
|
|
3
2
|
from dataclasses import dataclass
|
|
4
3
|
from typing import Any, AsyncIterator, Awaitable, Callable, Dict, Iterator, List, Optional, Union
|
|
5
4
|
from uuid import uuid4
|
|
@@ -289,7 +288,6 @@ class Condition:
|
|
|
289
288
|
session_id: Optional[str] = None,
|
|
290
289
|
user_id: Optional[str] = None,
|
|
291
290
|
stream_events: bool = False,
|
|
292
|
-
stream_intermediate_steps: bool = False, # type: ignore
|
|
293
291
|
stream_executor_events: bool = True,
|
|
294
292
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
295
293
|
step_index: Optional[Union[int, tuple]] = None,
|
|
@@ -316,15 +314,6 @@ class Condition:
|
|
|
316
314
|
condition_result = self._evaluate_condition(step_input, session_state=session_state)
|
|
317
315
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
318
316
|
|
|
319
|
-
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
320
|
-
if stream_intermediate_steps is not None:
|
|
321
|
-
warnings.warn(
|
|
322
|
-
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
323
|
-
DeprecationWarning,
|
|
324
|
-
stacklevel=2,
|
|
325
|
-
)
|
|
326
|
-
stream_events = stream_events or stream_intermediate_steps
|
|
327
|
-
|
|
328
317
|
if stream_events and workflow_run_response:
|
|
329
318
|
# Yield condition started event
|
|
330
319
|
yield ConditionExecutionStartedEvent(
|
|
@@ -582,7 +571,6 @@ class Condition:
|
|
|
582
571
|
session_id: Optional[str] = None,
|
|
583
572
|
user_id: Optional[str] = None,
|
|
584
573
|
stream_events: bool = False,
|
|
585
|
-
stream_intermediate_steps: bool = False,
|
|
586
574
|
stream_executor_events: bool = True,
|
|
587
575
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
588
576
|
step_index: Optional[Union[int, tuple]] = None,
|
|
@@ -609,15 +597,6 @@ class Condition:
|
|
|
609
597
|
condition_result = await self._aevaluate_condition(step_input, session_state=session_state)
|
|
610
598
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
611
599
|
|
|
612
|
-
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
613
|
-
if stream_intermediate_steps is not None:
|
|
614
|
-
warnings.warn(
|
|
615
|
-
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
616
|
-
DeprecationWarning,
|
|
617
|
-
stacklevel=2,
|
|
618
|
-
)
|
|
619
|
-
stream_events = stream_events or stream_intermediate_steps
|
|
620
|
-
|
|
621
600
|
if stream_events and workflow_run_response:
|
|
622
601
|
# Yield condition started event
|
|
623
602
|
yield ConditionExecutionStartedEvent(
|
agno/workflow/loop.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import inspect
|
|
2
|
-
import warnings
|
|
3
2
|
from dataclasses import dataclass
|
|
4
3
|
from typing import Any, AsyncIterator, Awaitable, Callable, Dict, Iterator, List, Optional, Union
|
|
5
4
|
from uuid import uuid4
|
|
@@ -241,7 +240,6 @@ class Loop:
|
|
|
241
240
|
session_id: Optional[str] = None,
|
|
242
241
|
user_id: Optional[str] = None,
|
|
243
242
|
stream_events: bool = False,
|
|
244
|
-
stream_intermediate_steps: bool = False,
|
|
245
243
|
stream_executor_events: bool = True,
|
|
246
244
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
247
245
|
step_index: Optional[Union[int, tuple]] = None,
|
|
@@ -262,15 +260,6 @@ class Loop:
|
|
|
262
260
|
|
|
263
261
|
loop_step_id = str(uuid4())
|
|
264
262
|
|
|
265
|
-
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
266
|
-
if stream_intermediate_steps is not None:
|
|
267
|
-
warnings.warn(
|
|
268
|
-
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
269
|
-
DeprecationWarning,
|
|
270
|
-
stacklevel=2,
|
|
271
|
-
)
|
|
272
|
-
stream_events = stream_events or stream_intermediate_steps
|
|
273
|
-
|
|
274
263
|
if stream_events and workflow_run_response:
|
|
275
264
|
# Yield loop started event
|
|
276
265
|
yield LoopExecutionStartedEvent(
|
|
@@ -566,7 +555,6 @@ class Loop:
|
|
|
566
555
|
session_id: Optional[str] = None,
|
|
567
556
|
user_id: Optional[str] = None,
|
|
568
557
|
stream_events: bool = False,
|
|
569
|
-
stream_intermediate_steps: bool = False,
|
|
570
558
|
stream_executor_events: bool = True,
|
|
571
559
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
572
560
|
step_index: Optional[Union[int, tuple]] = None,
|
|
@@ -587,15 +575,6 @@ class Loop:
|
|
|
587
575
|
# Prepare steps first
|
|
588
576
|
self._prepare_steps()
|
|
589
577
|
|
|
590
|
-
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
591
|
-
if stream_intermediate_steps is not None:
|
|
592
|
-
warnings.warn(
|
|
593
|
-
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
594
|
-
DeprecationWarning,
|
|
595
|
-
stacklevel=2,
|
|
596
|
-
)
|
|
597
|
-
stream_events = stream_events or stream_intermediate_steps
|
|
598
|
-
|
|
599
578
|
if stream_events and workflow_run_response:
|
|
600
579
|
# Yield loop started event
|
|
601
580
|
yield LoopExecutionStartedEvent(
|
agno/workflow/parallel.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import warnings
|
|
3
2
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
4
3
|
from contextvars import copy_context
|
|
5
4
|
from copy import deepcopy
|
|
@@ -329,7 +328,6 @@ class Parallel:
|
|
|
329
328
|
session_id: Optional[str] = None,
|
|
330
329
|
user_id: Optional[str] = None,
|
|
331
330
|
stream_events: bool = False,
|
|
332
|
-
stream_intermediate_steps: bool = False,
|
|
333
331
|
stream_executor_events: bool = True,
|
|
334
332
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
335
333
|
step_index: Optional[Union[int, tuple]] = None,
|
|
@@ -361,15 +359,6 @@ class Parallel:
|
|
|
361
359
|
else:
|
|
362
360
|
session_state_copies.append({})
|
|
363
361
|
|
|
364
|
-
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
365
|
-
if stream_intermediate_steps is not None:
|
|
366
|
-
warnings.warn(
|
|
367
|
-
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
368
|
-
DeprecationWarning,
|
|
369
|
-
stacklevel=2,
|
|
370
|
-
)
|
|
371
|
-
stream_events = stream_events or stream_intermediate_steps
|
|
372
|
-
|
|
373
362
|
if stream_events and workflow_run_response:
|
|
374
363
|
# Yield parallel step started event
|
|
375
364
|
yield ParallelExecutionStartedEvent(
|
|
@@ -665,7 +654,6 @@ class Parallel:
|
|
|
665
654
|
session_id: Optional[str] = None,
|
|
666
655
|
user_id: Optional[str] = None,
|
|
667
656
|
stream_events: bool = False,
|
|
668
|
-
stream_intermediate_steps: bool = False,
|
|
669
657
|
stream_executor_events: bool = True,
|
|
670
658
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
671
659
|
step_index: Optional[Union[int, tuple]] = None,
|
|
@@ -697,15 +685,6 @@ class Parallel:
|
|
|
697
685
|
else:
|
|
698
686
|
session_state_copies.append({})
|
|
699
687
|
|
|
700
|
-
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
701
|
-
if stream_intermediate_steps is not None:
|
|
702
|
-
warnings.warn(
|
|
703
|
-
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
704
|
-
DeprecationWarning,
|
|
705
|
-
stacklevel=2,
|
|
706
|
-
)
|
|
707
|
-
stream_events = stream_events or stream_intermediate_steps
|
|
708
|
-
|
|
709
688
|
if stream_events and workflow_run_response:
|
|
710
689
|
# Yield parallel step started event
|
|
711
690
|
yield ParallelExecutionStartedEvent(
|
agno/workflow/router.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import inspect
|
|
2
|
-
import warnings
|
|
3
2
|
from dataclasses import dataclass
|
|
4
3
|
from typing import Any, AsyncIterator, Awaitable, Callable, Dict, Iterator, List, Optional, Union
|
|
5
4
|
from uuid import uuid4
|
|
@@ -279,7 +278,6 @@ class Router:
|
|
|
279
278
|
run_context: Optional[RunContext] = None,
|
|
280
279
|
session_state: Optional[Dict[str, Any]] = None,
|
|
281
280
|
stream_events: bool = False,
|
|
282
|
-
stream_intermediate_steps: bool = False,
|
|
283
281
|
stream_executor_events: bool = True,
|
|
284
282
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
285
283
|
step_index: Optional[Union[int, tuple]] = None,
|
|
@@ -304,15 +302,6 @@ class Router:
|
|
|
304
302
|
steps_to_execute = self._route_steps(step_input, session_state=session_state)
|
|
305
303
|
log_debug(f"Router {self.name}: Selected {len(steps_to_execute)} steps to execute")
|
|
306
304
|
|
|
307
|
-
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
308
|
-
if stream_intermediate_steps is not None:
|
|
309
|
-
warnings.warn(
|
|
310
|
-
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
311
|
-
DeprecationWarning,
|
|
312
|
-
stacklevel=2,
|
|
313
|
-
)
|
|
314
|
-
stream_events = stream_events or stream_intermediate_steps
|
|
315
|
-
|
|
316
305
|
if stream_events and workflow_run_response:
|
|
317
306
|
# Yield router started event
|
|
318
307
|
yield RouterExecutionStartedEvent(
|
|
@@ -558,7 +547,6 @@ class Router:
|
|
|
558
547
|
run_context: Optional[RunContext] = None,
|
|
559
548
|
session_state: Optional[Dict[str, Any]] = None,
|
|
560
549
|
stream_events: bool = False,
|
|
561
|
-
stream_intermediate_steps: bool = False,
|
|
562
550
|
stream_executor_events: bool = True,
|
|
563
551
|
workflow_run_response: Optional[WorkflowRunOutput] = None,
|
|
564
552
|
step_index: Optional[Union[int, tuple]] = None,
|
|
@@ -583,15 +571,6 @@ class Router:
|
|
|
583
571
|
steps_to_execute = await self._aroute_steps(step_input, session_state=session_state)
|
|
584
572
|
log_debug(f"Router {self.name} selected: {len(steps_to_execute)} steps to execute")
|
|
585
573
|
|
|
586
|
-
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
587
|
-
if stream_intermediate_steps is not None:
|
|
588
|
-
warnings.warn(
|
|
589
|
-
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
590
|
-
DeprecationWarning,
|
|
591
|
-
stacklevel=2,
|
|
592
|
-
)
|
|
593
|
-
stream_events = stream_events or stream_intermediate_steps
|
|
594
|
-
|
|
595
574
|
if stream_events and workflow_run_response:
|
|
596
575
|
# Yield router started event
|
|
597
576
|
yield RouterExecutionStartedEvent(
|
agno/workflow/step.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import inspect
|
|
2
|
-
import warnings
|
|
3
2
|
from copy import copy
|
|
4
3
|
from dataclasses import dataclass
|
|
5
4
|
from typing import Any, AsyncIterator, Awaitable, Callable, Dict, Iterator, List, Optional, Union, cast
|
|
@@ -9,9 +8,11 @@ from pydantic import BaseModel
|
|
|
9
8
|
from typing_extensions import TypeGuard
|
|
10
9
|
|
|
11
10
|
from agno.agent import Agent
|
|
11
|
+
from agno.db.base import BaseDb
|
|
12
12
|
from agno.media import Audio, Image, Video
|
|
13
13
|
from agno.models.message import Message
|
|
14
14
|
from agno.models.metrics import Metrics
|
|
15
|
+
from agno.registry import Registry
|
|
15
16
|
from agno.run import RunContext
|
|
16
17
|
from agno.run.agent import RunContentEvent, RunOutput
|
|
17
18
|
from agno.run.base import BaseRunOutputEvent
|
|
@@ -61,7 +62,6 @@ class Step:
|
|
|
61
62
|
|
|
62
63
|
# Step configuration
|
|
63
64
|
max_retries: int = 3
|
|
64
|
-
timeout_seconds: Optional[int] = None
|
|
65
65
|
|
|
66
66
|
skip_on_failure: bool = False
|
|
67
67
|
|
|
@@ -83,7 +83,6 @@ class Step:
|
|
|
83
83
|
step_id: Optional[str] = None,
|
|
84
84
|
description: Optional[str] = None,
|
|
85
85
|
max_retries: int = 3,
|
|
86
|
-
timeout_seconds: Optional[int] = None,
|
|
87
86
|
skip_on_failure: bool = False,
|
|
88
87
|
strict_input_validation: bool = False,
|
|
89
88
|
add_workflow_history: Optional[bool] = None,
|
|
@@ -104,7 +103,6 @@ class Step:
|
|
|
104
103
|
self.step_id = step_id
|
|
105
104
|
self.description = description
|
|
106
105
|
self.max_retries = max_retries
|
|
107
|
-
self.timeout_seconds = timeout_seconds
|
|
108
106
|
self.skip_on_failure = skip_on_failure
|
|
109
107
|
self.strict_input_validation = strict_input_validation
|
|
110
108
|
self.add_workflow_history = add_workflow_history
|
|
@@ -117,6 +115,121 @@ class Step:
|
|
|
117
115
|
# Set the active executor
|
|
118
116
|
self._set_active_executor()
|
|
119
117
|
|
|
118
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
119
|
+
"""Convert step to a dictionary representation."""
|
|
120
|
+
result = {
|
|
121
|
+
"name": self.name,
|
|
122
|
+
"step_id": self.step_id,
|
|
123
|
+
"description": self.description,
|
|
124
|
+
"max_retries": self.max_retries,
|
|
125
|
+
"skip_on_failure": self.skip_on_failure,
|
|
126
|
+
"strict_input_validation": self.strict_input_validation,
|
|
127
|
+
"add_workflow_history": self.add_workflow_history,
|
|
128
|
+
"num_history_runs": self.num_history_runs,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if self.agent is not None:
|
|
132
|
+
result["agent_id"] = self.agent.id
|
|
133
|
+
if self.team is not None:
|
|
134
|
+
result["team_id"] = self.team.id
|
|
135
|
+
# TODO: Add support for custom executors
|
|
136
|
+
|
|
137
|
+
return result
|
|
138
|
+
|
|
139
|
+
@classmethod
|
|
140
|
+
def from_dict(
|
|
141
|
+
cls,
|
|
142
|
+
data: Dict[str, Any],
|
|
143
|
+
registry: Optional[Registry] = None,
|
|
144
|
+
db: Optional["BaseDb"] = None,
|
|
145
|
+
links: Optional[List[Dict[str, Any]]] = None,
|
|
146
|
+
) -> "Step":
|
|
147
|
+
"""
|
|
148
|
+
Create a Step from a dictionary.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
data: Dictionary containing step configuration
|
|
152
|
+
registry: Optional registry for rehydrating non-serializable objects
|
|
153
|
+
db: Optional database for loading agents/teams in steps
|
|
154
|
+
links: Optional links for this step version
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
Step: Reconstructed step instance
|
|
158
|
+
"""
|
|
159
|
+
config = data.copy()
|
|
160
|
+
|
|
161
|
+
agent = None
|
|
162
|
+
team = None
|
|
163
|
+
executor = None
|
|
164
|
+
|
|
165
|
+
# --- Handle Agent reconstruction ---
|
|
166
|
+
if "agent_id" in config and config["agent_id"]:
|
|
167
|
+
from agno.agent.agent import get_agent_by_id
|
|
168
|
+
|
|
169
|
+
agent_id = config.get("agent_id")
|
|
170
|
+
if db is not None and agent_id is not None:
|
|
171
|
+
agent = get_agent_by_id(db=db, id=agent_id, registry=registry)
|
|
172
|
+
|
|
173
|
+
# --- Handle Team reconstruction ---
|
|
174
|
+
# if "team_id" in config and config["team_id"] and registry:
|
|
175
|
+
# from agno.team.team import get_team_by_id
|
|
176
|
+
# team = get_team_by_id(db=db, id=config["team_id"])
|
|
177
|
+
|
|
178
|
+
# --- Handle Executor reconstruction ---
|
|
179
|
+
# TODO: Implement executor reconstruction
|
|
180
|
+
# if "executor_ref" in config and config["executor_ref"] and registry:
|
|
181
|
+
# executor = registry.rehydrate_function(config["executor_ref"])
|
|
182
|
+
|
|
183
|
+
return cls(
|
|
184
|
+
name=config.get("name"),
|
|
185
|
+
step_id=config.get("step_id"),
|
|
186
|
+
description=config.get("description"),
|
|
187
|
+
max_retries=config.get("max_retries", 3),
|
|
188
|
+
skip_on_failure=config.get("skip_on_failure", False),
|
|
189
|
+
strict_input_validation=config.get("strict_input_validation", False),
|
|
190
|
+
add_workflow_history=config.get("add_workflow_history"),
|
|
191
|
+
num_history_runs=config.get("num_history_runs", 3),
|
|
192
|
+
agent=agent,
|
|
193
|
+
team=team,
|
|
194
|
+
executor=executor,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
def get_links(self, position: int = 0) -> List[Dict[str, Any]]:
|
|
198
|
+
"""Get links for this step's agent/team.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
position: Position of this step in the workflow.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
List of link dictionaries for the links table.
|
|
205
|
+
"""
|
|
206
|
+
links = []
|
|
207
|
+
link_key = self.step_id or self.name
|
|
208
|
+
|
|
209
|
+
if self.agent is not None:
|
|
210
|
+
links.append(
|
|
211
|
+
{
|
|
212
|
+
"link_kind": "step_agent",
|
|
213
|
+
"link_key": link_key,
|
|
214
|
+
"child_component_id": self.agent.id,
|
|
215
|
+
"child_version": None,
|
|
216
|
+
"position": position,
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
if self.team is not None:
|
|
221
|
+
links.append(
|
|
222
|
+
{
|
|
223
|
+
"link_kind": "step_team",
|
|
224
|
+
"link_key": link_key,
|
|
225
|
+
"child_component_id": self.team.id,
|
|
226
|
+
"child_version": None,
|
|
227
|
+
"position": position,
|
|
228
|
+
}
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
return links
|
|
232
|
+
|
|
120
233
|
@property
|
|
121
234
|
def executor_name(self) -> str:
|
|
122
235
|
"""Get the name of the current executor"""
|
|
@@ -464,7 +577,6 @@ class Step:
|
|
|
464
577
|
session_id: Optional[str] = None,
|
|
465
578
|
user_id: Optional[str] = None,
|
|
466
579
|
stream_events: bool = False,
|
|
467
|
-
stream_intermediate_steps: bool = False,
|
|
468
580
|
stream_executor_events: bool = True,
|
|
469
581
|
workflow_run_response: Optional["WorkflowRunOutput"] = None,
|
|
470
582
|
run_context: Optional[RunContext] = None,
|
|
@@ -492,15 +604,6 @@ class Step:
|
|
|
492
604
|
else:
|
|
493
605
|
session_state_copy = copy(session_state) if session_state is not None else {}
|
|
494
606
|
|
|
495
|
-
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
496
|
-
if stream_intermediate_steps is not None:
|
|
497
|
-
warnings.warn(
|
|
498
|
-
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
499
|
-
DeprecationWarning,
|
|
500
|
-
stacklevel=2,
|
|
501
|
-
)
|
|
502
|
-
stream_events = stream_events or stream_intermediate_steps
|
|
503
|
-
|
|
504
607
|
# Emit StepStartedEvent
|
|
505
608
|
if stream_events and workflow_run_response:
|
|
506
609
|
yield StepStartedEvent(
|
|
@@ -949,7 +1052,6 @@ class Step:
|
|
|
949
1052
|
session_id: Optional[str] = None,
|
|
950
1053
|
user_id: Optional[str] = None,
|
|
951
1054
|
stream_events: bool = False,
|
|
952
|
-
stream_intermediate_steps: bool = False,
|
|
953
1055
|
stream_executor_events: bool = True,
|
|
954
1056
|
workflow_run_response: Optional["WorkflowRunOutput"] = None,
|
|
955
1057
|
run_context: Optional[RunContext] = None,
|
|
@@ -977,15 +1079,6 @@ class Step:
|
|
|
977
1079
|
else:
|
|
978
1080
|
session_state_copy = copy(session_state) if session_state is not None else {}
|
|
979
1081
|
|
|
980
|
-
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
981
|
-
if stream_intermediate_steps is not None:
|
|
982
|
-
warnings.warn(
|
|
983
|
-
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
984
|
-
DeprecationWarning,
|
|
985
|
-
stacklevel=2,
|
|
986
|
-
)
|
|
987
|
-
stream_events = stream_events or stream_intermediate_steps
|
|
988
|
-
|
|
989
1082
|
if stream_events and workflow_run_response:
|
|
990
1083
|
# Emit StepStartedEvent
|
|
991
1084
|
yield StepStartedEvent(
|