agno 2.2.3__py3-none-any.whl → 2.2.4__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 +26 -5
- agno/db/dynamo/utils.py +1 -1
- agno/db/firestore/utils.py +1 -1
- agno/db/gcs_json/utils.py +1 -1
- agno/db/in_memory/utils.py +1 -1
- agno/db/json/utils.py +1 -1
- agno/db/mongo/async_mongo.py +1 -1
- agno/db/mongo/utils.py +1 -1
- agno/db/mysql/utils.py +1 -1
- agno/db/postgres/async_postgres.py +8 -3
- agno/db/postgres/utils.py +1 -1
- agno/db/redis/utils.py +1 -1
- agno/db/singlestore/utils.py +1 -1
- agno/db/sqlite/utils.py +1 -1
- agno/knowledge/embedder/ollama.py +8 -0
- agno/memory/manager.py +5 -5
- agno/os/app.py +105 -42
- agno/run/agent.py +27 -0
- agno/run/team.py +27 -0
- agno/session/agent.py +57 -17
- agno/session/team.py +57 -18
- agno/team/team.py +29 -9
- {agno-2.2.3.dist-info → agno-2.2.4.dist-info}/METADATA +1 -1
- {agno-2.2.3.dist-info → agno-2.2.4.dist-info}/RECORD +27 -27
- {agno-2.2.3.dist-info → agno-2.2.4.dist-info}/WHEEL +0 -0
- {agno-2.2.3.dist-info → agno-2.2.4.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.3.dist-info → agno-2.2.4.dist-info}/top_level.txt +0 -0
agno/agent/agent.py
CHANGED
|
@@ -220,7 +220,9 @@ class Agent:
|
|
|
220
220
|
# add_history_to_context=true adds messages from the chat history to the messages list sent to the Model.
|
|
221
221
|
add_history_to_context: bool = False
|
|
222
222
|
# Number of historical runs to include in the messages
|
|
223
|
-
num_history_runs: int =
|
|
223
|
+
num_history_runs: Optional[int] = None
|
|
224
|
+
# Number of historical messages to include in the messages list sent to the Model.
|
|
225
|
+
num_history_messages: Optional[int] = None
|
|
224
226
|
# Maximum number of tool calls to include from history (None = no limit)
|
|
225
227
|
max_tool_calls_from_history: Optional[int] = None
|
|
226
228
|
|
|
@@ -438,7 +440,8 @@ class Agent:
|
|
|
438
440
|
add_session_summary_to_context: Optional[bool] = None,
|
|
439
441
|
session_summary_manager: Optional[SessionSummaryManager] = None,
|
|
440
442
|
add_history_to_context: bool = False,
|
|
441
|
-
num_history_runs: int =
|
|
443
|
+
num_history_runs: Optional[int] = None,
|
|
444
|
+
num_history_messages: Optional[int] = None,
|
|
442
445
|
max_tool_calls_from_history: Optional[int] = None,
|
|
443
446
|
store_media: bool = True,
|
|
444
447
|
store_tool_messages: bool = True,
|
|
@@ -541,6 +544,15 @@ class Agent:
|
|
|
541
544
|
|
|
542
545
|
self.add_history_to_context = add_history_to_context
|
|
543
546
|
self.num_history_runs = num_history_runs
|
|
547
|
+
self.num_history_messages = num_history_messages
|
|
548
|
+
if self.num_history_messages is not None and self.num_history_runs is not None:
|
|
549
|
+
log_warning(
|
|
550
|
+
"num_history_messages and num_history_runs cannot be set at the same time. Using num_history_runs."
|
|
551
|
+
)
|
|
552
|
+
self.num_history_messages = None
|
|
553
|
+
if self.num_history_messages is None and self.num_history_runs is None:
|
|
554
|
+
self.num_history_runs = 3
|
|
555
|
+
|
|
544
556
|
self.max_tool_calls_from_history = max_tool_calls_from_history
|
|
545
557
|
|
|
546
558
|
self.store_media = store_media
|
|
@@ -5133,7 +5145,7 @@ class Agent:
|
|
|
5133
5145
|
run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
|
|
5134
5146
|
)
|
|
5135
5147
|
if user_message_str is not None and user_message_str.strip() != "" and self.memory_manager is not None:
|
|
5136
|
-
log_debug("
|
|
5148
|
+
log_debug("Managing user memories")
|
|
5137
5149
|
self.memory_manager.create_user_memories( # type: ignore
|
|
5138
5150
|
message=user_message_str,
|
|
5139
5151
|
user_id=user_id,
|
|
@@ -5174,7 +5186,7 @@ class Agent:
|
|
|
5174
5186
|
run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
|
|
5175
5187
|
)
|
|
5176
5188
|
if user_message_str is not None and user_message_str.strip() != "" and self.memory_manager is not None:
|
|
5177
|
-
log_debug("
|
|
5189
|
+
log_debug("Managing user memories")
|
|
5178
5190
|
await self.memory_manager.acreate_user_memories( # type: ignore
|
|
5179
5191
|
message=user_message_str,
|
|
5180
5192
|
user_id=user_id,
|
|
@@ -7461,6 +7473,7 @@ class Agent:
|
|
|
7461
7473
|
|
|
7462
7474
|
history: List[Message] = session.get_messages_from_last_n_runs(
|
|
7463
7475
|
last_n=self.num_history_runs,
|
|
7476
|
+
last_n_messages=self.num_history_messages,
|
|
7464
7477
|
skip_role=skip_role,
|
|
7465
7478
|
agent_id=self.id if self.team_id is not None else None,
|
|
7466
7479
|
)
|
|
@@ -7658,9 +7671,17 @@ class Agent:
|
|
|
7658
7671
|
if add_history_to_context:
|
|
7659
7672
|
from copy import deepcopy
|
|
7660
7673
|
|
|
7674
|
+
# Only skip messages from history when system_message_role is NOT a standard conversation role.
|
|
7675
|
+
# Standard conversation roles ("user", "assistant", "tool") should never be filtered
|
|
7676
|
+
# to preserve conversation continuity.
|
|
7677
|
+
skip_role = (
|
|
7678
|
+
self.system_message_role if self.system_message_role not in ["user", "assistant", "tool"] else None
|
|
7679
|
+
)
|
|
7680
|
+
|
|
7661
7681
|
history: List[Message] = session.get_messages_from_last_n_runs(
|
|
7662
7682
|
last_n=self.num_history_runs,
|
|
7663
|
-
|
|
7683
|
+
last_n_messages=self.num_history_messages,
|
|
7684
|
+
skip_role=skip_role,
|
|
7664
7685
|
agent_id=self.id if self.team_id is not None else None,
|
|
7665
7686
|
)
|
|
7666
7687
|
|
agno/db/dynamo/utils.py
CHANGED
|
@@ -361,7 +361,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
|
361
361
|
token_metrics[field] += session_metrics.get(field, 0)
|
|
362
362
|
model_metrics = []
|
|
363
363
|
for model, count in model_counts.items():
|
|
364
|
-
model_id, model_provider = model.
|
|
364
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
365
365
|
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
366
366
|
metrics["users_count"] = len(all_user_ids)
|
|
367
367
|
current_time = int(time.time())
|
agno/db/firestore/utils.py
CHANGED
|
@@ -224,7 +224,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
|
224
224
|
|
|
225
225
|
model_metrics = []
|
|
226
226
|
for model, count in model_counts.items():
|
|
227
|
-
model_id, model_provider = model.
|
|
227
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
228
228
|
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
229
229
|
|
|
230
230
|
metrics["users_count"] = len(all_user_ids)
|
agno/db/gcs_json/utils.py
CHANGED
|
@@ -99,7 +99,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
|
99
99
|
|
|
100
100
|
model_metrics = []
|
|
101
101
|
for model, count in model_counts.items():
|
|
102
|
-
model_id, model_provider = model.
|
|
102
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
103
103
|
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
104
104
|
|
|
105
105
|
metrics["users_count"] = len(all_user_ids)
|
agno/db/in_memory/utils.py
CHANGED
|
@@ -99,7 +99,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
|
99
99
|
|
|
100
100
|
model_metrics = []
|
|
101
101
|
for model, count in model_counts.items():
|
|
102
|
-
model_id, model_provider = model.
|
|
102
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
103
103
|
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
104
104
|
|
|
105
105
|
metrics["users_count"] = len(all_user_ids)
|
agno/db/json/utils.py
CHANGED
|
@@ -99,7 +99,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
|
99
99
|
|
|
100
100
|
model_metrics = []
|
|
101
101
|
for model, count in model_counts.items():
|
|
102
|
-
model_id, model_provider = model.
|
|
102
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
103
103
|
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
104
104
|
|
|
105
105
|
metrics["users_count"] = len(all_user_ids)
|
agno/db/mongo/async_mongo.py
CHANGED
|
@@ -1089,7 +1089,7 @@ class AsyncMongoDb(AsyncBaseDb):
|
|
|
1089
1089
|
if limit is not None:
|
|
1090
1090
|
if page is not None:
|
|
1091
1091
|
pipeline.append({"$skip": (page - 1) * limit}) # type: ignore
|
|
1092
|
-
pipeline.append({"$limit": limit})
|
|
1092
|
+
pipeline.append({"$limit": limit}) # type: ignore
|
|
1093
1093
|
|
|
1094
1094
|
results = await collection.aggregate(pipeline).to_list(length=None)
|
|
1095
1095
|
|
agno/db/mongo/utils.py
CHANGED
|
@@ -117,7 +117,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
|
117
117
|
|
|
118
118
|
model_metrics = []
|
|
119
119
|
for model, count in model_counts.items():
|
|
120
|
-
model_id, model_provider = model.
|
|
120
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
121
121
|
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
122
122
|
|
|
123
123
|
metrics["users_count"] = len(all_user_ids)
|
agno/db/mysql/utils.py
CHANGED
|
@@ -226,7 +226,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
|
226
226
|
|
|
227
227
|
model_metrics = []
|
|
228
228
|
for model, count in model_counts.items():
|
|
229
|
-
model_id, model_provider = model.
|
|
229
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
230
230
|
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
231
231
|
|
|
232
232
|
metrics["users_count"] = len(all_user_ids)
|
|
@@ -37,7 +37,7 @@ except ImportError:
|
|
|
37
37
|
class AsyncPostgresDb(AsyncBaseDb):
|
|
38
38
|
def __init__(
|
|
39
39
|
self,
|
|
40
|
-
|
|
40
|
+
id: Optional[str] = None,
|
|
41
41
|
db_url: Optional[str] = None,
|
|
42
42
|
db_engine: Optional[AsyncEngine] = None,
|
|
43
43
|
db_schema: Optional[str] = None,
|
|
@@ -47,6 +47,7 @@ class AsyncPostgresDb(AsyncBaseDb):
|
|
|
47
47
|
eval_table: Optional[str] = None,
|
|
48
48
|
knowledge_table: Optional[str] = None,
|
|
49
49
|
culture_table: Optional[str] = None,
|
|
50
|
+
db_id: Optional[str] = None, # Deprecated, use id instead.
|
|
50
51
|
):
|
|
51
52
|
"""
|
|
52
53
|
Async interface for interacting with a PostgreSQL database.
|
|
@@ -57,7 +58,7 @@ class AsyncPostgresDb(AsyncBaseDb):
|
|
|
57
58
|
3. Raise an error if neither is provided
|
|
58
59
|
|
|
59
60
|
Args:
|
|
60
|
-
|
|
61
|
+
id (Optional[str]): The ID of the database.
|
|
61
62
|
db_url (Optional[str]): The database URL to connect to.
|
|
62
63
|
db_engine (Optional[AsyncEngine]): The SQLAlchemy async database engine to use.
|
|
63
64
|
db_schema (Optional[str]): The database schema to use.
|
|
@@ -67,13 +68,17 @@ class AsyncPostgresDb(AsyncBaseDb):
|
|
|
67
68
|
eval_table (Optional[str]): Name of the table to store evaluation runs data.
|
|
68
69
|
knowledge_table (Optional[str]): Name of the table to store knowledge content.
|
|
69
70
|
culture_table (Optional[str]): Name of the table to store cultural knowledge.
|
|
71
|
+
db_id: Deprecated, use id instead.
|
|
70
72
|
|
|
71
73
|
Raises:
|
|
72
74
|
ValueError: If neither db_url nor db_engine is provided.
|
|
73
75
|
ValueError: If none of the tables are provided.
|
|
74
76
|
"""
|
|
77
|
+
if db_id is not None:
|
|
78
|
+
log_warning("db_id is deprecated and will be removed in a future version, use id instead.")
|
|
79
|
+
|
|
75
80
|
super().__init__(
|
|
76
|
-
id=db_id,
|
|
81
|
+
id=id or db_id,
|
|
77
82
|
session_table=session_table,
|
|
78
83
|
memory_table=memory_table,
|
|
79
84
|
metrics_table=metrics_table,
|
agno/db/postgres/utils.py
CHANGED
|
@@ -313,7 +313,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
|
313
313
|
|
|
314
314
|
model_metrics = []
|
|
315
315
|
for model, count in model_counts.items():
|
|
316
|
-
model_id, model_provider = model.
|
|
316
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
317
317
|
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
318
318
|
|
|
319
319
|
metrics["users_count"] = len(all_user_ids)
|
agno/db/redis/utils.py
CHANGED
|
@@ -221,7 +221,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
|
221
221
|
|
|
222
222
|
model_metrics = []
|
|
223
223
|
for model, count in model_counts.items():
|
|
224
|
-
model_id, model_provider = model.
|
|
224
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
225
225
|
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
226
226
|
|
|
227
227
|
metrics["users_count"] = len(all_user_ids)
|
agno/db/singlestore/utils.py
CHANGED
|
@@ -255,7 +255,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
|
255
255
|
|
|
256
256
|
model_metrics = []
|
|
257
257
|
for model, count in model_counts.items():
|
|
258
|
-
model_id, model_provider = model.
|
|
258
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
259
259
|
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
260
260
|
|
|
261
261
|
metrics["users_count"] = len(all_user_ids)
|
agno/db/sqlite/utils.py
CHANGED
|
@@ -298,7 +298,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
|
298
298
|
|
|
299
299
|
model_metrics = []
|
|
300
300
|
for model, count in model_counts.items():
|
|
301
|
-
model_id, model_provider = model.
|
|
301
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
302
302
|
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
303
303
|
|
|
304
304
|
metrics["users_count"] = len(all_user_ids)
|
|
@@ -85,6 +85,10 @@ class OllamaEmbedder(Embedder):
|
|
|
85
85
|
if self.options is not None:
|
|
86
86
|
kwargs["options"] = self.options
|
|
87
87
|
|
|
88
|
+
# Add dimensions parameter for models that support it
|
|
89
|
+
if self.dimensions is not None:
|
|
90
|
+
kwargs["dimensions"] = self.dimensions
|
|
91
|
+
|
|
88
92
|
response = self.client.embed(input=text, model=self.id, **kwargs)
|
|
89
93
|
if response and "embeddings" in response:
|
|
90
94
|
embeddings = response["embeddings"]
|
|
@@ -117,6 +121,10 @@ class OllamaEmbedder(Embedder):
|
|
|
117
121
|
if self.options is not None:
|
|
118
122
|
kwargs["options"] = self.options
|
|
119
123
|
|
|
124
|
+
# Add dimensions parameter for models that support it
|
|
125
|
+
if self.dimensions is not None:
|
|
126
|
+
kwargs["dimensions"] = self.dimensions
|
|
127
|
+
|
|
120
128
|
response = await self.aclient.embed(input=text, model=self.id, **kwargs)
|
|
121
129
|
if response and "embeddings" in response:
|
|
122
130
|
embeddings = response["embeddings"]
|
agno/memory/manager.py
CHANGED
|
@@ -843,7 +843,7 @@ class MemoryManager:
|
|
|
843
843
|
team_id=team_id,
|
|
844
844
|
enable_add_memory=add_memories,
|
|
845
845
|
enable_update_memory=update_memories,
|
|
846
|
-
enable_delete_memory=
|
|
846
|
+
enable_delete_memory=True,
|
|
847
847
|
enable_clear_memory=False,
|
|
848
848
|
),
|
|
849
849
|
)
|
|
@@ -854,7 +854,7 @@ class MemoryManager:
|
|
|
854
854
|
existing_memories=existing_memories,
|
|
855
855
|
enable_update_memory=update_memories,
|
|
856
856
|
enable_add_memory=add_memories,
|
|
857
|
-
enable_delete_memory=
|
|
857
|
+
enable_delete_memory=True,
|
|
858
858
|
enable_clear_memory=False,
|
|
859
859
|
),
|
|
860
860
|
*messages,
|
|
@@ -906,7 +906,7 @@ class MemoryManager:
|
|
|
906
906
|
team_id=team_id,
|
|
907
907
|
enable_add_memory=add_memories,
|
|
908
908
|
enable_update_memory=update_memories,
|
|
909
|
-
enable_delete_memory=
|
|
909
|
+
enable_delete_memory=True,
|
|
910
910
|
enable_clear_memory=False,
|
|
911
911
|
),
|
|
912
912
|
)
|
|
@@ -920,7 +920,7 @@ class MemoryManager:
|
|
|
920
920
|
team_id=team_id,
|
|
921
921
|
enable_add_memory=add_memories,
|
|
922
922
|
enable_update_memory=update_memories,
|
|
923
|
-
enable_delete_memory=
|
|
923
|
+
enable_delete_memory=True,
|
|
924
924
|
enable_clear_memory=False,
|
|
925
925
|
),
|
|
926
926
|
)
|
|
@@ -931,7 +931,7 @@ class MemoryManager:
|
|
|
931
931
|
existing_memories=existing_memories,
|
|
932
932
|
enable_update_memory=update_memories,
|
|
933
933
|
enable_add_memory=add_memories,
|
|
934
|
-
enable_delete_memory=
|
|
934
|
+
enable_delete_memory=True,
|
|
935
935
|
enable_clear_memory=False,
|
|
936
936
|
),
|
|
937
937
|
*messages,
|
agno/os/app.py
CHANGED
|
@@ -187,54 +187,50 @@ class AgentOS:
|
|
|
187
187
|
self.mcp_tools: List[Any] = []
|
|
188
188
|
self._mcp_app: Optional[Any] = None
|
|
189
189
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if agent.tools:
|
|
194
|
-
for tool in agent.tools:
|
|
195
|
-
# Checking if the tool is a MCPTools or MultiMCPTools instance
|
|
196
|
-
type_name = type(tool).__name__
|
|
197
|
-
if type_name in ("MCPTools", "MultiMCPTools"):
|
|
198
|
-
if tool not in self.mcp_tools:
|
|
199
|
-
self.mcp_tools.append(tool)
|
|
200
|
-
|
|
201
|
-
agent.initialize_agent()
|
|
190
|
+
self._initialize_agents()
|
|
191
|
+
self._initialize_teams()
|
|
192
|
+
self._initialize_workflows()
|
|
202
193
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if self.teams:
|
|
207
|
-
for team in self.teams:
|
|
208
|
-
# Track all MCP tools recursively
|
|
209
|
-
collect_mcp_tools_from_team(team, self.mcp_tools)
|
|
194
|
+
if self.telemetry:
|
|
195
|
+
from agno.api.os import OSLaunch, log_os_telemetry
|
|
210
196
|
|
|
211
|
-
|
|
197
|
+
log_os_telemetry(launch=OSLaunch(os_id=self.id, data=self._get_telemetry_data()))
|
|
212
198
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
member.initialize_agent()
|
|
217
|
-
elif isinstance(member, Team):
|
|
218
|
-
member.initialize_team()
|
|
199
|
+
def _add_agent_os_to_lifespan_function(self, lifespan):
|
|
200
|
+
"""
|
|
201
|
+
Inspect a lifespan function and wrap it to pass agent_os if it accepts it.
|
|
219
202
|
|
|
220
|
-
|
|
221
|
-
|
|
203
|
+
Returns:
|
|
204
|
+
A wrapped lifespan that passes agent_os if the lifespan function expects it.
|
|
205
|
+
"""
|
|
206
|
+
# Getting the actual function inside the lifespan
|
|
207
|
+
lifespan_function = lifespan
|
|
208
|
+
if hasattr(lifespan, "__wrapped__"):
|
|
209
|
+
lifespan_function = lifespan.__wrapped__
|
|
222
210
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
# Track MCP tools recursively in workflow members
|
|
226
|
-
collect_mcp_tools_from_workflow(workflow, self.mcp_tools)
|
|
211
|
+
try:
|
|
212
|
+
from inspect import signature
|
|
227
213
|
|
|
228
|
-
|
|
229
|
-
|
|
214
|
+
# Inspecting the lifespan function signature to find its parameters
|
|
215
|
+
sig = signature(lifespan_function)
|
|
216
|
+
params = list(sig.parameters.keys())
|
|
230
217
|
|
|
231
|
-
|
|
232
|
-
|
|
218
|
+
# If the lifespan function expects the 'agent_os' parameter, add it
|
|
219
|
+
if "agent_os" in params:
|
|
220
|
+
return partial(lifespan, agent_os=self)
|
|
221
|
+
else:
|
|
222
|
+
return lifespan
|
|
233
223
|
|
|
234
|
-
|
|
235
|
-
|
|
224
|
+
except (ValueError, TypeError):
|
|
225
|
+
return lifespan
|
|
236
226
|
|
|
237
|
-
|
|
227
|
+
def resync(self) -> None:
|
|
228
|
+
"""Resync the AgentOS to discover, initialize and configure: agents, teams, workflows, databases and knowledge bases."""
|
|
229
|
+
self._initialize_agents()
|
|
230
|
+
self._initialize_teams()
|
|
231
|
+
self._initialize_workflows()
|
|
232
|
+
self._auto_discover_databases()
|
|
233
|
+
self._auto_discover_knowledge_instances()
|
|
238
234
|
|
|
239
235
|
def _make_app(self, lifespan: Optional[Any] = None) -> FastAPI:
|
|
240
236
|
# Adjust the FastAPI app lifespan to handle MCP connections if relevant
|
|
@@ -265,6 +261,63 @@ class AgentOS:
|
|
|
265
261
|
lifespan=app_lifespan,
|
|
266
262
|
)
|
|
267
263
|
|
|
264
|
+
def _initialize_agents(self) -> None:
|
|
265
|
+
"""Initialize and configure all agents for AgentOS usage."""
|
|
266
|
+
if not self.agents:
|
|
267
|
+
return
|
|
268
|
+
|
|
269
|
+
for agent in self.agents:
|
|
270
|
+
# Track all MCP tools to later handle their connection
|
|
271
|
+
if agent.tools:
|
|
272
|
+
for tool in agent.tools:
|
|
273
|
+
# Checking if the tool is a MCPTools or MultiMCPTools instance
|
|
274
|
+
type_name = type(tool).__name__
|
|
275
|
+
if type_name in ("MCPTools", "MultiMCPTools"):
|
|
276
|
+
if tool not in self.mcp_tools:
|
|
277
|
+
self.mcp_tools.append(tool)
|
|
278
|
+
|
|
279
|
+
agent.initialize_agent()
|
|
280
|
+
|
|
281
|
+
# Required for the built-in routes to work
|
|
282
|
+
agent.store_events = True
|
|
283
|
+
|
|
284
|
+
def _initialize_teams(self) -> None:
|
|
285
|
+
"""Initialize and configure all teams for AgentOS usage."""
|
|
286
|
+
if not self.teams:
|
|
287
|
+
return
|
|
288
|
+
|
|
289
|
+
for team in self.teams:
|
|
290
|
+
# Track all MCP tools recursively
|
|
291
|
+
collect_mcp_tools_from_team(team, self.mcp_tools)
|
|
292
|
+
|
|
293
|
+
team.initialize_team()
|
|
294
|
+
|
|
295
|
+
for member in team.members:
|
|
296
|
+
if isinstance(member, Agent):
|
|
297
|
+
member.team_id = None
|
|
298
|
+
member.initialize_agent()
|
|
299
|
+
elif isinstance(member, Team):
|
|
300
|
+
member.initialize_team()
|
|
301
|
+
|
|
302
|
+
# Required for the built-in routes to work
|
|
303
|
+
team.store_events = True
|
|
304
|
+
|
|
305
|
+
def _initialize_workflows(self) -> None:
|
|
306
|
+
"""Initialize and configure all workflows for AgentOS usage."""
|
|
307
|
+
if not self.workflows:
|
|
308
|
+
return
|
|
309
|
+
|
|
310
|
+
if self.workflows:
|
|
311
|
+
for workflow in self.workflows:
|
|
312
|
+
# Track MCP tools recursively in workflow members
|
|
313
|
+
collect_mcp_tools_from_workflow(workflow, self.mcp_tools)
|
|
314
|
+
|
|
315
|
+
if not workflow.id:
|
|
316
|
+
workflow.id = generate_id_from_name(workflow.name)
|
|
317
|
+
|
|
318
|
+
# Required for the built-in routes to work
|
|
319
|
+
workflow.store_events = True
|
|
320
|
+
|
|
268
321
|
def get_app(self) -> FastAPI:
|
|
269
322
|
if self.base_app:
|
|
270
323
|
fastapi_app = self.base_app
|
|
@@ -288,7 +341,9 @@ class AgentOS:
|
|
|
288
341
|
lifespans.append(self._mcp_app.lifespan)
|
|
289
342
|
|
|
290
343
|
if self.lifespan:
|
|
291
|
-
|
|
344
|
+
# Wrap the user lifespan with agent_os parameter
|
|
345
|
+
wrapped_lifespan = self._add_agent_os_to_lifespan_function(self.lifespan)
|
|
346
|
+
lifespans.append(wrapped_lifespan)
|
|
292
347
|
|
|
293
348
|
# Combine lifespans and set them in the app
|
|
294
349
|
if lifespans:
|
|
@@ -304,11 +359,14 @@ class AgentOS:
|
|
|
304
359
|
|
|
305
360
|
final_lifespan = self._mcp_app.lifespan # type: ignore
|
|
306
361
|
if self.lifespan is not None:
|
|
362
|
+
# Wrap the user lifespan with agent_os parameter
|
|
363
|
+
wrapped_lifespan = self._add_agent_os_to_lifespan_function(self.lifespan)
|
|
364
|
+
|
|
307
365
|
# Combine both lifespans
|
|
308
366
|
@asynccontextmanager
|
|
309
367
|
async def combined_lifespan(app: FastAPI):
|
|
310
368
|
# Run both lifespans
|
|
311
|
-
async with
|
|
369
|
+
async with wrapped_lifespan(app): # type: ignore
|
|
312
370
|
async with self._mcp_app.lifespan(app): # type: ignore
|
|
313
371
|
yield
|
|
314
372
|
|
|
@@ -316,7 +374,12 @@ class AgentOS:
|
|
|
316
374
|
|
|
317
375
|
fastapi_app = self._make_app(lifespan=final_lifespan)
|
|
318
376
|
else:
|
|
319
|
-
|
|
377
|
+
# Wrap the user lifespan with agent_os parameter
|
|
378
|
+
wrapped_user_lifespan = None
|
|
379
|
+
if self.lifespan is not None:
|
|
380
|
+
wrapped_user_lifespan = self._add_agent_os_to_lifespan_function(self.lifespan)
|
|
381
|
+
|
|
382
|
+
fastapi_app = self._make_app(lifespan=wrapped_user_lifespan)
|
|
320
383
|
|
|
321
384
|
# Add routes
|
|
322
385
|
self._add_router(fastapi_app, get_base_router(self, settings=self.settings))
|
agno/run/agent.py
CHANGED
|
@@ -70,12 +70,39 @@ class RunInput:
|
|
|
70
70
|
result["input_content"] = self.input_content.model_dump(exclude_none=True)
|
|
71
71
|
elif isinstance(self.input_content, Message):
|
|
72
72
|
result["input_content"] = self.input_content.to_dict()
|
|
73
|
+
|
|
74
|
+
# Handle input_content provided as a list of Message objects
|
|
73
75
|
elif (
|
|
74
76
|
isinstance(self.input_content, list)
|
|
75
77
|
and self.input_content
|
|
76
78
|
and isinstance(self.input_content[0], Message)
|
|
77
79
|
):
|
|
78
80
|
result["input_content"] = [m.to_dict() for m in self.input_content]
|
|
81
|
+
|
|
82
|
+
# Handle input_content provided as a list of dicts
|
|
83
|
+
elif (
|
|
84
|
+
isinstance(self.input_content, list) and self.input_content and isinstance(self.input_content[0], dict)
|
|
85
|
+
):
|
|
86
|
+
for content in self.input_content:
|
|
87
|
+
# Handle media input
|
|
88
|
+
if isinstance(content, dict):
|
|
89
|
+
if content.get("images"):
|
|
90
|
+
content["images"] = [
|
|
91
|
+
img.to_dict() if isinstance(img, Image) else img for img in content["images"]
|
|
92
|
+
]
|
|
93
|
+
if content.get("videos"):
|
|
94
|
+
content["videos"] = [
|
|
95
|
+
vid.to_dict() if isinstance(vid, Video) else vid for vid in content["videos"]
|
|
96
|
+
]
|
|
97
|
+
if content.get("audios"):
|
|
98
|
+
content["audios"] = [
|
|
99
|
+
aud.to_dict() if isinstance(aud, Audio) else aud for aud in content["audios"]
|
|
100
|
+
]
|
|
101
|
+
if content.get("files"):
|
|
102
|
+
content["files"] = [
|
|
103
|
+
file.to_dict() if isinstance(file, File) else file for file in content["files"]
|
|
104
|
+
]
|
|
105
|
+
result["input_content"] = self.input_content
|
|
79
106
|
else:
|
|
80
107
|
result["input_content"] = self.input_content
|
|
81
108
|
|
agno/run/team.py
CHANGED
|
@@ -66,12 +66,39 @@ class TeamRunInput:
|
|
|
66
66
|
result["input_content"] = self.input_content.model_dump(exclude_none=True)
|
|
67
67
|
elif isinstance(self.input_content, Message):
|
|
68
68
|
result["input_content"] = self.input_content.to_dict()
|
|
69
|
+
|
|
70
|
+
# Handle input_content provided as a list of Message objects
|
|
69
71
|
elif (
|
|
70
72
|
isinstance(self.input_content, list)
|
|
71
73
|
and self.input_content
|
|
72
74
|
and isinstance(self.input_content[0], Message)
|
|
73
75
|
):
|
|
74
76
|
result["input_content"] = [m.to_dict() for m in self.input_content]
|
|
77
|
+
|
|
78
|
+
# Handle input_content provided as a list of dicts
|
|
79
|
+
elif (
|
|
80
|
+
isinstance(self.input_content, list) and self.input_content and isinstance(self.input_content[0], dict)
|
|
81
|
+
):
|
|
82
|
+
for content in self.input_content:
|
|
83
|
+
# Handle media input
|
|
84
|
+
if isinstance(content, dict):
|
|
85
|
+
if content.get("images"):
|
|
86
|
+
content["images"] = [
|
|
87
|
+
img.to_dict() if isinstance(img, Image) else img for img in content["images"]
|
|
88
|
+
]
|
|
89
|
+
if content.get("videos"):
|
|
90
|
+
content["videos"] = [
|
|
91
|
+
vid.to_dict() if isinstance(vid, Video) else vid for vid in content["videos"]
|
|
92
|
+
]
|
|
93
|
+
if content.get("audios"):
|
|
94
|
+
content["audios"] = [
|
|
95
|
+
aud.to_dict() if isinstance(aud, Audio) else aud for aud in content["audios"]
|
|
96
|
+
]
|
|
97
|
+
if content.get("files"):
|
|
98
|
+
content["files"] = [
|
|
99
|
+
file.to_dict() if isinstance(file, File) else file for file in content["files"]
|
|
100
|
+
]
|
|
101
|
+
result["input_content"] = self.input_content
|
|
75
102
|
else:
|
|
76
103
|
result["input_content"] = self.input_content
|
|
77
104
|
|
agno/session/agent.py
CHANGED
|
@@ -107,11 +107,25 @@ class AgentSession:
|
|
|
107
107
|
return run
|
|
108
108
|
return None
|
|
109
109
|
|
|
110
|
+
def _should_skip_message(
|
|
111
|
+
self, message: Message, skip_role: Optional[str] = None, skip_history_messages: bool = True
|
|
112
|
+
) -> bool:
|
|
113
|
+
"""Processes a message for history"""
|
|
114
|
+
# Skip messages that were tagged as history in previous runs
|
|
115
|
+
if hasattr(message, "from_history") and message.from_history and skip_history_messages:
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
# Skip messages with specified role
|
|
119
|
+
if skip_role and message.role == skip_role:
|
|
120
|
+
return True
|
|
121
|
+
return False
|
|
122
|
+
|
|
110
123
|
def get_messages_from_last_n_runs(
|
|
111
124
|
self,
|
|
112
125
|
agent_id: Optional[str] = None,
|
|
113
126
|
team_id: Optional[str] = None,
|
|
114
127
|
last_n: Optional[int] = None,
|
|
128
|
+
last_n_messages: Optional[int] = None,
|
|
115
129
|
skip_role: Optional[str] = None,
|
|
116
130
|
skip_status: Optional[List[RunStatus]] = None,
|
|
117
131
|
skip_history_messages: bool = True,
|
|
@@ -121,6 +135,7 @@ class AgentSession:
|
|
|
121
135
|
agent_id: The id of the agent to get the messages from.
|
|
122
136
|
team_id: The id of the team to get the messages from.
|
|
123
137
|
last_n: The number of runs to return from the end of the conversation. Defaults to all runs.
|
|
138
|
+
last_n_messages: The number of messages to return from the end of the conversation. Defaults to all messages.
|
|
124
139
|
skip_role: Skip messages with this role.
|
|
125
140
|
skip_status: Skip messages with this status.
|
|
126
141
|
skip_history_messages: Skip messages that were tagged as history in previous runs.
|
|
@@ -146,30 +161,55 @@ class AgentSession:
|
|
|
146
161
|
# Filter by status
|
|
147
162
|
session_runs = [run for run in session_runs if hasattr(run, "status") and run.status not in skip_status] # type: ignore
|
|
148
163
|
|
|
149
|
-
# Filter by last_n
|
|
150
|
-
runs_to_process = session_runs[-last_n:] if last_n is not None else session_runs
|
|
151
164
|
messages_from_history = []
|
|
152
165
|
system_message = None
|
|
153
|
-
for run_response in runs_to_process:
|
|
154
|
-
if not (run_response and run_response.messages):
|
|
155
|
-
continue
|
|
156
166
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
167
|
+
# Filter by last_n_messages
|
|
168
|
+
if last_n_messages is not None:
|
|
169
|
+
for run_response in session_runs:
|
|
170
|
+
if not run_response or not run_response.messages:
|
|
160
171
|
continue
|
|
161
172
|
|
|
162
|
-
|
|
163
|
-
|
|
173
|
+
for message in run_response.messages or []:
|
|
174
|
+
if self._should_skip_message(message, skip_role, skip_history_messages):
|
|
175
|
+
continue
|
|
176
|
+
|
|
177
|
+
if message.role == "system":
|
|
178
|
+
# Only add the system message once
|
|
179
|
+
if system_message is None:
|
|
180
|
+
system_message = message
|
|
181
|
+
else:
|
|
182
|
+
messages_from_history.append(message)
|
|
183
|
+
|
|
184
|
+
if system_message:
|
|
185
|
+
messages_from_history = [system_message] + messages_from_history[
|
|
186
|
+
-(last_n_messages - 1) :
|
|
187
|
+
] # Grab one less message then add the system message
|
|
188
|
+
else:
|
|
189
|
+
messages_from_history = messages_from_history[-last_n_messages:]
|
|
190
|
+
|
|
191
|
+
# Remove tool result messages that don't have an associated assistant message with tool calls
|
|
192
|
+
while len(messages_from_history) > 0 and messages_from_history[0].role == "tool":
|
|
193
|
+
messages_from_history.pop(0)
|
|
194
|
+
|
|
195
|
+
else:
|
|
196
|
+
# Filter by last_n runs
|
|
197
|
+
runs_to_process = session_runs[-last_n:] if last_n is not None else session_runs
|
|
198
|
+
for run_response in runs_to_process:
|
|
199
|
+
if not run_response or not run_response.messages:
|
|
164
200
|
continue
|
|
165
201
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
202
|
+
for message in run_response.messages or []:
|
|
203
|
+
if self._should_skip_message(message, skip_role, skip_history_messages):
|
|
204
|
+
continue
|
|
205
|
+
|
|
206
|
+
if message.role == "system":
|
|
207
|
+
# Only add the system message once
|
|
208
|
+
if system_message is None:
|
|
209
|
+
system_message = message
|
|
210
|
+
messages_from_history.append(system_message)
|
|
211
|
+
else:
|
|
212
|
+
messages_from_history.append(message)
|
|
173
213
|
|
|
174
214
|
log_debug(f"Getting messages from previous runs: {len(messages_from_history)}")
|
|
175
215
|
return messages_from_history
|
agno/session/team.py
CHANGED
|
@@ -113,11 +113,25 @@ class TeamSession:
|
|
|
113
113
|
|
|
114
114
|
log_debug("Added RunOutput to Team Session")
|
|
115
115
|
|
|
116
|
+
def _should_skip_message(
|
|
117
|
+
self, message: Message, skip_role: Optional[str] = None, skip_history_messages: bool = True
|
|
118
|
+
) -> bool:
|
|
119
|
+
"""Processes a message for history"""
|
|
120
|
+
# Skip messages that were tagged as history in previous runs
|
|
121
|
+
if hasattr(message, "from_history") and message.from_history and skip_history_messages:
|
|
122
|
+
return True
|
|
123
|
+
|
|
124
|
+
# Skip messages with specified role
|
|
125
|
+
if skip_role and message.role == skip_role:
|
|
126
|
+
return True
|
|
127
|
+
return False
|
|
128
|
+
|
|
116
129
|
def get_messages_from_last_n_runs(
|
|
117
130
|
self,
|
|
118
131
|
agent_id: Optional[str] = None,
|
|
119
132
|
team_id: Optional[str] = None,
|
|
120
133
|
last_n: Optional[int] = None,
|
|
134
|
+
last_n_messages: Optional[int] = None,
|
|
121
135
|
skip_role: Optional[str] = None,
|
|
122
136
|
skip_status: Optional[List[RunStatus]] = None,
|
|
123
137
|
skip_history_messages: bool = True,
|
|
@@ -129,6 +143,7 @@ class TeamSession:
|
|
|
129
143
|
agent_id: The id of the agent to get the messages from.
|
|
130
144
|
team_id: The id of the team to get the messages from.
|
|
131
145
|
last_n: The number of runs to return from the end of the conversation. Defaults to all runs.
|
|
146
|
+
last_n_messages: The number of messages to return from the end of the conversation. Defaults to all messages.
|
|
132
147
|
skip_role: Skip messages with this role.
|
|
133
148
|
skip_status: Skip messages with this status.
|
|
134
149
|
skip_history_messages: Skip messages that were tagged as history in previous runs.
|
|
@@ -155,31 +170,55 @@ class TeamSession:
|
|
|
155
170
|
# Filter by status
|
|
156
171
|
session_runs = [run for run in session_runs if hasattr(run, "status") and run.status not in skip_status] # type: ignore
|
|
157
172
|
|
|
158
|
-
# Filter by last_n
|
|
159
|
-
runs_to_process = session_runs[-last_n:] if last_n is not None else session_runs
|
|
160
173
|
messages_from_history = []
|
|
161
174
|
system_message = None
|
|
162
175
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
for message in run_response.messages or []:
|
|
168
|
-
# Skip messages that were tagged as history in previous runs
|
|
169
|
-
if hasattr(message, "from_history") and message.from_history and skip_history_messages:
|
|
176
|
+
# Filter by last_n_messages
|
|
177
|
+
if last_n_messages is not None:
|
|
178
|
+
for run_response in session_runs:
|
|
179
|
+
if not run_response or not run_response.messages:
|
|
170
180
|
continue
|
|
171
181
|
|
|
172
|
-
|
|
173
|
-
|
|
182
|
+
for message in run_response.messages or []:
|
|
183
|
+
if self._should_skip_message(message, skip_role, skip_history_messages):
|
|
184
|
+
continue
|
|
185
|
+
|
|
186
|
+
if message.role == "system":
|
|
187
|
+
# Only add the system message once
|
|
188
|
+
if system_message is None:
|
|
189
|
+
system_message = message
|
|
190
|
+
else:
|
|
191
|
+
messages_from_history.append(message)
|
|
192
|
+
|
|
193
|
+
if system_message:
|
|
194
|
+
messages_from_history = [system_message] + messages_from_history[
|
|
195
|
+
-(last_n_messages - 1) :
|
|
196
|
+
] # Grab one less message then add the system message
|
|
197
|
+
else:
|
|
198
|
+
messages_from_history = messages_from_history[-last_n_messages:]
|
|
199
|
+
|
|
200
|
+
# Remove tool result messages that don't have an associated assistant message with tool calls
|
|
201
|
+
while len(messages_from_history) > 0 and messages_from_history[0].role == "tool":
|
|
202
|
+
messages_from_history.pop(0)
|
|
203
|
+
else:
|
|
204
|
+
# Filter by last_n runs
|
|
205
|
+
runs_to_process = session_runs[-last_n:] if last_n is not None else session_runs
|
|
206
|
+
|
|
207
|
+
for run_response in runs_to_process:
|
|
208
|
+
if not (run_response and run_response.messages):
|
|
174
209
|
continue
|
|
175
210
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
211
|
+
for message in run_response.messages or []:
|
|
212
|
+
if self._should_skip_message(message, skip_role, skip_history_messages):
|
|
213
|
+
continue
|
|
214
|
+
|
|
215
|
+
if message.role == "system":
|
|
216
|
+
# Only add the system message once
|
|
217
|
+
if system_message is None:
|
|
218
|
+
system_message = message
|
|
219
|
+
messages_from_history.append(system_message)
|
|
220
|
+
else:
|
|
221
|
+
messages_from_history.append(message)
|
|
183
222
|
|
|
184
223
|
log_debug(f"Getting messages from previous runs: {len(messages_from_history)}")
|
|
185
224
|
return messages_from_history
|
agno/team/team.py
CHANGED
|
@@ -378,7 +378,9 @@ class Team:
|
|
|
378
378
|
# add_history_to_context=true adds messages from the chat history to the messages list sent to the Model.
|
|
379
379
|
add_history_to_context: bool = False
|
|
380
380
|
# Number of historical runs to include in the messages
|
|
381
|
-
num_history_runs: int =
|
|
381
|
+
num_history_runs: Optional[int] = None
|
|
382
|
+
# Number of historical messages to include in the messages list sent to the Model.
|
|
383
|
+
num_history_messages: Optional[int] = None
|
|
382
384
|
# Maximum number of tool calls to include from history (None = no limit)
|
|
383
385
|
max_tool_calls_from_history: Optional[int] = None
|
|
384
386
|
|
|
@@ -485,7 +487,9 @@ class Team:
|
|
|
485
487
|
store_history_messages: bool = True,
|
|
486
488
|
send_media_to_model: bool = True,
|
|
487
489
|
add_history_to_context: bool = False,
|
|
488
|
-
num_history_runs: int =
|
|
490
|
+
num_history_runs: Optional[int] = None,
|
|
491
|
+
num_history_messages: Optional[int] = None,
|
|
492
|
+
max_tool_calls_from_history: Optional[int] = None,
|
|
489
493
|
tools: Optional[List[Union[Toolkit, Callable, Function, Dict]]] = None,
|
|
490
494
|
tool_call_limit: Optional[int] = None,
|
|
491
495
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
@@ -508,7 +512,6 @@ class Team:
|
|
|
508
512
|
enable_session_summaries: bool = False,
|
|
509
513
|
session_summary_manager: Optional[SessionSummaryManager] = None,
|
|
510
514
|
add_session_summary_to_context: Optional[bool] = None,
|
|
511
|
-
max_tool_calls_from_history: Optional[int] = None,
|
|
512
515
|
metadata: Optional[Dict[str, Any]] = None,
|
|
513
516
|
reasoning: bool = False,
|
|
514
517
|
reasoning_model: Optional[Model] = None,
|
|
@@ -553,6 +556,17 @@ class Team:
|
|
|
553
556
|
|
|
554
557
|
self.add_history_to_context = add_history_to_context
|
|
555
558
|
self.num_history_runs = num_history_runs
|
|
559
|
+
self.num_history_messages = num_history_messages
|
|
560
|
+
if self.num_history_messages is not None and self.num_history_runs is not None:
|
|
561
|
+
log_warning(
|
|
562
|
+
"num_history_messages and num_history_runs cannot be set at the same time. Using num_history_runs."
|
|
563
|
+
)
|
|
564
|
+
self.num_history_messages = None
|
|
565
|
+
if self.num_history_messages is None and self.num_history_runs is None:
|
|
566
|
+
self.num_history_runs = 3
|
|
567
|
+
|
|
568
|
+
self.max_tool_calls_from_history = max_tool_calls_from_history
|
|
569
|
+
|
|
556
570
|
self.add_team_history_to_members = add_team_history_to_members
|
|
557
571
|
self.num_team_history_runs = num_team_history_runs
|
|
558
572
|
self.search_session_history = search_session_history
|
|
@@ -620,9 +634,6 @@ class Team:
|
|
|
620
634
|
self.enable_session_summaries = enable_session_summaries
|
|
621
635
|
self.session_summary_manager = session_summary_manager
|
|
622
636
|
self.add_session_summary_to_context = add_session_summary_to_context
|
|
623
|
-
self.add_history_to_context = add_history_to_context
|
|
624
|
-
self.num_history_runs = num_history_runs
|
|
625
|
-
self.max_tool_calls_from_history = max_tool_calls_from_history
|
|
626
637
|
self.metadata = metadata
|
|
627
638
|
|
|
628
639
|
self.reasoning = reasoning
|
|
@@ -3457,7 +3468,7 @@ class Team:
|
|
|
3457
3468
|
run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
|
|
3458
3469
|
)
|
|
3459
3470
|
if user_message_str is not None and user_message_str.strip() != "" and self.memory_manager is not None:
|
|
3460
|
-
log_debug("
|
|
3471
|
+
log_debug("Managing user memories")
|
|
3461
3472
|
self.memory_manager.create_user_memories(
|
|
3462
3473
|
message=user_message_str,
|
|
3463
3474
|
user_id=user_id,
|
|
@@ -3473,7 +3484,7 @@ class Team:
|
|
|
3473
3484
|
run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
|
|
3474
3485
|
)
|
|
3475
3486
|
if user_message_str is not None and user_message_str.strip() != "" and self.memory_manager is not None:
|
|
3476
|
-
log_debug("
|
|
3487
|
+
log_debug("Managing user memories")
|
|
3477
3488
|
await self.memory_manager.acreate_user_memories(
|
|
3478
3489
|
message=user_message_str,
|
|
3479
3490
|
user_id=user_id,
|
|
@@ -5928,6 +5939,7 @@ class Team:
|
|
|
5928
5939
|
|
|
5929
5940
|
history = session.get_messages_from_last_n_runs(
|
|
5930
5941
|
last_n=self.num_history_runs,
|
|
5942
|
+
last_n_messages=self.num_history_messages,
|
|
5931
5943
|
skip_role=skip_role,
|
|
5932
5944
|
team_id=self.id if self.parent_team_id is not None else None,
|
|
5933
5945
|
)
|
|
@@ -6059,9 +6071,16 @@ class Team:
|
|
|
6059
6071
|
if add_history_to_context:
|
|
6060
6072
|
from copy import deepcopy
|
|
6061
6073
|
|
|
6074
|
+
# Only skip messages from history when system_message_role is NOT a standard conversation role.
|
|
6075
|
+
# Standard conversation roles ("user", "assistant", "tool") should never be filtered
|
|
6076
|
+
# to preserve conversation continuity.
|
|
6077
|
+
skip_role = (
|
|
6078
|
+
self.system_message_role if self.system_message_role not in ["user", "assistant", "tool"] else None
|
|
6079
|
+
)
|
|
6062
6080
|
history = session.get_messages_from_last_n_runs(
|
|
6063
6081
|
last_n=self.num_history_runs,
|
|
6064
|
-
|
|
6082
|
+
last_n_messages=self.num_history_messages,
|
|
6083
|
+
skip_role=skip_role,
|
|
6065
6084
|
team_id=self.id,
|
|
6066
6085
|
)
|
|
6067
6086
|
|
|
@@ -6765,6 +6784,7 @@ class Team:
|
|
|
6765
6784
|
|
|
6766
6785
|
history = session.get_messages_from_last_n_runs(
|
|
6767
6786
|
last_n=member_agent.num_history_runs or self.num_history_runs,
|
|
6787
|
+
last_n_messages=member_agent.num_history_messages,
|
|
6768
6788
|
skip_role=skip_role,
|
|
6769
6789
|
agent_id=member_agent_id,
|
|
6770
6790
|
team_id=member_team_id,
|
|
@@ -4,7 +4,7 @@ agno/exceptions.py,sha256=7xqLur8sWHugnViIJz4PvPKSHljSiVKNAqaKQOJgZiU,4982
|
|
|
4
4
|
agno/media.py,sha256=eTfYb_pwhX_PCIVPSrW4VYRqmoxKABEF1aZClrVvQ30,16500
|
|
5
5
|
agno/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
agno/agent/__init__.py,sha256=s7S3FgsjZxuaabzi8L5n4aSH8IZAiZ7XaNNcySGR-EQ,1051
|
|
7
|
-
agno/agent/agent.py,sha256=
|
|
7
|
+
agno/agent/agent.py,sha256=U0xx271S2I6WdzrJqyJMZ7z_6VY7Tc4PGvazsLKdAfk,454283
|
|
8
8
|
agno/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
agno/api/agent.py,sha256=fKlQ62E_C9Rjd7Zus3Gs3R1RG-IhzFV-ICpkb6SLqYc,932
|
|
10
10
|
agno/api/api.py,sha256=Z7iWbrjheJcGLeeDYrtTCWiKTVqjH0uJI35UNWOtAXw,973
|
|
@@ -36,40 +36,40 @@ agno/db/async_postgres/__init__.py,sha256=ja_thcYP3bP0DD3da6iUVDR_w2-S6B3M-UxBlk
|
|
|
36
36
|
agno/db/dynamo/__init__.py,sha256=fZ7NwKbyhoIu7_4T6hVz44HkIINXMnTfFrDrgB6bpEo,67
|
|
37
37
|
agno/db/dynamo/dynamo.py,sha256=SlpKYVbfb67q8r2tp48lDRWyW2wfURo6S1TjWuqzPks,78126
|
|
38
38
|
agno/db/dynamo/schemas.py,sha256=Pdtpa0wV_M8G_inM2rA8pBn2LdxdjG-irltQpYIQPMo,12932
|
|
39
|
-
agno/db/dynamo/utils.py,sha256=
|
|
39
|
+
agno/db/dynamo/utils.py,sha256=2tt1poijpdsKqh4jipiP_ZeJ5tvwWlxNLqLrRzCnd2U,27394
|
|
40
40
|
agno/db/firestore/__init__.py,sha256=lYAJjUs4jMxJFty1GYZw464K35zeuBlcoFR9uuIQYtI,79
|
|
41
41
|
agno/db/firestore/firestore.py,sha256=ck2UtZzoSfOjXUOR_BXf2LuZ66pNidPkA5_-aKSWhq0,70496
|
|
42
42
|
agno/db/firestore/schemas.py,sha256=sPbi2teuzCfRECnCyj6LrNNu0drSqbBHpH-o1xoJYfs,4392
|
|
43
|
-
agno/db/firestore/utils.py,sha256=
|
|
43
|
+
agno/db/firestore/utils.py,sha256=hQudu539CDkEKG1GvtDPOJbzdhIpSTE7Y-Uu8IdooDU,13812
|
|
44
44
|
agno/db/gcs_json/__init__.py,sha256=aTR4o3aFrzfANHtRw7nX9uc5_GsY52ch0rmoo7uXuc4,76
|
|
45
45
|
agno/db/gcs_json/gcs_json_db.py,sha256=vtLrWlwEALSDAkHu3k8YEthkBLGENuYyO1yH493NOc8,54561
|
|
46
|
-
agno/db/gcs_json/utils.py,sha256=
|
|
46
|
+
agno/db/gcs_json/utils.py,sha256=mleGhIY2J7s5rPUteQbIBosJQgRsRDPNJEwGBzh7Hws,8008
|
|
47
47
|
agno/db/in_memory/__init__.py,sha256=OvR_FONhOh9PmcRfUA_6gvplZT5UGIBAgVKqVg6SWTA,80
|
|
48
48
|
agno/db/in_memory/in_memory_db.py,sha256=IapPmv178SXv5Gy9t395PjvvcjpyIDNt_mpwL-2QGB8,45991
|
|
49
|
-
agno/db/in_memory/utils.py,sha256=
|
|
49
|
+
agno/db/in_memory/utils.py,sha256=KM-FlcN8IszNU4dtP82oSAg5ImpYil3ygH0mOxWV2Ns,8061
|
|
50
50
|
agno/db/json/__init__.py,sha256=zyPTmVF9S-OwXCL7FSkrDmunZ_Q14YZO3NYUv1Pa14Y,62
|
|
51
51
|
agno/db/json/json_db.py,sha256=JgBintmR0gGaXsPLTprgvawpivXbEXhhW_2h5da5HB8,52632
|
|
52
|
-
agno/db/json/utils.py,sha256=
|
|
52
|
+
agno/db/json/utils.py,sha256=a4dOAKLIP8vHh64gZ3ebBTrf69EzSM4vd2_80_WwRa8,8056
|
|
53
53
|
agno/db/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
54
|
agno/db/migrations/v1_to_v2.py,sha256=gj8deaEWUxOr0qJyMfjOpV3LxEh-otOSOxDckeUq0qU,24938
|
|
55
55
|
agno/db/mongo/__init__.py,sha256=NG2WC2jE5PX1kMXTYCVHjhomf5DAJgvzSj45QHdvl2E,466
|
|
56
|
-
agno/db/mongo/async_mongo.py,sha256=
|
|
56
|
+
agno/db/mongo/async_mongo.py,sha256=7U7wTcqWewtR4a_aJi108GjD9uTw4oGmuNOXfMIrZf8,80357
|
|
57
57
|
agno/db/mongo/mongo.py,sha256=0Mqr_U_ViK8S7clJR6nre-bAMaaGvfhEdSQtgKP9gfw,77034
|
|
58
58
|
agno/db/mongo/schemas.py,sha256=d2ZxqqzKYwz0Iexgrv1HWArGnmk3KUKJ37PCzFykodI,2314
|
|
59
|
-
agno/db/mongo/utils.py,sha256=
|
|
59
|
+
agno/db/mongo/utils.py,sha256=9xdra4QRe01f441VrSpBMMy9gv7SYeKrJJchlOdwfsE,9252
|
|
60
60
|
agno/db/mysql/__init__.py,sha256=ohBMZ1E6ctioEF0XX5PjC4LtUQrc6lFkjsE4ojyXA8g,63
|
|
61
61
|
agno/db/mysql/mysql.py,sha256=rkfUFwOcJ2lxyPq1QE0SItJ0ZhP2oY1Zj556jSJ77xk,95134
|
|
62
62
|
agno/db/mysql/schemas.py,sha256=OpdAWhh-ElwQ5JOg1MKJqGJ16qzVTuyS56iH9Zw3oHs,6171
|
|
63
|
-
agno/db/mysql/utils.py,sha256=
|
|
63
|
+
agno/db/mysql/utils.py,sha256=XHuvgI-xAe0Y0sBZWSXW9B0xM0KKgI-JDssG7Tyqlbs,12360
|
|
64
64
|
agno/db/postgres/__init__.py,sha256=Ojk00nTCzQFiH2ViD7KIBjgpkTKLRNPCwWnuXMKtNXY,154
|
|
65
|
-
agno/db/postgres/async_postgres.py,sha256=
|
|
65
|
+
agno/db/postgres/async_postgres.py,sha256=y3l3R6gw4xb9Wlhh5YYrnEJ-n-Rmqzne2MC9FYKzxtA,78604
|
|
66
66
|
agno/db/postgres/postgres.py,sha256=HnxdgdIFik3fPnFQLtAmz4y5y0EDNMcKzfh-Wlh8SoM,91345
|
|
67
67
|
agno/db/postgres/schemas.py,sha256=O049oyPU07tHwnyuOzYyiKcK1NYvh6cQmmsFOvA7LTs,5971
|
|
68
|
-
agno/db/postgres/utils.py,sha256=
|
|
68
|
+
agno/db/postgres/utils.py,sha256=ZHWmVlx96pqI07h-hoiMm6TZTsudpf2zxID4MJtiY9s,15465
|
|
69
69
|
agno/db/redis/__init__.py,sha256=rZWeZ4CpVeKP-enVQ-SRoJ777i0rdGNgoNDRS9gsfAc,63
|
|
70
70
|
agno/db/redis/redis.py,sha256=QoM8J8uXCv5x5w0RZsFs9mpNzctXkCSBaZo46rrHvxs,62821
|
|
71
71
|
agno/db/redis/schemas.py,sha256=3WilZq3NqZqRONyu_mAjjmQpClgYDYoWjfkvlOh0Tfw,4038
|
|
72
|
-
agno/db/redis/utils.py,sha256=
|
|
72
|
+
agno/db/redis/utils.py,sha256=4iql9MavWM3okOhuOFKK7r0TP1AAT5qAAbiL5jTE84k,11236
|
|
73
73
|
agno/db/schemas/__init__.py,sha256=g72Zr5_nm00yXHStv4pf9PG9bGLKXEK7Av6YQtrDbCQ,147
|
|
74
74
|
agno/db/schemas/culture.py,sha256=w4azKAVLf5X4xyRUFXMIEq0CA0pnyeN03W3eMpqScxo,4342
|
|
75
75
|
agno/db/schemas/evals.py,sha256=T1zIiwrN5fxZVD2em85wQ9CV-HSVZvNF4D4v9_w30VA,786
|
|
@@ -79,12 +79,12 @@ agno/db/schemas/metrics.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
79
79
|
agno/db/singlestore/__init__.py,sha256=dufbaod8ZZIeZIVi0hYJQ8Eu2DfIfWdIy00cpqAsx9U,87
|
|
80
80
|
agno/db/singlestore/schemas.py,sha256=Eb9wipCjWr48dlF3CMDa53WDvFsr7QhLOSaTgbUkMKg,6178
|
|
81
81
|
agno/db/singlestore/singlestore.py,sha256=B_RG3f67j7JLOQ_xs4bnGw8ZjTLqopzd5GGg2GjTPUc,93042
|
|
82
|
-
agno/db/singlestore/utils.py,sha256=
|
|
82
|
+
agno/db/singlestore/utils.py,sha256=NnA6YJAk1Oj-5w7Y-juxuQ7eiFnpjVAiGCV5U7QcjVE,13671
|
|
83
83
|
agno/db/sqlite/__init__.py,sha256=09V3i4y0-tBjt60--57ivZ__SaaS67GCsDT4Apzv-5Y,138
|
|
84
84
|
agno/db/sqlite/async_sqlite.py,sha256=EGHkhETD-UPxzm0wvOHJo99BlOOddW1NRtahNnpFTFw,95604
|
|
85
85
|
agno/db/sqlite/schemas.py,sha256=NyEvAFG-hi3Inm5femgJdorxJ5l2-bXLWBhxJ4r7jW0,5832
|
|
86
86
|
agno/db/sqlite/sqlite.py,sha256=NQfh56217Xki1KnDCM_kAfPjn4RHz_0wYbXJBaUOi3Q,93789
|
|
87
|
-
agno/db/sqlite/utils.py,sha256=
|
|
87
|
+
agno/db/sqlite/utils.py,sha256=21Z1PjQNjz1QaeY0BQY-abg0sv0nIJJ3oHuFUTV-raU,15551
|
|
88
88
|
agno/db/surrealdb/__init__.py,sha256=C8qp5-Nx9YnSmgKEtGua-sqG_ntCXONBw1qqnNyKPqI,75
|
|
89
89
|
agno/db/surrealdb/metrics.py,sha256=oKDRyjRQ6KR3HaO8zDHQLVMG7-0NDkOFOKX5I7mD5FA,10336
|
|
90
90
|
agno/db/surrealdb/models.py,sha256=2KBxSxiEI4yQ2OTOr1HVeL8Fd52tQfWkM53kwzqUmyw,11512
|
|
@@ -133,7 +133,7 @@ agno/knowledge/embedder/jina.py,sha256=M2M2ki0XyylyitJs_ZL2JoepC1y70IJzYntPsCVUx
|
|
|
133
133
|
agno/knowledge/embedder/langdb.py,sha256=_vbE1Jbj16WGP4aEkh54D7ESTu0LlI1_lp5WiXPIABA,731
|
|
134
134
|
agno/knowledge/embedder/mistral.py,sha256=AMc3VBpQCKFxetx2gRd9c6iRvR4-bSEWJ1Q4JPwQg28,8608
|
|
135
135
|
agno/knowledge/embedder/nebius.py,sha256=4I2irehvR6Di00Al4jbG4vAa6KZnbOJ-7QqVjB7Mn64,363
|
|
136
|
-
agno/knowledge/embedder/ollama.py,sha256=
|
|
136
|
+
agno/knowledge/embedder/ollama.py,sha256=faLkOvPt2dWs8h87anAgeeG3LJpMH4jVMWP7_3f7JHs,6313
|
|
137
137
|
agno/knowledge/embedder/openai.py,sha256=oUEyqIyREIPYRCtQBjAn-aIjxI7DQkMZQmXOt0OkLbo,7331
|
|
138
138
|
agno/knowledge/embedder/sentence_transformer.py,sha256=khJJbJlBFDeVJm7yd4ub3e7n7rM-l5z00f594jGtIaU,2203
|
|
139
139
|
agno/knowledge/embedder/together.py,sha256=Pt524Lh6YRDKfD8rfmLu0Qlw4dDh4vLz7KEMIvIULBk,387
|
|
@@ -165,7 +165,7 @@ agno/knowledge/reranker/cohere.py,sha256=2Be5blVyeZ3vYlnFa2NYvJuytjaCB8G2OWJ11pQ
|
|
|
165
165
|
agno/knowledge/reranker/infinity.py,sha256=N9geg9xZqRdJZksfQcvbGJgMymXrQVJl_K5KICWqH8o,7193
|
|
166
166
|
agno/knowledge/reranker/sentence_transformer.py,sha256=ZN4SqnMZsUhg5G7AzlONM1_UjezfNrjFYXpNVHD4U-U,1912
|
|
167
167
|
agno/memory/__init__.py,sha256=XWKJU5SJObYZqEKMZ2XYwgH8-YeuWUoSRfT4dEI5HnY,101
|
|
168
|
-
agno/memory/manager.py,sha256=
|
|
168
|
+
agno/memory/manager.py,sha256=p7ZHhzrfYYEj_7ALCdvU72qWa_qtxkQc-A9taqVfLAw,51829
|
|
169
169
|
agno/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
170
170
|
agno/models/base.py,sha256=6ucSAOgG95n6uT2VaWp8QtZctVnH67FS4JwYt4P4_Rw,95015
|
|
171
171
|
agno/models/defaults.py,sha256=1_fe4-ZbNriE8BgqxVRVi4KGzEYxYKYsz4hn6CZNEEM,40
|
|
@@ -257,7 +257,7 @@ agno/models/vllm/vllm.py,sha256=UtiiSvUR4pG_1CzuhY5MWduRgzM2hGVTakKJ6ZBdQmo,2730
|
|
|
257
257
|
agno/models/xai/__init__.py,sha256=ukcCxnCHxTtkJNA2bAMTX4MhCv1wJcbiq8ZIfYczIxs,55
|
|
258
258
|
agno/models/xai/xai.py,sha256=jA6_39tfapkjkHKdzbKaNq1t9qIvO1IaZY1hQqEmFVs,4181
|
|
259
259
|
agno/os/__init__.py,sha256=h8oQu7vhD5RZf09jkyM_Kt1Kdq_d5kFB9gJju8QPwcY,55
|
|
260
|
-
agno/os/app.py,sha256=
|
|
260
|
+
agno/os/app.py,sha256=N6sBJqx2ShfuPaPJdy3waHC5cZ5OH-Owa0ApgTojNm8,30217
|
|
261
261
|
agno/os/auth.py,sha256=FyBtAKWtg-qSunCas5m5pK1dVEmikOSZvcCp5r25tTA,1844
|
|
262
262
|
agno/os/config.py,sha256=u4R9yazQXIcKjR3QzEIZw_XAe_OHp3xn0ff7SVkj2jA,2893
|
|
263
263
|
agno/os/mcp.py,sha256=vJhjjSm1KC61HLoxPj24lSrjkjo7plkoFfcQX2BmTp0,10253
|
|
@@ -316,19 +316,19 @@ agno/reasoning/openai.py,sha256=JYk-mR9cMf1ibprX3MdL8oeCEDyQ3XaJw9PAIYvWeGk,3234
|
|
|
316
316
|
agno/reasoning/step.py,sha256=6DaOb_0DJRz9Yh1w_mxcRaOSVzIQDrj3lQ6rzHLdIwA,1220
|
|
317
317
|
agno/reasoning/vertexai.py,sha256=O9ntvalkIY2jLmWviEH1DnecMskqTL-mRZQBZohoHiU,2974
|
|
318
318
|
agno/run/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
319
|
-
agno/run/agent.py,sha256=
|
|
319
|
+
agno/run/agent.py,sha256=uTtruA2DCrt5qPuAH6QuDQZ-s4E7TEP8NkIGBE7n-OA,26887
|
|
320
320
|
agno/run/base.py,sha256=2KEu0TLfCM-0Dd3JQ6aSQf_dqtKHtDIUt0oCPdk7rIk,7756
|
|
321
321
|
agno/run/cancel.py,sha256=yoSj3fnx8D7Gf-fSngVIgd3GOp3tRaDhHH_4QeHDoAk,2667
|
|
322
322
|
agno/run/messages.py,sha256=rAC4CLW-xBA6qFS1BOvcjJ9j_qYf0a7sX1mcdY04zMU,1126
|
|
323
|
-
agno/run/team.py,sha256=
|
|
323
|
+
agno/run/team.py,sha256=hR61LilAVVvVzVTbyJ600youEP29poX2CosmKa0f4kU,27343
|
|
324
324
|
agno/run/workflow.py,sha256=dxnrvG7icRt7oOiFYyJvqI_XpSj4A0dCAMRCmsSo1XQ,23377
|
|
325
325
|
agno/session/__init__.py,sha256=p6eqzWcLSHiMex2yZvkwv2yrFUNdGs21TGMS49xrEC4,376
|
|
326
|
-
agno/session/agent.py,sha256=
|
|
326
|
+
agno/session/agent.py,sha256=UGgDQB5nTxFwJcqWpWAmRGjXMLhwSCqRXDyoEi5a-jg,11763
|
|
327
327
|
agno/session/summary.py,sha256=JEvSnvOgYf6pxmExXsQu7kQGx5p4OLVuQtgsypz2jhY,10130
|
|
328
|
-
agno/session/team.py,sha256=
|
|
328
|
+
agno/session/team.py,sha256=M9QEmGYyQM64ZsvPWRdp1xZV6EQGuun6pjJL05AzU-k,15260
|
|
329
329
|
agno/session/workflow.py,sha256=tluE_3ERMBYJtffpwlrhdETWlzJk6Xw2x06FZ1Y3fXg,7397
|
|
330
330
|
agno/team/__init__.py,sha256=toHidBOo5M3n_TIVtIKHgcDbLL9HR-_U-YQYuIt_XtE,847
|
|
331
|
-
agno/team/team.py,sha256=
|
|
331
|
+
agno/team/team.py,sha256=s1Xd-1S50HJR7iDhJM1lw-gYTRKhEs_fsUT8aZpS56Y,400633
|
|
332
332
|
agno/tools/__init__.py,sha256=jNll2sELhPPbqm5nPeT4_uyzRO2_KRTW-8Or60kioS0,210
|
|
333
333
|
agno/tools/agentql.py,sha256=S82Z9aTNr-E5wnA4fbFs76COljJtiQIjf2grjz3CkHU,4104
|
|
334
334
|
agno/tools/airflow.py,sha256=uf2rOzZpSU64l_qRJ5Raku-R3Gky-uewmYkh6W0-oxg,2610
|
|
@@ -561,8 +561,8 @@ agno/workflow/step.py,sha256=3t83LwEajM-jHjcXzJR74iEO36P4ZVqenocmiWLtQOg,60532
|
|
|
561
561
|
agno/workflow/steps.py,sha256=O3lbKw56ziSnuJndAGm8hjlEwdTh2jQXf1s0587Va3M,25671
|
|
562
562
|
agno/workflow/types.py,sha256=J474F5MWHCHHVjrzTUPJihlcrRLUnQ3hVW2-9TWdxWw,18519
|
|
563
563
|
agno/workflow/workflow.py,sha256=LBy_jVjvglRE4sOLAITZGaOJctJYbP59oV0HvuiHopA,147346
|
|
564
|
-
agno-2.2.
|
|
565
|
-
agno-2.2.
|
|
566
|
-
agno-2.2.
|
|
567
|
-
agno-2.2.
|
|
568
|
-
agno-2.2.
|
|
564
|
+
agno-2.2.4.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
|
565
|
+
agno-2.2.4.dist-info/METADATA,sha256=IRtlV1luuV_lGWilSVIOVmjhZnUf90G2ZbRPJBHQKNA,28193
|
|
566
|
+
agno-2.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
567
|
+
agno-2.2.4.dist-info/top_level.txt,sha256=MKyeuVesTyOKIXUhc-d_tPa2Hrh0oTA4LM0izowpx70,5
|
|
568
|
+
agno-2.2.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|