agno 2.2.5__py3-none-any.whl → 2.2.7__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 (57) hide show
  1. agno/agent/agent.py +500 -423
  2. agno/api/os.py +1 -1
  3. agno/culture/manager.py +12 -8
  4. agno/guardrails/prompt_injection.py +1 -0
  5. agno/knowledge/chunking/agentic.py +6 -2
  6. agno/knowledge/embedder/vllm.py +262 -0
  7. agno/knowledge/knowledge.py +37 -5
  8. agno/memory/manager.py +9 -4
  9. agno/models/anthropic/claude.py +1 -2
  10. agno/models/azure/ai_foundry.py +31 -14
  11. agno/models/azure/openai_chat.py +12 -4
  12. agno/models/base.py +106 -65
  13. agno/models/cerebras/cerebras.py +11 -6
  14. agno/models/groq/groq.py +7 -4
  15. agno/models/meta/llama.py +12 -6
  16. agno/models/meta/llama_openai.py +5 -1
  17. agno/models/openai/chat.py +26 -17
  18. agno/models/openai/responses.py +11 -63
  19. agno/models/requesty/requesty.py +5 -2
  20. agno/models/utils.py +254 -8
  21. agno/models/vertexai/claude.py +9 -13
  22. agno/os/app.py +13 -12
  23. agno/os/routers/evals/evals.py +8 -8
  24. agno/os/routers/evals/utils.py +1 -0
  25. agno/os/schema.py +56 -38
  26. agno/os/utils.py +27 -0
  27. agno/run/__init__.py +6 -0
  28. agno/run/agent.py +5 -0
  29. agno/run/base.py +18 -1
  30. agno/run/team.py +13 -9
  31. agno/run/workflow.py +39 -0
  32. agno/session/summary.py +8 -2
  33. agno/session/workflow.py +4 -3
  34. agno/team/team.py +302 -369
  35. agno/tools/exa.py +21 -16
  36. agno/tools/file.py +153 -25
  37. agno/tools/function.py +98 -17
  38. agno/tools/mcp/mcp.py +8 -1
  39. agno/tools/notion.py +204 -0
  40. agno/utils/agent.py +78 -0
  41. agno/utils/events.py +2 -0
  42. agno/utils/hooks.py +1 -1
  43. agno/utils/models/claude.py +25 -8
  44. agno/utils/print_response/workflow.py +115 -16
  45. agno/vectordb/__init__.py +2 -1
  46. agno/vectordb/milvus/milvus.py +5 -0
  47. agno/vectordb/redis/__init__.py +5 -0
  48. agno/vectordb/redis/redisdb.py +687 -0
  49. agno/workflow/__init__.py +2 -0
  50. agno/workflow/agent.py +299 -0
  51. agno/workflow/step.py +13 -2
  52. agno/workflow/workflow.py +969 -72
  53. {agno-2.2.5.dist-info → agno-2.2.7.dist-info}/METADATA +10 -3
  54. {agno-2.2.5.dist-info → agno-2.2.7.dist-info}/RECORD +57 -52
  55. {agno-2.2.5.dist-info → agno-2.2.7.dist-info}/WHEEL +0 -0
  56. {agno-2.2.5.dist-info → agno-2.2.7.dist-info}/licenses/LICENSE +0 -0
  57. {agno-2.2.5.dist-info → agno-2.2.7.dist-info}/top_level.txt +0 -0
agno/os/schema.py CHANGED
@@ -13,14 +13,18 @@ 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
  )
22
+ from agno.run import RunContext
20
23
  from agno.run.agent import RunOutput
21
24
  from agno.run.team import TeamRunOutput
22
25
  from agno.session import AgentSession, TeamSession, WorkflowSession
23
26
  from agno.team.team import Team
27
+ from agno.workflow.agent import WorkflowAgent
24
28
  from agno.workflow.workflow import Workflow
25
29
 
26
30
 
