agno 2.2.13__py3-none-any.whl → 2.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/agent/agent.py +197 -110
- agno/api/api.py +2 -0
- agno/db/base.py +26 -0
- agno/db/dynamo/dynamo.py +8 -0
- agno/db/dynamo/schemas.py +1 -0
- agno/db/firestore/firestore.py +8 -0
- agno/db/firestore/schemas.py +1 -0
- agno/db/gcs_json/gcs_json_db.py +8 -0
- agno/db/in_memory/in_memory_db.py +8 -1
- agno/db/json/json_db.py +8 -0
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/async_mongo.py +16 -6
- agno/db/mongo/mongo.py +11 -0
- agno/db/mongo/schemas.py +3 -0
- agno/db/mongo/utils.py +17 -0
- agno/db/mysql/mysql.py +76 -3
- agno/db/mysql/schemas.py +20 -10
- agno/db/postgres/async_postgres.py +99 -25
- agno/db/postgres/postgres.py +75 -6
- agno/db/postgres/schemas.py +30 -20
- agno/db/redis/redis.py +15 -2
- agno/db/redis/schemas.py +4 -0
- agno/db/schemas/memory.py +13 -0
- agno/db/singlestore/schemas.py +11 -0
- agno/db/singlestore/singlestore.py +79 -5
- agno/db/sqlite/async_sqlite.py +97 -19
- agno/db/sqlite/schemas.py +10 -0
- agno/db/sqlite/sqlite.py +79 -2
- agno/db/surrealdb/surrealdb.py +8 -0
- agno/knowledge/chunking/semantic.py +7 -2
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/knowledge.py +57 -86
- agno/knowledge/reader/csv_reader.py +7 -9
- agno/knowledge/reader/docx_reader.py +5 -5
- agno/knowledge/reader/field_labeled_csv_reader.py +16 -18
- agno/knowledge/reader/json_reader.py +5 -4
- agno/knowledge/reader/markdown_reader.py +8 -8
- agno/knowledge/reader/pdf_reader.py +11 -11
- agno/knowledge/reader/pptx_reader.py +5 -5
- agno/knowledge/reader/s3_reader.py +3 -3
- agno/knowledge/reader/text_reader.py +8 -8
- agno/knowledge/reader/web_search_reader.py +1 -48
- agno/knowledge/reader/website_reader.py +10 -10
- agno/models/anthropic/claude.py +319 -28
- agno/models/aws/claude.py +32 -0
- agno/models/azure/openai_chat.py +19 -10
- agno/models/base.py +612 -545
- agno/models/cerebras/cerebras.py +8 -11
- agno/models/cohere/chat.py +27 -1
- agno/models/google/gemini.py +39 -7
- agno/models/groq/groq.py +25 -11
- agno/models/meta/llama.py +20 -9
- agno/models/meta/llama_openai.py +3 -19
- agno/models/nebius/nebius.py +4 -4
- agno/models/openai/chat.py +30 -14
- agno/models/openai/responses.py +10 -13
- agno/models/response.py +1 -0
- agno/models/vertexai/claude.py +26 -0
- agno/os/app.py +8 -19
- agno/os/router.py +54 -0
- agno/os/routers/knowledge/knowledge.py +2 -2
- agno/os/schema.py +2 -2
- agno/session/agent.py +57 -92
- agno/session/summary.py +1 -1
- agno/session/team.py +62 -112
- agno/session/workflow.py +353 -57
- agno/team/team.py +227 -125
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/nano_banana.py +151 -0
- agno/tools/yfinance.py +12 -11
- agno/utils/http.py +111 -0
- agno/utils/media.py +11 -0
- agno/utils/models/claude.py +8 -0
- agno/utils/print_response/agent.py +33 -12
- agno/utils/print_response/team.py +22 -12
- agno/vectordb/couchbase/couchbase.py +6 -2
- agno/workflow/condition.py +13 -0
- agno/workflow/loop.py +13 -0
- agno/workflow/parallel.py +13 -0
- agno/workflow/router.py +13 -0
- agno/workflow/step.py +120 -20
- agno/workflow/steps.py +13 -0
- agno/workflow/workflow.py +76 -63
- {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/METADATA +6 -2
- {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/RECORD +91 -88
- agno/tools/googlesearch.py +0 -98
- {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/WHEEL +0 -0
- {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/top_level.txt +0 -0
agno/agent/agent.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import warnings
|
|
3
4
|
from asyncio import CancelledError, create_task
|
|
4
5
|
from collections import ChainMap, deque
|
|
5
6
|
from dataclasses import dataclass
|
|
@@ -72,7 +73,6 @@ from agno.session.summary import SessionSummary
|
|
|
72
73
|
from agno.tools import Toolkit
|
|
73
74
|
from agno.tools.function import Function
|
|
74
75
|
from agno.utils.agent import (
|
|
75
|
-
aget_chat_history_util,
|
|
76
76
|
aget_last_run_output_util,
|
|
77
77
|
aget_run_output_util,
|
|
78
78
|
aget_session_metrics_util,
|
|
@@ -86,7 +86,6 @@ from agno.utils.agent import (
|
|
|
86
86
|
collect_joint_files,
|
|
87
87
|
collect_joint_images,
|
|
88
88
|
collect_joint_videos,
|
|
89
|
-
get_chat_history_util,
|
|
90
89
|
get_last_run_output_util,
|
|
91
90
|
get_run_output_util,
|
|
92
91
|
get_session_metrics_util,
|
|
@@ -376,8 +375,6 @@ class Agent:
|
|
|
376
375
|
stream: Optional[bool] = None
|
|
377
376
|
# Stream the intermediate steps from the Agent
|
|
378
377
|
stream_events: Optional[bool] = None
|
|
379
|
-
# [Deprecated] Stream the intermediate steps from the Agent
|
|
380
|
-
stream_intermediate_steps: Optional[bool] = None
|
|
381
378
|
|
|
382
379
|
# Persist the events on the run response
|
|
383
380
|
store_events: bool = False
|
|
@@ -417,6 +414,9 @@ class Agent:
|
|
|
417
414
|
# This helps us improve the Agent and provide better support
|
|
418
415
|
telemetry: bool = True
|
|
419
416
|
|
|
417
|
+
# Deprecated. Use stream_events instead
|
|
418
|
+
stream_intermediate_steps: Optional[bool] = None
|
|
419
|
+
|
|
420
420
|
def __init__(
|
|
421
421
|
self,
|
|
422
422
|
*,
|
|
@@ -627,6 +627,13 @@ class Agent:
|
|
|
627
627
|
self.save_response_to_file = save_response_to_file
|
|
628
628
|
|
|
629
629
|
self.stream = stream
|
|
630
|
+
|
|
631
|
+
if stream_intermediate_steps is not None:
|
|
632
|
+
warnings.warn(
|
|
633
|
+
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
634
|
+
DeprecationWarning,
|
|
635
|
+
stacklevel=2,
|
|
636
|
+
)
|
|
630
637
|
self.stream_events = stream_events or stream_intermediate_steps
|
|
631
638
|
|
|
632
639
|
self.store_events = store_events
|
|
@@ -1538,6 +1545,13 @@ class Agent:
|
|
|
1538
1545
|
"add_history_to_context is True, but no database has been assigned to the agent. History will not be added to the context."
|
|
1539
1546
|
)
|
|
1540
1547
|
|
|
1548
|
+
if yield_run_response is not None:
|
|
1549
|
+
warnings.warn(
|
|
1550
|
+
"The 'yield_run_response' parameter is deprecated and will be removed in future versions. Use 'yield_run_output' instead.",
|
|
1551
|
+
DeprecationWarning,
|
|
1552
|
+
stacklevel=2,
|
|
1553
|
+
)
|
|
1554
|
+
|
|
1541
1555
|
# Create a run_id for this specific run
|
|
1542
1556
|
run_id = str(uuid4())
|
|
1543
1557
|
|
|
@@ -1616,6 +1630,12 @@ class Agent:
|
|
|
1616
1630
|
stream = False if self.stream is None else self.stream
|
|
1617
1631
|
|
|
1618
1632
|
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
1633
|
+
if stream_intermediate_steps is not None:
|
|
1634
|
+
warnings.warn(
|
|
1635
|
+
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
1636
|
+
DeprecationWarning,
|
|
1637
|
+
stacklevel=2,
|
|
1638
|
+
)
|
|
1619
1639
|
stream_events = stream_events or stream_intermediate_steps
|
|
1620
1640
|
|
|
1621
1641
|
# Can't stream events if streaming is disabled
|
|
@@ -2003,6 +2023,7 @@ class Agent:
|
|
|
2003
2023
|
await cultural_knowledge_task
|
|
2004
2024
|
except CancelledError:
|
|
2005
2025
|
pass
|
|
2026
|
+
|
|
2006
2027
|
# Always clean up the run tracking
|
|
2007
2028
|
cleanup_run(run_response.run_id) # type: ignore
|
|
2008
2029
|
|
|
@@ -2458,6 +2479,13 @@ class Agent:
|
|
|
2458
2479
|
"add_history_to_context is True, but no database has been assigned to the agent. History will not be added to the context."
|
|
2459
2480
|
)
|
|
2460
2481
|
|
|
2482
|
+
if yield_run_response is not None:
|
|
2483
|
+
warnings.warn(
|
|
2484
|
+
"The 'yield_run_response' parameter is deprecated and will be removed in future versions. Use 'yield_run_output' instead.",
|
|
2485
|
+
DeprecationWarning,
|
|
2486
|
+
stacklevel=2,
|
|
2487
|
+
)
|
|
2488
|
+
|
|
2461
2489
|
# Create a run_id for this specific run
|
|
2462
2490
|
run_id = str(uuid4())
|
|
2463
2491
|
|
|
@@ -2508,6 +2536,12 @@ class Agent:
|
|
|
2508
2536
|
stream = False if self.stream is None else self.stream
|
|
2509
2537
|
|
|
2510
2538
|
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
2539
|
+
if stream_intermediate_steps is not None:
|
|
2540
|
+
warnings.warn(
|
|
2541
|
+
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
2542
|
+
DeprecationWarning,
|
|
2543
|
+
stacklevel=2,
|
|
2544
|
+
)
|
|
2511
2545
|
stream_events = stream_events or stream_intermediate_steps
|
|
2512
2546
|
|
|
2513
2547
|
# Can't stream events if streaming is disabled
|
|
@@ -2790,6 +2824,12 @@ class Agent:
|
|
|
2790
2824
|
stream = False if self.stream is None else self.stream
|
|
2791
2825
|
|
|
2792
2826
|
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
2827
|
+
if stream_intermediate_steps is not None:
|
|
2828
|
+
warnings.warn(
|
|
2829
|
+
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
2830
|
+
DeprecationWarning,
|
|
2831
|
+
stacklevel=2,
|
|
2832
|
+
)
|
|
2793
2833
|
stream_events = stream_events or stream_intermediate_steps
|
|
2794
2834
|
|
|
2795
2835
|
# Can't stream events if streaming is disabled
|
|
@@ -3313,6 +3353,12 @@ class Agent:
|
|
|
3313
3353
|
stream = False if self.stream is None else self.stream
|
|
3314
3354
|
|
|
3315
3355
|
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
3356
|
+
if stream_intermediate_steps is not None:
|
|
3357
|
+
warnings.warn(
|
|
3358
|
+
"The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Use 'stream_events' instead.",
|
|
3359
|
+
DeprecationWarning,
|
|
3360
|
+
stacklevel=2,
|
|
3361
|
+
)
|
|
3316
3362
|
stream_events = stream_events or stream_intermediate_steps
|
|
3317
3363
|
|
|
3318
3364
|
# Can't stream events if streaming is disabled
|
|
@@ -6168,36 +6214,6 @@ class Agent:
|
|
|
6168
6214
|
self._upsert_session(session=session)
|
|
6169
6215
|
log_debug(f"Created or updated AgentSession record: {session.session_id}")
|
|
6170
6216
|
|
|
6171
|
-
def get_chat_history(self, session_id: Optional[str] = None) -> List[Message]:
|
|
6172
|
-
"""Read the chat history from the session
|
|
6173
|
-
|
|
6174
|
-
Args:
|
|
6175
|
-
session_id: The session ID to get the chat history for. If not provided, the current cached session ID is used.
|
|
6176
|
-
Returns:
|
|
6177
|
-
List[Message]: The chat history from the session.
|
|
6178
|
-
"""
|
|
6179
|
-
session_id = session_id or self.session_id
|
|
6180
|
-
if session_id is None:
|
|
6181
|
-
log_warning("Session ID is not set, cannot get chat history")
|
|
6182
|
-
return []
|
|
6183
|
-
|
|
6184
|
-
return get_chat_history_util(self, session_id=session_id)
|
|
6185
|
-
|
|
6186
|
-
async def aget_chat_history(self, session_id: Optional[str] = None) -> List[Message]:
|
|
6187
|
-
"""Read the chat history from the session
|
|
6188
|
-
|
|
6189
|
-
Args:
|
|
6190
|
-
session_id: The session ID to get the chat history for. If not provided, the current cached session ID is used.
|
|
6191
|
-
Returns:
|
|
6192
|
-
List[Message]: The chat history from the session.
|
|
6193
|
-
"""
|
|
6194
|
-
session_id = session_id or self.session_id
|
|
6195
|
-
if session_id is None:
|
|
6196
|
-
log_warning("Session ID is not set, cannot get chat history")
|
|
6197
|
-
return []
|
|
6198
|
-
|
|
6199
|
-
return await aget_chat_history_util(self, session_id=session_id)
|
|
6200
|
-
|
|
6201
6217
|
# -*- Session Management Functions
|
|
6202
6218
|
def rename(self, name: str, session_id: Optional[str] = None) -> None:
|
|
6203
6219
|
"""
|
|
@@ -6311,7 +6327,7 @@ class Agent:
|
|
|
6311
6327
|
|
|
6312
6328
|
gen_session_name_prompt = "Conversation\n"
|
|
6313
6329
|
|
|
6314
|
-
messages_for_generating_session_name = session.
|
|
6330
|
+
messages_for_generating_session_name = session.get_messages()
|
|
6315
6331
|
|
|
6316
6332
|
for message in messages_for_generating_session_name:
|
|
6317
6333
|
gen_session_name_prompt += f"{message.role.upper()}: {message.content}\n"
|
|
@@ -6467,11 +6483,25 @@ class Agent:
|
|
|
6467
6483
|
return
|
|
6468
6484
|
await self.db.delete_session(session_id=session_id) # type: ignore
|
|
6469
6485
|
|
|
6470
|
-
def
|
|
6471
|
-
|
|
6486
|
+
def get_session_messages(
|
|
6487
|
+
self,
|
|
6488
|
+
session_id: Optional[str] = None,
|
|
6489
|
+
last_n_runs: Optional[int] = None,
|
|
6490
|
+
limit: Optional[int] = None,
|
|
6491
|
+
skip_roles: Optional[List[str]] = None,
|
|
6492
|
+
skip_statuses: Optional[List[RunStatus]] = None,
|
|
6493
|
+
skip_history_messages: bool = True,
|
|
6494
|
+
) -> List[Message]:
|
|
6495
|
+
"""Get all messages belonging to the given session.
|
|
6472
6496
|
|
|
6473
6497
|
Args:
|
|
6474
|
-
session_id: The session ID to get the messages for. If not provided, the
|
|
6498
|
+
session_id: The session ID to get the messages for. If not provided, the latest used session ID is used.
|
|
6499
|
+
last_n_runs: The number of runs to return messages from, counting from the latest. Defaults to all runs.
|
|
6500
|
+
limit: The number of messages to return, counting from the latest. Defaults to all messages.
|
|
6501
|
+
skip_roles: Skip messages with these roles.
|
|
6502
|
+
skip_statuses: Skip messages with these statuses.
|
|
6503
|
+
skip_history_messages: Skip messages that were tagged as history in previous runs.
|
|
6504
|
+
|
|
6475
6505
|
Returns:
|
|
6476
6506
|
List[Message]: The messages for the session.
|
|
6477
6507
|
"""
|
|
@@ -6481,20 +6511,49 @@ class Agent:
|
|
|
6481
6511
|
return []
|
|
6482
6512
|
|
|
6483
6513
|
session = self.get_session(session_id=session_id)
|
|
6484
|
-
|
|
6485
6514
|
if session is None:
|
|
6486
6515
|
raise Exception("Session not found")
|
|
6487
6516
|
|
|
6488
|
-
#
|
|
6489
|
-
|
|
6517
|
+
# Handle the case in which the agent is reusing a team session
|
|
6518
|
+
if isinstance(session, TeamSession):
|
|
6519
|
+
return session.get_messages(
|
|
6520
|
+
member_ids=[self.id] if self.team_id and self.id else None,
|
|
6521
|
+
last_n_runs=last_n_runs,
|
|
6522
|
+
limit=limit,
|
|
6523
|
+
skip_roles=skip_roles,
|
|
6524
|
+
skip_statuses=skip_statuses,
|
|
6525
|
+
skip_history_messages=skip_history_messages,
|
|
6526
|
+
)
|
|
6527
|
+
|
|
6528
|
+
return session.get_messages(
|
|
6529
|
+
# Only filter by agent_id if this is part of a team
|
|
6490
6530
|
agent_id=self.id if self.team_id is not None else None,
|
|
6531
|
+
last_n_runs=last_n_runs,
|
|
6532
|
+
limit=limit,
|
|
6533
|
+
skip_roles=skip_roles,
|
|
6534
|
+
skip_statuses=skip_statuses,
|
|
6535
|
+
skip_history_messages=skip_history_messages,
|
|
6491
6536
|
)
|
|
6492
6537
|
|
|
6493
|
-
async def
|
|
6494
|
-
|
|
6538
|
+
async def aget_session_messages(
|
|
6539
|
+
self,
|
|
6540
|
+
session_id: Optional[str] = None,
|
|
6541
|
+
last_n_runs: Optional[int] = None,
|
|
6542
|
+
limit: Optional[int] = None,
|
|
6543
|
+
skip_roles: Optional[List[str]] = None,
|
|
6544
|
+
skip_statuses: Optional[List[RunStatus]] = None,
|
|
6545
|
+
skip_history_messages: bool = True,
|
|
6546
|
+
) -> List[Message]:
|
|
6547
|
+
"""Get all messages belonging to the given session.
|
|
6495
6548
|
|
|
6496
6549
|
Args:
|
|
6497
6550
|
session_id: The session ID to get the messages for. If not provided, the current cached session ID is used.
|
|
6551
|
+
last_n_runs: The number of runs to return messages from, counting from the latest. Defaults to all runs.
|
|
6552
|
+
limit: The number of messages to return, counting from the latest. Defaults to all messages.
|
|
6553
|
+
skip_roles: Skip messages with these roles.
|
|
6554
|
+
skip_statuses: Skip messages with these statuses.
|
|
6555
|
+
skip_history_messages: Skip messages that were tagged as history in previous runs.
|
|
6556
|
+
|
|
6498
6557
|
Returns:
|
|
6499
6558
|
List[Message]: The messages for the session.
|
|
6500
6559
|
"""
|
|
@@ -6504,13 +6563,50 @@ class Agent:
|
|
|
6504
6563
|
return []
|
|
6505
6564
|
|
|
6506
6565
|
session = await self.aget_session(session_id=session_id)
|
|
6507
|
-
|
|
6508
6566
|
if session is None:
|
|
6509
6567
|
raise Exception("Session not found")
|
|
6510
6568
|
|
|
6569
|
+
# Handle the case in which the agent is reusing a team session
|
|
6570
|
+
if isinstance(session, TeamSession):
|
|
6571
|
+
return session.get_messages(
|
|
6572
|
+
member_ids=[self.id] if self.team_id and self.id else None,
|
|
6573
|
+
last_n_runs=last_n_runs,
|
|
6574
|
+
limit=limit,
|
|
6575
|
+
skip_roles=skip_roles,
|
|
6576
|
+
skip_statuses=skip_statuses,
|
|
6577
|
+
skip_history_messages=skip_history_messages,
|
|
6578
|
+
)
|
|
6579
|
+
|
|
6511
6580
|
# Only filter by agent_id if this is part of a team
|
|
6512
|
-
return session.
|
|
6581
|
+
return session.get_messages(
|
|
6513
6582
|
agent_id=self.id if self.team_id is not None else None,
|
|
6583
|
+
last_n_runs=last_n_runs,
|
|
6584
|
+
limit=limit,
|
|
6585
|
+
skip_roles=skip_roles,
|
|
6586
|
+
skip_statuses=skip_statuses,
|
|
6587
|
+
skip_history_messages=skip_history_messages,
|
|
6588
|
+
)
|
|
6589
|
+
|
|
6590
|
+
def get_chat_history(self, session_id: Optional[str] = None, last_n_runs: Optional[int] = None) -> List[Message]:
|
|
6591
|
+
"""Return the chat history (user and assistant messages) for the session.
|
|
6592
|
+
Use get_messages() for more filtering options.
|
|
6593
|
+
|
|
6594
|
+
Returns:
|
|
6595
|
+
A list of user and assistant Messages belonging to the session.
|
|
6596
|
+
"""
|
|
6597
|
+
return self.get_session_messages(session_id=session_id, last_n_runs=last_n_runs, skip_roles=["system", "tool"])
|
|
6598
|
+
|
|
6599
|
+
async def aget_chat_history(
|
|
6600
|
+
self, session_id: Optional[str] = None, last_n_runs: Optional[int] = None
|
|
6601
|
+
) -> List[Message]:
|
|
6602
|
+
"""Return the chat history (user and assistant messages) for the session.
|
|
6603
|
+
Use get_messages() for more filtering options.
|
|
6604
|
+
|
|
6605
|
+
Returns:
|
|
6606
|
+
A list of user and assistant Messages belonging to the session.
|
|
6607
|
+
"""
|
|
6608
|
+
return await self.aget_session_messages(
|
|
6609
|
+
session_id=session_id, last_n_runs=last_n_runs, skip_roles=["system", "tool"]
|
|
6514
6610
|
)
|
|
6515
6611
|
|
|
6516
6612
|
def get_session_summary(self, session_id: Optional[str] = None) -> Optional[SessionSummary]:
|
|
@@ -6518,6 +6614,7 @@ class Agent:
|
|
|
6518
6614
|
|
|
6519
6615
|
Args:
|
|
6520
6616
|
session_id: The session ID to get the summary for. If not provided, the current cached session ID is used.
|
|
6617
|
+
|
|
6521
6618
|
Returns:
|
|
6522
6619
|
SessionSummary: The session summary.
|
|
6523
6620
|
"""
|
|
@@ -7136,7 +7233,7 @@ class Agent:
|
|
|
7136
7233
|
|
|
7137
7234
|
# 3.2.5 Add information about agentic filters if enabled
|
|
7138
7235
|
if self.knowledge is not None and self.enable_agentic_knowledge_filters:
|
|
7139
|
-
valid_filters = await self.knowledge.
|
|
7236
|
+
valid_filters = await self.knowledge.async_get_valid_filters()
|
|
7140
7237
|
if valid_filters:
|
|
7141
7238
|
valid_filters_str = ", ".join(valid_filters)
|
|
7142
7239
|
additional_information.append(
|
|
@@ -7628,10 +7725,10 @@ class Agent:
|
|
|
7628
7725
|
self.system_message_role if self.system_message_role not in ["user", "assistant", "tool"] else None
|
|
7629
7726
|
)
|
|
7630
7727
|
|
|
7631
|
-
history: List[Message] = session.
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7728
|
+
history: List[Message] = session.get_messages(
|
|
7729
|
+
last_n_runs=self.num_history_runs,
|
|
7730
|
+
limit=self.num_history_messages,
|
|
7731
|
+
skip_roles=[skip_role] if skip_role else None,
|
|
7635
7732
|
agent_id=self.id if self.team_id is not None else None,
|
|
7636
7733
|
)
|
|
7637
7734
|
|
|
@@ -7841,10 +7938,10 @@ class Agent:
|
|
|
7841
7938
|
self.system_message_role if self.system_message_role not in ["user", "assistant", "tool"] else None
|
|
7842
7939
|
)
|
|
7843
7940
|
|
|
7844
|
-
history: List[Message] = session.
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7941
|
+
history: List[Message] = session.get_messages(
|
|
7942
|
+
last_n_runs=self.num_history_runs,
|
|
7943
|
+
limit=self.num_history_messages,
|
|
7944
|
+
skip_roles=[skip_role] if skip_role else None,
|
|
7848
7945
|
agent_id=self.id if self.team_id is not None else None,
|
|
7849
7946
|
)
|
|
7850
7947
|
|
|
@@ -8042,6 +8139,7 @@ class Agent:
|
|
|
8042
8139
|
query: str,
|
|
8043
8140
|
num_documents: Optional[int] = None,
|
|
8044
8141
|
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
8142
|
+
validate_filters: bool = False,
|
|
8045
8143
|
**kwargs,
|
|
8046
8144
|
) -> Optional[List[Union[Dict[str, Any], str]]]:
|
|
8047
8145
|
"""Get relevant docs from the knowledge base to answer a query.
|
|
@@ -8050,6 +8148,7 @@ class Agent:
|
|
|
8050
8148
|
query (str): The query to search for.
|
|
8051
8149
|
num_documents (Optional[int]): Number of documents to return.
|
|
8052
8150
|
filters (Optional[Dict[str, Any]]): Filters to apply to the search.
|
|
8151
|
+
validate_filters (bool): Whether to validate the filters against known valid filter keys.
|
|
8053
8152
|
**kwargs: Additional keyword arguments.
|
|
8054
8153
|
|
|
8055
8154
|
Returns:
|
|
@@ -8060,23 +8159,23 @@ class Agent:
|
|
|
8060
8159
|
if num_documents is None and self.knowledge is not None:
|
|
8061
8160
|
num_documents = self.knowledge.max_results
|
|
8062
8161
|
# Validate the filters against known valid filter keys
|
|
8063
|
-
if self.knowledge is not None:
|
|
8064
|
-
|
|
8162
|
+
if self.knowledge is not None and filters is not None:
|
|
8163
|
+
if validate_filters:
|
|
8164
|
+
valid_filters, invalid_keys = self.knowledge.validate_filters(filters) # type: ignore
|
|
8065
8165
|
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
log_info(f"Valid filter keys are: {self.knowledge.valid_metadata_filters}") # type: ignore
|
|
8166
|
+
# Warn about invalid filter keys
|
|
8167
|
+
if invalid_keys:
|
|
8168
|
+
# type: ignore
|
|
8169
|
+
log_warning(f"Invalid filter keys provided: {invalid_keys}. These filters will be ignored.")
|
|
8071
8170
|
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8171
|
+
# Only use valid filters
|
|
8172
|
+
filters = valid_filters
|
|
8173
|
+
if not filters:
|
|
8174
|
+
log_warning("No valid filters remain after validation. Search will proceed without filters.")
|
|
8076
8175
|
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8176
|
+
if invalid_keys == [] and valid_filters == {}:
|
|
8177
|
+
log_warning("No valid filters provided. Search will proceed without filters.")
|
|
8178
|
+
filters = None
|
|
8080
8179
|
|
|
8081
8180
|
if self.knowledge_retriever is not None and callable(self.knowledge_retriever):
|
|
8082
8181
|
from inspect import signature
|
|
@@ -8125,6 +8224,7 @@ class Agent:
|
|
|
8125
8224
|
query: str,
|
|
8126
8225
|
num_documents: Optional[int] = None,
|
|
8127
8226
|
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
8227
|
+
validate_filters: bool = False,
|
|
8128
8228
|
**kwargs,
|
|
8129
8229
|
) -> Optional[List[Union[Dict[str, Any], str]]]:
|
|
8130
8230
|
"""Get relevant documents from knowledge base asynchronously."""
|
|
@@ -8134,22 +8234,22 @@ class Agent:
|
|
|
8134
8234
|
num_documents = self.knowledge.max_results
|
|
8135
8235
|
|
|
8136
8236
|
# Validate the filters against known valid filter keys
|
|
8137
|
-
if self.knowledge is not None:
|
|
8138
|
-
|
|
8237
|
+
if self.knowledge is not None and filters is not None:
|
|
8238
|
+
if validate_filters:
|
|
8239
|
+
valid_filters, invalid_keys = await self.knowledge.async_validate_filters(filters) # type: ignore
|
|
8139
8240
|
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
log_info(f"Valid filter keys are: {self.knowledge.valid_metadata_filters}") # type: ignore
|
|
8241
|
+
# Warn about invalid filter keys
|
|
8242
|
+
if invalid_keys: # type: ignore
|
|
8243
|
+
log_warning(f"Invalid filter keys provided: {invalid_keys}. These filters will be ignored.")
|
|
8144
8244
|
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8245
|
+
# Only use valid filters
|
|
8246
|
+
filters = valid_filters
|
|
8247
|
+
if not filters:
|
|
8248
|
+
log_warning("No valid filters remain after validation. Search will proceed without filters.")
|
|
8149
8249
|
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8250
|
+
if invalid_keys == [] and valid_filters == {}:
|
|
8251
|
+
log_warning("No valid filters provided. Search will proceed without filters.")
|
|
8252
|
+
filters = None
|
|
8153
8253
|
|
|
8154
8254
|
if self.knowledge_retriever is not None and callable(self.knowledge_retriever):
|
|
8155
8255
|
from inspect import isawaitable, signature
|
|
@@ -9416,7 +9516,7 @@ class Agent:
|
|
|
9416
9516
|
import json
|
|
9417
9517
|
|
|
9418
9518
|
history: List[Dict[str, Any]] = []
|
|
9419
|
-
all_chats = session.
|
|
9519
|
+
all_chats = session.get_messages()
|
|
9420
9520
|
|
|
9421
9521
|
if len(all_chats) == 0:
|
|
9422
9522
|
return ""
|
|
@@ -9569,7 +9669,9 @@ class Agent:
|
|
|
9569
9669
|
# Get the relevant documents from the knowledge base, passing filters
|
|
9570
9670
|
retrieval_timer = Timer()
|
|
9571
9671
|
retrieval_timer.start()
|
|
9572
|
-
docs_from_knowledge = self.get_relevant_docs_from_knowledge(
|
|
9672
|
+
docs_from_knowledge = self.get_relevant_docs_from_knowledge(
|
|
9673
|
+
query=query, filters=search_filters, validate_filters=True
|
|
9674
|
+
)
|
|
9573
9675
|
if docs_from_knowledge is not None:
|
|
9574
9676
|
references = MessageReferences(
|
|
9575
9677
|
query=query,
|
|
@@ -9604,7 +9706,9 @@ class Agent:
|
|
|
9604
9706
|
|
|
9605
9707
|
retrieval_timer = Timer()
|
|
9606
9708
|
retrieval_timer.start()
|
|
9607
|
-
docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(
|
|
9709
|
+
docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(
|
|
9710
|
+
query=query, filters=search_filters, validate_filters=True
|
|
9711
|
+
)
|
|
9608
9712
|
if docs_from_knowledge is not None:
|
|
9609
9713
|
references = MessageReferences(
|
|
9610
9714
|
query=query,
|
|
@@ -9628,7 +9732,7 @@ class Agent:
|
|
|
9628
9732
|
|
|
9629
9733
|
return Function.from_callable(
|
|
9630
9734
|
search_knowledge_base_function,
|
|
9631
|
-
name="
|
|
9735
|
+
name="search_knowledge_base",
|
|
9632
9736
|
)
|
|
9633
9737
|
|
|
9634
9738
|
def add_to_knowledge(self, query: str, result: str) -> str:
|
|
@@ -9689,6 +9793,8 @@ class Agent:
|
|
|
9689
9793
|
session_type=SessionType.AGENT,
|
|
9690
9794
|
limit=num_history_sessions,
|
|
9691
9795
|
user_id=user_id,
|
|
9796
|
+
sort_by="created_at",
|
|
9797
|
+
sort_order="desc",
|
|
9692
9798
|
)
|
|
9693
9799
|
|
|
9694
9800
|
all_messages = []
|
|
@@ -9815,8 +9921,6 @@ class Agent:
|
|
|
9815
9921
|
videos: Optional[Sequence[Video]] = None,
|
|
9816
9922
|
files: Optional[Sequence[File]] = None,
|
|
9817
9923
|
stream: Optional[bool] = None,
|
|
9818
|
-
stream_events: Optional[bool] = None,
|
|
9819
|
-
stream_intermediate_steps: Optional[bool] = None,
|
|
9820
9924
|
markdown: Optional[bool] = None,
|
|
9821
9925
|
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
9822
9926
|
add_history_to_context: Optional[bool] = None,
|
|
@@ -9851,15 +9955,8 @@ class Agent:
|
|
|
9851
9955
|
if stream is None:
|
|
9852
9956
|
stream = False if self.stream is None else self.stream
|
|
9853
9957
|
|
|
9854
|
-
|
|
9855
|
-
|
|
9856
|
-
|
|
9857
|
-
# Can't stream events if streaming is disabled
|
|
9858
|
-
if stream is False:
|
|
9859
|
-
stream_events = False
|
|
9860
|
-
|
|
9861
|
-
if stream_events is None:
|
|
9862
|
-
stream_events = False if self.stream_events is None else self.stream_events
|
|
9958
|
+
if "stream_events" in kwargs:
|
|
9959
|
+
kwargs.pop("stream_events")
|
|
9863
9960
|
|
|
9864
9961
|
if stream:
|
|
9865
9962
|
print_response_stream(
|
|
@@ -9872,7 +9969,7 @@ class Agent:
|
|
|
9872
9969
|
images=images,
|
|
9873
9970
|
videos=videos,
|
|
9874
9971
|
files=files,
|
|
9875
|
-
stream_events=
|
|
9972
|
+
stream_events=True,
|
|
9876
9973
|
knowledge_filters=knowledge_filters,
|
|
9877
9974
|
debug_mode=debug_mode,
|
|
9878
9975
|
markdown=markdown,
|
|
@@ -9900,7 +9997,6 @@ class Agent:
|
|
|
9900
9997
|
images=images,
|
|
9901
9998
|
videos=videos,
|
|
9902
9999
|
files=files,
|
|
9903
|
-
stream_events=stream_events,
|
|
9904
10000
|
knowledge_filters=knowledge_filters,
|
|
9905
10001
|
debug_mode=debug_mode,
|
|
9906
10002
|
markdown=markdown,
|
|
@@ -9929,8 +10025,6 @@ class Agent:
|
|
|
9929
10025
|
videos: Optional[Sequence[Video]] = None,
|
|
9930
10026
|
files: Optional[Sequence[File]] = None,
|
|
9931
10027
|
stream: Optional[bool] = None,
|
|
9932
|
-
stream_events: Optional[bool] = None,
|
|
9933
|
-
stream_intermediate_steps: Optional[bool] = None,
|
|
9934
10028
|
markdown: Optional[bool] = None,
|
|
9935
10029
|
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
9936
10030
|
add_history_to_context: Optional[bool] = None,
|
|
@@ -9959,15 +10053,8 @@ class Agent:
|
|
|
9959
10053
|
if stream is None:
|
|
9960
10054
|
stream = self.stream or False
|
|
9961
10055
|
|
|
9962
|
-
|
|
9963
|
-
|
|
9964
|
-
|
|
9965
|
-
# Can't stream events if streaming is disabled
|
|
9966
|
-
if stream is False:
|
|
9967
|
-
stream_events = False
|
|
9968
|
-
|
|
9969
|
-
if stream_events is None:
|
|
9970
|
-
stream_events = False if self.stream_events is None else self.stream_events
|
|
10056
|
+
if "stream_events" in kwargs:
|
|
10057
|
+
kwargs.pop("stream_events")
|
|
9971
10058
|
|
|
9972
10059
|
if stream:
|
|
9973
10060
|
await aprint_response_stream(
|
|
@@ -9980,7 +10067,7 @@ class Agent:
|
|
|
9980
10067
|
images=images,
|
|
9981
10068
|
videos=videos,
|
|
9982
10069
|
files=files,
|
|
9983
|
-
stream_events=
|
|
10070
|
+
stream_events=True,
|
|
9984
10071
|
knowledge_filters=knowledge_filters,
|
|
9985
10072
|
debug_mode=debug_mode,
|
|
9986
10073
|
markdown=markdown,
|
agno/api/api.py
CHANGED
|
@@ -19,6 +19,7 @@ class Api:
|
|
|
19
19
|
base_url=agno_api_settings.api_url,
|
|
20
20
|
headers=self.headers,
|
|
21
21
|
timeout=60,
|
|
22
|
+
http2=True,
|
|
22
23
|
)
|
|
23
24
|
|
|
24
25
|
def AsyncClient(self) -> HttpxAsyncClient:
|
|
@@ -26,6 +27,7 @@ class Api:
|
|
|
26
27
|
base_url=agno_api_settings.api_url,
|
|
27
28
|
headers=self.headers,
|
|
28
29
|
timeout=60,
|
|
30
|
+
http2=True,
|
|
29
31
|
)
|
|
30
32
|
|
|
31
33
|
|
agno/db/base.py
CHANGED
|
@@ -20,6 +20,9 @@ class SessionType(str, Enum):
|
|
|
20
20
|
class BaseDb(ABC):
|
|
21
21
|
"""Base abstract class for all our Database implementations."""
|
|
22
22
|
|
|
23
|
+
# We assume the database to be up to date with the 2.0.0 release
|
|
24
|
+
default_schema_version = "2.0.0"
|
|
25
|
+
|
|
23
26
|
def __init__(
|
|
24
27
|
self,
|
|
25
28
|
session_table: Optional[str] = None,
|
|
@@ -28,6 +31,7 @@ class BaseDb(ABC):
|
|
|
28
31
|
metrics_table: Optional[str] = None,
|
|
29
32
|
eval_table: Optional[str] = None,
|
|
30
33
|
knowledge_table: Optional[str] = None,
|
|
34
|
+
versions_table: Optional[str] = None,
|
|
31
35
|
id: Optional[str] = None,
|
|
32
36
|
):
|
|
33
37
|
self.id = id or str(uuid4())
|
|
@@ -37,6 +41,7 @@ class BaseDb(ABC):
|
|
|
37
41
|
self.metrics_table_name = metrics_table or "agno_metrics"
|
|
38
42
|
self.eval_table_name = eval_table or "agno_eval_runs"
|
|
39
43
|
self.knowledge_table_name = knowledge_table or "agno_knowledge"
|
|
44
|
+
self.versions_table_name = versions_table or "agno_schema_versions"
|
|
40
45
|
|
|
41
46
|
@abstractmethod
|
|
42
47
|
def table_exists(self, table_name: str) -> bool:
|
|
@@ -46,6 +51,16 @@ class BaseDb(ABC):
|
|
|
46
51
|
"""Create all tables for this database."""
|
|
47
52
|
pass
|
|
48
53
|
|
|
54
|
+
# --- Schema Version ---
|
|
55
|
+
@abstractmethod
|
|
56
|
+
def get_latest_schema_version(self, table_name: str):
|
|
57
|
+
raise NotImplementedError
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def upsert_schema_version(self, table_name: str, version: str):
|
|
61
|
+
"""Upsert the schema version into the database."""
|
|
62
|
+
raise NotImplementedError
|
|
63
|
+
|
|
49
64
|
# --- Sessions ---
|
|
50
65
|
@abstractmethod
|
|
51
66
|
def delete_session(self, session_id: str) -> bool:
|
|
@@ -327,6 +342,7 @@ class AsyncBaseDb(ABC):
|
|
|
327
342
|
eval_table: Optional[str] = None,
|
|
328
343
|
knowledge_table: Optional[str] = None,
|
|
329
344
|
culture_table: Optional[str] = None,
|
|
345
|
+
versions_table: Optional[str] = None,
|
|
330
346
|
):
|
|
331
347
|
self.id = id or str(uuid4())
|
|
332
348
|
self.session_table_name = session_table or "agno_sessions"
|
|
@@ -335,6 +351,7 @@ class AsyncBaseDb(ABC):
|
|
|
335
351
|
self.eval_table_name = eval_table or "agno_eval_runs"
|
|
336
352
|
self.knowledge_table_name = knowledge_table or "agno_knowledge"
|
|
337
353
|
self.culture_table_name = culture_table or "agno_culture"
|
|
354
|
+
self.versions_table_name = versions_table or "agno_schema_versions"
|
|
338
355
|
|
|
339
356
|
@abstractmethod
|
|
340
357
|
async def table_exists(self, table_name: str) -> bool:
|
|
@@ -351,6 +368,15 @@ class AsyncBaseDb(ABC):
|
|
|
351
368
|
"""
|
|
352
369
|
raise NotImplementedError
|
|
353
370
|
|
|
371
|
+
@abstractmethod
|
|
372
|
+
async def get_latest_schema_version(self, table_name: str) -> str:
|
|
373
|
+
raise NotImplementedError
|
|
374
|
+
|
|
375
|
+
@abstractmethod
|
|
376
|
+
async def upsert_schema_version(self, table_name: str, version: str):
|
|
377
|
+
"""Upsert the schema version into the database."""
|
|
378
|
+
raise NotImplementedError
|
|
379
|
+
|
|
354
380
|
# --- Sessions ---
|
|
355
381
|
@abstractmethod
|
|
356
382
|
async def delete_session(self, session_id: str) -> bool:
|