agno 2.1.10__py3-none-any.whl → 2.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/agent/agent.py +1578 -1247
- agno/models/anthropic/claude.py +2 -2
- agno/models/ollama/chat.py +7 -2
- agno/os/app.py +1 -1
- agno/os/interfaces/a2a/router.py +2 -2
- agno/os/interfaces/agui/router.py +2 -2
- agno/os/router.py +7 -7
- agno/os/routers/evals/schemas.py +31 -31
- agno/os/routers/health.py +6 -2
- agno/os/routers/knowledge/schemas.py +49 -47
- agno/os/routers/memory/schemas.py +16 -16
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +382 -7
- agno/os/schema.py +254 -231
- agno/os/utils.py +1 -1
- agno/run/agent.py +49 -1
- agno/run/team.py +43 -0
- agno/session/summary.py +45 -13
- agno/session/team.py +90 -5
- agno/team/team.py +1117 -856
- agno/utils/agent.py +372 -0
- agno/utils/events.py +144 -2
- agno/utils/print_response/agent.py +10 -6
- agno/utils/print_response/team.py +6 -4
- agno/utils/print_response/workflow.py +7 -5
- agno/utils/team.py +9 -8
- agno/workflow/condition.py +17 -9
- agno/workflow/loop.py +18 -10
- agno/workflow/parallel.py +14 -6
- agno/workflow/router.py +16 -8
- agno/workflow/step.py +14 -6
- agno/workflow/steps.py +14 -6
- agno/workflow/workflow.py +245 -122
- {agno-2.1.10.dist-info → agno-2.2.0.dist-info}/METADATA +60 -23
- {agno-2.1.10.dist-info → agno-2.2.0.dist-info}/RECORD +38 -37
- {agno-2.1.10.dist-info → agno-2.2.0.dist-info}/WHEEL +0 -0
- {agno-2.1.10.dist-info → agno-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {agno-2.1.10.dist-info → agno-2.2.0.dist-info}/top_level.txt +0 -0
agno/os/utils.py
CHANGED
|
@@ -158,7 +158,7 @@ def extract_input_media(run_dict: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
158
158
|
"files": [],
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
input = run_dict.get("input",
|
|
161
|
+
input = run_dict.get("input", {})
|
|
162
162
|
input_media["images"].extend(input.get("images", []))
|
|
163
163
|
input_media["videos"].extend(input.get("videos", []))
|
|
164
164
|
input_media["audios"].extend(input.get("audios", []))
|
agno/run/agent.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from dataclasses import asdict, dataclass, field
|
|
2
2
|
from enum import Enum
|
|
3
3
|
from time import time
|
|
4
|
-
from typing import Any, Dict, List, Optional, Sequence, Union
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Union
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
|
|
@@ -13,6 +13,9 @@ from agno.reasoning.step import ReasoningStep
|
|
|
13
13
|
from agno.run.base import BaseRunOutputEvent, MessageReferences, RunStatus
|
|
14
14
|
from agno.utils.log import logger
|
|
15
15
|
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from agno.session.summary import SessionSummary
|
|
18
|
+
|
|
16
19
|
|
|
17
20
|
@dataclass
|
|
18
21
|
class RunInput:
|
|
@@ -109,6 +112,7 @@ class RunEvent(str, Enum):
|
|
|
109
112
|
|
|
110
113
|
run_started = "RunStarted"
|
|
111
114
|
run_content = "RunContent"
|
|
115
|
+
run_content_completed = "RunContentCompleted"
|
|
112
116
|
run_intermediate_content = "RunIntermediateContent"
|
|
113
117
|
run_completed = "RunCompleted"
|
|
114
118
|
run_error = "RunError"
|
|
@@ -120,6 +124,9 @@ class RunEvent(str, Enum):
|
|
|
120
124
|
pre_hook_started = "PreHookStarted"
|
|
121
125
|
pre_hook_completed = "PreHookCompleted"
|
|
122
126
|
|
|
127
|
+
post_hook_started = "PostHookStarted"
|
|
128
|
+
post_hook_completed = "PostHookCompleted"
|
|
129
|
+
|
|
123
130
|
tool_call_started = "ToolCallStarted"
|
|
124
131
|
tool_call_completed = "ToolCallCompleted"
|
|
125
132
|
|
|
@@ -130,6 +137,9 @@ class RunEvent(str, Enum):
|
|
|
130
137
|
memory_update_started = "MemoryUpdateStarted"
|
|
131
138
|
memory_update_completed = "MemoryUpdateCompleted"
|
|
132
139
|
|
|
140
|
+
session_summary_started = "SessionSummaryStarted"
|
|
141
|
+
session_summary_completed = "SessionSummaryCompleted"
|
|
142
|
+
|
|
133
143
|
parser_model_response_started = "ParserModelResponseStarted"
|
|
134
144
|
parser_model_response_completed = "ParserModelResponseCompleted"
|
|
135
145
|
|
|
@@ -200,6 +210,11 @@ class RunContentEvent(BaseAgentRunEvent):
|
|
|
200
210
|
reasoning_messages: Optional[List[Message]] = None
|
|
201
211
|
|
|
202
212
|
|
|
213
|
+
@dataclass
|
|
214
|
+
class RunContentCompletedEvent(BaseAgentRunEvent):
|
|
215
|
+
event: str = RunEvent.run_content_completed.value
|
|
216
|
+
|
|
217
|
+
|
|
203
218
|
@dataclass
|
|
204
219
|
class IntermediateRunContentEvent(BaseAgentRunEvent):
|
|
205
220
|
event: str = RunEvent.run_intermediate_content.value
|
|
@@ -277,6 +292,18 @@ class PreHookCompletedEvent(BaseAgentRunEvent):
|
|
|
277
292
|
run_input: Optional[RunInput] = None
|
|
278
293
|
|
|
279
294
|
|
|
295
|
+
@dataclass
|
|
296
|
+
class PostHookStartedEvent(BaseAgentRunEvent):
|
|
297
|
+
event: str = RunEvent.post_hook_started.value
|
|
298
|
+
post_hook_name: Optional[str] = None
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
@dataclass
|
|
302
|
+
class PostHookCompletedEvent(BaseAgentRunEvent):
|
|
303
|
+
event: str = RunEvent.post_hook_completed.value
|
|
304
|
+
post_hook_name: Optional[str] = None
|
|
305
|
+
|
|
306
|
+
|
|
280
307
|
@dataclass
|
|
281
308
|
class MemoryUpdateStartedEvent(BaseAgentRunEvent):
|
|
282
309
|
event: str = RunEvent.memory_update_started.value
|
|
@@ -287,6 +314,17 @@ class MemoryUpdateCompletedEvent(BaseAgentRunEvent):
|
|
|
287
314
|
event: str = RunEvent.memory_update_completed.value
|
|
288
315
|
|
|
289
316
|
|
|
317
|
+
@dataclass
|
|
318
|
+
class SessionSummaryStartedEvent(BaseAgentRunEvent):
|
|
319
|
+
event: str = RunEvent.session_summary_started.value
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
@dataclass
|
|
323
|
+
class SessionSummaryCompletedEvent(BaseAgentRunEvent):
|
|
324
|
+
event: str = RunEvent.session_summary_completed.value
|
|
325
|
+
session_summary: Optional["SessionSummary"] = None
|
|
326
|
+
|
|
327
|
+
|
|
290
328
|
@dataclass
|
|
291
329
|
class ReasoningStartedEvent(BaseAgentRunEvent):
|
|
292
330
|
event: str = RunEvent.reasoning_started.value
|
|
@@ -352,6 +390,7 @@ RunOutputEvent = Union[
|
|
|
352
390
|
RunStartedEvent,
|
|
353
391
|
RunContentEvent,
|
|
354
392
|
IntermediateRunContentEvent,
|
|
393
|
+
RunContentCompletedEvent,
|
|
355
394
|
RunCompletedEvent,
|
|
356
395
|
RunErrorEvent,
|
|
357
396
|
RunCancelledEvent,
|
|
@@ -359,11 +398,15 @@ RunOutputEvent = Union[
|
|
|
359
398
|
RunContinuedEvent,
|
|
360
399
|
PreHookStartedEvent,
|
|
361
400
|
PreHookCompletedEvent,
|
|
401
|
+
PostHookStartedEvent,
|
|
402
|
+
PostHookCompletedEvent,
|
|
362
403
|
ReasoningStartedEvent,
|
|
363
404
|
ReasoningStepEvent,
|
|
364
405
|
ReasoningCompletedEvent,
|
|
365
406
|
MemoryUpdateStartedEvent,
|
|
366
407
|
MemoryUpdateCompletedEvent,
|
|
408
|
+
SessionSummaryStartedEvent,
|
|
409
|
+
SessionSummaryCompletedEvent,
|
|
367
410
|
ToolCallStartedEvent,
|
|
368
411
|
ToolCallCompletedEvent,
|
|
369
412
|
ParserModelResponseStartedEvent,
|
|
@@ -378,6 +421,7 @@ RunOutputEvent = Union[
|
|
|
378
421
|
RUN_EVENT_TYPE_REGISTRY = {
|
|
379
422
|
RunEvent.run_started.value: RunStartedEvent,
|
|
380
423
|
RunEvent.run_content.value: RunContentEvent,
|
|
424
|
+
RunEvent.run_content_completed.value: RunContentCompletedEvent,
|
|
381
425
|
RunEvent.run_intermediate_content.value: IntermediateRunContentEvent,
|
|
382
426
|
RunEvent.run_completed.value: RunCompletedEvent,
|
|
383
427
|
RunEvent.run_error.value: RunErrorEvent,
|
|
@@ -386,11 +430,15 @@ RUN_EVENT_TYPE_REGISTRY = {
|
|
|
386
430
|
RunEvent.run_continued.value: RunContinuedEvent,
|
|
387
431
|
RunEvent.pre_hook_started.value: PreHookStartedEvent,
|
|
388
432
|
RunEvent.pre_hook_completed.value: PreHookCompletedEvent,
|
|
433
|
+
RunEvent.post_hook_started.value: PostHookStartedEvent,
|
|
434
|
+
RunEvent.post_hook_completed.value: PostHookCompletedEvent,
|
|
389
435
|
RunEvent.reasoning_started.value: ReasoningStartedEvent,
|
|
390
436
|
RunEvent.reasoning_step.value: ReasoningStepEvent,
|
|
391
437
|
RunEvent.reasoning_completed.value: ReasoningCompletedEvent,
|
|
392
438
|
RunEvent.memory_update_started.value: MemoryUpdateStartedEvent,
|
|
393
439
|
RunEvent.memory_update_completed.value: MemoryUpdateCompletedEvent,
|
|
440
|
+
RunEvent.session_summary_started.value: SessionSummaryStartedEvent,
|
|
441
|
+
RunEvent.session_summary_completed.value: SessionSummaryCompletedEvent,
|
|
394
442
|
RunEvent.tool_call_started.value: ToolCallStartedEvent,
|
|
395
443
|
RunEvent.tool_call_completed.value: ToolCallCompletedEvent,
|
|
396
444
|
RunEvent.parser_model_response_started.value: ParserModelResponseStartedEvent,
|
agno/run/team.py
CHANGED
|
@@ -109,6 +109,7 @@ class TeamRunEvent(str, Enum):
|
|
|
109
109
|
run_started = "TeamRunStarted"
|
|
110
110
|
run_content = "TeamRunContent"
|
|
111
111
|
run_intermediate_content = "TeamRunIntermediateContent"
|
|
112
|
+
run_content_completed = "TeamRunContentCompleted"
|
|
112
113
|
run_completed = "TeamRunCompleted"
|
|
113
114
|
run_error = "TeamRunError"
|
|
114
115
|
run_cancelled = "TeamRunCancelled"
|
|
@@ -116,6 +117,9 @@ class TeamRunEvent(str, Enum):
|
|
|
116
117
|
pre_hook_started = "TeamPreHookStarted"
|
|
117
118
|
pre_hook_completed = "TeamPreHookCompleted"
|
|
118
119
|
|
|
120
|
+
post_hook_started = "TeamPostHookStarted"
|
|
121
|
+
post_hook_completed = "TeamPostHookCompleted"
|
|
122
|
+
|
|
119
123
|
tool_call_started = "TeamToolCallStarted"
|
|
120
124
|
tool_call_completed = "TeamToolCallCompleted"
|
|
121
125
|
|
|
@@ -126,6 +130,9 @@ class TeamRunEvent(str, Enum):
|
|
|
126
130
|
memory_update_started = "TeamMemoryUpdateStarted"
|
|
127
131
|
memory_update_completed = "TeamMemoryUpdateCompleted"
|
|
128
132
|
|
|
133
|
+
session_summary_started = "TeamSessionSummaryStarted"
|
|
134
|
+
session_summary_completed = "TeamSessionSummaryCompleted"
|
|
135
|
+
|
|
129
136
|
parser_model_response_started = "TeamParserModelResponseStarted"
|
|
130
137
|
parser_model_response_completed = "TeamParserModelResponseCompleted"
|
|
131
138
|
|
|
@@ -207,6 +214,11 @@ class IntermediateRunContentEvent(BaseTeamRunEvent):
|
|
|
207
214
|
content_type: str = "str"
|
|
208
215
|
|
|
209
216
|
|
|
217
|
+
@dataclass
|
|
218
|
+
class RunContentCompletedEvent(BaseTeamRunEvent):
|
|
219
|
+
event: str = TeamRunEvent.run_content_completed.value
|
|
220
|
+
|
|
221
|
+
|
|
210
222
|
@dataclass
|
|
211
223
|
class RunCompletedEvent(BaseTeamRunEvent):
|
|
212
224
|
event: str = TeamRunEvent.run_completed.value
|
|
@@ -263,6 +275,18 @@ class PreHookCompletedEvent(BaseTeamRunEvent):
|
|
|
263
275
|
run_input: Optional[TeamRunInput] = None
|
|
264
276
|
|
|
265
277
|
|
|
278
|
+
@dataclass
|
|
279
|
+
class PostHookStartedEvent(BaseTeamRunEvent):
|
|
280
|
+
event: str = TeamRunEvent.post_hook_started.value
|
|
281
|
+
post_hook_name: Optional[str] = None
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
@dataclass
|
|
285
|
+
class PostHookCompletedEvent(BaseTeamRunEvent):
|
|
286
|
+
event: str = TeamRunEvent.post_hook_completed.value
|
|
287
|
+
post_hook_name: Optional[str] = None
|
|
288
|
+
|
|
289
|
+
|
|
266
290
|
@dataclass
|
|
267
291
|
class MemoryUpdateStartedEvent(BaseTeamRunEvent):
|
|
268
292
|
event: str = TeamRunEvent.memory_update_started.value
|
|
@@ -273,6 +297,17 @@ class MemoryUpdateCompletedEvent(BaseTeamRunEvent):
|
|
|
273
297
|
event: str = TeamRunEvent.memory_update_completed.value
|
|
274
298
|
|
|
275
299
|
|
|
300
|
+
@dataclass
|
|
301
|
+
class SessionSummaryStartedEvent(BaseTeamRunEvent):
|
|
302
|
+
event: str = TeamRunEvent.session_summary_started.value
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@dataclass
|
|
306
|
+
class SessionSummaryCompletedEvent(BaseTeamRunEvent):
|
|
307
|
+
event: str = TeamRunEvent.session_summary_completed.value
|
|
308
|
+
session_summary: Optional[Any] = None
|
|
309
|
+
|
|
310
|
+
|
|
276
311
|
@dataclass
|
|
277
312
|
class ReasoningStartedEvent(BaseTeamRunEvent):
|
|
278
313
|
event: str = TeamRunEvent.reasoning_started.value
|
|
@@ -338,6 +373,7 @@ TeamRunOutputEvent = Union[
|
|
|
338
373
|
RunStartedEvent,
|
|
339
374
|
RunContentEvent,
|
|
340
375
|
IntermediateRunContentEvent,
|
|
376
|
+
RunContentCompletedEvent,
|
|
341
377
|
RunCompletedEvent,
|
|
342
378
|
RunErrorEvent,
|
|
343
379
|
RunCancelledEvent,
|
|
@@ -348,6 +384,8 @@ TeamRunOutputEvent = Union[
|
|
|
348
384
|
ReasoningCompletedEvent,
|
|
349
385
|
MemoryUpdateStartedEvent,
|
|
350
386
|
MemoryUpdateCompletedEvent,
|
|
387
|
+
SessionSummaryStartedEvent,
|
|
388
|
+
SessionSummaryCompletedEvent,
|
|
351
389
|
ToolCallStartedEvent,
|
|
352
390
|
ToolCallCompletedEvent,
|
|
353
391
|
ParserModelResponseStartedEvent,
|
|
@@ -362,16 +400,21 @@ TEAM_RUN_EVENT_TYPE_REGISTRY = {
|
|
|
362
400
|
TeamRunEvent.run_started.value: RunStartedEvent,
|
|
363
401
|
TeamRunEvent.run_content.value: RunContentEvent,
|
|
364
402
|
TeamRunEvent.run_intermediate_content.value: IntermediateRunContentEvent,
|
|
403
|
+
TeamRunEvent.run_content_completed.value: RunContentCompletedEvent,
|
|
365
404
|
TeamRunEvent.run_completed.value: RunCompletedEvent,
|
|
366
405
|
TeamRunEvent.run_error.value: RunErrorEvent,
|
|
367
406
|
TeamRunEvent.run_cancelled.value: RunCancelledEvent,
|
|
368
407
|
TeamRunEvent.pre_hook_started.value: PreHookStartedEvent,
|
|
369
408
|
TeamRunEvent.pre_hook_completed.value: PreHookCompletedEvent,
|
|
409
|
+
TeamRunEvent.post_hook_started.value: PostHookStartedEvent,
|
|
410
|
+
TeamRunEvent.post_hook_completed.value: PostHookCompletedEvent,
|
|
370
411
|
TeamRunEvent.reasoning_started.value: ReasoningStartedEvent,
|
|
371
412
|
TeamRunEvent.reasoning_step.value: ReasoningStepEvent,
|
|
372
413
|
TeamRunEvent.reasoning_completed.value: ReasoningCompletedEvent,
|
|
373
414
|
TeamRunEvent.memory_update_started.value: MemoryUpdateStartedEvent,
|
|
374
415
|
TeamRunEvent.memory_update_completed.value: MemoryUpdateCompletedEvent,
|
|
416
|
+
TeamRunEvent.session_summary_started.value: SessionSummaryStartedEvent,
|
|
417
|
+
TeamRunEvent.session_summary_completed.value: SessionSummaryCompletedEvent,
|
|
375
418
|
TeamRunEvent.tool_call_started.value: ToolCallStartedEvent,
|
|
376
419
|
TeamRunEvent.tool_call_completed.value: ToolCallCompletedEvent,
|
|
377
420
|
TeamRunEvent.parser_model_response_started.value: ParserModelResponseStartedEvent,
|
agno/session/summary.py
CHANGED
|
@@ -102,7 +102,23 @@ class SessionSummaryManager:
|
|
|
102
102
|
system_prompt += "<conversation>"
|
|
103
103
|
for message in conversation:
|
|
104
104
|
if message.role == "user":
|
|
105
|
-
|
|
105
|
+
# Handle empty user messages with media - note what media was provided
|
|
106
|
+
if not message.content or (isinstance(message.content, str) and message.content.strip() == ""):
|
|
107
|
+
media_types = []
|
|
108
|
+
if hasattr(message, "images") and message.images:
|
|
109
|
+
media_types.append(f"{len(message.images)} image(s)")
|
|
110
|
+
if hasattr(message, "videos") and message.videos:
|
|
111
|
+
media_types.append(f"{len(message.videos)} video(s)")
|
|
112
|
+
if hasattr(message, "audio") and message.audio:
|
|
113
|
+
media_types.append(f"{len(message.audio)} audio file(s)")
|
|
114
|
+
if hasattr(message, "files") and message.files:
|
|
115
|
+
media_types.append(f"{len(message.files)} file(s)")
|
|
116
|
+
|
|
117
|
+
if media_types:
|
|
118
|
+
conversation_messages.append(f"User: [Provided {', '.join(media_types)}]")
|
|
119
|
+
# Skip empty messages with no media
|
|
120
|
+
else:
|
|
121
|
+
conversation_messages.append(f"User: {message.content}")
|
|
106
122
|
elif message.role in ["assistant", "model"]:
|
|
107
123
|
conversation_messages.append(f"Assistant: {message.content}\n")
|
|
108
124
|
system_prompt += "\n".join(conversation_messages)
|
|
@@ -118,23 +134,27 @@ class SessionSummaryManager:
|
|
|
118
134
|
def _prepare_summary_messages(
|
|
119
135
|
self,
|
|
120
136
|
session: Optional["Session"] = None,
|
|
121
|
-
) -> List[Message]:
|
|
122
|
-
"""Prepare messages for session summary generation"""
|
|
137
|
+
) -> Optional[List[Message]]:
|
|
138
|
+
"""Prepare messages for session summary generation. Returns None if no meaningful messages to summarize."""
|
|
139
|
+
if not session:
|
|
140
|
+
return None
|
|
141
|
+
|
|
123
142
|
self.model = cast(Model, self.model)
|
|
124
143
|
response_format = self.get_response_format(self.model)
|
|
125
144
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
conversation=session.get_messages_for_session(), # type: ignore
|
|
130
|
-
response_format=response_format,
|
|
131
|
-
),
|
|
132
|
-
Message(role="user", content="Provide the summary of the conversation."),
|
|
133
|
-
]
|
|
134
|
-
if session
|
|
135
|
-
else []
|
|
145
|
+
system_message = self.get_system_message(
|
|
146
|
+
conversation=session.get_messages_for_session(), # type: ignore
|
|
147
|
+
response_format=response_format,
|
|
136
148
|
)
|
|
137
149
|
|
|
150
|
+
if system_message is None:
|
|
151
|
+
return None
|
|
152
|
+
|
|
153
|
+
return [
|
|
154
|
+
system_message,
|
|
155
|
+
Message(role="user", content="Provide the summary of the conversation."),
|
|
156
|
+
]
|
|
157
|
+
|
|
138
158
|
def _process_summary_response(self, summary_response, session_summary_model: "Model") -> Optional[SessionSummary]: # type: ignore
|
|
139
159
|
"""Process the model response into a SessionSummary"""
|
|
140
160
|
from datetime import datetime
|
|
@@ -191,6 +211,12 @@ class SessionSummaryManager:
|
|
|
191
211
|
return None
|
|
192
212
|
|
|
193
213
|
messages = self._prepare_summary_messages(session)
|
|
214
|
+
|
|
215
|
+
# Skip summary generation if there are no meaningful messages
|
|
216
|
+
if messages is None:
|
|
217
|
+
log_debug("No meaningful messages to summarize, skipping session summary")
|
|
218
|
+
return None
|
|
219
|
+
|
|
194
220
|
response_format = self.get_response_format(self.model)
|
|
195
221
|
|
|
196
222
|
summary_response = self.model.response(messages=messages, response_format=response_format)
|
|
@@ -212,6 +238,12 @@ class SessionSummaryManager:
|
|
|
212
238
|
return None
|
|
213
239
|
|
|
214
240
|
messages = self._prepare_summary_messages(session)
|
|
241
|
+
|
|
242
|
+
# Skip summary generation if there are no meaningful messages
|
|
243
|
+
if messages is None:
|
|
244
|
+
log_debug("No meaningful messages to summarize, skipping session summary")
|
|
245
|
+
return None
|
|
246
|
+
|
|
215
247
|
response_format = self.get_response_format(self.model)
|
|
216
248
|
|
|
217
249
|
summary_response = await self.model.aresponse(messages=messages, response_format=response_format)
|
agno/session/team.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import asdict, dataclass
|
|
4
|
-
from typing import Any, Dict, List, Mapping, Optional, Union
|
|
4
|
+
from typing import Any, Dict, List, Mapping, Optional, Tuple, Union
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel
|
|
5
7
|
|
|
6
8
|
from agno.models.message import Message
|
|
7
9
|
from agno.run.agent import RunOutput, RunStatus
|
|
@@ -243,6 +245,78 @@ class TeamSession:
|
|
|
243
245
|
final_messages.append(assistant_message_from_run)
|
|
244
246
|
return final_messages
|
|
245
247
|
|
|
248
|
+
def get_team_history(self, num_runs: Optional[int] = None) -> List[Tuple[str, str]]:
|
|
249
|
+
"""Get team history as structured data (input, response pairs) -> This is the history of the team leader, not the members.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
num_runs: Number of recent runs to include. If None, returns all available history.
|
|
253
|
+
"""
|
|
254
|
+
if not self.runs:
|
|
255
|
+
return []
|
|
256
|
+
|
|
257
|
+
from agno.run.base import RunStatus
|
|
258
|
+
|
|
259
|
+
# Get completed runs only (exclude current/pending run)
|
|
260
|
+
completed_runs = [run for run in self.runs if run.status == RunStatus.completed and run.parent_run_id is None]
|
|
261
|
+
|
|
262
|
+
if num_runs is not None and len(completed_runs) > num_runs:
|
|
263
|
+
recent_runs = completed_runs[-num_runs:]
|
|
264
|
+
else:
|
|
265
|
+
recent_runs = completed_runs
|
|
266
|
+
|
|
267
|
+
if not recent_runs:
|
|
268
|
+
return []
|
|
269
|
+
|
|
270
|
+
# Return structured data as list of (input, response) tuples
|
|
271
|
+
history_data = []
|
|
272
|
+
for run in recent_runs:
|
|
273
|
+
# Get input
|
|
274
|
+
input_str = ""
|
|
275
|
+
if run.input:
|
|
276
|
+
input_str = run.input.input_content_string()
|
|
277
|
+
|
|
278
|
+
# Get response
|
|
279
|
+
response_str = ""
|
|
280
|
+
if run.content:
|
|
281
|
+
response_str = (
|
|
282
|
+
run.content.model_dump_json(indent=2, exclude_none=True)
|
|
283
|
+
if isinstance(run.content, BaseModel)
|
|
284
|
+
else str(run.content)
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
history_data.append((input_str, response_str))
|
|
288
|
+
|
|
289
|
+
return history_data
|
|
290
|
+
|
|
291
|
+
def get_team_history_context(self, num_runs: Optional[int] = None) -> Optional[str]:
|
|
292
|
+
"""Get formatted team history context for steps
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
num_runs: Number of recent runs to include. If None, returns all available history.
|
|
296
|
+
"""
|
|
297
|
+
history_data = self.get_team_history(num_runs)
|
|
298
|
+
|
|
299
|
+
if not history_data:
|
|
300
|
+
return None
|
|
301
|
+
|
|
302
|
+
# Format as team history context using the structured data
|
|
303
|
+
context_parts = ["<team_history_context>"]
|
|
304
|
+
|
|
305
|
+
for i, (input_str, response_str) in enumerate(history_data, 1):
|
|
306
|
+
context_parts.append(f"[run-{i}]")
|
|
307
|
+
|
|
308
|
+
if input_str:
|
|
309
|
+
context_parts.append(f"input: {input_str}")
|
|
310
|
+
if response_str:
|
|
311
|
+
context_parts.append(f"response: {response_str}")
|
|
312
|
+
|
|
313
|
+
context_parts.append("") # Empty line between runs
|
|
314
|
+
|
|
315
|
+
context_parts.append("</team_history_context>")
|
|
316
|
+
context_parts.append("") # Empty line before current input
|
|
317
|
+
|
|
318
|
+
return "\n".join(context_parts)
|
|
319
|
+
|
|
246
320
|
def get_session_summary(self) -> Optional[SessionSummary]:
|
|
247
321
|
"""Get the session summary for the session"""
|
|
248
322
|
|
|
@@ -252,17 +326,28 @@ class TeamSession:
|
|
|
252
326
|
return self.summary # type: ignore
|
|
253
327
|
|
|
254
328
|
# Chat History functions
|
|
255
|
-
def get_chat_history(
|
|
256
|
-
|
|
329
|
+
def get_chat_history(
|
|
330
|
+
self, skip_history_messages: bool = True, skip_roles: Optional[List[str]] = None
|
|
331
|
+
) -> List[Message]:
|
|
332
|
+
"""
|
|
333
|
+
Get the chat history for the session.
|
|
334
|
+
This is all messages across all runs for the team leader.
|
|
335
|
+
"""
|
|
257
336
|
|
|
258
337
|
messages = []
|
|
259
338
|
if self.runs is None:
|
|
260
339
|
return []
|
|
261
340
|
|
|
262
341
|
for run in self.runs or []:
|
|
263
|
-
if run.
|
|
342
|
+
if run.parent_run_id is not None:
|
|
264
343
|
continue
|
|
265
344
|
|
|
266
|
-
|
|
345
|
+
if run.messages is not None:
|
|
346
|
+
for msg in run.messages or []:
|
|
347
|
+
if skip_history_messages and msg.from_history:
|
|
348
|
+
continue
|
|
349
|
+
if skip_roles and msg.role in skip_roles:
|
|
350
|
+
continue
|
|
351
|
+
messages.append(msg)
|
|
267
352
|
|
|
268
353
|
return messages
|