@@ -166,21 +170,22 @@ class ModelResponse(BaseModel):
166
170
 
167
171
 
168
172
  class AgentResponse(BaseModel):
169
- id: Optional[str] = Field(None, description="Unique identifier for the agent")
170
- name: Optional[str] = Field(None, description="Name of the agent")
171
- db_id: Optional[str] = Field(None, description="Database identifier")
172
- model: Optional[ModelResponse] = Field(None, description="Model configuration")
173
- tools: Optional[Dict[str, Any]] = Field(None, description="Tool configurations")
174
- sessions: Optional[Dict[str, Any]] = Field(None, description="Session configurations")
175
- knowledge: Optional[Dict[str, Any]] = Field(None, description="Knowledge base configurations")
176
- memory: Optional[Dict[str, Any]] = Field(None, description="Memory configurations")
177
- reasoning: Optional[Dict[str, Any]] = Field(None, description="Reasoning configurations")
178
- default_tools: Optional[Dict[str, Any]] = Field(None, description="Default tool settings")
179
- system_message: Optional[Dict[str, Any]] = Field(None, description="System message configurations")
180
- extra_messages: Optional[Dict[str, Any]] = Field(None, description="Extra message configurations")
181
- response_settings: Optional[Dict[str, Any]] = Field(None, description="Response settings")
182
- streaming: Optional[Dict[str, Any]] = Field(None, description="Streaming configurations")
183
- metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata")
173
+ id: Optional[str] = None
174
+ name: Optional[str] = None
175
+ db_id: Optional[str] = None
176
+ model: Optional[ModelResponse] = None
177
+ tools: Optional[Dict[str, Any]] = None
178
+ sessions: Optional[Dict[str, Any]] = None
179
+ knowledge: Optional[Dict[str, Any]] = None
180
+ memory: Optional[Dict[str, Any]] = None
181
+ reasoning: Optional[Dict[str, Any]] = None
182
+ default_tools: Optional[Dict[str, Any]] = None
183
+ system_message: Optional[Dict[str, Any]] = None
184
+ extra_messages: Optional[Dict[str, Any]] = None
185
+ response_settings: Optional[Dict[str, Any]] = None
186
+ streaming: Optional[Dict[str, Any]] = None
187
+ metadata: Optional[Dict[str, Any]] = None
188
+ input_schema: Optional[Dict[str, Any]] = None
184
189
 
185
190
  @classmethod
186
191
  async def from_agent(cls, agent: Agent) -> "AgentResponse":
@@ -243,9 +248,12 @@ class AgentResponse(BaseModel):
243
248
  "stream_intermediate_steps": False,
244
249
  }
245
250
 
251
+ session_id = str(uuid4())
252
+ run_id = str(uuid4())
246
253
  agent_tools = await agent.aget_tools(
247
- session=AgentSession(session_id=str(uuid4()), session_data={}),
248
- run_response=RunOutput(run_id=str(uuid4())),
254
+ session=AgentSession(session_id=session_id, session_data={}),
255
+ run_response=RunOutput(run_id=run_id, session_id=session_id),
256
+ run_context=RunContext(run_id=run_id, session_id=session_id, user_id=agent.user_id),
249
257
  check_mcp_tools=False,
250
258
  )
251
259
  formatted_tools = format_tools(agent_tools) if agent_tools else None
@@ -375,6 +383,7 @@ class AgentResponse(BaseModel):
375
383
  "stream_events": agent.stream_events,
376
384
  "stream_intermediate_steps": agent.stream_intermediate_steps,
377
385
  }
386
+
378
387
  return AgentResponse(
379
388
  id=agent.id,
380
389
  name=agent.name,
@@ -391,28 +400,28 @@ class AgentResponse(BaseModel):
391
400
  response_settings=filter_meaningful_config(response_settings_info, agent_defaults),
392
401
  streaming=filter_meaningful_config(streaming_info, agent_defaults),
393
402
  metadata=agent.metadata,
403
+ input_schema=get_agent_input_schema_dict(agent),
394
404
  )
