agno 2.0.0rc2__py3-none-any.whl → 2.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/agent/agent.py +6009 -2874
- agno/api/api.py +2 -0
- agno/api/os.py +1 -1
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +385 -6
- agno/db/dynamo/dynamo.py +388 -81
- agno/db/dynamo/schemas.py +47 -10
- agno/db/dynamo/utils.py +63 -4
- agno/db/firestore/firestore.py +435 -64
- agno/db/firestore/schemas.py +11 -0
- agno/db/firestore/utils.py +102 -4
- agno/db/gcs_json/gcs_json_db.py +384 -42
- agno/db/gcs_json/utils.py +60 -26
- agno/db/in_memory/in_memory_db.py +351 -66
- agno/db/in_memory/utils.py +60 -2
- agno/db/json/json_db.py +339 -48
- agno/db/json/utils.py +60 -26
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +510 -37
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +15 -1
- agno/db/mongo/async_mongo.py +2036 -0
- agno/db/mongo/mongo.py +653 -76
- agno/db/mongo/schemas.py +13 -0
- agno/db/mongo/utils.py +80 -8
- agno/db/mysql/mysql.py +687 -25
- agno/db/mysql/schemas.py +61 -37
- agno/db/mysql/utils.py +60 -2
- agno/db/postgres/__init__.py +2 -1
- agno/db/postgres/async_postgres.py +2001 -0
- agno/db/postgres/postgres.py +676 -57
- agno/db/postgres/schemas.py +43 -18
- agno/db/postgres/utils.py +164 -2
- agno/db/redis/redis.py +344 -38
- agno/db/redis/schemas.py +18 -0
- agno/db/redis/utils.py +60 -2
- agno/db/schemas/__init__.py +2 -1
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/memory.py +13 -0
- agno/db/singlestore/schemas.py +26 -1
- agno/db/singlestore/singlestore.py +687 -53
- agno/db/singlestore/utils.py +60 -2
- agno/db/sqlite/__init__.py +2 -1
- agno/db/sqlite/async_sqlite.py +2371 -0
- agno/db/sqlite/schemas.py +24 -0
- agno/db/sqlite/sqlite.py +774 -85
- agno/db/sqlite/utils.py +168 -5
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +309 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1361 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +50 -22
- agno/eval/accuracy.py +50 -43
- agno/eval/performance.py +6 -3
- agno/eval/reliability.py +6 -3
- agno/eval/utils.py +33 -16
- agno/exceptions.py +68 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/integrations/discord/client.py +1 -0
- agno/knowledge/chunking/agentic.py +13 -10
- agno/knowledge/chunking/fixed.py +1 -1
- agno/knowledge/chunking/semantic.py +40 -8
- agno/knowledge/chunking/strategy.py +59 -15
- agno/knowledge/embedder/aws_bedrock.py +9 -4
- agno/knowledge/embedder/azure_openai.py +54 -0
- agno/knowledge/embedder/base.py +2 -0
- agno/knowledge/embedder/cohere.py +184 -5
- agno/knowledge/embedder/fastembed.py +1 -1
- agno/knowledge/embedder/google.py +79 -1
- agno/knowledge/embedder/huggingface.py +9 -4
- agno/knowledge/embedder/jina.py +63 -0
- agno/knowledge/embedder/mistral.py +78 -11
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/ollama.py +13 -0
- agno/knowledge/embedder/openai.py +37 -65
- agno/knowledge/embedder/sentence_transformer.py +8 -4
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +69 -16
- agno/knowledge/knowledge.py +595 -187
- agno/knowledge/reader/base.py +9 -2
- agno/knowledge/reader/csv_reader.py +8 -10
- agno/knowledge/reader/docx_reader.py +5 -6
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/json_reader.py +6 -5
- agno/knowledge/reader/markdown_reader.py +13 -13
- agno/knowledge/reader/pdf_reader.py +43 -68
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +51 -6
- agno/knowledge/reader/s3_reader.py +3 -15
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/knowledge/reader/text_reader.py +13 -13
- agno/knowledge/reader/web_search_reader.py +2 -43
- agno/knowledge/reader/website_reader.py +43 -25
- agno/knowledge/reranker/__init__.py +3 -0
- agno/knowledge/types.py +9 -0
- agno/knowledge/utils.py +20 -0
- agno/media.py +339 -266
- agno/memory/manager.py +336 -82
- agno/models/aimlapi/aimlapi.py +2 -2
- agno/models/anthropic/claude.py +183 -37
- agno/models/aws/bedrock.py +52 -112
- agno/models/aws/claude.py +33 -1
- agno/models/azure/ai_foundry.py +33 -15
- agno/models/azure/openai_chat.py +25 -8
- agno/models/base.py +1011 -566
- agno/models/cerebras/cerebras.py +19 -13
- agno/models/cerebras/cerebras_openai.py +8 -5
- agno/models/cohere/chat.py +27 -1
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/dashscope/dashscope.py +1 -0
- agno/models/deepinfra/deepinfra.py +2 -2
- agno/models/deepseek/deepseek.py +2 -2
- agno/models/fireworks/fireworks.py +2 -2
- agno/models/google/gemini.py +110 -37
- agno/models/groq/groq.py +28 -11
- agno/models/huggingface/huggingface.py +2 -1
- agno/models/internlm/internlm.py +2 -2
- agno/models/langdb/langdb.py +4 -4
- agno/models/litellm/chat.py +18 -1
- agno/models/litellm/litellm_openai.py +2 -2
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/message.py +143 -4
- agno/models/meta/llama.py +27 -10
- agno/models/meta/llama_openai.py +5 -17
- agno/models/nebius/nebius.py +6 -6
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/nvidia.py +2 -2
- agno/models/ollama/chat.py +60 -6
- agno/models/openai/chat.py +102 -43
- agno/models/openai/responses.py +103 -106
- agno/models/openrouter/openrouter.py +41 -3
- agno/models/perplexity/perplexity.py +4 -5
- agno/models/portkey/portkey.py +3 -3
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +52 -0
- agno/models/response.py +81 -5
- agno/models/sambanova/sambanova.py +2 -2
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/models/together/together.py +2 -2
- agno/models/utils.py +254 -8
- agno/models/vercel/v0.py +2 -2
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +96 -0
- agno/models/vllm/vllm.py +1 -0
- agno/models/xai/xai.py +3 -2
- agno/os/app.py +543 -175
- agno/os/auth.py +24 -14
- agno/os/config.py +1 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +250 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/agui.py +23 -7
- agno/os/interfaces/agui/router.py +27 -3
- agno/os/interfaces/agui/utils.py +242 -142
- agno/os/interfaces/base.py +6 -2
- agno/os/interfaces/slack/router.py +81 -23
- agno/os/interfaces/slack/slack.py +29 -14
- agno/os/interfaces/whatsapp/router.py +11 -4
- agno/os/interfaces/whatsapp/whatsapp.py +14 -7
- agno/os/mcp.py +111 -54
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +556 -139
- agno/os/routers/evals/evals.py +71 -34
- agno/os/routers/evals/schemas.py +31 -31
- agno/os/routers/evals/utils.py +6 -5
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/knowledge.py +185 -38
- agno/os/routers/knowledge/schemas.py +82 -22
- agno/os/routers/memory/memory.py +158 -53
- agno/os/routers/memory/schemas.py +20 -16
- agno/os/routers/metrics/metrics.py +20 -8
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +499 -38
- agno/os/schema.py +308 -198
- agno/os/utils.py +401 -41
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +2 -2
- agno/reasoning/deepseek.py +2 -2
- agno/reasoning/default.py +3 -1
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +2 -2
- agno/reasoning/ollama.py +2 -2
- agno/reasoning/openai.py +7 -2
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +266 -112
- agno/run/base.py +53 -24
- agno/run/team.py +252 -111
- agno/run/workflow.py +156 -45
- agno/session/agent.py +105 -89
- agno/session/summary.py +65 -25
- agno/session/team.py +176 -96
- agno/session/workflow.py +406 -40
- agno/team/team.py +3854 -1692
- agno/tools/brightdata.py +3 -3
- agno/tools/cartesia.py +3 -5
- agno/tools/dalle.py +9 -8
- agno/tools/decorator.py +4 -2
- agno/tools/desi_vocal.py +2 -2
- agno/tools/duckduckgo.py +15 -11
- agno/tools/e2b.py +20 -13
- agno/tools/eleven_labs.py +26 -28
- agno/tools/exa.py +21 -16
- agno/tools/fal.py +4 -4
- agno/tools/file.py +153 -23
- agno/tools/file_generation.py +350 -0
- agno/tools/firecrawl.py +4 -4
- agno/tools/function.py +257 -37
- agno/tools/giphy.py +2 -2
- agno/tools/gmail.py +238 -14
- agno/tools/google_drive.py +270 -0
- agno/tools/googlecalendar.py +36 -8
- agno/tools/googlesheets.py +20 -5
- agno/tools/jira.py +20 -0
- agno/tools/knowledge.py +3 -3
- agno/tools/lumalab.py +3 -3
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +11 -17
- agno/tools/memori.py +1 -53
- agno/tools/memory.py +419 -0
- agno/tools/models/azure_openai.py +2 -2
- agno/tools/models/gemini.py +3 -3
- agno/tools/models/groq.py +3 -5
- agno/tools/models/nebius.py +7 -7
- agno/tools/models_labs.py +25 -15
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +4 -9
- agno/tools/opencv.py +3 -3
- agno/tools/parallel.py +314 -0
- agno/tools/replicate.py +7 -7
- agno/tools/scrapegraph.py +58 -31
- agno/tools/searxng.py +2 -2
- agno/tools/serper.py +2 -2
- agno/tools/slack.py +18 -3
- agno/tools/spider.py +2 -2
- agno/tools/tavily.py +146 -0
- agno/tools/whatsapp.py +1 -1
- agno/tools/workflow.py +278 -0
- agno/tools/yfinance.py +12 -11
- agno/utils/agent.py +820 -0
- agno/utils/audio.py +27 -0
- agno/utils/common.py +90 -1
- agno/utils/events.py +222 -7
- agno/utils/gemini.py +181 -23
- agno/utils/hooks.py +57 -0
- agno/utils/http.py +111 -0
- agno/utils/knowledge.py +12 -5
- agno/utils/log.py +1 -0
- agno/utils/mcp.py +95 -5
- agno/utils/media.py +188 -10
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +60 -0
- agno/utils/models/claude.py +40 -11
- agno/utils/models/cohere.py +1 -1
- agno/utils/models/watsonx.py +1 -1
- agno/utils/openai.py +1 -1
- agno/utils/print_response/agent.py +105 -21
- agno/utils/print_response/team.py +103 -38
- agno/utils/print_response/workflow.py +251 -34
- agno/utils/reasoning.py +22 -1
- agno/utils/serialize.py +32 -0
- agno/utils/streamlit.py +16 -10
- agno/utils/string.py +41 -0
- agno/utils/team.py +98 -9
- agno/utils/tools.py +1 -1
- agno/vectordb/base.py +23 -4
- agno/vectordb/cassandra/cassandra.py +65 -9
- agno/vectordb/chroma/chromadb.py +182 -38
- agno/vectordb/clickhouse/clickhousedb.py +64 -11
- agno/vectordb/couchbase/couchbase.py +105 -10
- agno/vectordb/lancedb/lance_db.py +183 -135
- agno/vectordb/langchaindb/langchaindb.py +25 -7
- agno/vectordb/lightrag/lightrag.py +17 -3
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +46 -7
- agno/vectordb/milvus/milvus.py +126 -9
- agno/vectordb/mongodb/__init__.py +7 -1
- agno/vectordb/mongodb/mongodb.py +112 -7
- agno/vectordb/pgvector/pgvector.py +142 -21
- agno/vectordb/pineconedb/pineconedb.py +80 -8
- agno/vectordb/qdrant/qdrant.py +125 -39
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +694 -0
- agno/vectordb/singlestore/singlestore.py +111 -25
- agno/vectordb/surrealdb/surrealdb.py +31 -5
- agno/vectordb/upstashdb/upstashdb.py +76 -8
- agno/vectordb/weaviate/weaviate.py +86 -15
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +112 -18
- agno/workflow/loop.py +69 -10
- agno/workflow/parallel.py +266 -118
- agno/workflow/router.py +110 -17
- agno/workflow/step.py +645 -136
- agno/workflow/steps.py +65 -6
- agno/workflow/types.py +71 -33
- agno/workflow/workflow.py +2113 -300
- agno-2.3.0.dist-info/METADATA +618 -0
- agno-2.3.0.dist-info/RECORD +577 -0
- agno-2.3.0.dist-info/licenses/LICENSE +201 -0
- agno/knowledge/reader/url_reader.py +0 -128
- agno/tools/googlesearch.py +0 -98
- agno/tools/mcp.py +0 -610
- agno/utils/models/aws_claude.py +0 -170
- agno-2.0.0rc2.dist-info/METADATA +0 -355
- agno-2.0.0rc2.dist-info/RECORD +0 -515
- agno-2.0.0rc2.dist-info/licenses/LICENSE +0 -375
- {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
- {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
agno/db/redis/redis.py
CHANGED
|
@@ -10,22 +10,26 @@ from agno.db.redis.utils import (
|
|
|
10
10
|
apply_sorting,
|
|
11
11
|
calculate_date_metrics,
|
|
12
12
|
create_index_entries,
|
|
13
|
+
deserialize_cultural_knowledge_from_db,
|
|
13
14
|
deserialize_data,
|
|
14
15
|
fetch_all_sessions_data,
|
|
15
16
|
generate_redis_key,
|
|
16
17
|
get_all_keys_for_table,
|
|
17
18
|
get_dates_to_calculate_metrics_for,
|
|
18
19
|
remove_index_entries,
|
|
20
|
+
serialize_cultural_knowledge_for_db,
|
|
19
21
|
serialize_data,
|
|
20
22
|
)
|
|
23
|
+
from agno.db.schemas.culture import CulturalKnowledge
|
|
21
24
|
from agno.db.schemas.evals import EvalFilterType, EvalRunRecord, EvalType
|
|
22
25
|
from agno.db.schemas.knowledge import KnowledgeRow
|
|
23
26
|
from agno.db.schemas.memory import UserMemory
|
|
24
27
|
from agno.session import AgentSession, Session, TeamSession, WorkflowSession
|
|
25
28
|
from agno.utils.log import log_debug, log_error, log_info
|
|
29
|
+
from agno.utils.string import generate_id
|
|
26
30
|
|
|
27
31
|
try:
|
|
28
|
-
from redis import Redis
|
|
32
|
+
from redis import Redis, RedisCluster
|
|
29
33
|
except ImportError:
|
|
30
34
|
raise ImportError("`redis` not installed. Please install it using `pip install redis`")
|
|
31
35
|
|
|
@@ -34,7 +38,7 @@ class RedisDb(BaseDb):
|
|
|
34
38
|
def __init__(
|
|
35
39
|
self,
|
|
36
40
|
id: Optional[str] = None,
|
|
37
|
-
redis_client: Optional[Redis] = None,
|
|
41
|
+
redis_client: Optional[Union[Redis, RedisCluster]] = None,
|
|
38
42
|
db_url: Optional[str] = None,
|
|
39
43
|
db_prefix: str = "agno",
|
|
40
44
|
expire: Optional[int] = None,
|
|
@@ -43,6 +47,7 @@ class RedisDb(BaseDb):
|
|
|
43
47
|
metrics_table: Optional[str] = None,
|
|
44
48
|
eval_table: Optional[str] = None,
|
|
45
49
|
knowledge_table: Optional[str] = None,
|
|
50
|
+
culture_table: Optional[str] = None,
|
|
46
51
|
):
|
|
47
52
|
"""
|
|
48
53
|
Interface for interacting with a Redis database.
|
|
@@ -52,6 +57,8 @@ class RedisDb(BaseDb):
|
|
|
52
57
|
2. Use the db_url
|
|
53
58
|
3. Raise an error if neither is provided
|
|
54
59
|
|
|
60
|
+
db_url only supports single-node Redis connections, if you need Redis Cluster support, provide a redis_client.
|
|
61
|
+
|
|
55
62
|
Args:
|
|
56
63
|
id (Optional[str]): The ID of the database.
|
|
57
64
|
redis_client (Optional[Redis]): Redis client instance to use. If not provided a new client will be created.
|
|
@@ -63,10 +70,16 @@ class RedisDb(BaseDb):
|
|
|
63
70
|
metrics_table (Optional[str]): Name of the table to store metrics
|
|
64
71
|
eval_table (Optional[str]): Name of the table to store evaluation runs
|
|
65
72
|
knowledge_table (Optional[str]): Name of the table to store knowledge documents
|
|
73
|
+
culture_table (Optional[str]): Name of the table to store cultural knowledge
|
|
66
74
|
|
|
67
75
|
Raises:
|
|
68
76
|
ValueError: If neither redis_client nor db_url is provided.
|
|
69
77
|
"""
|
|
78
|
+
if id is None:
|
|
79
|
+
base_seed = db_url or str(redis_client)
|
|
80
|
+
seed = f"{base_seed}#{db_prefix}"
|
|
81
|
+
id = generate_id(seed)
|
|
82
|
+
|
|
70
83
|
super().__init__(
|
|
71
84
|
id=id,
|
|
72
85
|
session_table=session_table,
|
|
@@ -74,6 +87,7 @@ class RedisDb(BaseDb):
|
|
|
74
87
|
metrics_table=metrics_table,
|
|
75
88
|
eval_table=eval_table,
|
|
76
89
|
knowledge_table=knowledge_table,
|
|
90
|
+
culture_table=culture_table,
|
|
77
91
|
)
|
|
78
92
|
|
|
79
93
|
self.db_prefix = db_prefix
|
|
@@ -88,6 +102,10 @@ class RedisDb(BaseDb):
|
|
|
88
102
|
|
|
89
103
|
# -- DB methods --
|
|
90
104
|
|
|
105
|
+
def table_exists(self, table_name: str) -> bool:
|
|
106
|
+
"""Redis implementation, always returns True."""
|
|
107
|
+
return True
|
|
108
|
+
|
|
91
109
|
def _get_table_name(self, table_type: str) -> str:
|
|
92
110
|
"""Get the active table name for the given table type."""
|
|
93
111
|
if table_type == "sessions":
|
|
@@ -105,6 +123,9 @@ class RedisDb(BaseDb):
|
|
|
105
123
|
elif table_type == "knowledge":
|
|
106
124
|
return self.knowledge_table_name
|
|
107
125
|
|
|
126
|
+
elif table_type == "culture":
|
|
127
|
+
return self.culture_table_name
|
|
128
|
+
|
|
108
129
|
else:
|
|
109
130
|
raise ValueError(f"Unknown table type: {table_type}")
|
|
110
131
|
|
|
@@ -233,6 +254,14 @@ class RedisDb(BaseDb):
|
|
|
233
254
|
log_error(f"Error getting all records for {table_type}: {e}")
|
|
234
255
|
return []
|
|
235
256
|
|
|
257
|
+
def get_latest_schema_version(self):
|
|
258
|
+
"""Get the latest version of the database schema."""
|
|
259
|
+
pass
|
|
260
|
+
|
|
261
|
+
def upsert_schema_version(self, version: str) -> None:
|
|
262
|
+
"""Upsert the schema version into the database."""
|
|
263
|
+
pass
|
|
264
|
+
|
|
236
265
|
# -- Session methods --
|
|
237
266
|
|
|
238
267
|
def delete_session(self, session_id: str) -> bool:
|
|
@@ -258,7 +287,7 @@ class RedisDb(BaseDb):
|
|
|
258
287
|
|
|
259
288
|
except Exception as e:
|
|
260
289
|
log_error(f"Error deleting session: {e}")
|
|
261
|
-
|
|
290
|
+
raise e
|
|
262
291
|
|
|
263
292
|
def delete_sessions(self, session_ids: List[str]) -> None:
|
|
264
293
|
"""Delete multiple sessions from Redis.
|
|
@@ -282,6 +311,7 @@ class RedisDb(BaseDb):
|
|
|
282
311
|
|
|
283
312
|
except Exception as e:
|
|
284
313
|
log_error(f"Error deleting sessions: {e}")
|
|
314
|
+
raise e
|
|
285
315
|
|
|
286
316
|
def get_session(
|
|
287
317
|
self,
|
|
@@ -294,8 +324,8 @@ class RedisDb(BaseDb):
|
|
|
294
324
|
|
|
295
325
|
Args:
|
|
296
326
|
session_id (str): The ID of the session to get.
|
|
327
|
+
session_type (SessionType): The type of session to get.
|
|
297
328
|
user_id (Optional[str]): The ID of the user to filter by.
|
|
298
|
-
session_type (Optional[SessionType]): The type of session to filter by.
|
|
299
329
|
|
|
300
330
|
Returns:
|
|
301
331
|
Optional[Union[AgentSession, TeamSession, WorkflowSession]]: The session if found, None otherwise.
|
|
@@ -311,8 +341,6 @@ class RedisDb(BaseDb):
|
|
|
311
341
|
# Apply filters
|
|
312
342
|
if user_id is not None and session.get("user_id") != user_id:
|
|
313
343
|
return None
|
|
314
|
-
if session_type is not None and session.get("session_type") != session_type:
|
|
315
|
-
return None
|
|
316
344
|
|
|
317
345
|
if not deserialize:
|
|
318
346
|
return session
|
|
@@ -328,7 +356,7 @@ class RedisDb(BaseDb):
|
|
|
328
356
|
|
|
329
357
|
except Exception as e:
|
|
330
358
|
log_error(f"Exception reading session: {e}")
|
|
331
|
-
|
|
359
|
+
raise e
|
|
332
360
|
|
|
333
361
|
# TODO: optimizable
|
|
334
362
|
def get_sessions(
|
|
@@ -409,7 +437,7 @@ class RedisDb(BaseDb):
|
|
|
409
437
|
|
|
410
438
|
except Exception as e:
|
|
411
439
|
log_error(f"Exception reading sessions: {e}")
|
|
412
|
-
|
|
440
|
+
raise e
|
|
413
441
|
|
|
414
442
|
def rename_session(
|
|
415
443
|
self, session_id: str, session_type: SessionType, session_name: str, deserialize: Optional[bool] = True
|
|
@@ -459,7 +487,7 @@ class RedisDb(BaseDb):
|
|
|
459
487
|
|
|
460
488
|
except Exception as e:
|
|
461
489
|
log_error(f"Error renaming session: {e}")
|
|
462
|
-
|
|
490
|
+
raise e
|
|
463
491
|
|
|
464
492
|
def upsert_session(
|
|
465
493
|
self, session: Session, deserialize: Optional[bool] = True
|
|
@@ -579,15 +607,53 @@ class RedisDb(BaseDb):
|
|
|
579
607
|
|
|
580
608
|
except Exception as e:
|
|
581
609
|
log_error(f"Error upserting session: {e}")
|
|
582
|
-
|
|
610
|
+
raise e
|
|
611
|
+
|
|
612
|
+
def upsert_sessions(
|
|
613
|
+
self, sessions: List[Session], deserialize: Optional[bool] = True, preserve_updated_at: bool = False
|
|
614
|
+
) -> List[Union[Session, Dict[str, Any]]]:
|
|
615
|
+
"""
|
|
616
|
+
Bulk upsert multiple sessions for improved performance on large datasets.
|
|
617
|
+
|
|
618
|
+
Args:
|
|
619
|
+
sessions (List[Session]): List of sessions to upsert.
|
|
620
|
+
deserialize (Optional[bool]): Whether to deserialize the sessions. Defaults to True.
|
|
621
|
+
|
|
622
|
+
Returns:
|
|
623
|
+
List[Union[Session, Dict[str, Any]]]: List of upserted sessions.
|
|
624
|
+
|
|
625
|
+
Raises:
|
|
626
|
+
Exception: If an error occurs during bulk upsert.
|
|
627
|
+
"""
|
|
628
|
+
if not sessions:
|
|
629
|
+
return []
|
|
630
|
+
|
|
631
|
+
try:
|
|
632
|
+
log_info(
|
|
633
|
+
f"RedisDb doesn't support efficient bulk operations, falling back to individual upserts for {len(sessions)} sessions"
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
# Fall back to individual upserts
|
|
637
|
+
results = []
|
|
638
|
+
for session in sessions:
|
|
639
|
+
if session is not None:
|
|
640
|
+
result = self.upsert_session(session, deserialize=deserialize)
|
|
641
|
+
if result is not None:
|
|
642
|
+
results.append(result)
|
|
643
|
+
return results
|
|
644
|
+
|
|
645
|
+
except Exception as e:
|
|
646
|
+
log_error(f"Exception during bulk session upsert: {e}")
|
|
647
|
+
return []
|
|
583
648
|
|
|
584
649
|
# -- Memory methods --
|
|
585
650
|
|
|
586
|
-
def delete_user_memory(self, memory_id: str):
|
|
651
|
+
def delete_user_memory(self, memory_id: str, user_id: Optional[str] = None):
|
|
587
652
|
"""Delete a user memory from Redis.
|
|
588
653
|
|
|
589
654
|
Args:
|
|
590
655
|
memory_id (str): The ID of the memory to delete.
|
|
656
|
+
user_id (Optional[str]): The ID of the user. If provided, verifies the memory belongs to this user before deleting.
|
|
591
657
|
|
|
592
658
|
Returns:
|
|
593
659
|
bool: True if the memory was deleted, False otherwise.
|
|
@@ -596,6 +662,16 @@ class RedisDb(BaseDb):
|
|
|
596
662
|
Exception: If any error occurs while deleting the memory.
|
|
597
663
|
"""
|
|
598
664
|
try:
|
|
665
|
+
# If user_id is provided, verify ownership before deleting
|
|
666
|
+
if user_id is not None:
|
|
667
|
+
memory = self._get_record("memories", memory_id)
|
|
668
|
+
if memory is None:
|
|
669
|
+
log_debug(f"No user memory found with id: {memory_id}")
|
|
670
|
+
return
|
|
671
|
+
if memory.get("user_id") != user_id:
|
|
672
|
+
log_debug(f"Memory {memory_id} does not belong to user {user_id}")
|
|
673
|
+
return
|
|
674
|
+
|
|
599
675
|
if self._delete_record(
|
|
600
676
|
"memories", memory_id, index_fields=["user_id", "agent_id", "team_id", "workflow_id"]
|
|
601
677
|
):
|
|
@@ -605,16 +681,27 @@ class RedisDb(BaseDb):
|
|
|
605
681
|
|
|
606
682
|
except Exception as e:
|
|
607
683
|
log_error(f"Error deleting user memory: {e}")
|
|
684
|
+
raise e
|
|
608
685
|
|
|
609
|
-
def delete_user_memories(self, memory_ids: List[str]) -> None:
|
|
686
|
+
def delete_user_memories(self, memory_ids: List[str], user_id: Optional[str] = None) -> None:
|
|
610
687
|
"""Delete user memories from Redis.
|
|
611
688
|
|
|
612
689
|
Args:
|
|
613
690
|
memory_ids (List[str]): The IDs of the memories to delete.
|
|
691
|
+
user_id (Optional[str]): The ID of the user. If provided, only deletes memories belonging to this user.
|
|
614
692
|
"""
|
|
615
693
|
try:
|
|
616
694
|
# TODO: cant we optimize this?
|
|
617
695
|
for memory_id in memory_ids:
|
|
696
|
+
# If user_id is provided, verify ownership before deleting
|
|
697
|
+
if user_id is not None:
|
|
698
|
+
memory = self._get_record("memories", memory_id)
|
|
699
|
+
if memory is None:
|
|
700
|
+
continue
|
|
701
|
+
if memory.get("user_id") != user_id:
|
|
702
|
+
log_debug(f"Memory {memory_id} does not belong to user {user_id}, skipping deletion")
|
|
703
|
+
continue
|
|
704
|
+
|
|
618
705
|
self._delete_record(
|
|
619
706
|
"memories",
|
|
620
707
|
memory_id,
|
|
@@ -623,6 +710,7 @@ class RedisDb(BaseDb):
|
|
|
623
710
|
|
|
624
711
|
except Exception as e:
|
|
625
712
|
log_error(f"Error deleting user memories: {e}")
|
|
713
|
+
raise e
|
|
626
714
|
|
|
627
715
|
def get_all_memory_topics(self) -> List[str]:
|
|
628
716
|
"""Get all memory topics from Redis.
|
|
@@ -643,15 +731,17 @@ class RedisDb(BaseDb):
|
|
|
643
731
|
|
|
644
732
|
except Exception as e:
|
|
645
733
|
log_error(f"Exception reading memory topics: {e}")
|
|
646
|
-
|
|
734
|
+
raise e
|
|
647
735
|
|
|
648
736
|
def get_user_memory(
|
|
649
|
-
self, memory_id: str, deserialize: Optional[bool] = True
|
|
737
|
+
self, memory_id: str, deserialize: Optional[bool] = True, user_id: Optional[str] = None
|
|
650
738
|
) -> Optional[Union[UserMemory, Dict[str, Any]]]:
|
|
651
739
|
"""Get a memory from Redis.
|
|
652
740
|
|
|
653
741
|
Args:
|
|
654
742
|
memory_id (str): The ID of the memory to get.
|
|
743
|
+
deserialize (Optional[bool]): Whether to deserialize the memory. Defaults to True.
|
|
744
|
+
user_id (Optional[str]): The ID of the user. If provided, only returns the memory if it belongs to this user.
|
|
655
745
|
|
|
656
746
|
Returns:
|
|
657
747
|
Optional[UserMemory]: The memory data if found, None otherwise.
|
|
@@ -661,6 +751,10 @@ class RedisDb(BaseDb):
|
|
|
661
751
|
if memory_raw is None:
|
|
662
752
|
return None
|
|
663
753
|
|
|
754
|
+
# Filter by user_id if provided
|
|
755
|
+
if user_id is not None and memory_raw.get("user_id") != user_id:
|
|
756
|
+
return None
|
|
757
|
+
|
|
664
758
|
if not deserialize:
|
|
665
759
|
return memory_raw
|
|
666
760
|
|
|
@@ -668,7 +762,7 @@ class RedisDb(BaseDb):
|
|
|
668
762
|
|
|
669
763
|
except Exception as e:
|
|
670
764
|
log_error(f"Exception reading memory: {e}")
|
|
671
|
-
|
|
765
|
+
raise e
|
|
672
766
|
|
|
673
767
|
def get_user_memories(
|
|
674
768
|
self,
|
|
@@ -741,7 +835,7 @@ class RedisDb(BaseDb):
|
|
|
741
835
|
|
|
742
836
|
except Exception as e:
|
|
743
837
|
log_error(f"Exception reading memories: {e}")
|
|
744
|
-
|
|
838
|
+
raise e
|
|
745
839
|
|
|
746
840
|
def get_user_memory_stats(
|
|
747
841
|
self,
|
|
@@ -766,21 +860,21 @@ class RedisDb(BaseDb):
|
|
|
766
860
|
# Group by user_id
|
|
767
861
|
user_stats = {}
|
|
768
862
|
for memory in all_memories:
|
|
769
|
-
|
|
770
|
-
if
|
|
863
|
+
memory_user_id = memory.get("user_id")
|
|
864
|
+
if memory_user_id is None:
|
|
771
865
|
continue
|
|
772
866
|
|
|
773
|
-
if
|
|
774
|
-
user_stats[
|
|
775
|
-
"user_id":
|
|
867
|
+
if memory_user_id not in user_stats:
|
|
868
|
+
user_stats[memory_user_id] = {
|
|
869
|
+
"user_id": memory_user_id,
|
|
776
870
|
"total_memories": 0,
|
|
777
871
|
"last_memory_updated_at": 0,
|
|
778
872
|
}
|
|
779
873
|
|
|
780
|
-
user_stats[
|
|
874
|
+
user_stats[memory_user_id]["total_memories"] += 1
|
|
781
875
|
updated_at = memory.get("updated_at", 0)
|
|
782
|
-
if updated_at > user_stats[
|
|
783
|
-
user_stats[
|
|
876
|
+
if updated_at > user_stats[memory_user_id]["last_memory_updated_at"]:
|
|
877
|
+
user_stats[memory_user_id]["last_memory_updated_at"] = updated_at
|
|
784
878
|
|
|
785
879
|
stats_list = list(user_stats.values())
|
|
786
880
|
|
|
@@ -795,7 +889,7 @@ class RedisDb(BaseDb):
|
|
|
795
889
|
|
|
796
890
|
except Exception as e:
|
|
797
891
|
log_error(f"Exception getting user memory stats: {e}")
|
|
798
|
-
|
|
892
|
+
raise e
|
|
799
893
|
|
|
800
894
|
def upsert_user_memory(
|
|
801
895
|
self, memory: UserMemory, deserialize: Optional[bool] = True
|
|
@@ -819,6 +913,9 @@ class RedisDb(BaseDb):
|
|
|
819
913
|
"memory_id": memory.memory_id,
|
|
820
914
|
"memory": memory.memory,
|
|
821
915
|
"topics": memory.topics,
|
|
916
|
+
"input": memory.input,
|
|
917
|
+
"feedback": memory.feedback,
|
|
918
|
+
"created_at": memory.created_at,
|
|
822
919
|
"updated_at": int(time.time()),
|
|
823
920
|
}
|
|
824
921
|
|
|
@@ -836,7 +933,44 @@ class RedisDb(BaseDb):
|
|
|
836
933
|
|
|
837
934
|
except Exception as e:
|
|
838
935
|
log_error(f"Error upserting user memory: {e}")
|
|
839
|
-
|
|
936
|
+
raise e
|
|
937
|
+
|
|
938
|
+
def upsert_memories(
|
|
939
|
+
self, memories: List[UserMemory], deserialize: Optional[bool] = True, preserve_updated_at: bool = False
|
|
940
|
+
) -> List[Union[UserMemory, Dict[str, Any]]]:
|
|
941
|
+
"""
|
|
942
|
+
Bulk upsert multiple user memories for improved performance on large datasets.
|
|
943
|
+
|
|
944
|
+
Args:
|
|
945
|
+
memories (List[UserMemory]): List of memories to upsert.
|
|
946
|
+
deserialize (Optional[bool]): Whether to deserialize the memories. Defaults to True.
|
|
947
|
+
|
|
948
|
+
Returns:
|
|
949
|
+
List[Union[UserMemory, Dict[str, Any]]]: List of upserted memories.
|
|
950
|
+
|
|
951
|
+
Raises:
|
|
952
|
+
Exception: If an error occurs during bulk upsert.
|
|
953
|
+
"""
|
|
954
|
+
if not memories:
|
|
955
|
+
return []
|
|
956
|
+
|
|
957
|
+
try:
|
|
958
|
+
log_info(
|
|
959
|
+
f"RedisDb doesn't support efficient bulk operations, falling back to individual upserts for {len(memories)} memories"
|
|
960
|
+
)
|
|
961
|
+
|
|
962
|
+
# Fall back to individual upserts
|
|
963
|
+
results = []
|
|
964
|
+
for memory in memories:
|
|
965
|
+
if memory is not None:
|
|
966
|
+
result = self.upsert_user_memory(memory, deserialize=deserialize)
|
|
967
|
+
if result is not None:
|
|
968
|
+
results.append(result)
|
|
969
|
+
return results
|
|
970
|
+
|
|
971
|
+
except Exception as e:
|
|
972
|
+
log_error(f"Exception during bulk memory upsert: {e}")
|
|
973
|
+
return []
|
|
840
974
|
|
|
841
975
|
def clear_memories(self) -> None:
|
|
842
976
|
"""Delete all memories from the database.
|
|
@@ -853,9 +987,8 @@ class RedisDb(BaseDb):
|
|
|
853
987
|
self.redis_client.delete(*keys)
|
|
854
988
|
|
|
855
989
|
except Exception as e:
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
log_warning(f"Exception deleting all memories: {e}")
|
|
990
|
+
log_error(f"Exception deleting all memories: {e}")
|
|
991
|
+
raise e
|
|
859
992
|
|
|
860
993
|
# -- Metrics methods --
|
|
861
994
|
|
|
@@ -893,7 +1026,7 @@ class RedisDb(BaseDb):
|
|
|
893
1026
|
|
|
894
1027
|
except Exception as e:
|
|
895
1028
|
log_error(f"Error reading sessions for metrics: {e}")
|
|
896
|
-
|
|
1029
|
+
raise e
|
|
897
1030
|
|
|
898
1031
|
def _get_metrics_calculation_starting_date(self) -> Optional[date]:
|
|
899
1032
|
"""Get the first date for which metrics calculation is needed.
|
|
@@ -930,7 +1063,7 @@ class RedisDb(BaseDb):
|
|
|
930
1063
|
|
|
931
1064
|
except Exception as e:
|
|
932
1065
|
log_error(f"Error getting metrics starting date: {e}")
|
|
933
|
-
|
|
1066
|
+
raise e
|
|
934
1067
|
|
|
935
1068
|
def calculate_metrics(self) -> Optional[list[dict]]:
|
|
936
1069
|
"""Calculate metrics for all dates without complete metrics.
|
|
@@ -1037,7 +1170,7 @@ class RedisDb(BaseDb):
|
|
|
1037
1170
|
|
|
1038
1171
|
except Exception as e:
|
|
1039
1172
|
log_error(f"Error getting metrics: {e}")
|
|
1040
|
-
|
|
1173
|
+
raise e
|
|
1041
1174
|
|
|
1042
1175
|
# -- Knowledge methods --
|
|
1043
1176
|
|
|
@@ -1055,6 +1188,7 @@ class RedisDb(BaseDb):
|
|
|
1055
1188
|
|
|
1056
1189
|
except Exception as e:
|
|
1057
1190
|
log_error(f"Error deleting knowledge content: {e}")
|
|
1191
|
+
raise e
|
|
1058
1192
|
|
|
1059
1193
|
def get_knowledge_content(self, id: str) -> Optional[KnowledgeRow]:
|
|
1060
1194
|
"""Get a knowledge row from the database.
|
|
@@ -1077,7 +1211,7 @@ class RedisDb(BaseDb):
|
|
|
1077
1211
|
|
|
1078
1212
|
except Exception as e:
|
|
1079
1213
|
log_error(f"Error getting knowledge content: {e}")
|
|
1080
|
-
|
|
1214
|
+
raise e
|
|
1081
1215
|
|
|
1082
1216
|
def get_knowledge_contents(
|
|
1083
1217
|
self,
|
|
@@ -1120,7 +1254,7 @@ class RedisDb(BaseDb):
|
|
|
1120
1254
|
|
|
1121
1255
|
except Exception as e:
|
|
1122
1256
|
log_error(f"Error getting knowledge contents: {e}")
|
|
1123
|
-
|
|
1257
|
+
raise e
|
|
1124
1258
|
|
|
1125
1259
|
def upsert_knowledge_content(self, knowledge_row: KnowledgeRow):
|
|
1126
1260
|
"""Upsert knowledge content in the database.
|
|
@@ -1142,7 +1276,7 @@ class RedisDb(BaseDb):
|
|
|
1142
1276
|
|
|
1143
1277
|
except Exception as e:
|
|
1144
1278
|
log_error(f"Error upserting knowledge content: {e}")
|
|
1145
|
-
|
|
1279
|
+
raise e
|
|
1146
1280
|
|
|
1147
1281
|
# -- Eval methods --
|
|
1148
1282
|
|
|
@@ -1175,7 +1309,7 @@ class RedisDb(BaseDb):
|
|
|
1175
1309
|
|
|
1176
1310
|
except Exception as e:
|
|
1177
1311
|
log_error(f"Error creating eval run: {e}")
|
|
1178
|
-
|
|
1312
|
+
raise e
|
|
1179
1313
|
|
|
1180
1314
|
def delete_eval_run(self, eval_run_id: str) -> None:
|
|
1181
1315
|
"""Delete an eval run from Redis.
|
|
@@ -1250,7 +1384,7 @@ class RedisDb(BaseDb):
|
|
|
1250
1384
|
|
|
1251
1385
|
except Exception as e:
|
|
1252
1386
|
log_error(f"Exception getting eval run {eval_run_id}: {e}")
|
|
1253
|
-
|
|
1387
|
+
raise e
|
|
1254
1388
|
|
|
1255
1389
|
def get_eval_runs(
|
|
1256
1390
|
self,
|
|
@@ -1326,7 +1460,7 @@ class RedisDb(BaseDb):
|
|
|
1326
1460
|
|
|
1327
1461
|
except Exception as e:
|
|
1328
1462
|
log_error(f"Exception getting eval runs: {e}")
|
|
1329
|
-
|
|
1463
|
+
raise e
|
|
1330
1464
|
|
|
1331
1465
|
def rename_eval_run(
|
|
1332
1466
|
self, eval_run_id: str, name: str, deserialize: Optional[bool] = True
|
|
@@ -1365,3 +1499,175 @@ class RedisDb(BaseDb):
|
|
|
1365
1499
|
except Exception as e:
|
|
1366
1500
|
log_error(f"Error updating eval run name {eval_run_id}: {e}")
|
|
1367
1501
|
raise
|
|
1502
|
+
|
|
1503
|
+
# -- Cultural Knowledge methods --
|
|
1504
|
+
def clear_cultural_knowledge(self) -> None:
|
|
1505
|
+
"""Delete all cultural knowledge from the database.
|
|
1506
|
+
|
|
1507
|
+
Raises:
|
|
1508
|
+
Exception: If an error occurs during deletion.
|
|
1509
|
+
"""
|
|
1510
|
+
try:
|
|
1511
|
+
keys = get_all_keys_for_table(redis_client=self.redis_client, prefix=self.db_prefix, table_type="culture")
|
|
1512
|
+
|
|
1513
|
+
if keys:
|
|
1514
|
+
self.redis_client.delete(*keys)
|
|
1515
|
+
|
|
1516
|
+
except Exception as e:
|
|
1517
|
+
log_error(f"Exception deleting all cultural knowledge: {e}")
|
|
1518
|
+
raise e
|
|
1519
|
+
|
|
1520
|
+
def delete_cultural_knowledge(self, id: str) -> None:
|
|
1521
|
+
"""Delete cultural knowledge by ID.
|
|
1522
|
+
|
|
1523
|
+
Args:
|
|
1524
|
+
id (str): The ID of the cultural knowledge to delete.
|
|
1525
|
+
|
|
1526
|
+
Raises:
|
|
1527
|
+
Exception: If an error occurs during deletion.
|
|
1528
|
+
"""
|
|
1529
|
+
try:
|
|
1530
|
+
if self._delete_record("culture", id, index_fields=["name", "agent_id", "team_id"]):
|
|
1531
|
+
log_debug(f"Successfully deleted cultural knowledge id: {id}")
|
|
1532
|
+
else:
|
|
1533
|
+
log_debug(f"No cultural knowledge found with id: {id}")
|
|
1534
|
+
|
|
1535
|
+
except Exception as e:
|
|
1536
|
+
log_error(f"Error deleting cultural knowledge: {e}")
|
|
1537
|
+
raise e
|
|
1538
|
+
|
|
1539
|
+
def get_cultural_knowledge(
|
|
1540
|
+
self, id: str, deserialize: Optional[bool] = True
|
|
1541
|
+
) -> Optional[Union[CulturalKnowledge, Dict[str, Any]]]:
|
|
1542
|
+
"""Get cultural knowledge by ID.
|
|
1543
|
+
|
|
1544
|
+
Args:
|
|
1545
|
+
id (str): The ID of the cultural knowledge to retrieve.
|
|
1546
|
+
deserialize (Optional[bool]): Whether to deserialize to CulturalKnowledge object. Defaults to True.
|
|
1547
|
+
|
|
1548
|
+
Returns:
|
|
1549
|
+
Optional[Union[CulturalKnowledge, Dict[str, Any]]]: The cultural knowledge if found, None otherwise.
|
|
1550
|
+
|
|
1551
|
+
Raises:
|
|
1552
|
+
Exception: If an error occurs during retrieval.
|
|
1553
|
+
"""
|
|
1554
|
+
try:
|
|
1555
|
+
cultural_knowledge = self._get_record("culture", id)
|
|
1556
|
+
|
|
1557
|
+
if cultural_knowledge is None:
|
|
1558
|
+
return None
|
|
1559
|
+
|
|
1560
|
+
if not deserialize:
|
|
1561
|
+
return cultural_knowledge
|
|
1562
|
+
|
|
1563
|
+
return deserialize_cultural_knowledge_from_db(cultural_knowledge)
|
|
1564
|
+
|
|
1565
|
+
except Exception as e:
|
|
1566
|
+
log_error(f"Error getting cultural knowledge: {e}")
|
|
1567
|
+
raise e
|
|
1568
|
+
|
|
1569
|
+
def get_all_cultural_knowledge(
|
|
1570
|
+
self,
|
|
1571
|
+
agent_id: Optional[str] = None,
|
|
1572
|
+
team_id: Optional[str] = None,
|
|
1573
|
+
name: Optional[str] = None,
|
|
1574
|
+
limit: Optional[int] = None,
|
|
1575
|
+
page: Optional[int] = None,
|
|
1576
|
+
sort_by: Optional[str] = None,
|
|
1577
|
+
sort_order: Optional[str] = None,
|
|
1578
|
+
deserialize: Optional[bool] = True,
|
|
1579
|
+
) -> Union[List[CulturalKnowledge], Tuple[List[Dict[str, Any]], int]]:
|
|
1580
|
+
"""Get all cultural knowledge with filtering and pagination.
|
|
1581
|
+
|
|
1582
|
+
Args:
|
|
1583
|
+
agent_id (Optional[str]): Filter by agent ID.
|
|
1584
|
+
team_id (Optional[str]): Filter by team ID.
|
|
1585
|
+
name (Optional[str]): Filter by name (case-insensitive partial match).
|
|
1586
|
+
limit (Optional[int]): Maximum number of results to return.
|
|
1587
|
+
page (Optional[int]): Page number for pagination.
|
|
1588
|
+
sort_by (Optional[str]): Field to sort by.
|
|
1589
|
+
sort_order (Optional[str]): Sort order ('asc' or 'desc').
|
|
1590
|
+
deserialize (Optional[bool]): Whether to deserialize to CulturalKnowledge objects. Defaults to True.
|
|
1591
|
+
|
|
1592
|
+
Returns:
|
|
1593
|
+
Union[List[CulturalKnowledge], Tuple[List[Dict[str, Any]], int]]:
|
|
1594
|
+
- When deserialize=True: List of CulturalKnowledge objects
|
|
1595
|
+
- When deserialize=False: Tuple with list of dictionaries and total count
|
|
1596
|
+
|
|
1597
|
+
Raises:
|
|
1598
|
+
Exception: If an error occurs during retrieval.
|
|
1599
|
+
"""
|
|
1600
|
+
try:
|
|
1601
|
+
all_cultural_knowledge = self._get_all_records("culture")
|
|
1602
|
+
|
|
1603
|
+
# Apply filters
|
|
1604
|
+
filtered_items = []
|
|
1605
|
+
for item in all_cultural_knowledge:
|
|
1606
|
+
if agent_id is not None and item.get("agent_id") != agent_id:
|
|
1607
|
+
continue
|
|
1608
|
+
if team_id is not None and item.get("team_id") != team_id:
|
|
1609
|
+
continue
|
|
1610
|
+
if name is not None and name.lower() not in item.get("name", "").lower():
|
|
1611
|
+
continue
|
|
1612
|
+
|
|
1613
|
+
filtered_items.append(item)
|
|
1614
|
+
|
|
1615
|
+
sorted_items = apply_sorting(records=filtered_items, sort_by=sort_by, sort_order=sort_order)
|
|
1616
|
+
paginated_items = apply_pagination(records=sorted_items, limit=limit, page=page)
|
|
1617
|
+
|
|
1618
|
+
if not deserialize:
|
|
1619
|
+
return paginated_items, len(filtered_items)
|
|
1620
|
+
|
|
1621
|
+
return [deserialize_cultural_knowledge_from_db(item) for item in paginated_items]
|
|
1622
|
+
|
|
1623
|
+
except Exception as e:
|
|
1624
|
+
log_error(f"Error getting all cultural knowledge: {e}")
|
|
1625
|
+
raise e
|
|
1626
|
+
|
|
1627
|
+
def upsert_cultural_knowledge(
|
|
1628
|
+
self, cultural_knowledge: CulturalKnowledge, deserialize: Optional[bool] = True
|
|
1629
|
+
) -> Optional[Union[CulturalKnowledge, Dict[str, Any]]]:
|
|
1630
|
+
"""Upsert cultural knowledge in Redis.
|
|
1631
|
+
|
|
1632
|
+
Args:
|
|
1633
|
+
cultural_knowledge (CulturalKnowledge): The cultural knowledge to upsert.
|
|
1634
|
+
deserialize (Optional[bool]): Whether to deserialize the result. Defaults to True.
|
|
1635
|
+
|
|
1636
|
+
Returns:
|
|
1637
|
+
Optional[Union[CulturalKnowledge, Dict[str, Any]]]: The upserted cultural knowledge.
|
|
1638
|
+
|
|
1639
|
+
Raises:
|
|
1640
|
+
Exception: If an error occurs during upsert.
|
|
1641
|
+
"""
|
|
1642
|
+
try:
|
|
1643
|
+
# Serialize content, categories, and notes into a dict for DB storage
|
|
1644
|
+
content_dict = serialize_cultural_knowledge_for_db(cultural_knowledge)
|
|
1645
|
+
item_id = cultural_knowledge.id or str(uuid4())
|
|
1646
|
+
|
|
1647
|
+
# Create the item dict with serialized content
|
|
1648
|
+
data = {
|
|
1649
|
+
"id": item_id,
|
|
1650
|
+
"name": cultural_knowledge.name,
|
|
1651
|
+
"summary": cultural_knowledge.summary,
|
|
1652
|
+
"content": content_dict if content_dict else None,
|
|
1653
|
+
"metadata": cultural_knowledge.metadata,
|
|
1654
|
+
"input": cultural_knowledge.input,
|
|
1655
|
+
"created_at": cultural_knowledge.created_at,
|
|
1656
|
+
"updated_at": int(time.time()),
|
|
1657
|
+
"agent_id": cultural_knowledge.agent_id,
|
|
1658
|
+
"team_id": cultural_knowledge.team_id,
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
success = self._store_record("culture", item_id, data, index_fields=["name", "agent_id", "team_id"])
|
|
1662
|
+
|
|
1663
|
+
if not success:
|
|
1664
|
+
return None
|
|
1665
|
+
|
|
1666
|
+
if not deserialize:
|
|
1667
|
+
return data
|
|
1668
|
+
|
|
1669
|
+
return deserialize_cultural_knowledge_from_db(data)
|
|
1670
|
+
|
|
1671
|
+
except Exception as e:
|
|
1672
|
+
log_error(f"Error upserting cultural knowledge: {e}")
|
|
1673
|
+
raise e
|