agno 2.2.5__py3-none-any.whl → 2.2.6__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/agent.py +82 -19
- agno/culture/manager.py +3 -4
- agno/knowledge/chunking/agentic.py +6 -2
- agno/memory/manager.py +9 -4
- agno/models/anthropic/claude.py +1 -2
- agno/models/azure/ai_foundry.py +31 -14
- agno/models/azure/openai_chat.py +12 -4
- agno/models/base.py +44 -11
- agno/models/cerebras/cerebras.py +11 -6
- agno/models/groq/groq.py +7 -4
- agno/models/meta/llama.py +12 -6
- agno/models/meta/llama_openai.py +5 -1
- agno/models/openai/chat.py +20 -12
- agno/models/openai/responses.py +10 -5
- agno/models/utils.py +254 -8
- agno/models/vertexai/claude.py +9 -13
- agno/os/routers/evals/evals.py +8 -8
- agno/os/routers/evals/utils.py +1 -0
- agno/os/schema.py +48 -33
- agno/os/utils.py +27 -0
- agno/run/agent.py +5 -0
- agno/run/team.py +2 -0
- agno/run/workflow.py +39 -0
- agno/session/summary.py +8 -2
- agno/session/workflow.py +4 -3
- agno/team/team.py +50 -14
- agno/tools/file.py +153 -25
- agno/tools/function.py +5 -1
- agno/tools/notion.py +201 -0
- agno/utils/events.py +2 -0
- agno/utils/print_response/workflow.py +115 -16
- agno/vectordb/milvus/milvus.py +5 -0
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +298 -0
- agno/workflow/workflow.py +929 -64
- {agno-2.2.5.dist-info → agno-2.2.6.dist-info}/METADATA +4 -1
- {agno-2.2.5.dist-info → agno-2.2.6.dist-info}/RECORD +40 -38
- {agno-2.2.5.dist-info → agno-2.2.6.dist-info}/WHEEL +0 -0
- {agno-2.2.5.dist-info → agno-2.2.6.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.5.dist-info → agno-2.2.6.dist-info}/top_level.txt +0 -0
agno/os/schema.py
CHANGED
|
@@ -13,14 +13,17 @@ from agno.os.utils import (
|
|
|
13
13
|
extract_input_media,
|
|
14
14
|
format_team_tools,
|
|
15
15
|
format_tools,
|
|
16
|
+
get_agent_input_schema_dict,
|
|
16
17
|
get_run_input,
|
|
17
18
|
get_session_name,
|
|
19
|
+
get_team_input_schema_dict,
|
|
18
20
|
get_workflow_input_schema_dict,
|
|
19
21
|
)
|
|
20
22
|
from agno.run.agent import RunOutput
|
|
21
23
|
from agno.run.team import TeamRunOutput
|
|
22
24
|
from agno.session import AgentSession, TeamSession, WorkflowSession
|
|
23
25
|
from agno.team.team import Team
|
|
26
|
+
from agno.workflow.agent import WorkflowAgent
|
|
24
27
|
from agno.workflow.workflow import Workflow
|
|
25
28
|
|
|
26
29
|
|
|
@@ -166,21 +169,25 @@ class ModelResponse(BaseModel):
|
|
|
166
169
|
|
|
167
170
|
|
|
168
171
|
class AgentResponse(BaseModel):
|
|
169
|
-
id: Optional[str] =
|
|
170
|
-
name: Optional[str] =
|
|
171
|
-
db_id: Optional[str] =
|
|
172
|
-
model: Optional[ModelResponse] =
|
|
173
|
-
tools: Optional[Dict[str, Any]] =
|
|
174
|
-
sessions: Optional[Dict[str, Any]] =
|
|
175
|
-
knowledge: Optional[Dict[str, Any]] =
|
|
176
|
-
memory: Optional[Dict[str, Any]] =
|
|
177
|
-
reasoning: Optional[Dict[str, Any]] =
|
|
178
|
-
default_tools: Optional[Dict[str, Any]] =
|
|
179
|
-
system_message: Optional[Dict[str, Any]] =
|
|
180
|
-
extra_messages: Optional[Dict[str, Any]] =
|
|
181
|
-
response_settings: Optional[Dict[str, Any]] =
|
|
182
|
-
streaming: Optional[Dict[str, Any]] =
|
|
183
|
-
metadata: Optional[Dict[str, Any]] =
|
|
172
|
+
id: Optional[str] = None
|
|
173
|
+
name: Optional[str] = None
|
|
174
|
+
db_id: Optional[str] = None
|
|
175
|
+
model: Optional[ModelResponse] = None
|
|
176
|
+
tools: Optional[Dict[str, Any]] = None
|
|
177
|
+
sessions: Optional[Dict[str, Any]] = None
|
|
178
|
+
knowledge: Optional[Dict[str, Any]] = None
|
|
179
|
+
memory: Optional[Dict[str, Any]] = None
|
|
180
|
+
reasoning: Optional[Dict[str, Any]] = None
|
|
181
|
+
default_tools: Optional[Dict[str, Any]] = None
|
|
182
|
+
system_message: Optional[Dict[str, Any]] = None
|
|
183
|
+
extra_messages: Optional[Dict[str, Any]] = None
|
|
184
|
+
response_settings: Optional[Dict[str, Any]] = None
|
|
185
|
+
streaming: Optional[Dict[str, Any]] = None
|
|
186
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
187
|
+
input_schema: Optional[Dict[str, Any]] = None
|
|
188
|
+
|
|
189
|
+
class Config:
|
|
190
|
+
exclude_none = True
|
|
184
191
|
|
|
185
192
|
@classmethod
|
|
186
193
|
async def from_agent(cls, agent: Agent) -> "AgentResponse":
|
|
@@ -375,6 +382,7 @@ class AgentResponse(BaseModel):
|
|
|
375
382
|
"stream_events": agent.stream_events,
|
|
376
383
|
"stream_intermediate_steps": agent.stream_intermediate_steps,
|
|
377
384
|
}
|
|
385
|
+
|
|
378
386
|
return AgentResponse(
|
|
379
387
|
id=agent.id,
|
|
380
388
|
name=agent.name,
|
|
@@ -391,28 +399,28 @@ class AgentResponse(BaseModel):
|
|
|
391
399
|
response_settings=filter_meaningful_config(response_settings_info, agent_defaults),
|
|
392
400
|
streaming=filter_meaningful_config(streaming_info, agent_defaults),
|
|
393
401
|
metadata=agent.metadata,
|
|
402
|
+
input_schema=get_agent_input_schema_dict(agent),
|
|
394
403
|
)
|
|
395
404
|
|
|
396
405
|
|
|
397
406
|
class TeamResponse(BaseModel):
|
|
398
|
-
id: Optional[str] =
|
|
399
|
-
name: Optional[str] =
|
|
400
|
-
db_id: Optional[str] =
|
|
401
|
-
description: Optional[str] =
|
|
402
|
-
model: Optional[ModelResponse] =
|
|
403
|
-
tools: Optional[Dict[str, Any]] =
|
|
404
|
-
sessions: Optional[Dict[str, Any]] =
|
|
405
|
-
knowledge: Optional[Dict[str, Any]] =
|
|
406
|
-
memory: Optional[Dict[str, Any]] =
|
|
407
|
-
reasoning: Optional[Dict[str, Any]] =
|
|
408
|
-
default_tools: Optional[Dict[str, Any]] =
|
|
409
|
-
system_message: Optional[Dict[str, Any]] =
|
|
410
|
-
response_settings: Optional[Dict[str, Any]] =
|
|
411
|
-
streaming: Optional[Dict[str, Any]] =
|
|
412
|
-
members: Optional[List[Union[AgentResponse, "TeamResponse"]]] =
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata")
|
|
407
|
+
id: Optional[str] = None
|
|
408
|
+
name: Optional[str] = None
|
|
409
|
+
db_id: Optional[str] = None
|
|
410
|
+
description: Optional[str] = None
|
|
411
|
+
model: Optional[ModelResponse] = None
|
|
412
|
+
tools: Optional[Dict[str, Any]] = None
|
|
413
|
+
sessions: Optional[Dict[str, Any]] = None
|
|
414
|
+
knowledge: Optional[Dict[str, Any]] = None
|
|
415
|
+
memory: Optional[Dict[str, Any]] = None
|
|
416
|
+
reasoning: Optional[Dict[str, Any]] = None
|
|
417
|
+
default_tools: Optional[Dict[str, Any]] = None
|
|
418
|
+
system_message: Optional[Dict[str, Any]] = None
|
|
419
|
+
response_settings: Optional[Dict[str, Any]] = None
|
|
420
|
+
streaming: Optional[Dict[str, Any]] = None
|
|
421
|
+
members: Optional[List[Union[AgentResponse, "TeamResponse"]]] = None
|
|
422
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
423
|
+
input_schema: Optional[Dict[str, Any]] = None
|
|
416
424
|
|
|
417
425
|
@classmethod
|
|
418
426
|
async def from_team(cls, team: Team) -> "TeamResponse":
|
|
@@ -621,6 +629,7 @@ class TeamResponse(BaseModel):
|
|
|
621
629
|
streaming=filter_meaningful_config(streaming_info, team_defaults),
|
|
622
630
|
members=members if members else None,
|
|
623
631
|
metadata=team.metadata,
|
|
632
|
+
input_schema=get_team_input_schema_dict(team),
|
|
624
633
|
)
|
|
625
634
|
|
|
626
635
|
|
|
@@ -634,6 +643,7 @@ class WorkflowResponse(BaseModel):
|
|
|
634
643
|
agent: Optional[AgentResponse] = Field(None, description="Agent configuration if used")
|
|
635
644
|
team: Optional[TeamResponse] = Field(None, description="Team configuration if used")
|
|
636
645
|
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata")
|
|
646
|
+
workflow_agent: bool = Field(False, description="Whether this workflow uses a WorkflowAgent")
|
|
637
647
|
|
|
638
648
|
@classmethod
|
|
639
649
|
async def _resolve_agents_and_teams_recursively(cls, steps: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
@@ -685,6 +695,7 @@ class WorkflowResponse(BaseModel):
|
|
|
685
695
|
steps=steps,
|
|
686
696
|
input_schema=get_workflow_input_schema_dict(workflow),
|
|
687
697
|
metadata=workflow.metadata,
|
|
698
|
+
workflow_agent=isinstance(workflow.agent, WorkflowAgent) if workflow.agent else False,
|
|
688
699
|
)
|
|
689
700
|
|
|
690
701
|
|
|
@@ -870,6 +881,7 @@ class RunSchema(BaseModel):
|
|
|
870
881
|
created_at: Optional[datetime] = Field(None, description="Run creation timestamp")
|
|
871
882
|
references: Optional[List[dict]] = Field(None, description="References cited in the run")
|
|
872
883
|
reasoning_messages: Optional[List[dict]] = Field(None, description="Reasoning process messages")
|
|
884
|
+
session_state: Optional[dict] = Field(None, description="Session state at the end of the run")
|
|
873
885
|
images: Optional[List[dict]] = Field(None, description="Images included in the run")
|
|
874
886
|
videos: Optional[List[dict]] = Field(None, description="Videos included in the run")
|
|
875
887
|
audio: Optional[List[dict]] = Field(None, description="Audio files included in the run")
|
|
@@ -897,6 +909,7 @@ class RunSchema(BaseModel):
|
|
|
897
909
|
events=[event for event in run_dict["events"]] if run_dict.get("events") else None,
|
|
898
910
|
references=run_dict.get("references", []),
|
|
899
911
|
reasoning_messages=run_dict.get("reasoning_messages", []),
|
|
912
|
+
session_state=run_dict.get("session_state"),
|
|
900
913
|
images=run_dict.get("images", []),
|
|
901
914
|
videos=run_dict.get("videos", []),
|
|
902
915
|
audio=run_dict.get("audio", []),
|
|
@@ -925,6 +938,7 @@ class TeamRunSchema(BaseModel):
|
|
|
925
938
|
created_at: Optional[datetime] = Field(None, description="Run creation timestamp")
|
|
926
939
|
references: Optional[List[dict]] = Field(None, description="References cited in the run")
|
|
927
940
|
reasoning_messages: Optional[List[dict]] = Field(None, description="Reasoning process messages")
|
|
941
|
+
session_state: Optional[dict] = Field(None, description="Session state at the end of the run")
|
|
928
942
|
input_media: Optional[Dict[str, Any]] = Field(None, description="Input media attachments")
|
|
929
943
|
images: Optional[List[dict]] = Field(None, description="Images included in the run")
|
|
930
944
|
videos: Optional[List[dict]] = Field(None, description="Videos included in the run")
|
|
@@ -954,6 +968,7 @@ class TeamRunSchema(BaseModel):
|
|
|
954
968
|
else None,
|
|
955
969
|
references=run_dict.get("references", []),
|
|
956
970
|
reasoning_messages=run_dict.get("reasoning_messages", []),
|
|
971
|
+
session_state=run_dict.get("session_state"),
|
|
957
972
|
images=run_dict.get("images", []),
|
|
958
973
|
videos=run_dict.get("videos", []),
|
|
959
974
|
audio=run_dict.get("audio", []),
|
agno/os/utils.py
CHANGED
|
@@ -274,6 +274,33 @@ def get_workflow_by_id(workflow_id: str, workflows: Optional[List[Workflow]] = N
|
|
|
274
274
|
return None
|
|
275
275
|
|
|
276
276
|
|
|
277
|
+
# INPUT SCHEMA VALIDATIONS
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def get_agent_input_schema_dict(agent: Agent) -> Optional[Dict[str, Any]]:
|
|
281
|
+
"""Get input schema as dictionary for API responses"""
|
|
282
|
+
|
|
283
|
+
if agent.input_schema is not None:
|
|
284
|
+
try:
|
|
285
|
+
return agent.input_schema.model_json_schema()
|
|
286
|
+
except Exception:
|
|
287
|
+
return None
|
|
288
|
+
|
|
289
|
+
return None
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def get_team_input_schema_dict(team: Team) -> Optional[Dict[str, Any]]:
|
|
293
|
+
"""Get input schema as dictionary for API responses"""
|
|
294
|
+
|
|
295
|
+
if team.input_schema is not None:
|
|
296
|
+
try:
|
|
297
|
+
return team.input_schema.model_json_schema()
|
|
298
|
+
except Exception:
|
|
299
|
+
return None
|
|
300
|
+
|
|
301
|
+
return None
|
|
302
|
+
|
|
303
|
+
|
|
277
304
|
def get_workflow_input_schema_dict(workflow: Workflow) -> Optional[Dict[str, Any]]:
|
|
278
305
|
"""Get input schema as dictionary for API responses"""
|
|
279
306
|
|
agno/run/agent.py
CHANGED
|
@@ -221,6 +221,9 @@ class RunContentEvent(BaseAgentRunEvent):
|
|
|
221
221
|
|
|
222
222
|
event: str = RunEvent.run_content.value
|
|
223
223
|
content: Optional[Any] = None
|
|
224
|
+
workflow_agent: bool = (
|
|
225
|
+
False # Used by consumers of the events to distinguish between workflow agent and regular agent
|
|
226
|
+
)
|
|
224
227
|
content_type: str = "str"
|
|
225
228
|
reasoning_content: Optional[str] = None
|
|
226
229
|
model_provider_data: Optional[Dict[str, Any]] = None
|
|
@@ -263,6 +266,7 @@ class RunCompletedEvent(BaseAgentRunEvent):
|
|
|
263
266
|
reasoning_messages: Optional[List[Message]] = None
|
|
264
267
|
metadata: Optional[Dict[str, Any]] = None
|
|
265
268
|
metrics: Optional[Metrics] = None
|
|
269
|
+
session_state: Optional[Dict[str, Any]] = None
|
|
266
270
|
|
|
267
271
|
|
|
268
272
|
@dataclass
|
|
@@ -527,6 +531,7 @@ class RunOutput:
|
|
|
527
531
|
references: Optional[List[MessageReferences]] = None
|
|
528
532
|
|
|
529
533
|
metadata: Optional[Dict[str, Any]] = None
|
|
534
|
+
session_state: Optional[Dict[str, Any]] = None
|
|
530
535
|
|
|
531
536
|
created_at: int = field(default_factory=lambda: int(time()))
|
|
532
537
|
|
agno/run/team.py
CHANGED
|
@@ -261,6 +261,7 @@ class RunCompletedEvent(BaseTeamRunEvent):
|
|
|
261
261
|
member_responses: List[Union["TeamRunOutput", RunOutput]] = field(default_factory=list)
|
|
262
262
|
metadata: Optional[Dict[str, Any]] = None
|
|
263
263
|
metrics: Optional[Metrics] = None
|
|
264
|
+
session_state: Optional[Dict[str, Any]] = None
|
|
264
265
|
|
|
265
266
|
|
|
266
267
|
@dataclass
|
|
@@ -500,6 +501,7 @@ class TeamRunOutput:
|
|
|
500
501
|
citations: Optional[Citations] = None
|
|
501
502
|
model_provider_data: Optional[Dict[str, Any]] = None
|
|
502
503
|
metadata: Optional[Dict[str, Any]] = None
|
|
504
|
+
session_state: Optional[Dict[str, Any]] = None
|
|
503
505
|
|
|
504
506
|
references: Optional[List[MessageReferences]] = None
|
|
505
507
|
additional_input: Optional[List[Message]] = None
|
agno/run/workflow.py
CHANGED
|
@@ -31,6 +31,9 @@ class WorkflowRunEvent(str, Enum):
|
|
|
31
31
|
workflow_cancelled = "WorkflowCancelled"
|
|
32
32
|
workflow_error = "WorkflowError"
|
|
33
33
|
|
|
34
|
+
workflow_agent_started = "WorkflowAgentStarted"
|
|
35
|
+
workflow_agent_completed = "WorkflowAgentCompleted"
|
|
36
|
+
|
|
34
37
|
step_started = "StepStarted"
|
|
35
38
|
step_completed = "StepCompleted"
|
|
36
39
|
step_error = "StepError"
|
|
@@ -126,6 +129,21 @@ class WorkflowStartedEvent(BaseWorkflowRunOutputEvent):
|
|
|
126
129
|
event: str = WorkflowRunEvent.workflow_started.value
|
|
127
130
|
|
|
128
131
|
|
|
132
|
+
@dataclass
|
|
133
|
+
class WorkflowAgentStartedEvent(BaseWorkflowRunOutputEvent):
|
|
134
|
+
"""Event sent when workflow agent starts (before deciding to run workflow or answer directly)"""
|
|
135
|
+
|
|
136
|
+
event: str = WorkflowRunEvent.workflow_agent_started.value
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@dataclass
|
|
140
|
+
class WorkflowAgentCompletedEvent(BaseWorkflowRunOutputEvent):
|
|
141
|
+
"""Event sent when workflow agent completes (after running workflow or answering directly)"""
|
|
142
|
+
|
|
143
|
+
event: str = WorkflowRunEvent.workflow_agent_completed.value
|
|
144
|
+
content: Optional[Any] = None
|
|
145
|
+
|
|
146
|
+
|
|
129
147
|
@dataclass
|
|
130
148
|
class WorkflowCompletedEvent(BaseWorkflowRunOutputEvent):
|
|
131
149
|
"""Event sent when workflow execution completes"""
|
|
@@ -403,6 +421,8 @@ class CustomEvent(BaseWorkflowRunOutputEvent):
|
|
|
403
421
|
# Union type for all workflow run response events
|
|
404
422
|
WorkflowRunOutputEvent = Union[
|
|
405
423
|
WorkflowStartedEvent,
|
|
424
|
+
WorkflowAgentStartedEvent,
|
|
425
|
+
WorkflowAgentCompletedEvent,
|
|
406
426
|
WorkflowCompletedEvent,
|
|
407
427
|
WorkflowErrorEvent,
|
|
408
428
|
WorkflowCancelledEvent,
|
|
@@ -428,6 +448,8 @@ WorkflowRunOutputEvent = Union[
|
|
|
428
448
|
# Map event string to dataclass for workflow events
|
|
429
449
|
WORKFLOW_RUN_EVENT_TYPE_REGISTRY = {
|
|
430
450
|
WorkflowRunEvent.workflow_started.value: WorkflowStartedEvent,
|
|
451
|
+
WorkflowRunEvent.workflow_agent_started.value: WorkflowAgentStartedEvent,
|
|
452
|
+
WorkflowRunEvent.workflow_agent_completed.value: WorkflowAgentCompletedEvent,
|
|
431
453
|
WorkflowRunEvent.workflow_completed.value: WorkflowCompletedEvent,
|
|
432
454
|
WorkflowRunEvent.workflow_cancelled.value: WorkflowCancelledEvent,
|
|
433
455
|
WorkflowRunEvent.workflow_error.value: WorkflowErrorEvent,
|
|
@@ -491,6 +513,10 @@ class WorkflowRunOutput:
|
|
|
491
513
|
# Store agent/team responses separately with parent_run_id references
|
|
492
514
|
step_executor_runs: Optional[List[Union[RunOutput, TeamRunOutput]]] = None
|
|
493
515
|
|
|
516
|
+
# Workflow agent run - stores the full agent RunOutput when workflow agent is used
|
|
517
|
+
# The agent's parent_run_id will point to this workflow run's run_id to establish the relationship
|
|
518
|
+
workflow_agent_run: Optional[RunOutput] = None
|
|
519
|
+
|
|
494
520
|
# Store events from workflow execution
|
|
495
521
|
events: Optional[List[WorkflowRunOutputEvent]] = None
|
|
496
522
|
|
|
@@ -522,6 +548,7 @@ class WorkflowRunOutput:
|
|
|
522
548
|
"step_executor_runs",
|
|
523
549
|
"events",
|
|
524
550
|
"metrics",
|
|
551
|
+
"workflow_agent_run",
|
|
525
552
|
]
|
|
526
553
|
}
|
|
527
554
|
|
|
@@ -557,6 +584,9 @@ class WorkflowRunOutput:
|
|
|
557
584
|
if self.step_executor_runs:
|
|
558
585
|
_dict["step_executor_runs"] = [run.to_dict() for run in self.step_executor_runs]
|
|
559
586
|
|
|
587
|
+
if self.workflow_agent_run is not None:
|
|
588
|
+
_dict["workflow_agent_run"] = self.workflow_agent_run.to_dict()
|
|
589
|
+
|
|
560
590
|
if self.metrics is not None:
|
|
561
591
|
_dict["metrics"] = self.metrics.to_dict()
|
|
562
592
|
|
|
@@ -604,6 +634,14 @@ class WorkflowRunOutput:
|
|
|
604
634
|
else:
|
|
605
635
|
step_executor_runs.append(RunOutput.from_dict(run_data))
|
|
606
636
|
|
|
637
|
+
workflow_agent_run_data = data.pop("workflow_agent_run", None)
|
|
638
|
+
workflow_agent_run = None
|
|
639
|
+
if workflow_agent_run_data:
|
|
640
|
+
if isinstance(workflow_agent_run_data, dict):
|
|
641
|
+
workflow_agent_run = RunOutput.from_dict(workflow_agent_run_data)
|
|
642
|
+
elif isinstance(workflow_agent_run_data, RunOutput):
|
|
643
|
+
workflow_agent_run = workflow_agent_run_data
|
|
644
|
+
|
|
607
645
|
metadata = data.pop("metadata", None)
|
|
608
646
|
|
|
609
647
|
images = reconstruct_images(data.pop("images", []))
|
|
@@ -640,6 +678,7 @@ class WorkflowRunOutput:
|
|
|
640
678
|
|
|
641
679
|
return cls(
|
|
642
680
|
step_results=parsed_step_results,
|
|
681
|
+
workflow_agent_run=workflow_agent_run,
|
|
643
682
|
metadata=metadata,
|
|
644
683
|
images=images,
|
|
645
684
|
videos=videos,
|
agno/session/summary.py
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from datetime import datetime
|
|
3
3
|
from textwrap import dedent
|
|
4
|
-
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel, Field
|
|
7
7
|
|
|
8
8
|
from agno.models.base import Model
|
|
9
|
+
from agno.models.utils import get_model
|
|
9
10
|
from agno.run.agent import Message
|
|
10
11
|
from agno.utils.log import log_debug, log_warning
|
|
11
12
|
|
|
@@ -142,7 +143,10 @@ class SessionSummaryManager:
|
|
|
142
143
|
if not session:
|
|
143
144
|
return None
|
|
144
145
|
|
|
145
|
-
self.model =
|
|
146
|
+
self.model = get_model(self.model)
|
|
147
|
+
if self.model is None:
|
|
148
|
+
return None
|
|
149
|
+
|
|
146
150
|
response_format = self.get_response_format(self.model)
|
|
147
151
|
|
|
148
152
|
system_message = self.get_system_message(
|
|
@@ -210,6 +214,7 @@ class SessionSummaryManager:
|
|
|
210
214
|
) -> Optional[SessionSummary]:
|
|
211
215
|
"""Creates a summary of the session"""
|
|
212
216
|
log_debug("Creating session summary", center=True)
|
|
217
|
+
self.model = get_model(self.model)
|
|
213
218
|
if self.model is None:
|
|
214
219
|
return None
|
|
215
220
|
|
|
@@ -237,6 +242,7 @@ class SessionSummaryManager:
|
|
|
237
242
|
) -> Optional[SessionSummary]:
|
|
238
243
|
"""Creates a summary of the session"""
|
|
239
244
|
log_debug("Creating session summary", center=True)
|
|
245
|
+
self.model = get_model(self.model)
|
|
240
246
|
if self.model is None:
|
|
241
247
|
return None
|
|
242
248
|
|
agno/session/workflow.py
CHANGED
|
@@ -129,12 +129,12 @@ class WorkflowSession:
|
|
|
129
129
|
context_parts = ["<workflow_history_context>"]
|
|
130
130
|
|
|
131
131
|
for i, (input_str, response_str) in enumerate(history_data, 1):
|
|
132
|
-
context_parts.append(f"[
|
|
132
|
+
context_parts.append(f"[Workflow Run-{i}]")
|
|
133
133
|
|
|
134
134
|
if input_str:
|
|
135
|
-
context_parts.append(f"input: {input_str}")
|
|
135
|
+
context_parts.append(f"User input: {input_str}")
|
|
136
136
|
if response_str:
|
|
137
|
-
context_parts.append(f"
|
|
137
|
+
context_parts.append(f"Workflow output: {response_str}")
|
|
138
138
|
|
|
139
139
|
context_parts.append("") # Empty line between runs
|
|
140
140
|
|
|
@@ -154,6 +154,7 @@ class WorkflowSession:
|
|
|
154
154
|
runs_data.append(run.to_dict())
|
|
155
155
|
except Exception as e:
|
|
156
156
|
raise ValueError(f"Serialization failed: {str(e)}")
|
|
157
|
+
|
|
157
158
|
return {
|
|
158
159
|
"session_id": self.session_id,
|
|
159
160
|
"user_id": self.user_id,
|
agno/team/team.py
CHANGED
|
@@ -45,6 +45,7 @@ from agno.models.base import Model
|
|
|
45
45
|
from agno.models.message import Message, MessageReferences
|
|
46
46
|
from agno.models.metrics import Metrics
|
|
47
47
|
from agno.models.response import ModelResponse, ModelResponseEvent
|
|
48
|
+
from agno.models.utils import get_model
|
|
48
49
|
from agno.reasoning.step import NextAction, ReasoningStep, ReasoningSteps
|
|
49
50
|
from agno.run.agent import RunEvent, RunOutput, RunOutputEvent
|
|
50
51
|
from agno.run.base import RunStatus
|
|
@@ -437,7 +438,7 @@ class Team:
|
|
|
437
438
|
self,
|
|
438
439
|
members: List[Union[Agent, "Team"]],
|
|
439
440
|
id: Optional[str] = None,
|
|
440
|
-
model: Optional[Model] = None,
|
|
441
|
+
model: Optional[Union[Model, str]] = None,
|
|
441
442
|
name: Optional[str] = None,
|
|
442
443
|
role: Optional[str] = None,
|
|
443
444
|
respond_directly: bool = False,
|
|
@@ -498,9 +499,9 @@ class Team:
|
|
|
498
499
|
post_hooks: Optional[Union[List[Callable[..., Any]], List[BaseGuardrail]]] = None,
|
|
499
500
|
input_schema: Optional[Type[BaseModel]] = None,
|
|
500
501
|
output_schema: Optional[Type[BaseModel]] = None,
|
|
501
|
-
parser_model: Optional[Model] = None,
|
|
502
|
+
parser_model: Optional[Union[Model, str]] = None,
|
|
502
503
|
parser_model_prompt: Optional[str] = None,
|
|
503
|
-
output_model: Optional[Model] = None,
|
|
504
|
+
output_model: Optional[Union[Model, str]] = None,
|
|
504
505
|
output_model_prompt: Optional[str] = None,
|
|
505
506
|
use_json_mode: bool = False,
|
|
506
507
|
parse_response: bool = True,
|
|
@@ -514,7 +515,7 @@ class Team:
|
|
|
514
515
|
add_session_summary_to_context: Optional[bool] = None,
|
|
515
516
|
metadata: Optional[Dict[str, Any]] = None,
|
|
516
517
|
reasoning: bool = False,
|
|
517
|
-
reasoning_model: Optional[Model] = None,
|
|
518
|
+
reasoning_model: Optional[Union[Model, str]] = None,
|
|
518
519
|
reasoning_agent: Optional[Agent] = None,
|
|
519
520
|
reasoning_min_steps: int = 1,
|
|
520
521
|
reasoning_max_steps: int = 10,
|
|
@@ -535,7 +536,7 @@ class Team:
|
|
|
535
536
|
):
|
|
536
537
|
self.members = members
|
|
537
538
|
|
|
538
|
-
self.model = model
|
|
539
|
+
self.model = model # type: ignore[assignment]
|
|
539
540
|
|
|
540
541
|
self.name = name
|
|
541
542
|
self.id = id
|
|
@@ -618,9 +619,9 @@ class Team:
|
|
|
618
619
|
|
|
619
620
|
self.input_schema = input_schema
|
|
620
621
|
self.output_schema = output_schema
|
|
621
|
-
self.parser_model = parser_model
|
|
622
|
+
self.parser_model = parser_model # type: ignore[assignment]
|
|
622
623
|
self.parser_model_prompt = parser_model_prompt
|
|
623
|
-
self.output_model = output_model
|
|
624
|
+
self.output_model = output_model # type: ignore[assignment]
|
|
624
625
|
self.output_model_prompt = output_model_prompt
|
|
625
626
|
self.use_json_mode = use_json_mode
|
|
626
627
|
self.parse_response = parse_response
|
|
@@ -637,7 +638,7 @@ class Team:
|
|
|
637
638
|
self.metadata = metadata
|
|
638
639
|
|
|
639
640
|
self.reasoning = reasoning
|
|
640
|
-
self.reasoning_model = reasoning_model
|
|
641
|
+
self.reasoning_model = reasoning_model # type: ignore[assignment]
|
|
641
642
|
self.reasoning_agent = reasoning_agent
|
|
642
643
|
self.reasoning_min_steps = reasoning_min_steps
|
|
643
644
|
self.reasoning_max_steps = reasoning_max_steps
|
|
@@ -694,6 +695,8 @@ class Team:
|
|
|
694
695
|
# Lazy-initialized shared thread pool executor for background tasks (memory, cultural knowledge, etc.)
|
|
695
696
|
self._background_executor: Optional[Any] = None
|
|
696
697
|
|
|
698
|
+
self._resolve_models()
|
|
699
|
+
|
|
697
700
|
@property
|
|
698
701
|
def background_executor(self) -> Any:
|
|
699
702
|
"""Lazy initialization of shared thread pool executor for background tasks.
|
|
@@ -902,6 +905,17 @@ class Team:
|
|
|
902
905
|
"""Return True if the db the team is equipped with is an Async implementation"""
|
|
903
906
|
return self.db is not None and isinstance(self.db, AsyncBaseDb)
|
|
904
907
|
|
|
908
|
+
def _resolve_models(self) -> None:
|
|
909
|
+
"""Resolve model strings to Model instances."""
|
|
910
|
+
if self.model is not None:
|
|
911
|
+
self.model = get_model(self.model)
|
|
912
|
+
if self.reasoning_model is not None:
|
|
913
|
+
self.reasoning_model = get_model(self.reasoning_model)
|
|
914
|
+
if self.parser_model is not None:
|
|
915
|
+
self.parser_model = get_model(self.parser_model)
|
|
916
|
+
if self.output_model is not None:
|
|
917
|
+
self.output_model = get_model(self.output_model)
|
|
918
|
+
|
|
905
919
|
def initialize_team(self, debug_mode: Optional[bool] = None) -> None:
|
|
906
920
|
# Make sure for the team, we are using the team logger
|
|
907
921
|
use_team_logger()
|
|
@@ -1593,6 +1607,7 @@ class Team:
|
|
|
1593
1607
|
tools=_tools,
|
|
1594
1608
|
response_format=response_format,
|
|
1595
1609
|
stream_events=stream_events,
|
|
1610
|
+
session_state=session_state,
|
|
1596
1611
|
):
|
|
1597
1612
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1598
1613
|
yield event
|
|
@@ -1604,6 +1619,7 @@ class Team:
|
|
|
1604
1619
|
tools=_tools,
|
|
1605
1620
|
response_format=response_format,
|
|
1606
1621
|
stream_events=stream_events,
|
|
1622
|
+
session_state=session_state,
|
|
1607
1623
|
):
|
|
1608
1624
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1609
1625
|
from agno.run.team import IntermediateRunContentEvent, RunContentEvent
|
|
@@ -1932,6 +1948,7 @@ class Team:
|
|
|
1932
1948
|
team_id=self.id,
|
|
1933
1949
|
team_name=self.name,
|
|
1934
1950
|
metadata=metadata,
|
|
1951
|
+
session_state=session_state,
|
|
1935
1952
|
input=run_input,
|
|
1936
1953
|
)
|
|
1937
1954
|
|
|
@@ -2439,6 +2456,7 @@ class Team:
|
|
|
2439
2456
|
tools=_tools,
|
|
2440
2457
|
response_format=response_format,
|
|
2441
2458
|
stream_events=stream_events,
|
|
2459
|
+
session_state=session_state,
|
|
2442
2460
|
):
|
|
2443
2461
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2444
2462
|
yield event
|
|
@@ -2450,6 +2468,7 @@ class Team:
|
|
|
2450
2468
|
tools=_tools,
|
|
2451
2469
|
response_format=response_format,
|
|
2452
2470
|
stream_events=stream_events,
|
|
2471
|
+
session_state=session_state,
|
|
2453
2472
|
):
|
|
2454
2473
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2455
2474
|
from agno.run.team import IntermediateRunContentEvent, RunContentEvent
|
|
@@ -2771,6 +2790,7 @@ class Team:
|
|
|
2771
2790
|
team_id=self.id,
|
|
2772
2791
|
team_name=self.name,
|
|
2773
2792
|
metadata=metadata,
|
|
2793
|
+
session_state=session_state,
|
|
2774
2794
|
input=run_input,
|
|
2775
2795
|
)
|
|
2776
2796
|
|
|
@@ -2930,6 +2950,12 @@ class Team:
|
|
|
2930
2950
|
if model_response.audio is not None:
|
|
2931
2951
|
run_response.response_audio = model_response.audio
|
|
2932
2952
|
|
|
2953
|
+
# Update session_state with changes from model response
|
|
2954
|
+
if model_response.updated_session_state is not None and run_response.session_state is not None:
|
|
2955
|
+
from agno.utils.merge_dict import merge_dictionaries
|
|
2956
|
+
|
|
2957
|
+
merge_dictionaries(run_response.session_state, model_response.updated_session_state)
|
|
2958
|
+
|
|
2933
2959
|
# Build a list of messages that should be added to the RunOutput
|
|
2934
2960
|
messages_for_run_response = [m for m in run_messages.messages if m.add_to_agent_memory]
|
|
2935
2961
|
|
|
@@ -2954,6 +2980,7 @@ class Team:
|
|
|
2954
2980
|
tools: Optional[List[Union[Function, dict]]] = None,
|
|
2955
2981
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
2956
2982
|
stream_events: bool = False,
|
|
2983
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
2957
2984
|
) -> Iterator[Union[TeamRunOutputEvent, RunOutputEvent]]:
|
|
2958
2985
|
self.model = cast(Model, self.model)
|
|
2959
2986
|
|
|
@@ -2985,6 +3012,7 @@ class Team:
|
|
|
2985
3012
|
reasoning_state=reasoning_state,
|
|
2986
3013
|
stream_events=stream_events,
|
|
2987
3014
|
parse_structured_output=self.should_parse_structured_output,
|
|
3015
|
+
session_state=session_state,
|
|
2988
3016
|
)
|
|
2989
3017
|
|
|
2990
3018
|
# 3. Update TeamRunOutput
|
|
@@ -3036,6 +3064,7 @@ class Team:
|
|
|
3036
3064
|
tools: Optional[List[Union[Function, dict]]] = None,
|
|
3037
3065
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
3038
3066
|
stream_events: bool = False,
|
|
3067
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
3039
3068
|
) -> AsyncIterator[Union[TeamRunOutputEvent, RunOutputEvent]]:
|
|
3040
3069
|
self.model = cast(Model, self.model)
|
|
3041
3070
|
|
|
@@ -3068,6 +3097,7 @@ class Team:
|
|
|
3068
3097
|
reasoning_state=reasoning_state,
|
|
3069
3098
|
stream_events=stream_events,
|
|
3070
3099
|
parse_structured_output=self.should_parse_structured_output,
|
|
3100
|
+
session_state=session_state,
|
|
3071
3101
|
):
|
|
3072
3102
|
yield event
|
|
3073
3103
|
|
|
@@ -3122,6 +3152,7 @@ class Team:
|
|
|
3122
3152
|
reasoning_state: Optional[Dict[str, Any]] = None,
|
|
3123
3153
|
stream_events: bool = False,
|
|
3124
3154
|
parse_structured_output: bool = False,
|
|
3155
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
3125
3156
|
) -> Iterator[Union[TeamRunOutputEvent, RunOutputEvent]]:
|
|
3126
3157
|
if isinstance(model_response_event, tuple(get_args(RunOutputEvent))) or isinstance(
|
|
3127
3158
|
model_response_event, tuple(get_args(TeamRunOutputEvent))
|
|
@@ -3299,10 +3330,15 @@ class Team:
|
|
|
3299
3330
|
|
|
3300
3331
|
# If the model response is a tool_call_completed, update the existing tool call in the run_response
|
|
3301
3332
|
elif model_response_event.event == ModelResponseEvent.tool_call_completed.value:
|
|
3302
|
-
if model_response_event.updated_session_state is not None
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3333
|
+
if model_response_event.updated_session_state is not None:
|
|
3334
|
+
# Update the session_state variable that TeamRunOutput references
|
|
3335
|
+
if session_state is not None:
|
|
3336
|
+
merge_dictionaries(session_state, model_response_event.updated_session_state)
|
|
3337
|
+
# Also update the DB session object
|
|
3338
|
+
if session.session_data is not None:
|
|
3339
|
+
merge_dictionaries(
|
|
3340
|
+
session.session_data["session_state"], model_response_event.updated_session_state
|
|
3341
|
+
)
|
|
3306
3342
|
|
|
3307
3343
|
if model_response_event.images is not None:
|
|
3308
3344
|
for image in model_response_event.images:
|
|
@@ -4498,7 +4534,7 @@ class Team:
|
|
|
4498
4534
|
store_events=self.store_events,
|
|
4499
4535
|
)
|
|
4500
4536
|
else:
|
|
4501
|
-
|
|
4537
|
+
log_info(
|
|
4502
4538
|
f"Reasoning model: {reasoning_model.__class__.__name__} is not a native reasoning model, defaulting to manual Chain-of-Thought reasoning"
|
|
4503
4539
|
)
|
|
4504
4540
|
use_default_reasoning = True
|
|
@@ -4779,7 +4815,7 @@ class Team:
|
|
|
4779
4815
|
store_events=self.store_events,
|
|
4780
4816
|
)
|
|
4781
4817
|
else:
|
|
4782
|
-
|
|
4818
|
+
log_info(
|
|
4783
4819
|
f"Reasoning model: {reasoning_model.__class__.__name__} is not a native reasoning model, defaulting to manual Chain-of-Thought reasoning"
|
|
4784
4820
|
)
|
|
4785
4821
|
use_default_reasoning = True
|