395
405
 
396
406
 
397
407
  class TeamResponse(BaseModel):
398
- id: Optional[str] = Field(None, description="Unique identifier for the team")
399
- name: Optional[str] = Field(None, description="Name of the team")
400
- db_id: Optional[str] = Field(None, description="Database identifier")
401
- description: Optional[str] = Field(None, description="Description of the team")
402
- model: Optional[ModelResponse] = Field(None, description="Model configuration")
403
- tools: Optional[Dict[str, Any]] = Field(None, description="Tool configurations")
404
- sessions: Optional[Dict[str, Any]] = Field(None, description="Session configurations")
405
- knowledge: Optional[Dict[str, Any]] = Field(None, description="Knowledge base configurations")
406
- memory: Optional[Dict[str, Any]] = Field(None, description="Memory configurations")
407
- reasoning: Optional[Dict[str, Any]] = Field(None, description="Reasoning configurations")
408
- default_tools: Optional[Dict[str, Any]] = Field(None, description="Default tool settings")
409
- system_message: Optional[Dict[str, Any]] = Field(None, description="System message configurations")
410
- response_settings: Optional[Dict[str, Any]] = Field(None, description="Response settings")
411
- streaming: Optional[Dict[str, Any]] = Field(None, description="Streaming configurations")
412
- members: Optional[List[Union[AgentResponse, "TeamResponse"]]] = Field(
413
- None, description="List of team members (agents or teams)"
414
- )
415
- metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata")
408
+ id: Optional[str] = None
409
+ name: Optional[str] = None
410
+ db_id: Optional[str] = None
411
+ description: Optional[str] = None
412
+ model: Optional[ModelResponse] = None
413
+ tools: Optional[Dict[str, Any]] = None
414
+ sessions: Optional[Dict[str, Any]] = None
415
+ knowledge: Optional[Dict[str, Any]] = None
416
+ memory: Optional[Dict[str, Any]] = None
417
+ reasoning: Optional[Dict[str, Any]] = None
418
+ default_tools: Optional[Dict[str, Any]] = None
419
+ system_message: Optional[Dict[str, Any]] = None
420
+ response_settings: Optional[Dict[str, Any]] = None
421
+ streaming: Optional[Dict[str, Any]] = None
422
+ members: Optional[List[Union[AgentResponse, "TeamResponse"]]] = None
423
+ metadata: Optional[Dict[str, Any]] = None
424
+ input_schema: Optional[Dict[str, Any]] = None
416
425
 
417
426
  @classmethod
418
427
  async def from_team(cls, team: Team) -> "TeamResponse":
@@ -466,12 +475,14 @@ class TeamResponse(BaseModel):
466
475
  "stream_member_events": False,
467
476
  }
468
477
 
478
+ run_id = str(uuid4())
479
+ session_id = str(uuid4())
469
480
  _tools = team._determine_tools_for_model(
470
481
  model=team.model, # type: ignore
471
- session=TeamSession(session_id=str(uuid4()), session_data={}),
472
- run_response=TeamRunOutput(run_id=str(uuid4())),
482
+ session=TeamSession(session_id=session_id, session_data={}),
483
+ run_response=TeamRunOutput(run_id=run_id),
484
+ run_context=RunContext(run_id=run_id, session_id=session_id, session_state={}),
473
485
  async_mode=True,
474
- session_state={},
475
486
  team_run_context={},
476
487
  check_mcp_tools=False,
477
488
  )
@@ -621,6 +632,7 @@ class TeamResponse(BaseModel):
621
632
  streaming=filter_meaningful_config(streaming_info, team_defaults),
622
633
  members=members if members else None,
623
634
  metadata=team.metadata,
635
+ input_schema=get_team_input_schema_dict(team),
624
636
  )
625
637
 
626
638
 
