agno 2.2.11__py3-none-any.whl → 2.2.12__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 +62 -47
- agno/db/mysql/mysql.py +1 -1
- agno/db/singlestore/singlestore.py +1 -1
- agno/db/sqlite/async_sqlite.py +1 -1
- agno/db/sqlite/sqlite.py +1 -1
- agno/filters.py +354 -0
- agno/knowledge/knowledge.py +43 -22
- agno/os/interfaces/slack/router.py +53 -33
- agno/os/interfaces/slack/slack.py +9 -1
- agno/os/router.py +25 -1
- agno/run/base.py +3 -2
- agno/session/agent.py +10 -5
- agno/team/team.py +44 -17
- agno/utils/agent.py +22 -17
- agno/utils/gemini.py +15 -5
- agno/utils/knowledge.py +12 -5
- agno/utils/log.py +1 -0
- agno/utils/print_response/agent.py +5 -4
- agno/utils/print_response/team.py +5 -4
- agno/vectordb/base.py +2 -4
- agno/vectordb/cassandra/cassandra.py +12 -5
- agno/vectordb/chroma/chromadb.py +10 -4
- agno/vectordb/clickhouse/clickhousedb.py +12 -4
- agno/vectordb/couchbase/couchbase.py +12 -3
- agno/vectordb/lancedb/lance_db.py +69 -144
- agno/vectordb/langchaindb/langchaindb.py +13 -4
- agno/vectordb/lightrag/lightrag.py +8 -3
- agno/vectordb/llamaindex/llamaindexdb.py +10 -4
- agno/vectordb/milvus/milvus.py +16 -5
- agno/vectordb/mongodb/mongodb.py +14 -3
- agno/vectordb/pgvector/pgvector.py +73 -15
- agno/vectordb/pineconedb/pineconedb.py +6 -2
- agno/vectordb/qdrant/qdrant.py +25 -13
- agno/vectordb/redis/redisdb.py +37 -30
- agno/vectordb/singlestore/singlestore.py +9 -4
- agno/vectordb/surrealdb/surrealdb.py +13 -3
- agno/vectordb/upstashdb/upstashdb.py +8 -5
- agno/vectordb/weaviate/weaviate.py +29 -12
- agno/workflow/workflow.py +13 -7
- {agno-2.2.11.dist-info → agno-2.2.12.dist-info}/METADATA +1 -1
- {agno-2.2.11.dist-info → agno-2.2.12.dist-info}/RECORD +44 -43
- {agno-2.2.11.dist-info → agno-2.2.12.dist-info}/WHEEL +0 -0
- {agno-2.2.11.dist-info → agno-2.2.12.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.11.dist-info → agno-2.2.12.dist-info}/top_level.txt +0 -0
agno/session/agent.py
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import asdict, dataclass
|
|
4
|
-
from typing import Any, Dict, List, Mapping, Optional
|
|
4
|
+
from typing import Any, Dict, List, Mapping, Optional, Union
|
|
5
5
|
|
|
6
6
|
from agno.models.message import Message
|
|
7
7
|
from agno.run.agent import RunOutput
|
|
8
8
|
from agno.run.base import RunStatus
|
|
9
|
+
from agno.run.team import TeamRunOutput
|
|
9
10
|
from agno.session.summary import SessionSummary
|
|
10
11
|
from agno.utils.log import log_debug, log_warning
|
|
11
12
|
|
|
@@ -33,7 +34,7 @@ class AgentSession:
|
|
|
33
34
|
# Agent Data: agent_id, name and model
|
|
34
35
|
agent_data: Optional[Dict[str, Any]] = None
|
|
35
36
|
# List of all runs in the session
|
|
36
|
-
runs: Optional[List[RunOutput]] = None
|
|
37
|
+
runs: Optional[List[Union[RunOutput, TeamRunOutput]]] = None
|
|
37
38
|
# Summary of the session
|
|
38
39
|
summary: Optional["SessionSummary"] = None
|
|
39
40
|
|
|
@@ -57,9 +58,13 @@ class AgentSession:
|
|
|
57
58
|
return None
|
|
58
59
|
|
|
59
60
|
runs = data.get("runs")
|
|
60
|
-
serialized_runs: List[RunOutput] = []
|
|
61
|
+
serialized_runs: List[Union[RunOutput, TeamRunOutput]] = []
|
|
61
62
|
if runs is not None and isinstance(runs[0], dict):
|
|
62
|
-
|
|
63
|
+
for run in runs:
|
|
64
|
+
if "agent_id" in run:
|
|
65
|
+
serialized_runs.append(RunOutput.from_dict(run))
|
|
66
|
+
elif "team_id" in run:
|
|
67
|
+
serialized_runs.append(TeamRunOutput.from_dict(run))
|
|
63
68
|
|
|
64
69
|
summary = data.get("summary")
|
|
65
70
|
if summary is not None and isinstance(summary, dict):
|
|
@@ -101,7 +106,7 @@ class AgentSession:
|
|
|
101
106
|
|
|
102
107
|
log_debug("Added RunOutput to Agent Session")
|
|
103
108
|
|
|
104
|
-
def get_run(self, run_id: str) -> Optional[RunOutput]:
|
|
109
|
+
def get_run(self, run_id: str) -> Optional[Union[RunOutput, TeamRunOutput]]:
|
|
105
110
|
for run in self.runs or []:
|
|
106
111
|
if run.run_id == run_id:
|
|
107
112
|
return run
|
agno/team/team.py
CHANGED
|
@@ -36,6 +36,7 @@ from agno.exceptions import (
|
|
|
36
36
|
OutputCheckError,
|
|
37
37
|
RunCancelledException,
|
|
38
38
|
)
|
|
39
|
+
from agno.filters import FilterExpr
|
|
39
40
|
from agno.guardrails import BaseGuardrail
|
|
40
41
|
from agno.knowledge.knowledge import Knowledge
|
|
41
42
|
from agno.knowledge.types import KnowledgeFilter
|
|
@@ -288,7 +289,7 @@ class Team:
|
|
|
288
289
|
# --- Agent Knowledge ---
|
|
289
290
|
knowledge: Optional[Knowledge] = None
|
|
290
291
|
# Add knowledge_filters to the Agent class attributes
|
|
291
|
-
knowledge_filters: Optional[Dict[str, Any]] = None
|
|
292
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
292
293
|
# Let the agent choose the knowledge filters
|
|
293
294
|
enable_agentic_knowledge_filters: Optional[bool] = False
|
|
294
295
|
# Add a tool that allows the Team to update Knowledge.
|
|
@@ -474,7 +475,7 @@ class Team:
|
|
|
474
475
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
475
476
|
add_dependencies_to_context: bool = False,
|
|
476
477
|
knowledge: Optional[Knowledge] = None,
|
|
477
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
478
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
478
479
|
add_knowledge_to_context: bool = False,
|
|
479
480
|
enable_agentic_knowledge_filters: Optional[bool] = False,
|
|
480
481
|
update_knowledge: bool = False,
|
|
@@ -1742,7 +1743,7 @@ class Team:
|
|
|
1742
1743
|
images: Optional[Sequence[Image]] = None,
|
|
1743
1744
|
videos: Optional[Sequence[Video]] = None,
|
|
1744
1745
|
files: Optional[Sequence[File]] = None,
|
|
1745
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1746
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
1746
1747
|
add_history_to_context: Optional[bool] = None,
|
|
1747
1748
|
add_dependencies_to_context: Optional[bool] = None,
|
|
1748
1749
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -1769,7 +1770,7 @@ class Team:
|
|
|
1769
1770
|
images: Optional[Sequence[Image]] = None,
|
|
1770
1771
|
videos: Optional[Sequence[Video]] = None,
|
|
1771
1772
|
files: Optional[Sequence[File]] = None,
|
|
1772
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1773
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
1773
1774
|
add_history_to_context: Optional[bool] = None,
|
|
1774
1775
|
add_dependencies_to_context: Optional[bool] = None,
|
|
1775
1776
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -1797,7 +1798,7 @@ class Team:
|
|
|
1797
1798
|
images: Optional[Sequence[Image]] = None,
|
|
1798
1799
|
videos: Optional[Sequence[Video]] = None,
|
|
1799
1800
|
files: Optional[Sequence[File]] = None,
|
|
1800
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1801
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
1801
1802
|
add_history_to_context: Optional[bool] = None,
|
|
1802
1803
|
add_dependencies_to_context: Optional[bool] = None,
|
|
1803
1804
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -2602,7 +2603,7 @@ class Team:
|
|
|
2602
2603
|
images: Optional[Sequence[Image]] = None,
|
|
2603
2604
|
videos: Optional[Sequence[Video]] = None,
|
|
2604
2605
|
files: Optional[Sequence[File]] = None,
|
|
2605
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
2606
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
2606
2607
|
add_history_to_context: Optional[bool] = None,
|
|
2607
2608
|
add_dependencies_to_context: Optional[bool] = None,
|
|
2608
2609
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -2629,7 +2630,7 @@ class Team:
|
|
|
2629
2630
|
images: Optional[Sequence[Image]] = None,
|
|
2630
2631
|
videos: Optional[Sequence[Video]] = None,
|
|
2631
2632
|
files: Optional[Sequence[File]] = None,
|
|
2632
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
2633
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
2633
2634
|
add_history_to_context: Optional[bool] = None,
|
|
2634
2635
|
add_dependencies_to_context: Optional[bool] = None,
|
|
2635
2636
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -2657,7 +2658,7 @@ class Team:
|
|
|
2657
2658
|
images: Optional[Sequence[Image]] = None,
|
|
2658
2659
|
videos: Optional[Sequence[Video]] = None,
|
|
2659
2660
|
files: Optional[Sequence[File]] = None,
|
|
2660
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
2661
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
2661
2662
|
add_history_to_context: Optional[bool] = None,
|
|
2662
2663
|
add_dependencies_to_context: Optional[bool] = None,
|
|
2663
2664
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -3872,7 +3873,7 @@ class Team:
|
|
|
3872
3873
|
videos: Optional[Sequence[Video]] = None,
|
|
3873
3874
|
files: Optional[Sequence[File]] = None,
|
|
3874
3875
|
markdown: Optional[bool] = None,
|
|
3875
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
3876
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
3876
3877
|
add_history_to_context: Optional[bool] = None,
|
|
3877
3878
|
add_dependencies_to_context: Optional[bool] = None,
|
|
3878
3879
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -3982,7 +3983,7 @@ class Team:
|
|
|
3982
3983
|
videos: Optional[Sequence[Video]] = None,
|
|
3983
3984
|
files: Optional[Sequence[File]] = None,
|
|
3984
3985
|
markdown: Optional[bool] = None,
|
|
3985
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
3986
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
3986
3987
|
add_history_to_context: Optional[bool] = None,
|
|
3987
3988
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
3988
3989
|
add_dependencies_to_context: Optional[bool] = None,
|
|
@@ -7144,7 +7145,7 @@ class Team:
|
|
|
7144
7145
|
|
|
7145
7146
|
# Yield the member event directly
|
|
7146
7147
|
member_agent_run_response_event.parent_run_id = (
|
|
7147
|
-
member_agent_run_response_event
|
|
7148
|
+
getattr(member_agent_run_response_event, 'parent_run_id', None) or run_response.run_id
|
|
7148
7149
|
)
|
|
7149
7150
|
yield member_agent_run_response_event
|
|
7150
7151
|
else:
|
|
@@ -8391,7 +8392,11 @@ class Team:
|
|
|
8391
8392
|
return "Successfully added to knowledge base"
|
|
8392
8393
|
|
|
8393
8394
|
def get_relevant_docs_from_knowledge(
|
|
8394
|
-
self,
|
|
8395
|
+
self,
|
|
8396
|
+
query: str,
|
|
8397
|
+
num_documents: Optional[int] = None,
|
|
8398
|
+
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
8399
|
+
**kwargs,
|
|
8395
8400
|
) -> Optional[List[Union[Dict[str, Any], str]]]:
|
|
8396
8401
|
"""Return a list of references from the knowledge base"""
|
|
8397
8402
|
from agno.knowledge.document import Document
|
|
@@ -8414,6 +8419,10 @@ class Team:
|
|
|
8414
8419
|
if not filters:
|
|
8415
8420
|
log_warning("No valid filters remain after validation. Search will proceed without filters.")
|
|
8416
8421
|
|
|
8422
|
+
if invalid_keys == [] and valid_filters == {}:
|
|
8423
|
+
log_warning("No valid filters provided. Search will proceed without filters.")
|
|
8424
|
+
filters = None
|
|
8425
|
+
|
|
8417
8426
|
if self.knowledge_retriever is not None and callable(self.knowledge_retriever):
|
|
8418
8427
|
from inspect import signature
|
|
8419
8428
|
|
|
@@ -8451,7 +8460,11 @@ class Team:
|
|
|
8451
8460
|
raise e
|
|
8452
8461
|
|
|
8453
8462
|
async def aget_relevant_docs_from_knowledge(
|
|
8454
|
-
self,
|
|
8463
|
+
self,
|
|
8464
|
+
query: str,
|
|
8465
|
+
num_documents: Optional[int] = None,
|
|
8466
|
+
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
8467
|
+
**kwargs,
|
|
8455
8468
|
) -> Optional[List[Union[Dict[str, Any], str]]]:
|
|
8456
8469
|
"""Get relevant documents from knowledge base asynchronously."""
|
|
8457
8470
|
from agno.knowledge.document import Document
|
|
@@ -8475,6 +8488,10 @@ class Team:
|
|
|
8475
8488
|
if not filters:
|
|
8476
8489
|
log_warning("No valid filters remain after validation. Search will proceed without filters.")
|
|
8477
8490
|
|
|
8491
|
+
if invalid_keys == [] and valid_filters == {}:
|
|
8492
|
+
log_warning("No valid filters provided. Search will proceed without filters.")
|
|
8493
|
+
filters = None
|
|
8494
|
+
|
|
8478
8495
|
if self.knowledge_retriever is not None and callable(self.knowledge_retriever):
|
|
8479
8496
|
from inspect import isawaitable, signature
|
|
8480
8497
|
|
|
@@ -8531,7 +8548,9 @@ class Team:
|
|
|
8531
8548
|
|
|
8532
8549
|
return json.dumps(docs, indent=2)
|
|
8533
8550
|
|
|
8534
|
-
def _get_effective_filters(
|
|
8551
|
+
def _get_effective_filters(
|
|
8552
|
+
self, knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
8553
|
+
) -> Optional[Any]:
|
|
8535
8554
|
"""
|
|
8536
8555
|
Determine effective filters for the team, considering:
|
|
8537
8556
|
1. Team-level filters (self.knowledge_filters)
|
|
@@ -8548,7 +8567,15 @@ class Team:
|
|
|
8548
8567
|
# Apply run-time filters if they exist
|
|
8549
8568
|
if knowledge_filters:
|
|
8550
8569
|
if effective_filters:
|
|
8551
|
-
effective_filters
|
|
8570
|
+
if isinstance(effective_filters, dict):
|
|
8571
|
+
if isinstance(knowledge_filters, dict):
|
|
8572
|
+
effective_filters.update(cast(Dict[str, Any], knowledge_filters))
|
|
8573
|
+
else:
|
|
8574
|
+
# If knowledge_filters is not a dict (e.g., list of FilterExpr), combine as list if effective_filters is dict
|
|
8575
|
+
# Convert the dict to a list and concatenate
|
|
8576
|
+
effective_filters = cast(Any, [effective_filters, *knowledge_filters])
|
|
8577
|
+
else:
|
|
8578
|
+
effective_filters = [*effective_filters, *knowledge_filters]
|
|
8552
8579
|
else:
|
|
8553
8580
|
effective_filters = knowledge_filters
|
|
8554
8581
|
|
|
@@ -8557,7 +8584,7 @@ class Team:
|
|
|
8557
8584
|
def _get_search_knowledge_base_function(
|
|
8558
8585
|
self,
|
|
8559
8586
|
run_response: TeamRunOutput,
|
|
8560
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
8587
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
8561
8588
|
async_mode: bool = False,
|
|
8562
8589
|
) -> Function:
|
|
8563
8590
|
"""Factory function to create a search_knowledge_base function with filters."""
|
|
@@ -8626,7 +8653,7 @@ class Team:
|
|
|
8626
8653
|
def _get_search_knowledge_base_with_agentic_filters_function(
|
|
8627
8654
|
self,
|
|
8628
8655
|
run_response: TeamRunOutput,
|
|
8629
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
8656
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
8630
8657
|
async_mode: bool = False,
|
|
8631
8658
|
) -> Function:
|
|
8632
8659
|
"""Factory function to create a search_knowledge_base function with filters."""
|
agno/utils/agent.py
CHANGED
|
@@ -8,7 +8,7 @@ from agno.models.response import ModelResponse
|
|
|
8
8
|
from agno.run.agent import RunEvent, RunInput, RunOutput, RunOutputEvent
|
|
9
9
|
from agno.run.team import RunOutputEvent as TeamRunOutputEvent
|
|
10
10
|
from agno.run.team import TeamRunOutput
|
|
11
|
-
from agno.session import AgentSession, TeamSession
|
|
11
|
+
from agno.session import AgentSession, TeamSession, WorkflowSession
|
|
12
12
|
from agno.utils.events import (
|
|
13
13
|
create_memory_update_completed_event,
|
|
14
14
|
create_memory_update_started_event,
|
|
@@ -457,7 +457,12 @@ def scrub_history_messages_from_run_output(run_response: Union[RunOutput, TeamRu
|
|
|
457
457
|
|
|
458
458
|
def get_run_output_util(
|
|
459
459
|
entity: Union["Agent", "Team"], run_id: str, session_id: Optional[str] = None
|
|
460
|
-
) -> Optional[
|
|
460
|
+
) -> Optional[
|
|
461
|
+
Union[
|
|
462
|
+
RunOutput,
|
|
463
|
+
TeamRunOutput,
|
|
464
|
+
]
|
|
465
|
+
]:
|
|
461
466
|
"""
|
|
462
467
|
Get a RunOutput from the database.
|
|
463
468
|
|
|
@@ -473,13 +478,13 @@ def get_run_output_util(
|
|
|
473
478
|
if session is not None:
|
|
474
479
|
run_response = session.get_run(run_id=run_id)
|
|
475
480
|
if run_response is not None:
|
|
476
|
-
return run_response
|
|
481
|
+
return run_response # type: ignore
|
|
477
482
|
else:
|
|
478
483
|
log_warning(f"RunOutput {run_id} not found in Session {session_id}")
|
|
479
484
|
elif entity.cached_session is not None:
|
|
480
485
|
run_response = entity.cached_session.get_run(run_id=run_id)
|
|
481
486
|
if run_response is not None:
|
|
482
|
-
return run_response
|
|
487
|
+
return run_response # type: ignore
|
|
483
488
|
else:
|
|
484
489
|
log_warning(f"RunOutput {run_id} not found in Session {entity.cached_session.session_id}")
|
|
485
490
|
return None
|
|
@@ -501,7 +506,7 @@ async def aget_run_output_util(
|
|
|
501
506
|
if session is not None:
|
|
502
507
|
run_response = session.get_run(run_id=run_id)
|
|
503
508
|
if run_response is not None:
|
|
504
|
-
return run_response
|
|
509
|
+
return run_response # type: ignore
|
|
505
510
|
else:
|
|
506
511
|
log_warning(f"RunOutput {run_id} not found in Session {session_id}")
|
|
507
512
|
elif entity.cached_session is not None:
|
|
@@ -535,10 +540,10 @@ def get_last_run_output_util(
|
|
|
535
540
|
for run_output in reversed(session.runs):
|
|
536
541
|
if entity.__class__.__name__ == "Agent":
|
|
537
542
|
if hasattr(run_output, "agent_id") and run_output.agent_id == entity.id:
|
|
538
|
-
return run_output
|
|
543
|
+
return run_output # type: ignore
|
|
539
544
|
elif entity.__class__.__name__ == "Team":
|
|
540
545
|
if hasattr(run_output, "team_id") and run_output.team_id == entity.id:
|
|
541
|
-
return run_output
|
|
546
|
+
return run_output # type: ignore
|
|
542
547
|
else:
|
|
543
548
|
log_warning(f"No run responses found in Session {session_id}")
|
|
544
549
|
|
|
@@ -550,10 +555,10 @@ def get_last_run_output_util(
|
|
|
550
555
|
for run_output in reversed(entity.cached_session.runs):
|
|
551
556
|
if entity.__class__.__name__ == "Agent":
|
|
552
557
|
if hasattr(run_output, "agent_id") and run_output.agent_id == entity.id:
|
|
553
|
-
return run_output
|
|
558
|
+
return run_output # type: ignore
|
|
554
559
|
elif entity.__class__.__name__ == "Team":
|
|
555
560
|
if hasattr(run_output, "team_id") and run_output.team_id == entity.id:
|
|
556
|
-
return run_output
|
|
561
|
+
return run_output # type: ignore
|
|
557
562
|
return None
|
|
558
563
|
|
|
559
564
|
|
|
@@ -575,10 +580,10 @@ async def aget_last_run_output_util(
|
|
|
575
580
|
for run_output in reversed(session.runs):
|
|
576
581
|
if entity.__class__.__name__ == "Agent":
|
|
577
582
|
if hasattr(run_output, "agent_id") and run_output.agent_id == entity.id:
|
|
578
|
-
return run_output
|
|
583
|
+
return run_output # type: ignore
|
|
579
584
|
elif entity.__class__.__name__ == "Team":
|
|
580
585
|
if hasattr(run_output, "team_id") and run_output.team_id == entity.id:
|
|
581
|
-
return run_output
|
|
586
|
+
return run_output # type: ignore
|
|
582
587
|
else:
|
|
583
588
|
log_warning(f"No run responses found in Session {session_id}")
|
|
584
589
|
|
|
@@ -590,16 +595,16 @@ async def aget_last_run_output_util(
|
|
|
590
595
|
for run_output in reversed(entity.cached_session.runs):
|
|
591
596
|
if entity.__class__.__name__ == "Agent":
|
|
592
597
|
if hasattr(run_output, "agent_id") and run_output.agent_id == entity.id:
|
|
593
|
-
return run_output
|
|
598
|
+
return run_output # type: ignore
|
|
594
599
|
elif entity.__class__.__name__ == "Team":
|
|
595
600
|
if hasattr(run_output, "team_id") and run_output.team_id == entity.id:
|
|
596
|
-
return run_output
|
|
601
|
+
return run_output # type: ignore
|
|
597
602
|
return None
|
|
598
603
|
|
|
599
604
|
|
|
600
605
|
def set_session_name_util(
|
|
601
606
|
entity: Union["Agent", "Team"], session_id: str, autogenerate: bool = False, session_name: Optional[str] = None
|
|
602
|
-
) -> Union[AgentSession, TeamSession]:
|
|
607
|
+
) -> Union[AgentSession, TeamSession, WorkflowSession]:
|
|
603
608
|
"""Set the session name and save to storage"""
|
|
604
609
|
if entity._has_async_db():
|
|
605
610
|
raise ValueError("Async database not supported for sync functions")
|
|
@@ -629,7 +634,7 @@ def set_session_name_util(
|
|
|
629
634
|
|
|
630
635
|
async def aset_session_name_util(
|
|
631
636
|
entity: Union["Agent", "Team"], session_id: str, autogenerate: bool = False, session_name: Optional[str] = None
|
|
632
|
-
) -> Union[AgentSession, TeamSession]:
|
|
637
|
+
) -> Union[AgentSession, TeamSession, WorkflowSession]:
|
|
633
638
|
"""Set the session name and save to storage"""
|
|
634
639
|
session = await entity.aget_session(session_id=session_id) # type: ignore
|
|
635
640
|
|
|
@@ -796,7 +801,7 @@ def get_chat_history_util(entity: Union["Agent", "Team"], session_id: str) -> Li
|
|
|
796
801
|
if session is None:
|
|
797
802
|
raise Exception("Session not found")
|
|
798
803
|
|
|
799
|
-
return session.get_chat_history()
|
|
804
|
+
return session.get_chat_history() # type: ignore
|
|
800
805
|
|
|
801
806
|
|
|
802
807
|
async def aget_chat_history_util(entity: Union["Agent", "Team"], session_id: str) -> List[Message]:
|
|
@@ -812,4 +817,4 @@ async def aget_chat_history_util(entity: Union["Agent", "Team"], session_id: str
|
|
|
812
817
|
if session is None:
|
|
813
818
|
raise Exception("Session not found")
|
|
814
819
|
|
|
815
|
-
return session.get_chat_history()
|
|
820
|
+
return session.get_chat_history() # type: ignore
|
agno/utils/gemini.py
CHANGED
|
@@ -225,12 +225,13 @@ def convert_schema(
|
|
|
225
225
|
if schema_type is None or schema_type == "null":
|
|
226
226
|
return None
|
|
227
227
|
description = schema_dict.get("description", None)
|
|
228
|
+
title = schema_dict.get("title", None)
|
|
228
229
|
default = schema_dict.get("default", None)
|
|
229
230
|
|
|
230
231
|
# Handle enum types
|
|
231
232
|
if "enum" in schema_dict:
|
|
232
233
|
enum_values = schema_dict["enum"]
|
|
233
|
-
return Schema(type=GeminiType.STRING, enum=enum_values, description=description, default=default)
|
|
234
|
+
return Schema(type=GeminiType.STRING, enum=enum_values, description=description, default=default, title=title)
|
|
234
235
|
|
|
235
236
|
if schema_type == "object":
|
|
236
237
|
# Handle regular objects with properties
|
|
@@ -250,6 +251,10 @@ def convert_schema(
|
|
|
250
251
|
if is_nullable:
|
|
251
252
|
converted_schema.nullable = True
|
|
252
253
|
properties[key] = converted_schema
|
|
254
|
+
else:
|
|
255
|
+
properties[key] = Schema(
|
|
256
|
+
title=prop_def.get("title", None), description=prop_def.get("description", None)
|
|
257
|
+
)
|
|
253
258
|
|
|
254
259
|
required = schema_dict.get("required", [])
|
|
255
260
|
|
|
@@ -260,9 +265,10 @@ def convert_schema(
|
|
|
260
265
|
required=required,
|
|
261
266
|
description=description,
|
|
262
267
|
default=default,
|
|
268
|
+
title=title,
|
|
263
269
|
)
|
|
264
270
|
else:
|
|
265
|
-
return Schema(type=GeminiType.OBJECT, description=description, default=default)
|
|
271
|
+
return Schema(type=GeminiType.OBJECT, description=description, default=default, title=title)
|
|
266
272
|
|
|
267
273
|
# Handle Dict types (objects with additionalProperties but no properties)
|
|
268
274
|
elif "additionalProperties" in schema_dict:
|
|
@@ -305,11 +311,11 @@ def convert_schema(
|
|
|
305
311
|
)
|
|
306
312
|
else:
|
|
307
313
|
# additionalProperties is false or true
|
|
308
|
-
return Schema(type=GeminiType.OBJECT, description=description, default=default)
|
|
314
|
+
return Schema(type=GeminiType.OBJECT, description=description, default=default, title=title)
|
|
309
315
|
|
|
310
316
|
# Handle empty objects
|
|
311
317
|
else:
|
|
312
|
-
return Schema(type=GeminiType.OBJECT, description=description, default=default)
|
|
318
|
+
return Schema(type=GeminiType.OBJECT, description=description, default=default, title=title)
|
|
313
319
|
|
|
314
320
|
elif schema_type == "array" and "items" in schema_dict:
|
|
315
321
|
if not schema_dict["items"]: # Handle empty {}
|
|
@@ -325,6 +331,7 @@ def convert_schema(
|
|
|
325
331
|
items=items,
|
|
326
332
|
min_items=min_items,
|
|
327
333
|
max_items=max_items,
|
|
334
|
+
title=title,
|
|
328
335
|
)
|
|
329
336
|
|
|
330
337
|
elif schema_type == "string":
|
|
@@ -332,6 +339,7 @@ def convert_schema(
|
|
|
332
339
|
"type": GeminiType.STRING,
|
|
333
340
|
"description": description,
|
|
334
341
|
"default": default,
|
|
342
|
+
"title": title,
|
|
335
343
|
}
|
|
336
344
|
if "format" in schema_dict:
|
|
337
345
|
schema_kwargs["format"] = schema_dict["format"]
|
|
@@ -342,6 +350,7 @@ def convert_schema(
|
|
|
342
350
|
"type": schema_type.upper(),
|
|
343
351
|
"description": description,
|
|
344
352
|
"default": default,
|
|
353
|
+
"title": title,
|
|
345
354
|
}
|
|
346
355
|
if "maximum" in schema_dict:
|
|
347
356
|
schema_kwargs["maximum"] = schema_dict["maximum"]
|
|
@@ -373,6 +382,7 @@ def convert_schema(
|
|
|
373
382
|
any_of=any_of,
|
|
374
383
|
description=description,
|
|
375
384
|
default=default,
|
|
385
|
+
title=title,
|
|
376
386
|
)
|
|
377
387
|
else:
|
|
378
388
|
if isinstance(schema_type, list):
|
|
@@ -384,7 +394,7 @@ def convert_schema(
|
|
|
384
394
|
# Only convert to uppercase if schema_type is not empty
|
|
385
395
|
if schema_type:
|
|
386
396
|
schema_type = schema_type.upper()
|
|
387
|
-
return Schema(type=schema_type, description=description, default=default)
|
|
397
|
+
return Schema(type=schema_type, description=description, default=default, title=title)
|
|
388
398
|
else:
|
|
389
399
|
# If we get here with an empty type and no other handlers matched,
|
|
390
400
|
# something is wrong with the schema
|
agno/utils/knowledge.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
from typing import Any, Dict, Optional
|
|
1
|
+
from typing import Any, Dict, List, Optional, Union
|
|
2
2
|
|
|
3
|
+
from agno.filters import FilterExpr
|
|
3
4
|
from agno.utils.log import log_info
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
def get_agentic_or_user_search_filters(
|
|
7
|
-
filters: Optional[Dict[str, Any]], effective_filters: Optional[Dict[str, Any]]
|
|
8
|
+
filters: Optional[Dict[str, Any]], effective_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]]
|
|
8
9
|
) -> Dict[str, Any]:
|
|
9
10
|
"""Helper function to determine the final filters to use for the search.
|
|
10
11
|
|
|
@@ -15,7 +16,7 @@ def get_agentic_or_user_search_filters(
|
|
|
15
16
|
Returns:
|
|
16
17
|
Dict[str, Any]: The final filters to use for the search.
|
|
17
18
|
"""
|
|
18
|
-
search_filters =
|
|
19
|
+
search_filters = None
|
|
19
20
|
|
|
20
21
|
# If agentic filters exist and manual filters (passed by user) do not, use agentic filters
|
|
21
22
|
if filters and not effective_filters:
|
|
@@ -23,7 +24,13 @@ def get_agentic_or_user_search_filters(
|
|
|
23
24
|
|
|
24
25
|
# If both agentic filters exist and manual filters (passed by user) exist, use manual filters (give priority to user and override)
|
|
25
26
|
if filters and effective_filters:
|
|
26
|
-
|
|
27
|
+
if isinstance(effective_filters, dict):
|
|
28
|
+
search_filters = effective_filters
|
|
29
|
+
elif isinstance(effective_filters, list):
|
|
30
|
+
# If effective_filters is a list (likely List[FilterExpr]), convert both filters and effective_filters to a dict if possible, otherwise raise
|
|
31
|
+
raise ValueError(
|
|
32
|
+
"Merging dict and list of filters is not supported; effective_filters should be a dict for search compatibility."
|
|
33
|
+
)
|
|
27
34
|
|
|
28
35
|
log_info(f"Filters used by Agent: {search_filters}")
|
|
29
|
-
return search_filters
|
|
36
|
+
return search_filters or {}
|
agno/utils/log.py
CHANGED
|
@@ -10,6 +10,7 @@ from rich.markdown import Markdown
|
|
|
10
10
|
from rich.status import Status
|
|
11
11
|
from rich.text import Text
|
|
12
12
|
|
|
13
|
+
from agno.filters import FilterExpr
|
|
13
14
|
from agno.media import Audio, File, Image, Video
|
|
14
15
|
from agno.models.message import Message
|
|
15
16
|
from agno.reasoning.step import ReasoningStep
|
|
@@ -35,7 +36,7 @@ def print_response_stream(
|
|
|
35
36
|
files: Optional[Sequence[File]] = None,
|
|
36
37
|
stream_events: bool = False,
|
|
37
38
|
stream_intermediate_steps: bool = False,
|
|
38
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
39
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
39
40
|
debug_mode: Optional[bool] = None,
|
|
40
41
|
markdown: bool = False,
|
|
41
42
|
show_message: bool = True,
|
|
@@ -227,7 +228,7 @@ async def aprint_response_stream(
|
|
|
227
228
|
files: Optional[Sequence[File]] = None,
|
|
228
229
|
stream_events: bool = False,
|
|
229
230
|
stream_intermediate_steps: bool = False,
|
|
230
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
231
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
231
232
|
debug_mode: Optional[bool] = None,
|
|
232
233
|
markdown: bool = False,
|
|
233
234
|
show_message: bool = True,
|
|
@@ -505,7 +506,7 @@ def print_response(
|
|
|
505
506
|
images: Optional[Sequence[Image]] = None,
|
|
506
507
|
videos: Optional[Sequence[Video]] = None,
|
|
507
508
|
files: Optional[Sequence[File]] = None,
|
|
508
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
509
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
509
510
|
debug_mode: Optional[bool] = None,
|
|
510
511
|
markdown: bool = False,
|
|
511
512
|
show_message: bool = True,
|
|
@@ -621,7 +622,7 @@ async def aprint_response(
|
|
|
621
622
|
images: Optional[Sequence[Image]] = None,
|
|
622
623
|
videos: Optional[Sequence[Video]] = None,
|
|
623
624
|
files: Optional[Sequence[File]] = None,
|
|
624
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
625
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
625
626
|
debug_mode: Optional[bool] = None,
|
|
626
627
|
markdown: bool = False,
|
|
627
628
|
show_message: bool = True,
|
|
@@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Set, Unio
|
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel
|
|
4
4
|
|
|
5
|
+
from agno.filters import FilterExpr
|
|
5
6
|
from agno.media import Audio, File, Image, Video
|
|
6
7
|
from agno.models.message import Message
|
|
7
8
|
from agno.models.response import ToolExecution
|
|
@@ -33,7 +34,7 @@ def print_response(
|
|
|
33
34
|
videos: Optional[Sequence[Video]] = None,
|
|
34
35
|
files: Optional[Sequence[File]] = None,
|
|
35
36
|
markdown: bool = False,
|
|
36
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
37
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
37
38
|
add_history_to_context: Optional[bool] = None,
|
|
38
39
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
39
40
|
add_dependencies_to_context: Optional[bool] = None,
|
|
@@ -333,7 +334,7 @@ def print_response_stream(
|
|
|
333
334
|
markdown: bool = False,
|
|
334
335
|
stream_events: bool = False,
|
|
335
336
|
stream_intermediate_steps: bool = False, # type: ignore
|
|
336
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
337
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
337
338
|
add_history_to_context: Optional[bool] = None,
|
|
338
339
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
339
340
|
add_dependencies_to_context: Optional[bool] = None,
|
|
@@ -865,7 +866,7 @@ async def aprint_response(
|
|
|
865
866
|
videos: Optional[Sequence[Video]] = None,
|
|
866
867
|
files: Optional[Sequence[File]] = None,
|
|
867
868
|
markdown: bool = False,
|
|
868
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
869
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
869
870
|
add_history_to_context: Optional[bool] = None,
|
|
870
871
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
871
872
|
add_dependencies_to_context: Optional[bool] = None,
|
|
@@ -1163,7 +1164,7 @@ async def aprint_response_stream(
|
|
|
1163
1164
|
markdown: bool = False,
|
|
1164
1165
|
stream_events: bool = False,
|
|
1165
1166
|
stream_intermediate_steps: bool = False, # type: ignore
|
|
1166
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1167
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
1167
1168
|
add_history_to_context: Optional[bool] = None,
|
|
1168
1169
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
1169
1170
|
add_dependencies_to_context: Optional[bool] = None,
|
agno/vectordb/base.py
CHANGED
|
@@ -72,13 +72,11 @@ class VectorDb(ABC):
|
|
|
72
72
|
raise NotImplementedError
|
|
73
73
|
|
|
74
74
|
@abstractmethod
|
|
75
|
-
def search(self, query: str, limit: int = 5, filters: Optional[
|
|
75
|
+
def search(self, query: str, limit: int = 5, filters: Optional[Any] = None) -> List[Document]:
|
|
76
76
|
raise NotImplementedError
|
|
77
77
|
|
|
78
78
|
@abstractmethod
|
|
79
|
-
async def async_search(
|
|
80
|
-
self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None
|
|
81
|
-
) -> List[Document]:
|
|
79
|
+
async def async_search(self, query: str, limit: int = 5, filters: Optional[Any] = None) -> List[Document]:
|
|
82
80
|
raise NotImplementedError
|
|
83
81
|
|
|
84
82
|
@abstractmethod
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from typing import Any, Dict, Iterable, List, Optional
|
|
2
|
+
from typing import Any, Dict, Iterable, List, Optional, Union
|
|
3
3
|
|
|
4
|
+
from agno.filters import FilterExpr
|
|
4
5
|
from agno.knowledge.document import Document
|
|
5
6
|
from agno.knowledge.embedder import Embedder
|
|
6
|
-
from agno.utils.log import log_debug, log_error, log_info
|
|
7
|
+
from agno.utils.log import log_debug, log_error, log_info, log_warning
|
|
7
8
|
from agno.vectordb.base import VectorDb
|
|
8
9
|
from agno.vectordb.cassandra.index import AgnoMetadataVectorCassandraTable
|
|
9
10
|
|
|
@@ -204,13 +205,17 @@ class Cassandra(VectorDb):
|
|
|
204
205
|
self.delete_by_content_hash(content_hash)
|
|
205
206
|
await self.async_insert(content_hash, documents, filters)
|
|
206
207
|
|
|
207
|
-
def search(
|
|
208
|
+
def search(
|
|
209
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
210
|
+
) -> List[Document]:
|
|
208
211
|
"""Keyword-based search on document metadata."""
|
|
209
212
|
log_debug(f"Cassandra VectorDB : Performing Vector Search on {self.table_name} with query {query}")
|
|
213
|
+
if filters is not None:
|
|
214
|
+
log_warning("Filters are not yet supported in Cassandra. No filters will be applied.")
|
|
210
215
|
return self.vector_search(query=query, limit=limit)
|
|
211
216
|
|
|
212
217
|
async def async_search(
|
|
213
|
-
self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None
|
|
218
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
214
219
|
) -> List[Document]:
|
|
215
220
|
"""Search asynchronously by running in a thread."""
|
|
216
221
|
return await asyncio.to_thread(self.search, query, limit, filters)
|
|
@@ -221,7 +226,9 @@ class Cassandra(VectorDb):
|
|
|
221
226
|
) -> List[Document]:
|
|
222
227
|
return [self._row_to_document(row=hit) for hit in hits]
|
|
223
228
|
|
|
224
|
-
def vector_search(
|
|
229
|
+
def vector_search(
|
|
230
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
231
|
+
) -> List[Document]:
|
|
225
232
|
"""Vector similarity search implementation."""
|
|
226
233
|
query_embedding = self.embedder.get_embedding(query)
|
|
227
234
|
hits = list(
|