vanna 0.7.8__py3-none-any.whl → 2.0.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.
- vanna/__init__.py +167 -395
- vanna/agents/__init__.py +7 -0
- vanna/capabilities/__init__.py +17 -0
- vanna/capabilities/agent_memory/__init__.py +21 -0
- vanna/capabilities/agent_memory/base.py +103 -0
- vanna/capabilities/agent_memory/models.py +53 -0
- vanna/capabilities/file_system/__init__.py +14 -0
- vanna/capabilities/file_system/base.py +71 -0
- vanna/capabilities/file_system/models.py +25 -0
- vanna/capabilities/sql_runner/__init__.py +13 -0
- vanna/capabilities/sql_runner/base.py +37 -0
- vanna/capabilities/sql_runner/models.py +13 -0
- vanna/components/__init__.py +92 -0
- vanna/components/base.py +11 -0
- vanna/components/rich/__init__.py +83 -0
- vanna/components/rich/containers/__init__.py +7 -0
- vanna/components/rich/containers/card.py +20 -0
- vanna/components/rich/data/__init__.py +9 -0
- vanna/components/rich/data/chart.py +17 -0
- vanna/components/rich/data/dataframe.py +93 -0
- vanna/components/rich/feedback/__init__.py +21 -0
- vanna/components/rich/feedback/badge.py +16 -0
- vanna/components/rich/feedback/icon_text.py +14 -0
- vanna/components/rich/feedback/log_viewer.py +41 -0
- vanna/components/rich/feedback/notification.py +19 -0
- vanna/components/rich/feedback/progress.py +37 -0
- vanna/components/rich/feedback/status_card.py +28 -0
- vanna/components/rich/feedback/status_indicator.py +14 -0
- vanna/components/rich/interactive/__init__.py +21 -0
- vanna/components/rich/interactive/button.py +95 -0
- vanna/components/rich/interactive/task_list.py +58 -0
- vanna/components/rich/interactive/ui_state.py +93 -0
- vanna/components/rich/specialized/__init__.py +7 -0
- vanna/components/rich/specialized/artifact.py +20 -0
- vanna/components/rich/text.py +16 -0
- vanna/components/simple/__init__.py +15 -0
- vanna/components/simple/image.py +15 -0
- vanna/components/simple/link.py +15 -0
- vanna/components/simple/text.py +11 -0
- vanna/core/__init__.py +193 -0
- vanna/core/_compat.py +19 -0
- vanna/core/agent/__init__.py +10 -0
- vanna/core/agent/agent.py +1407 -0
- vanna/core/agent/config.py +123 -0
- vanna/core/audit/__init__.py +28 -0
- vanna/core/audit/base.py +299 -0
- vanna/core/audit/models.py +131 -0
- vanna/core/component_manager.py +329 -0
- vanna/core/components.py +53 -0
- vanna/core/enhancer/__init__.py +11 -0
- vanna/core/enhancer/base.py +94 -0
- vanna/core/enhancer/default.py +118 -0
- vanna/core/enricher/__init__.py +10 -0
- vanna/core/enricher/base.py +59 -0
- vanna/core/errors.py +47 -0
- vanna/core/evaluation/__init__.py +81 -0
- vanna/core/evaluation/base.py +186 -0
- vanna/core/evaluation/dataset.py +254 -0
- vanna/core/evaluation/evaluators.py +376 -0
- vanna/core/evaluation/report.py +289 -0
- vanna/core/evaluation/runner.py +313 -0
- vanna/core/filter/__init__.py +10 -0
- vanna/core/filter/base.py +67 -0
- vanna/core/lifecycle/__init__.py +10 -0
- vanna/core/lifecycle/base.py +83 -0
- vanna/core/llm/__init__.py +16 -0
- vanna/core/llm/base.py +40 -0
- vanna/core/llm/models.py +61 -0
- vanna/core/middleware/__init__.py +10 -0
- vanna/core/middleware/base.py +69 -0
- vanna/core/observability/__init__.py +11 -0
- vanna/core/observability/base.py +88 -0
- vanna/core/observability/models.py +47 -0
- vanna/core/recovery/__init__.py +11 -0
- vanna/core/recovery/base.py +84 -0
- vanna/core/recovery/models.py +32 -0
- vanna/core/registry.py +278 -0
- vanna/core/rich_component.py +156 -0
- vanna/core/simple_component.py +27 -0
- vanna/core/storage/__init__.py +14 -0
- vanna/core/storage/base.py +46 -0
- vanna/core/storage/models.py +46 -0
- vanna/core/system_prompt/__init__.py +13 -0
- vanna/core/system_prompt/base.py +36 -0
- vanna/core/system_prompt/default.py +157 -0
- vanna/core/tool/__init__.py +18 -0
- vanna/core/tool/base.py +70 -0
- vanna/core/tool/models.py +84 -0
- vanna/core/user/__init__.py +17 -0
- vanna/core/user/base.py +29 -0
- vanna/core/user/models.py +25 -0
- vanna/core/user/request_context.py +70 -0
- vanna/core/user/resolver.py +42 -0
- vanna/core/validation.py +164 -0
- vanna/core/workflow/__init__.py +12 -0
- vanna/core/workflow/base.py +254 -0
- vanna/core/workflow/default.py +789 -0
- vanna/examples/__init__.py +1 -0
- vanna/examples/__main__.py +44 -0
- vanna/examples/anthropic_quickstart.py +80 -0
- vanna/examples/artifact_example.py +293 -0
- vanna/examples/claude_sqlite_example.py +236 -0
- vanna/examples/coding_agent_example.py +300 -0
- vanna/examples/custom_system_prompt_example.py +174 -0
- vanna/examples/default_workflow_handler_example.py +208 -0
- vanna/examples/email_auth_example.py +340 -0
- vanna/examples/evaluation_example.py +269 -0
- vanna/examples/extensibility_example.py +262 -0
- vanna/examples/minimal_example.py +67 -0
- vanna/examples/mock_auth_example.py +227 -0
- vanna/examples/mock_custom_tool.py +311 -0
- vanna/examples/mock_quickstart.py +79 -0
- vanna/examples/mock_quota_example.py +145 -0
- vanna/examples/mock_rich_components_demo.py +396 -0
- vanna/examples/mock_sqlite_example.py +223 -0
- vanna/examples/openai_quickstart.py +83 -0
- vanna/examples/primitive_components_demo.py +305 -0
- vanna/examples/quota_lifecycle_example.py +139 -0
- vanna/examples/visualization_example.py +251 -0
- vanna/integrations/__init__.py +17 -0
- vanna/integrations/anthropic/__init__.py +9 -0
- vanna/integrations/anthropic/llm.py +270 -0
- vanna/integrations/azureopenai/__init__.py +9 -0
- vanna/integrations/azureopenai/llm.py +329 -0
- vanna/integrations/azuresearch/__init__.py +7 -0
- vanna/integrations/azuresearch/agent_memory.py +413 -0
- vanna/integrations/bigquery/__init__.py +5 -0
- vanna/integrations/bigquery/sql_runner.py +81 -0
- vanna/integrations/chromadb/__init__.py +104 -0
- vanna/integrations/chromadb/agent_memory.py +416 -0
- vanna/integrations/clickhouse/__init__.py +5 -0
- vanna/integrations/clickhouse/sql_runner.py +82 -0
- vanna/integrations/duckdb/__init__.py +5 -0
- vanna/integrations/duckdb/sql_runner.py +65 -0
- vanna/integrations/faiss/__init__.py +7 -0
- vanna/integrations/faiss/agent_memory.py +431 -0
- vanna/integrations/google/__init__.py +9 -0
- vanna/integrations/google/gemini.py +370 -0
- vanna/integrations/hive/__init__.py +5 -0
- vanna/integrations/hive/sql_runner.py +87 -0
- vanna/integrations/local/__init__.py +17 -0
- vanna/integrations/local/agent_memory/__init__.py +7 -0
- vanna/integrations/local/agent_memory/in_memory.py +285 -0
- vanna/integrations/local/audit.py +59 -0
- vanna/integrations/local/file_system.py +242 -0
- vanna/integrations/local/file_system_conversation_store.py +255 -0
- vanna/integrations/local/storage.py +62 -0
- vanna/integrations/marqo/__init__.py +7 -0
- vanna/integrations/marqo/agent_memory.py +354 -0
- vanna/integrations/milvus/__init__.py +7 -0
- vanna/integrations/milvus/agent_memory.py +458 -0
- vanna/integrations/mock/__init__.py +9 -0
- vanna/integrations/mock/llm.py +65 -0
- vanna/integrations/mssql/__init__.py +5 -0
- vanna/integrations/mssql/sql_runner.py +66 -0
- vanna/integrations/mysql/__init__.py +5 -0
- vanna/integrations/mysql/sql_runner.py +92 -0
- vanna/integrations/ollama/__init__.py +7 -0
- vanna/integrations/ollama/llm.py +252 -0
- vanna/integrations/openai/__init__.py +10 -0
- vanna/integrations/openai/llm.py +267 -0
- vanna/integrations/openai/responses.py +163 -0
- vanna/integrations/opensearch/__init__.py +7 -0
- vanna/integrations/opensearch/agent_memory.py +411 -0
- vanna/integrations/oracle/__init__.py +5 -0
- vanna/integrations/oracle/sql_runner.py +75 -0
- vanna/integrations/pinecone/__init__.py +7 -0
- vanna/integrations/pinecone/agent_memory.py +329 -0
- vanna/integrations/plotly/__init__.py +5 -0
- vanna/integrations/plotly/chart_generator.py +313 -0
- vanna/integrations/postgres/__init__.py +9 -0
- vanna/integrations/postgres/sql_runner.py +112 -0
- vanna/integrations/premium/agent_memory/__init__.py +7 -0
- vanna/integrations/premium/agent_memory/premium.py +186 -0
- vanna/integrations/presto/__init__.py +5 -0
- vanna/integrations/presto/sql_runner.py +107 -0
- vanna/integrations/qdrant/__init__.py +7 -0
- vanna/integrations/qdrant/agent_memory.py +461 -0
- vanna/integrations/snowflake/__init__.py +5 -0
- vanna/integrations/snowflake/sql_runner.py +147 -0
- vanna/integrations/sqlite/__init__.py +9 -0
- vanna/integrations/sqlite/sql_runner.py +65 -0
- vanna/integrations/weaviate/__init__.py +7 -0
- vanna/integrations/weaviate/agent_memory.py +428 -0
- vanna/{ZhipuAI → legacy/ZhipuAI}/ZhipuAI_embeddings.py +11 -11
- vanna/legacy/__init__.py +403 -0
- vanna/legacy/adapter.py +463 -0
- vanna/{advanced → legacy/advanced}/__init__.py +3 -1
- vanna/{anthropic → legacy/anthropic}/anthropic_chat.py +9 -7
- vanna/{azuresearch → legacy/azuresearch}/azuresearch_vector.py +79 -41
- vanna/{base → legacy/base}/base.py +247 -223
- vanna/legacy/bedrock/__init__.py +1 -0
- vanna/{bedrock → legacy/bedrock}/bedrock_converse.py +13 -12
- vanna/{chromadb → legacy/chromadb}/chromadb_vector.py +3 -1
- vanna/legacy/cohere/__init__.py +2 -0
- vanna/{cohere → legacy/cohere}/cohere_chat.py +19 -14
- vanna/{cohere → legacy/cohere}/cohere_embeddings.py +25 -19
- vanna/{deepseek → legacy/deepseek}/deepseek_chat.py +5 -6
- vanna/legacy/faiss/__init__.py +1 -0
- vanna/{faiss → legacy/faiss}/faiss.py +113 -59
- vanna/{flask → legacy/flask}/__init__.py +84 -43
- vanna/{flask → legacy/flask}/assets.py +5 -5
- vanna/{flask → legacy/flask}/auth.py +5 -4
- vanna/{google → legacy/google}/bigquery_vector.py +75 -42
- vanna/{google → legacy/google}/gemini_chat.py +7 -3
- vanna/{hf → legacy/hf}/hf.py +0 -1
- vanna/{milvus → legacy/milvus}/milvus_vector.py +58 -35
- vanna/{mock → legacy/mock}/llm.py +0 -1
- vanna/legacy/mock/vectordb.py +67 -0
- vanna/legacy/ollama/ollama.py +110 -0
- vanna/{openai → legacy/openai}/openai_chat.py +2 -6
- vanna/legacy/opensearch/opensearch_vector.py +369 -0
- vanna/legacy/opensearch/opensearch_vector_semantic.py +200 -0
- vanna/legacy/oracle/oracle_vector.py +584 -0
- vanna/{pgvector → legacy/pgvector}/pgvector.py +42 -13
- vanna/{qdrant → legacy/qdrant}/qdrant.py +2 -6
- vanna/legacy/qianfan/Qianfan_Chat.py +170 -0
- vanna/legacy/qianfan/Qianfan_embeddings.py +36 -0
- vanna/legacy/qianwen/QianwenAI_chat.py +132 -0
- vanna/{remote.py → legacy/remote.py} +28 -26
- vanna/{utils.py → legacy/utils.py} +6 -11
- vanna/{vannadb → legacy/vannadb}/vannadb_vector.py +115 -46
- vanna/{vllm → legacy/vllm}/vllm.py +5 -6
- vanna/{weaviate → legacy/weaviate}/weaviate_vector.py +59 -40
- vanna/{xinference → legacy/xinference}/xinference.py +6 -6
- vanna/py.typed +0 -0
- vanna/servers/__init__.py +16 -0
- vanna/servers/__main__.py +8 -0
- vanna/servers/base/__init__.py +18 -0
- vanna/servers/base/chat_handler.py +65 -0
- vanna/servers/base/models.py +111 -0
- vanna/servers/base/rich_chat_handler.py +141 -0
- vanna/servers/base/templates.py +331 -0
- vanna/servers/cli/__init__.py +7 -0
- vanna/servers/cli/server_runner.py +204 -0
- vanna/servers/fastapi/__init__.py +7 -0
- vanna/servers/fastapi/app.py +163 -0
- vanna/servers/fastapi/routes.py +183 -0
- vanna/servers/flask/__init__.py +7 -0
- vanna/servers/flask/app.py +132 -0
- vanna/servers/flask/routes.py +137 -0
- vanna/tools/__init__.py +41 -0
- vanna/tools/agent_memory.py +322 -0
- vanna/tools/file_system.py +879 -0
- vanna/tools/python.py +222 -0
- vanna/tools/run_sql.py +165 -0
- vanna/tools/visualize_data.py +195 -0
- vanna/utils/__init__.py +0 -0
- vanna/web_components/__init__.py +44 -0
- vanna-2.0.0.dist-info/METADATA +485 -0
- vanna-2.0.0.dist-info/RECORD +289 -0
- vanna-2.0.0.dist-info/entry_points.txt +3 -0
- vanna/bedrock/__init__.py +0 -1
- vanna/cohere/__init__.py +0 -2
- vanna/faiss/__init__.py +0 -1
- vanna/mock/vectordb.py +0 -55
- vanna/ollama/ollama.py +0 -103
- vanna/opensearch/opensearch_vector.py +0 -392
- vanna/opensearch/opensearch_vector_semantic.py +0 -175
- vanna/oracle/oracle_vector.py +0 -585
- vanna/qianfan/Qianfan_Chat.py +0 -165
- vanna/qianfan/Qianfan_embeddings.py +0 -36
- vanna/qianwen/QianwenAI_chat.py +0 -133
- vanna-0.7.8.dist-info/METADATA +0 -408
- vanna-0.7.8.dist-info/RECORD +0 -79
- /vanna/{ZhipuAI → legacy/ZhipuAI}/ZhipuAI_Chat.py +0 -0
- /vanna/{ZhipuAI → legacy/ZhipuAI}/__init__.py +0 -0
- /vanna/{anthropic → legacy/anthropic}/__init__.py +0 -0
- /vanna/{azuresearch → legacy/azuresearch}/__init__.py +0 -0
- /vanna/{base → legacy/base}/__init__.py +0 -0
- /vanna/{chromadb → legacy/chromadb}/__init__.py +0 -0
- /vanna/{deepseek → legacy/deepseek}/__init__.py +0 -0
- /vanna/{exceptions → legacy/exceptions}/__init__.py +0 -0
- /vanna/{google → legacy/google}/__init__.py +0 -0
- /vanna/{hf → legacy/hf}/__init__.py +0 -0
- /vanna/{local.py → legacy/local.py} +0 -0
- /vanna/{marqo → legacy/marqo}/__init__.py +0 -0
- /vanna/{marqo → legacy/marqo}/marqo.py +0 -0
- /vanna/{milvus → legacy/milvus}/__init__.py +0 -0
- /vanna/{mistral → legacy/mistral}/__init__.py +0 -0
- /vanna/{mistral → legacy/mistral}/mistral.py +0 -0
- /vanna/{mock → legacy/mock}/__init__.py +0 -0
- /vanna/{mock → legacy/mock}/embedding.py +0 -0
- /vanna/{ollama → legacy/ollama}/__init__.py +0 -0
- /vanna/{openai → legacy/openai}/__init__.py +0 -0
- /vanna/{openai → legacy/openai}/openai_embeddings.py +0 -0
- /vanna/{opensearch → legacy/opensearch}/__init__.py +0 -0
- /vanna/{oracle → legacy/oracle}/__init__.py +0 -0
- /vanna/{pgvector → legacy/pgvector}/__init__.py +0 -0
- /vanna/{pinecone → legacy/pinecone}/__init__.py +0 -0
- /vanna/{pinecone → legacy/pinecone}/pinecone_vector.py +0 -0
- /vanna/{qdrant → legacy/qdrant}/__init__.py +0 -0
- /vanna/{qianfan → legacy/qianfan}/__init__.py +0 -0
- /vanna/{qianwen → legacy/qianwen}/QianwenAI_embeddings.py +0 -0
- /vanna/{qianwen → legacy/qianwen}/__init__.py +0 -0
- /vanna/{types → legacy/types}/__init__.py +0 -0
- /vanna/{vannadb → legacy/vannadb}/__init__.py +0 -0
- /vanna/{vllm → legacy/vllm}/__init__.py +0 -0
- /vanna/{weaviate → legacy/weaviate}/__init__.py +0 -0
- /vanna/{xinference → legacy/xinference}/__init__.py +0 -0
- {vanna-0.7.8.dist-info → vanna-2.0.0.dist-info}/WHEEL +0 -0
- {vanna-0.7.8.dist-info → vanna-2.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,789 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Default workflow handler implementation with setup health checking.
|
|
3
|
+
|
|
4
|
+
This module provides a default implementation of the WorkflowHandler interface
|
|
5
|
+
that provides a smart starter UI based on available tools and setup status.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import TYPE_CHECKING, List, Optional, Dict, Any
|
|
9
|
+
import traceback
|
|
10
|
+
import uuid
|
|
11
|
+
from .base import WorkflowHandler, WorkflowResult
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from ..agent.agent import Agent
|
|
15
|
+
from ..user.models import User
|
|
16
|
+
from ..storage import Conversation
|
|
17
|
+
|
|
18
|
+
# Import components at module level to avoid circular imports
|
|
19
|
+
from vanna.components import (
|
|
20
|
+
UiComponent,
|
|
21
|
+
RichTextComponent,
|
|
22
|
+
StatusCardComponent,
|
|
23
|
+
ButtonComponent,
|
|
24
|
+
ButtonGroupComponent,
|
|
25
|
+
SimpleTextComponent,
|
|
26
|
+
CardComponent,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Note: StatusCardComponent and ButtonGroupComponent are kept for /status command compatibility
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class DefaultWorkflowHandler(WorkflowHandler):
|
|
33
|
+
"""Default workflow handler that provides setup health checking and starter UI.
|
|
34
|
+
|
|
35
|
+
This handler provides a starter UI that:
|
|
36
|
+
- Checks if run_sql tool is available (critical)
|
|
37
|
+
- Checks if memory tools are available (warning if missing)
|
|
38
|
+
- Checks if visualization tools are available
|
|
39
|
+
- Provides appropriate setup guidance based on what's missing
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(self, welcome_message: Optional[str] = None):
|
|
43
|
+
"""Initialize with optional custom welcome message.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
welcome_message: Optional custom welcome message. If not provided,
|
|
47
|
+
generates one based on available tools.
|
|
48
|
+
"""
|
|
49
|
+
self.welcome_message = welcome_message
|
|
50
|
+
|
|
51
|
+
async def try_handle(
|
|
52
|
+
self, agent: "Agent", user: "User", conversation: "Conversation", message: str
|
|
53
|
+
) -> WorkflowResult:
|
|
54
|
+
"""Handle basic commands, but mostly passes through to LLM."""
|
|
55
|
+
|
|
56
|
+
# Handle basic help command
|
|
57
|
+
if message.strip().lower() in ["/help", "help", "/h"]:
|
|
58
|
+
# Check if user is admin
|
|
59
|
+
is_admin = "admin" in user.group_memberships
|
|
60
|
+
|
|
61
|
+
help_content = (
|
|
62
|
+
"## 🤖 Vanna AI Assistant\n\n"
|
|
63
|
+
"I'm your AI data analyst! Here's what I can help you with:\n\n"
|
|
64
|
+
"**💬 Natural Language Queries**\n"
|
|
65
|
+
'- "Show me sales data for last quarter"\n'
|
|
66
|
+
'- "Which customers have the highest orders?"\n'
|
|
67
|
+
'- "Create a chart of revenue by month"\n\n'
|
|
68
|
+
"**🔧 Commands**\n"
|
|
69
|
+
"- `/help` - Show this help message\n"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if is_admin:
|
|
73
|
+
help_content += (
|
|
74
|
+
"\n**🔒 Admin Commands**\n"
|
|
75
|
+
"- `/status` - Check setup status\n"
|
|
76
|
+
"- `/memories` - View and manage recent memories\n"
|
|
77
|
+
"- `/delete [id]` - Delete a memory by ID\n"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
help_content += "\n\nJust ask me anything about your data in plain English!"
|
|
81
|
+
|
|
82
|
+
return WorkflowResult(
|
|
83
|
+
should_skip_llm=True,
|
|
84
|
+
components=[
|
|
85
|
+
UiComponent(
|
|
86
|
+
rich_component=RichTextComponent(
|
|
87
|
+
content=help_content,
|
|
88
|
+
markdown=True,
|
|
89
|
+
),
|
|
90
|
+
simple_component=None,
|
|
91
|
+
)
|
|
92
|
+
],
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Handle status check command (admin-only)
|
|
96
|
+
if message.strip().lower() in ["/status", "status"]:
|
|
97
|
+
# Check if user is admin
|
|
98
|
+
if "admin" not in user.group_memberships:
|
|
99
|
+
return WorkflowResult(
|
|
100
|
+
should_skip_llm=True,
|
|
101
|
+
components=[
|
|
102
|
+
UiComponent(
|
|
103
|
+
rich_component=RichTextComponent(
|
|
104
|
+
content="# 🔒 Access Denied\n\n"
|
|
105
|
+
"The `/status` command is only available to administrators.\n\n"
|
|
106
|
+
"If you need access to system status information, please contact your system administrator.",
|
|
107
|
+
markdown=True,
|
|
108
|
+
),
|
|
109
|
+
simple_component=None,
|
|
110
|
+
)
|
|
111
|
+
],
|
|
112
|
+
)
|
|
113
|
+
return await self._generate_status_check(agent, user)
|
|
114
|
+
|
|
115
|
+
# Handle get recent memories command (admin-only)
|
|
116
|
+
if message.strip().lower() in [
|
|
117
|
+
"/memories",
|
|
118
|
+
"memories",
|
|
119
|
+
"/recent_memories",
|
|
120
|
+
"recent_memories",
|
|
121
|
+
]:
|
|
122
|
+
# Check if user is admin
|
|
123
|
+
if "admin" not in user.group_memberships:
|
|
124
|
+
return WorkflowResult(
|
|
125
|
+
should_skip_llm=True,
|
|
126
|
+
components=[
|
|
127
|
+
UiComponent(
|
|
128
|
+
rich_component=RichTextComponent(
|
|
129
|
+
content="# 🔒 Access Denied\n\n"
|
|
130
|
+
"The `/memories` command is only available to administrators.\n\n"
|
|
131
|
+
"If you need access to memory management features, please contact your system administrator.",
|
|
132
|
+
markdown=True,
|
|
133
|
+
),
|
|
134
|
+
simple_component=None,
|
|
135
|
+
)
|
|
136
|
+
],
|
|
137
|
+
)
|
|
138
|
+
return await self._get_recent_memories(agent, user, conversation)
|
|
139
|
+
|
|
140
|
+
# Handle delete memory command (admin-only)
|
|
141
|
+
if message.strip().lower().startswith("/delete "):
|
|
142
|
+
# Check if user is admin
|
|
143
|
+
if "admin" not in user.group_memberships:
|
|
144
|
+
return WorkflowResult(
|
|
145
|
+
should_skip_llm=True,
|
|
146
|
+
components=[
|
|
147
|
+
UiComponent(
|
|
148
|
+
rich_component=RichTextComponent(
|
|
149
|
+
content="# 🔒 Access Denied\n\n"
|
|
150
|
+
"The `/delete` command is only available to administrators.\n\n"
|
|
151
|
+
"If you need access to memory management features, please contact your system administrator.",
|
|
152
|
+
markdown=True,
|
|
153
|
+
),
|
|
154
|
+
simple_component=None,
|
|
155
|
+
)
|
|
156
|
+
],
|
|
157
|
+
)
|
|
158
|
+
memory_id = message.strip()[8:].strip() # Extract ID after "/delete "
|
|
159
|
+
return await self._delete_memory(agent, user, conversation, memory_id)
|
|
160
|
+
|
|
161
|
+
# Don't handle other messages, pass to LLM
|
|
162
|
+
return WorkflowResult(should_skip_llm=False)
|
|
163
|
+
|
|
164
|
+
async def get_starter_ui(
|
|
165
|
+
self, agent: "Agent", user: "User", conversation: "Conversation"
|
|
166
|
+
) -> Optional[List[UiComponent]]:
|
|
167
|
+
"""Generate starter UI based on available tools and setup status."""
|
|
168
|
+
|
|
169
|
+
# Get available tools
|
|
170
|
+
tools = await agent.tool_registry.get_schemas(user)
|
|
171
|
+
tool_names = [tool.name for tool in tools]
|
|
172
|
+
|
|
173
|
+
# Analyze setup
|
|
174
|
+
setup_analysis = self._analyze_setup(tool_names)
|
|
175
|
+
|
|
176
|
+
# Check if user is admin (has 'admin' in group memberships)
|
|
177
|
+
is_admin = "admin" in user.group_memberships
|
|
178
|
+
|
|
179
|
+
# Generate single concise card
|
|
180
|
+
if self.welcome_message:
|
|
181
|
+
# Use custom welcome message
|
|
182
|
+
return [
|
|
183
|
+
UiComponent(
|
|
184
|
+
rich_component=RichTextComponent(
|
|
185
|
+
content=self.welcome_message, markdown=True
|
|
186
|
+
),
|
|
187
|
+
simple_component=None,
|
|
188
|
+
)
|
|
189
|
+
]
|
|
190
|
+
else:
|
|
191
|
+
# Generate role-aware welcome card
|
|
192
|
+
return [self._generate_starter_card(setup_analysis, is_admin)]
|
|
193
|
+
|
|
194
|
+
def _generate_starter_card(
|
|
195
|
+
self, analysis: Dict[str, Any], is_admin: bool
|
|
196
|
+
) -> UiComponent:
|
|
197
|
+
"""Generate a single concise starter card based on role and setup status."""
|
|
198
|
+
|
|
199
|
+
if is_admin:
|
|
200
|
+
# Admin view: includes setup status and memory management
|
|
201
|
+
return self._generate_admin_starter_card(analysis)
|
|
202
|
+
else:
|
|
203
|
+
# User view: simple welcome message
|
|
204
|
+
return self._generate_user_starter_card(analysis)
|
|
205
|
+
|
|
206
|
+
def _generate_admin_starter_card(self, analysis: Dict[str, Any]) -> UiComponent:
|
|
207
|
+
"""Generate admin starter card with setup info and memory management."""
|
|
208
|
+
|
|
209
|
+
# Build concise content
|
|
210
|
+
if not analysis["has_sql"]:
|
|
211
|
+
title = "Admin: Setup Required"
|
|
212
|
+
content = "**🔒 Admin View** - You have admin privileges and will see additional system information.\n\n**Vanna AI** requires a SQL connection to function.\n\nPlease configure a SQL tool to get started."
|
|
213
|
+
status = "error"
|
|
214
|
+
icon = "⚠️"
|
|
215
|
+
elif analysis["is_complete"]:
|
|
216
|
+
title = "Admin: System Ready"
|
|
217
|
+
content = "**🔒 Admin View** - You have admin privileges and will see additional system information.\n\n**Vanna AI** is fully configured and ready.\n\n"
|
|
218
|
+
content += "**Setup:** SQL ✓ | Memory ✓ | Visualization ✓"
|
|
219
|
+
status = "success"
|
|
220
|
+
icon = "✅"
|
|
221
|
+
else:
|
|
222
|
+
title = "Admin: System Ready"
|
|
223
|
+
content = "**🔒 Admin View** - You have admin privileges and will see additional system information.\n\n**Vanna AI** is ready to query your database.\n\n"
|
|
224
|
+
setup_items = []
|
|
225
|
+
setup_items.append("SQL ✓")
|
|
226
|
+
setup_items.append("Memory ✓" if analysis["has_memory"] else "Memory ✗")
|
|
227
|
+
setup_items.append("Viz ✓" if analysis["has_viz"] else "Viz ✗")
|
|
228
|
+
content += f"**Setup:** {' | '.join(setup_items)}"
|
|
229
|
+
status = "warning" if not analysis["has_memory"] else "success"
|
|
230
|
+
icon = "⚠️" if not analysis["has_memory"] else "✅"
|
|
231
|
+
|
|
232
|
+
# Add memory management info for admins
|
|
233
|
+
actions: List[Dict[str, Any]] = []
|
|
234
|
+
if analysis["has_sql"]:
|
|
235
|
+
actions.append(
|
|
236
|
+
{
|
|
237
|
+
"label": "💡 Help",
|
|
238
|
+
"action": "/help",
|
|
239
|
+
"variant": "secondary",
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
if analysis["has_memory"]:
|
|
244
|
+
content += "\n\n**Memory Management:** Tool and text memories are available. As an admin, you can view and manage these memories to help me learn from successful queries."
|
|
245
|
+
actions.append(
|
|
246
|
+
{
|
|
247
|
+
"label": "🧠 View Memories",
|
|
248
|
+
"action": "/memories",
|
|
249
|
+
"variant": "secondary",
|
|
250
|
+
}
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
return UiComponent(
|
|
254
|
+
rich_component=CardComponent(
|
|
255
|
+
title=title,
|
|
256
|
+
content=content,
|
|
257
|
+
icon=icon,
|
|
258
|
+
status=status,
|
|
259
|
+
actions=actions,
|
|
260
|
+
markdown=True,
|
|
261
|
+
),
|
|
262
|
+
simple_component=None,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
def _generate_user_starter_card(self, analysis: Dict[str, Any]) -> UiComponent:
|
|
266
|
+
"""Generate simple user starter view using RichTextComponent."""
|
|
267
|
+
|
|
268
|
+
if not analysis["has_sql"]:
|
|
269
|
+
content = (
|
|
270
|
+
"# ⚠️ Setup Required\n\n"
|
|
271
|
+
"Vanna AI requires configuration before it can help you analyze data."
|
|
272
|
+
)
|
|
273
|
+
else:
|
|
274
|
+
content = (
|
|
275
|
+
"# 👋 Welcome to Vanna AI\n\n"
|
|
276
|
+
"I'm your AI data analyst assistant. Ask me anything about your data in plain English!\n\n"
|
|
277
|
+
"Type `/help` to see what I can do."
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
return UiComponent(
|
|
281
|
+
rich_component=RichTextComponent(content=content, markdown=True),
|
|
282
|
+
simple_component=None,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
def _analyze_setup(self, tool_names: List[str]) -> Dict[str, Any]:
|
|
286
|
+
"""Analyze the current tool setup and return status."""
|
|
287
|
+
|
|
288
|
+
# Critical tools
|
|
289
|
+
has_sql = any(
|
|
290
|
+
name in tool_names
|
|
291
|
+
for name in ["run_sql", "sql_query", "execute_sql", "query_sql"]
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
# Memory tools (important but not critical)
|
|
295
|
+
has_search = "search_saved_correct_tool_uses" in tool_names
|
|
296
|
+
has_save = "save_question_tool_args" in tool_names
|
|
297
|
+
has_memory = has_search and has_save
|
|
298
|
+
|
|
299
|
+
# Visualization tools (nice to have)
|
|
300
|
+
has_viz = any(
|
|
301
|
+
name in tool_names
|
|
302
|
+
for name in [
|
|
303
|
+
"visualize_data",
|
|
304
|
+
"create_chart",
|
|
305
|
+
"plot_data",
|
|
306
|
+
"generate_chart",
|
|
307
|
+
]
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
# Other useful tools
|
|
311
|
+
has_calculator = any(
|
|
312
|
+
name in tool_names for name in ["calculator", "calc", "calculate"]
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
# Determine overall status
|
|
316
|
+
is_complete = has_sql and has_memory and has_viz
|
|
317
|
+
is_functional = has_sql
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
"has_sql": has_sql,
|
|
321
|
+
"has_memory": has_memory,
|
|
322
|
+
"has_search": has_search,
|
|
323
|
+
"has_save": has_save,
|
|
324
|
+
"has_viz": has_viz,
|
|
325
|
+
"has_calculator": has_calculator,
|
|
326
|
+
"is_complete": is_complete,
|
|
327
|
+
"is_functional": is_functional,
|
|
328
|
+
"tool_count": len(tool_names),
|
|
329
|
+
"tool_names": tool_names,
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
def _generate_setup_status_cards(
|
|
333
|
+
self, analysis: Dict[str, Any]
|
|
334
|
+
) -> List[UiComponent]:
|
|
335
|
+
"""Generate status cards showing setup health (used by /status command)."""
|
|
336
|
+
|
|
337
|
+
cards = []
|
|
338
|
+
|
|
339
|
+
# SQL Tool Status (Critical)
|
|
340
|
+
if analysis["has_sql"]:
|
|
341
|
+
sql_card = StatusCardComponent(
|
|
342
|
+
title="SQL Connection",
|
|
343
|
+
status="success",
|
|
344
|
+
description="Database connection configured and ready",
|
|
345
|
+
icon="✅",
|
|
346
|
+
)
|
|
347
|
+
else:
|
|
348
|
+
sql_card = StatusCardComponent(
|
|
349
|
+
title="SQL Connection",
|
|
350
|
+
status="error",
|
|
351
|
+
description="No SQL tool detected - this is required for data analysis",
|
|
352
|
+
icon="❌",
|
|
353
|
+
)
|
|
354
|
+
cards.append(UiComponent(rich_component=sql_card, simple_component=None))
|
|
355
|
+
|
|
356
|
+
# Memory Tools Status (Important)
|
|
357
|
+
if analysis["has_memory"]:
|
|
358
|
+
memory_card = StatusCardComponent(
|
|
359
|
+
title="Memory System",
|
|
360
|
+
status="success",
|
|
361
|
+
description="Search and save tools configured - I can learn from successful queries",
|
|
362
|
+
icon="🧠",
|
|
363
|
+
)
|
|
364
|
+
elif analysis["has_search"] or analysis["has_save"]:
|
|
365
|
+
memory_card = StatusCardComponent(
|
|
366
|
+
title="Memory System",
|
|
367
|
+
status="warning",
|
|
368
|
+
description="Partial memory setup - both search and save tools recommended",
|
|
369
|
+
icon="⚠️",
|
|
370
|
+
)
|
|
371
|
+
else:
|
|
372
|
+
memory_card = StatusCardComponent(
|
|
373
|
+
title="Memory System",
|
|
374
|
+
status="warning",
|
|
375
|
+
description="Memory tools not configured - I won't remember successful patterns",
|
|
376
|
+
icon="⚠️",
|
|
377
|
+
)
|
|
378
|
+
cards.append(UiComponent(rich_component=memory_card, simple_component=None))
|
|
379
|
+
|
|
380
|
+
# Visualization Status (Nice to have)
|
|
381
|
+
if analysis["has_viz"]:
|
|
382
|
+
viz_card = StatusCardComponent(
|
|
383
|
+
title="Visualization",
|
|
384
|
+
status="success",
|
|
385
|
+
description="Chart creation tools available",
|
|
386
|
+
icon="📊",
|
|
387
|
+
)
|
|
388
|
+
else:
|
|
389
|
+
viz_card = StatusCardComponent(
|
|
390
|
+
title="Visualization",
|
|
391
|
+
status="info",
|
|
392
|
+
description="No visualization tools - results will be text/tables only",
|
|
393
|
+
icon="📋",
|
|
394
|
+
)
|
|
395
|
+
cards.append(UiComponent(rich_component=viz_card, simple_component=None))
|
|
396
|
+
|
|
397
|
+
return cards
|
|
398
|
+
|
|
399
|
+
def _generate_setup_guidance(
|
|
400
|
+
self, analysis: Dict[str, Any]
|
|
401
|
+
) -> Optional[UiComponent]:
|
|
402
|
+
"""Generate setup guidance based on what's missing (used by /status command)."""
|
|
403
|
+
|
|
404
|
+
if not analysis["has_sql"]:
|
|
405
|
+
# Critical guidance - need SQL
|
|
406
|
+
content = (
|
|
407
|
+
"## 🚨 Setup Required\n\n"
|
|
408
|
+
"To get started with Vanna AI, you need to configure a SQL connection tool:\n\n"
|
|
409
|
+
"```python\n"
|
|
410
|
+
"from vanna.tools import RunSqlTool\n\n"
|
|
411
|
+
"# Add SQL tool to your agent\n"
|
|
412
|
+
"tool_registry.register(RunSqlTool(\n"
|
|
413
|
+
' connection_string="your-database-connection"\n'
|
|
414
|
+
"))\n"
|
|
415
|
+
"```\n\n"
|
|
416
|
+
"**Next Steps:**\n"
|
|
417
|
+
"1. Configure your database connection\n"
|
|
418
|
+
"2. Add memory tools for learning\n"
|
|
419
|
+
"3. Add visualization tools for charts"
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
else:
|
|
423
|
+
# Improvement suggestions
|
|
424
|
+
suggestions = []
|
|
425
|
+
|
|
426
|
+
if not analysis["has_memory"]:
|
|
427
|
+
suggestions.append(
|
|
428
|
+
"**🧠 Add Memory Tools** - Help me learn from successful queries:\n"
|
|
429
|
+
"```python\n"
|
|
430
|
+
"from vanna.tools import SearchSavedCorrectToolUses, SaveQuestionToolArgs\n"
|
|
431
|
+
"tool_registry.register(SearchSavedCorrectToolUses())\n"
|
|
432
|
+
"tool_registry.register(SaveQuestionToolArgs())\n"
|
|
433
|
+
"```"
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
if not analysis["has_viz"]:
|
|
437
|
+
suggestions.append(
|
|
438
|
+
"**📊 Add Visualization** - Create charts and graphs:\n"
|
|
439
|
+
"```python\n"
|
|
440
|
+
"from vanna.tools import VisualizeDataTool\n"
|
|
441
|
+
"tool_registry.register(VisualizeDataTool())\n"
|
|
442
|
+
"```"
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
if suggestions:
|
|
446
|
+
content = "## 💡 Suggested Improvements\n\n" + "\n\n".join(suggestions)
|
|
447
|
+
else:
|
|
448
|
+
return None # No guidance needed
|
|
449
|
+
|
|
450
|
+
return UiComponent(
|
|
451
|
+
rich_component=RichTextComponent(content=content, markdown=True),
|
|
452
|
+
simple_component=None,
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
async def _generate_status_check(
|
|
456
|
+
self, agent: "Agent", user: "User"
|
|
457
|
+
) -> WorkflowResult:
|
|
458
|
+
"""Generate a detailed status check response."""
|
|
459
|
+
|
|
460
|
+
# Get available tools
|
|
461
|
+
tools = await agent.tool_registry.get_schemas(user)
|
|
462
|
+
tool_names = [tool.name for tool in tools]
|
|
463
|
+
analysis = self._analyze_setup(tool_names)
|
|
464
|
+
|
|
465
|
+
# Generate status report
|
|
466
|
+
status_content = "# 🔍 Setup Status Report\n\n"
|
|
467
|
+
|
|
468
|
+
if analysis["is_complete"]:
|
|
469
|
+
status_content += (
|
|
470
|
+
"🎉 **Excellent!** Your Vanna AI setup is complete and optimized.\n\n"
|
|
471
|
+
)
|
|
472
|
+
elif analysis["is_functional"]:
|
|
473
|
+
status_content += (
|
|
474
|
+
"✅ **Good!** Your setup is functional with room for improvement.\n\n"
|
|
475
|
+
)
|
|
476
|
+
else:
|
|
477
|
+
status_content += (
|
|
478
|
+
"⚠️ **Action Required** - Your setup needs configuration.\n\n"
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
status_content += f"**Tools Detected:** {analysis['tool_count']} total\n\n"
|
|
482
|
+
|
|
483
|
+
# Tool breakdown
|
|
484
|
+
status_content += "## Tool Status\n\n"
|
|
485
|
+
status_content += f"- **SQL Connection:** {'✅ Available' if analysis['has_sql'] else '❌ Missing (Required)'}\n"
|
|
486
|
+
status_content += f"- **Memory System:** {'✅ Complete' if analysis['has_memory'] else '⚠️ Incomplete' if analysis['has_search'] or analysis['has_save'] else '❌ Missing'}\n"
|
|
487
|
+
status_content += f"- **Visualization:** {'✅ Available' if analysis['has_viz'] else '📋 Text/Tables Only'}\n"
|
|
488
|
+
status_content += f"- **Calculator:** {'✅ Available' if analysis['has_calculator'] else '➖ Not Available'}\n\n"
|
|
489
|
+
|
|
490
|
+
if analysis["tool_names"]:
|
|
491
|
+
status_content += (
|
|
492
|
+
f"**Available Tools:** {', '.join(sorted(analysis['tool_names']))}"
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
components = [
|
|
496
|
+
UiComponent(
|
|
497
|
+
rich_component=RichTextComponent(content=status_content, markdown=True),
|
|
498
|
+
simple_component=None,
|
|
499
|
+
)
|
|
500
|
+
]
|
|
501
|
+
|
|
502
|
+
# Add status cards
|
|
503
|
+
components.extend(self._generate_setup_status_cards(analysis))
|
|
504
|
+
|
|
505
|
+
# Add guidance if needed
|
|
506
|
+
guidance = self._generate_setup_guidance(analysis)
|
|
507
|
+
if guidance:
|
|
508
|
+
components.append(guidance)
|
|
509
|
+
|
|
510
|
+
return WorkflowResult(should_skip_llm=True, components=components)
|
|
511
|
+
|
|
512
|
+
async def _get_recent_memories(
|
|
513
|
+
self, agent: "Agent", user: "User", conversation: "Conversation"
|
|
514
|
+
) -> WorkflowResult:
|
|
515
|
+
"""Get and display recent memories from agent memory."""
|
|
516
|
+
try:
|
|
517
|
+
# Check if agent has memory capability
|
|
518
|
+
if not hasattr(agent, "agent_memory") or agent.agent_memory is None:
|
|
519
|
+
return WorkflowResult(
|
|
520
|
+
should_skip_llm=True,
|
|
521
|
+
components=[
|
|
522
|
+
UiComponent(
|
|
523
|
+
rich_component=RichTextComponent(
|
|
524
|
+
content="# ⚠️ No Memory System\n\n"
|
|
525
|
+
"Agent memory is not configured. Recent memories are not available.\n\n"
|
|
526
|
+
"To enable memory, configure an AgentMemory implementation in your agent setup.",
|
|
527
|
+
markdown=True,
|
|
528
|
+
),
|
|
529
|
+
simple_component=None,
|
|
530
|
+
)
|
|
531
|
+
],
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
# Create tool context
|
|
535
|
+
from vanna.core.tool import ToolContext
|
|
536
|
+
|
|
537
|
+
context = ToolContext(
|
|
538
|
+
user=user,
|
|
539
|
+
conversation_id=conversation.id,
|
|
540
|
+
request_id=str(uuid.uuid4()),
|
|
541
|
+
agent_memory=agent.agent_memory,
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
# Get both tool memories and text memories
|
|
545
|
+
tool_memories = await agent.agent_memory.get_recent_memories(
|
|
546
|
+
context=context, limit=10
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
# Try to get text memories (may not be implemented in all memory backends)
|
|
550
|
+
text_memories = []
|
|
551
|
+
try:
|
|
552
|
+
text_memories = await agent.agent_memory.get_recent_text_memories(
|
|
553
|
+
context=context, limit=10
|
|
554
|
+
)
|
|
555
|
+
except (AttributeError, NotImplementedError):
|
|
556
|
+
# Text memories not supported by this implementation
|
|
557
|
+
pass
|
|
558
|
+
|
|
559
|
+
if not tool_memories and not text_memories:
|
|
560
|
+
return WorkflowResult(
|
|
561
|
+
should_skip_llm=True,
|
|
562
|
+
components=[
|
|
563
|
+
UiComponent(
|
|
564
|
+
rich_component=RichTextComponent(
|
|
565
|
+
content="# 🧠 Recent Memories\n\n"
|
|
566
|
+
"No recent memories found. As you use tools and ask questions, "
|
|
567
|
+
"successful patterns will be saved here for future reference.",
|
|
568
|
+
markdown=True,
|
|
569
|
+
),
|
|
570
|
+
simple_component=None,
|
|
571
|
+
)
|
|
572
|
+
],
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
components = []
|
|
576
|
+
|
|
577
|
+
# Header
|
|
578
|
+
total_count = len(tool_memories) + len(text_memories)
|
|
579
|
+
header_content = f"# 🧠 Recent Memories\n\nFound {total_count} recent memor{'y' if total_count == 1 else 'ies'}"
|
|
580
|
+
components.append(
|
|
581
|
+
UiComponent(
|
|
582
|
+
rich_component=RichTextComponent(
|
|
583
|
+
content=header_content, markdown=True
|
|
584
|
+
),
|
|
585
|
+
simple_component=None,
|
|
586
|
+
)
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
# Display text memories
|
|
590
|
+
if text_memories:
|
|
591
|
+
components.append(
|
|
592
|
+
UiComponent(
|
|
593
|
+
rich_component=RichTextComponent(
|
|
594
|
+
content=f"## 📝 Text Memories ({len(text_memories)})",
|
|
595
|
+
markdown=True,
|
|
596
|
+
),
|
|
597
|
+
simple_component=None,
|
|
598
|
+
)
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
for memory in text_memories:
|
|
602
|
+
# Create card with delete button
|
|
603
|
+
card_content = f"**Content:** {memory.content}\n\n"
|
|
604
|
+
if memory.timestamp:
|
|
605
|
+
card_content += f"**Timestamp:** {memory.timestamp}\n\n"
|
|
606
|
+
card_content += f"**ID:** `{memory.memory_id}`"
|
|
607
|
+
|
|
608
|
+
card = CardComponent(
|
|
609
|
+
title="Text Memory",
|
|
610
|
+
content=card_content,
|
|
611
|
+
icon="📝",
|
|
612
|
+
actions=[
|
|
613
|
+
{
|
|
614
|
+
"label": "🗑️ Delete",
|
|
615
|
+
"action": f"/delete {memory.memory_id}",
|
|
616
|
+
"variant": "error",
|
|
617
|
+
}
|
|
618
|
+
],
|
|
619
|
+
)
|
|
620
|
+
components.append(
|
|
621
|
+
UiComponent(rich_component=card, simple_component=None)
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
# Display tool memories
|
|
625
|
+
if tool_memories:
|
|
626
|
+
components.append(
|
|
627
|
+
UiComponent(
|
|
628
|
+
rich_component=RichTextComponent(
|
|
629
|
+
content=f"## 🔧 Tool Memories ({len(tool_memories)})",
|
|
630
|
+
markdown=True,
|
|
631
|
+
),
|
|
632
|
+
simple_component=None,
|
|
633
|
+
)
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
for tool_memory in tool_memories:
|
|
637
|
+
# Create card with delete button
|
|
638
|
+
card_content = f"**Question:** {tool_memory.question}\n\n"
|
|
639
|
+
card_content += f"**Tool:** {tool_memory.tool_name}\n\n"
|
|
640
|
+
card_content += f"**Arguments:** `{tool_memory.args}`\n\n"
|
|
641
|
+
card_content += f"**Success:** {'✅ Yes' if tool_memory.success else '❌ No'}\n\n"
|
|
642
|
+
if tool_memory.timestamp:
|
|
643
|
+
card_content += f"**Timestamp:** {tool_memory.timestamp}\n\n"
|
|
644
|
+
card_content += f"**ID:** `{tool_memory.memory_id}`"
|
|
645
|
+
|
|
646
|
+
card = CardComponent(
|
|
647
|
+
title=f"Tool: {tool_memory.tool_name}",
|
|
648
|
+
content=card_content,
|
|
649
|
+
markdown=True,
|
|
650
|
+
icon="🔧",
|
|
651
|
+
status="success" if tool_memory.success else "error",
|
|
652
|
+
actions=[
|
|
653
|
+
{
|
|
654
|
+
"label": "🗑️ Delete",
|
|
655
|
+
"action": f"/delete {tool_memory.memory_id}",
|
|
656
|
+
"variant": "error",
|
|
657
|
+
}
|
|
658
|
+
],
|
|
659
|
+
)
|
|
660
|
+
components.append(
|
|
661
|
+
UiComponent(rich_component=card, simple_component=None)
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
return WorkflowResult(should_skip_llm=True, components=components)
|
|
665
|
+
|
|
666
|
+
except Exception as e:
|
|
667
|
+
traceback.print_exc()
|
|
668
|
+
return WorkflowResult(
|
|
669
|
+
should_skip_llm=True,
|
|
670
|
+
components=[
|
|
671
|
+
UiComponent(
|
|
672
|
+
rich_component=RichTextComponent(
|
|
673
|
+
content=f"# ❌ Error Retrieving Memories\n\n"
|
|
674
|
+
f"Failed to get recent memories: {str(e)}\n\n"
|
|
675
|
+
f"This may indicate an issue with the agent memory configuration.",
|
|
676
|
+
markdown=True,
|
|
677
|
+
),
|
|
678
|
+
simple_component=None,
|
|
679
|
+
)
|
|
680
|
+
],
|
|
681
|
+
)
|
|
682
|
+
|
|
683
|
+
async def _delete_memory(
|
|
684
|
+
self, agent: "Agent", user: "User", conversation: "Conversation", memory_id: str
|
|
685
|
+
) -> WorkflowResult:
|
|
686
|
+
"""Delete a memory by its ID."""
|
|
687
|
+
try:
|
|
688
|
+
# Check if agent has memory capability
|
|
689
|
+
if not hasattr(agent, "agent_memory") or agent.agent_memory is None:
|
|
690
|
+
return WorkflowResult(
|
|
691
|
+
should_skip_llm=True,
|
|
692
|
+
components=[
|
|
693
|
+
UiComponent(
|
|
694
|
+
rich_component=RichTextComponent(
|
|
695
|
+
content="# ⚠️ No Memory System\n\n"
|
|
696
|
+
"Agent memory is not configured. Cannot delete memories.",
|
|
697
|
+
markdown=True,
|
|
698
|
+
),
|
|
699
|
+
simple_component=None,
|
|
700
|
+
)
|
|
701
|
+
],
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
if not memory_id:
|
|
705
|
+
return WorkflowResult(
|
|
706
|
+
should_skip_llm=True,
|
|
707
|
+
components=[
|
|
708
|
+
UiComponent(
|
|
709
|
+
rich_component=RichTextComponent(
|
|
710
|
+
content="# ⚠️ Invalid Command\n\n"
|
|
711
|
+
"Please provide a memory ID to delete.\n\n"
|
|
712
|
+
"Usage: `/delete [memory_id]`",
|
|
713
|
+
markdown=True,
|
|
714
|
+
),
|
|
715
|
+
simple_component=None,
|
|
716
|
+
)
|
|
717
|
+
],
|
|
718
|
+
)
|
|
719
|
+
|
|
720
|
+
# Create tool context
|
|
721
|
+
from vanna.core.tool import ToolContext
|
|
722
|
+
|
|
723
|
+
context = ToolContext(
|
|
724
|
+
user=user,
|
|
725
|
+
conversation_id=conversation.id,
|
|
726
|
+
request_id=str(uuid.uuid4()),
|
|
727
|
+
agent_memory=agent.agent_memory,
|
|
728
|
+
)
|
|
729
|
+
|
|
730
|
+
# Try to delete as a tool memory first
|
|
731
|
+
deleted = await agent.agent_memory.delete_by_id(context, memory_id)
|
|
732
|
+
|
|
733
|
+
# If not found as tool memory, try as text memory
|
|
734
|
+
if not deleted:
|
|
735
|
+
try:
|
|
736
|
+
deleted = await agent.agent_memory.delete_text_memory(
|
|
737
|
+
context, memory_id
|
|
738
|
+
)
|
|
739
|
+
except (AttributeError, NotImplementedError):
|
|
740
|
+
# Text memory deletion not supported by this implementation
|
|
741
|
+
pass
|
|
742
|
+
|
|
743
|
+
if deleted:
|
|
744
|
+
return WorkflowResult(
|
|
745
|
+
should_skip_llm=True,
|
|
746
|
+
components=[
|
|
747
|
+
UiComponent(
|
|
748
|
+
rich_component=RichTextComponent(
|
|
749
|
+
content=f"# ✅ Memory Deleted\n\n"
|
|
750
|
+
f"Successfully deleted memory with ID: `{memory_id}`\n\n"
|
|
751
|
+
f"You can view remaining memories using `/memories`.",
|
|
752
|
+
markdown=True,
|
|
753
|
+
),
|
|
754
|
+
simple_component=None,
|
|
755
|
+
)
|
|
756
|
+
],
|
|
757
|
+
)
|
|
758
|
+
else:
|
|
759
|
+
return WorkflowResult(
|
|
760
|
+
should_skip_llm=True,
|
|
761
|
+
components=[
|
|
762
|
+
UiComponent(
|
|
763
|
+
rich_component=RichTextComponent(
|
|
764
|
+
content=f"# ❌ Memory Not Found\n\n"
|
|
765
|
+
f"Could not find memory with ID: `{memory_id}`\n\n"
|
|
766
|
+
f"Use `/memories` to see available memory IDs.",
|
|
767
|
+
markdown=True,
|
|
768
|
+
),
|
|
769
|
+
simple_component=None,
|
|
770
|
+
)
|
|
771
|
+
],
|
|
772
|
+
)
|
|
773
|
+
|
|
774
|
+
except Exception as e:
|
|
775
|
+
traceback.print_exc()
|
|
776
|
+
return WorkflowResult(
|
|
777
|
+
should_skip_llm=True,
|
|
778
|
+
components=[
|
|
779
|
+
UiComponent(
|
|
780
|
+
rich_component=RichTextComponent(
|
|
781
|
+
content=f"# ❌ Error Deleting Memory\n\n"
|
|
782
|
+
f"Failed to delete memory: {str(e)}\n\n"
|
|
783
|
+
f"This may indicate an issue with the agent memory configuration.",
|
|
784
|
+
markdown=True,
|
|
785
|
+
),
|
|
786
|
+
simple_component=None,
|
|
787
|
+
)
|
|
788
|
+
],
|
|
789
|
+
)
|