@@ -634,6 +646,7 @@ class WorkflowResponse(BaseModel):
634
646
  agent: Optional[AgentResponse] = Field(None, description="Agent configuration if used")
635
647
  team: Optional[TeamResponse] = Field(None, description="Team configuration if used")
636
648
  metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata")
649
+ workflow_agent: bool = Field(False, description="Whether this workflow uses a WorkflowAgent")
637
650
 
638
651
  @classmethod
639
652
  async def _resolve_agents_and_teams_recursively(cls, steps: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
@@ -685,6 +698,7 @@ class WorkflowResponse(BaseModel):
685
698
  steps=steps,
686
699
  input_schema=get_workflow_input_schema_dict(workflow),
687
700
  metadata=workflow.metadata,
701
+ workflow_agent=isinstance(workflow.agent, WorkflowAgent) if workflow.agent else False,
688
702
  )
689
703
 
690
704
 
@@ -870,6 +884,7 @@ class RunSchema(BaseModel):
870
884
  created_at: Optional[datetime] = Field(None, description="Run creation timestamp")
871
885
  references: Optional[List[dict]] = Field(None, description="References cited in the run")
872
886
  reasoning_messages: Optional[List[dict]] = Field(None, description="Reasoning process messages")
887
+ session_state: Optional[dict] = Field(None, description="Session state at the end of the run")
873
888
  images: Optional[List[dict]] = Field(None, description="Images included in the run")
874
889
  videos: Optional[List[dict]] = Field(None, description="Videos included in the run")
875
890
  audio: Optional[List[dict]] = Field(None, description="Audio files included in the run")
@@ -897,6 +912,7 @@ class RunSchema(BaseModel):
897
912
  events=[event for event in run_dict["events"]] if run_dict.get("events") else None,
898
913
  references=run_dict.get("references", []),
899
914
  reasoning_messages=run_dict.get("reasoning_messages", []),
915
+ session_state=run_dict.get("session_state"),
900
916
  images=run_dict.get("images", []),
901
917
  videos=run_dict.get("videos", []),
902
918
  audio=run_dict.get("audio", []),
@@ -925,6 +941,7 @@ class TeamRunSchema(BaseModel):
925
941
  created_at: Optional[datetime] = Field(None, description="Run creation timestamp")
926
942
  references: Optional[List[dict]] = Field(None, description="References cited in the run")
927
943
  reasoning_messages: Optional[List[dict]] = Field(None, description="Reasoning process messages")
944
+ session_state: Optional[dict] = Field(None, description="Session state at the end of the run")
928
945
  input_media: Optional[Dict[str, Any]] = Field(None, description="Input media attachments")
929
946
  images: Optional[List[dict]] = Field(None, description="Images included in the run")
930
947
  videos: Optional[List[dict]] = Field(None, description="Videos included in the run")
@@ -954,6 +971,7 @@ class TeamRunSchema(BaseModel):
954
971
  else None,
955
972
  references=run_dict.get("references", []),
956
973
  reasoning_messages=run_dict.get("reasoning_messages", []),
974
+ session_state=run_dict.get("session_state"),
957
975
  images=run_dict.get("images", []),
958
976
  videos=run_dict.get("videos", []),
959
977
  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/__init__.py CHANGED
@@ -0,0 +1,6 @@
1
+ from agno.run.base import RunContext, RunStatus
2
+
3
+ __all__ = [
4
+ "RunContext",
5
+ "RunStatus",
6
+ ]
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/base.py CHANGED
@@ -7,11 +7,22 @@ from pydantic import BaseModel
7
7
  from agno.media import Audio, Image, Video
8
8
  from agno.models.message import Citations, Message, MessageReferences
9
9
  from agno.models.metrics import Metrics
10
- from agno.models.response import ToolExecution
11
10
  from agno.reasoning.step import ReasoningStep
12
11
  from agno.utils.log import log_error
13
12
 
14
13
 
14
+ @dataclass
15
+ class RunContext:
16
+ run_id: str
17
+ session_id: str
18
+ user_id: Optional[str] = None
19
+
20
+ dependencies: Optional[Dict[str, Any]] = None
21
+ knowledge_filters: Optional[Dict[str, Any]] = None
22
+ metadata: Optional[Dict[str, Any]] = None
23
+ session_state: Optional[Dict[str, Any]] = None
24
+
25
+
15
26
  @dataclass
16
27
  class BaseRunOutputEvent:
17
28
  def to_dict(self) -> Dict[str, Any]:
@@ -98,6 +109,8 @@ class BaseRunOutputEvent:
98
109
  _dict["content"] = self.content.model_dump(exclude_none=True)
99
110
 
100
111
  if hasattr(self, "tools") and self.tools is not None:
112
+ from agno.models.response import ToolExecution
113
+
101
114
  _dict["tools"] = []
102
115
  for tool in self.tools:
103
116
  if isinstance(tool, ToolExecution):
@@ -106,6 +119,8 @@ class BaseRunOutputEvent:
106
119
  _dict["tools"].append(tool)
107
120
 
108
121
  if hasattr(self, "tool") and self.tool is not None:
122
+ from agno.models.response import ToolExecution
123
+
109
124
  if isinstance(self.tool, ToolExecution):
110
125
  _dict["tool"] = self.tool.to_dict()
111
126
  else:
@@ -139,6 +154,8 @@ class BaseRunOutputEvent:
139
154
  def from_dict(cls, data: Dict[str, Any]):
140
155
  tool = data.pop("tool", None)
141
156
  if tool:
157
+ from agno.models.response import ToolExecution
158
+
142
159
  data["tool"] = ToolExecution.from_dict(tool)
143
160
 
144
161
  images = data.pop("images", None)
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
@@ -468,8 +469,19 @@ def team_run_output_event_from_dict(data: dict) -> BaseTeamRunEvent:
468
469
  class TeamRunOutput:
469
470
  """Response returned by Team.run() functions"""
470
471
 
472
+ run_id: Optional[str] = None
473
+ team_id: Optional[str] = None
474
+ team_name: Optional[str] = None
475
+ session_id: Optional[str] = None
476
+ parent_run_id: Optional[str] = None
477
+ user_id: Optional[str] = None
478
+
479
+ # Input media and messages from user
480
+ input: Optional[TeamRunInput] = None
481
+
471
482
  content: Optional[Any] = None
472
483
  content_type: str = "str"
484
+
473
485
  messages: Optional[List[Message]] = None
474
486
  metrics: Optional[Metrics] = None
475
487
  model: Optional[str] = None
@@ -477,12 +489,6 @@ class TeamRunOutput:
477
489
 
478
490
  member_responses: List[Union["TeamRunOutput", RunOutput]] = field(default_factory=list)
479
491
 
480
- run_id: Optional[str] = None
481
- team_id: Optional[str] = None
482
- team_name: Optional[str] = None
483
- session_id: Optional[str] = None
484
- parent_run_id: Optional[str] = None
485
-
486
492
  tools: Optional[List[ToolExecution]] = None
487
493
 
488
494
  images: Optional[List[Image]] = None # Images from member runs
@@ -492,14 +498,12 @@ class TeamRunOutput:
492
498
 
493
499
  response_audio: Optional[Audio] = None # Model audio response
494
500
 
495
- # Input media and messages from user
496
- input: Optional[TeamRunInput] = None
497
-
498
501
  reasoning_content: Optional[str] = None
499
502
 
500
503
  citations: Optional[Citations] = None
501
504
  model_provider_data: Optional[Dict[str, Any]] = None
502
505
  metadata: Optional[Dict[str, Any]] = None
506
+ session_state: Optional[Dict[str, Any]] = None
503
507
 
504
508
  references: Optional[List[MessageReferences]] = None
505
509
  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, cast
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 = cast(Model, 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"[run-{i}]")
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"response: {response_str}")
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,