vanna 0.7.9__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.
Files changed (302) hide show
  1. vanna/__init__.py +167 -395
  2. vanna/agents/__init__.py +7 -0
  3. vanna/capabilities/__init__.py +17 -0
  4. vanna/capabilities/agent_memory/__init__.py +21 -0
  5. vanna/capabilities/agent_memory/base.py +103 -0
  6. vanna/capabilities/agent_memory/models.py +53 -0
  7. vanna/capabilities/file_system/__init__.py +14 -0
  8. vanna/capabilities/file_system/base.py +71 -0
  9. vanna/capabilities/file_system/models.py +25 -0
  10. vanna/capabilities/sql_runner/__init__.py +13 -0
  11. vanna/capabilities/sql_runner/base.py +37 -0
  12. vanna/capabilities/sql_runner/models.py +13 -0
  13. vanna/components/__init__.py +92 -0
  14. vanna/components/base.py +11 -0
  15. vanna/components/rich/__init__.py +83 -0
  16. vanna/components/rich/containers/__init__.py +7 -0
  17. vanna/components/rich/containers/card.py +20 -0
  18. vanna/components/rich/data/__init__.py +9 -0
  19. vanna/components/rich/data/chart.py +17 -0
  20. vanna/components/rich/data/dataframe.py +93 -0
  21. vanna/components/rich/feedback/__init__.py +21 -0
  22. vanna/components/rich/feedback/badge.py +16 -0
  23. vanna/components/rich/feedback/icon_text.py +14 -0
  24. vanna/components/rich/feedback/log_viewer.py +41 -0
  25. vanna/components/rich/feedback/notification.py +19 -0
  26. vanna/components/rich/feedback/progress.py +37 -0
  27. vanna/components/rich/feedback/status_card.py +28 -0
  28. vanna/components/rich/feedback/status_indicator.py +14 -0
  29. vanna/components/rich/interactive/__init__.py +21 -0
  30. vanna/components/rich/interactive/button.py +95 -0
  31. vanna/components/rich/interactive/task_list.py +58 -0
  32. vanna/components/rich/interactive/ui_state.py +93 -0
  33. vanna/components/rich/specialized/__init__.py +7 -0
  34. vanna/components/rich/specialized/artifact.py +20 -0
  35. vanna/components/rich/text.py +16 -0
  36. vanna/components/simple/__init__.py +15 -0
  37. vanna/components/simple/image.py +15 -0
  38. vanna/components/simple/link.py +15 -0
  39. vanna/components/simple/text.py +11 -0
  40. vanna/core/__init__.py +193 -0
  41. vanna/core/_compat.py +19 -0
  42. vanna/core/agent/__init__.py +10 -0
  43. vanna/core/agent/agent.py +1407 -0
  44. vanna/core/agent/config.py +123 -0
  45. vanna/core/audit/__init__.py +28 -0
  46. vanna/core/audit/base.py +299 -0
  47. vanna/core/audit/models.py +131 -0
  48. vanna/core/component_manager.py +329 -0
  49. vanna/core/components.py +53 -0
  50. vanna/core/enhancer/__init__.py +11 -0
  51. vanna/core/enhancer/base.py +94 -0
  52. vanna/core/enhancer/default.py +118 -0
  53. vanna/core/enricher/__init__.py +10 -0
  54. vanna/core/enricher/base.py +59 -0
  55. vanna/core/errors.py +47 -0
  56. vanna/core/evaluation/__init__.py +81 -0
  57. vanna/core/evaluation/base.py +186 -0
  58. vanna/core/evaluation/dataset.py +254 -0
  59. vanna/core/evaluation/evaluators.py +376 -0
  60. vanna/core/evaluation/report.py +289 -0
  61. vanna/core/evaluation/runner.py +313 -0
  62. vanna/core/filter/__init__.py +10 -0
  63. vanna/core/filter/base.py +67 -0
  64. vanna/core/lifecycle/__init__.py +10 -0
  65. vanna/core/lifecycle/base.py +83 -0
  66. vanna/core/llm/__init__.py +16 -0
  67. vanna/core/llm/base.py +40 -0
  68. vanna/core/llm/models.py +61 -0
  69. vanna/core/middleware/__init__.py +10 -0
  70. vanna/core/middleware/base.py +69 -0
  71. vanna/core/observability/__init__.py +11 -0
  72. vanna/core/observability/base.py +88 -0
  73. vanna/core/observability/models.py +47 -0
  74. vanna/core/recovery/__init__.py +11 -0
  75. vanna/core/recovery/base.py +84 -0
  76. vanna/core/recovery/models.py +32 -0
  77. vanna/core/registry.py +278 -0
  78. vanna/core/rich_component.py +156 -0
  79. vanna/core/simple_component.py +27 -0
  80. vanna/core/storage/__init__.py +14 -0
  81. vanna/core/storage/base.py +46 -0
  82. vanna/core/storage/models.py +46 -0
  83. vanna/core/system_prompt/__init__.py +13 -0
  84. vanna/core/system_prompt/base.py +36 -0
  85. vanna/core/system_prompt/default.py +157 -0
  86. vanna/core/tool/__init__.py +18 -0
  87. vanna/core/tool/base.py +70 -0
  88. vanna/core/tool/models.py +84 -0
  89. vanna/core/user/__init__.py +17 -0
  90. vanna/core/user/base.py +29 -0
  91. vanna/core/user/models.py +25 -0
  92. vanna/core/user/request_context.py +70 -0
  93. vanna/core/user/resolver.py +42 -0
  94. vanna/core/validation.py +164 -0
  95. vanna/core/workflow/__init__.py +12 -0
  96. vanna/core/workflow/base.py +254 -0
  97. vanna/core/workflow/default.py +789 -0
  98. vanna/examples/__init__.py +1 -0
  99. vanna/examples/__main__.py +44 -0
  100. vanna/examples/anthropic_quickstart.py +80 -0
  101. vanna/examples/artifact_example.py +293 -0
  102. vanna/examples/claude_sqlite_example.py +236 -0
  103. vanna/examples/coding_agent_example.py +300 -0
  104. vanna/examples/custom_system_prompt_example.py +174 -0
  105. vanna/examples/default_workflow_handler_example.py +208 -0
  106. vanna/examples/email_auth_example.py +340 -0
  107. vanna/examples/evaluation_example.py +269 -0
  108. vanna/examples/extensibility_example.py +262 -0
  109. vanna/examples/minimal_example.py +67 -0
  110. vanna/examples/mock_auth_example.py +227 -0
  111. vanna/examples/mock_custom_tool.py +311 -0
  112. vanna/examples/mock_quickstart.py +79 -0
  113. vanna/examples/mock_quota_example.py +145 -0
  114. vanna/examples/mock_rich_components_demo.py +396 -0
  115. vanna/examples/mock_sqlite_example.py +223 -0
  116. vanna/examples/openai_quickstart.py +83 -0
  117. vanna/examples/primitive_components_demo.py +305 -0
  118. vanna/examples/quota_lifecycle_example.py +139 -0
  119. vanna/examples/visualization_example.py +251 -0
  120. vanna/integrations/__init__.py +17 -0
  121. vanna/integrations/anthropic/__init__.py +9 -0
  122. vanna/integrations/anthropic/llm.py +270 -0
  123. vanna/integrations/azureopenai/__init__.py +9 -0
  124. vanna/integrations/azureopenai/llm.py +329 -0
  125. vanna/integrations/azuresearch/__init__.py +7 -0
  126. vanna/integrations/azuresearch/agent_memory.py +413 -0
  127. vanna/integrations/bigquery/__init__.py +5 -0
  128. vanna/integrations/bigquery/sql_runner.py +81 -0
  129. vanna/integrations/chromadb/__init__.py +104 -0
  130. vanna/integrations/chromadb/agent_memory.py +416 -0
  131. vanna/integrations/clickhouse/__init__.py +5 -0
  132. vanna/integrations/clickhouse/sql_runner.py +82 -0
  133. vanna/integrations/duckdb/__init__.py +5 -0
  134. vanna/integrations/duckdb/sql_runner.py +65 -0
  135. vanna/integrations/faiss/__init__.py +7 -0
  136. vanna/integrations/faiss/agent_memory.py +431 -0
  137. vanna/integrations/google/__init__.py +9 -0
  138. vanna/integrations/google/gemini.py +370 -0
  139. vanna/integrations/hive/__init__.py +5 -0
  140. vanna/integrations/hive/sql_runner.py +87 -0
  141. vanna/integrations/local/__init__.py +17 -0
  142. vanna/integrations/local/agent_memory/__init__.py +7 -0
  143. vanna/integrations/local/agent_memory/in_memory.py +285 -0
  144. vanna/integrations/local/audit.py +59 -0
  145. vanna/integrations/local/file_system.py +242 -0
  146. vanna/integrations/local/file_system_conversation_store.py +255 -0
  147. vanna/integrations/local/storage.py +62 -0
  148. vanna/integrations/marqo/__init__.py +7 -0
  149. vanna/integrations/marqo/agent_memory.py +354 -0
  150. vanna/integrations/milvus/__init__.py +7 -0
  151. vanna/integrations/milvus/agent_memory.py +458 -0
  152. vanna/integrations/mock/__init__.py +9 -0
  153. vanna/integrations/mock/llm.py +65 -0
  154. vanna/integrations/mssql/__init__.py +5 -0
  155. vanna/integrations/mssql/sql_runner.py +66 -0
  156. vanna/integrations/mysql/__init__.py +5 -0
  157. vanna/integrations/mysql/sql_runner.py +92 -0
  158. vanna/integrations/ollama/__init__.py +7 -0
  159. vanna/integrations/ollama/llm.py +252 -0
  160. vanna/integrations/openai/__init__.py +10 -0
  161. vanna/integrations/openai/llm.py +267 -0
  162. vanna/integrations/openai/responses.py +163 -0
  163. vanna/integrations/opensearch/__init__.py +7 -0
  164. vanna/integrations/opensearch/agent_memory.py +411 -0
  165. vanna/integrations/oracle/__init__.py +5 -0
  166. vanna/integrations/oracle/sql_runner.py +75 -0
  167. vanna/integrations/pinecone/__init__.py +7 -0
  168. vanna/integrations/pinecone/agent_memory.py +329 -0
  169. vanna/integrations/plotly/__init__.py +5 -0
  170. vanna/integrations/plotly/chart_generator.py +313 -0
  171. vanna/integrations/postgres/__init__.py +9 -0
  172. vanna/integrations/postgres/sql_runner.py +112 -0
  173. vanna/integrations/premium/agent_memory/__init__.py +7 -0
  174. vanna/integrations/premium/agent_memory/premium.py +186 -0
  175. vanna/integrations/presto/__init__.py +5 -0
  176. vanna/integrations/presto/sql_runner.py +107 -0
  177. vanna/integrations/qdrant/__init__.py +7 -0
  178. vanna/integrations/qdrant/agent_memory.py +461 -0
  179. vanna/integrations/snowflake/__init__.py +5 -0
  180. vanna/integrations/snowflake/sql_runner.py +147 -0
  181. vanna/integrations/sqlite/__init__.py +9 -0
  182. vanna/integrations/sqlite/sql_runner.py +65 -0
  183. vanna/integrations/weaviate/__init__.py +7 -0
  184. vanna/integrations/weaviate/agent_memory.py +428 -0
  185. vanna/{ZhipuAI → legacy/ZhipuAI}/ZhipuAI_embeddings.py +11 -11
  186. vanna/legacy/__init__.py +403 -0
  187. vanna/legacy/adapter.py +463 -0
  188. vanna/{advanced → legacy/advanced}/__init__.py +3 -1
  189. vanna/{anthropic → legacy/anthropic}/anthropic_chat.py +9 -7
  190. vanna/{azuresearch → legacy/azuresearch}/azuresearch_vector.py +79 -41
  191. vanna/{base → legacy/base}/base.py +224 -217
  192. vanna/legacy/bedrock/__init__.py +1 -0
  193. vanna/{bedrock → legacy/bedrock}/bedrock_converse.py +13 -12
  194. vanna/{chromadb → legacy/chromadb}/chromadb_vector.py +3 -1
  195. vanna/legacy/cohere/__init__.py +2 -0
  196. vanna/{cohere → legacy/cohere}/cohere_chat.py +19 -14
  197. vanna/{cohere → legacy/cohere}/cohere_embeddings.py +25 -19
  198. vanna/{deepseek → legacy/deepseek}/deepseek_chat.py +5 -6
  199. vanna/legacy/faiss/__init__.py +1 -0
  200. vanna/{faiss → legacy/faiss}/faiss.py +113 -59
  201. vanna/{flask → legacy/flask}/__init__.py +84 -43
  202. vanna/{flask → legacy/flask}/assets.py +5 -5
  203. vanna/{flask → legacy/flask}/auth.py +5 -4
  204. vanna/{google → legacy/google}/bigquery_vector.py +75 -42
  205. vanna/{google → legacy/google}/gemini_chat.py +7 -3
  206. vanna/{hf → legacy/hf}/hf.py +0 -1
  207. vanna/{milvus → legacy/milvus}/milvus_vector.py +58 -35
  208. vanna/{mock → legacy/mock}/llm.py +0 -1
  209. vanna/legacy/mock/vectordb.py +67 -0
  210. vanna/legacy/ollama/ollama.py +110 -0
  211. vanna/{openai → legacy/openai}/openai_chat.py +2 -6
  212. vanna/legacy/opensearch/opensearch_vector.py +369 -0
  213. vanna/legacy/opensearch/opensearch_vector_semantic.py +200 -0
  214. vanna/legacy/oracle/oracle_vector.py +584 -0
  215. vanna/{pgvector → legacy/pgvector}/pgvector.py +42 -13
  216. vanna/{qdrant → legacy/qdrant}/qdrant.py +2 -6
  217. vanna/legacy/qianfan/Qianfan_Chat.py +170 -0
  218. vanna/legacy/qianfan/Qianfan_embeddings.py +36 -0
  219. vanna/legacy/qianwen/QianwenAI_chat.py +132 -0
  220. vanna/{remote.py → legacy/remote.py} +28 -26
  221. vanna/{utils.py → legacy/utils.py} +6 -11
  222. vanna/{vannadb → legacy/vannadb}/vannadb_vector.py +115 -46
  223. vanna/{vllm → legacy/vllm}/vllm.py +5 -6
  224. vanna/{weaviate → legacy/weaviate}/weaviate_vector.py +59 -40
  225. vanna/{xinference → legacy/xinference}/xinference.py +6 -6
  226. vanna/py.typed +0 -0
  227. vanna/servers/__init__.py +16 -0
  228. vanna/servers/__main__.py +8 -0
  229. vanna/servers/base/__init__.py +18 -0
  230. vanna/servers/base/chat_handler.py +65 -0
  231. vanna/servers/base/models.py +111 -0
  232. vanna/servers/base/rich_chat_handler.py +141 -0
  233. vanna/servers/base/templates.py +331 -0
  234. vanna/servers/cli/__init__.py +7 -0
  235. vanna/servers/cli/server_runner.py +204 -0
  236. vanna/servers/fastapi/__init__.py +7 -0
  237. vanna/servers/fastapi/app.py +163 -0
  238. vanna/servers/fastapi/routes.py +183 -0
  239. vanna/servers/flask/__init__.py +7 -0
  240. vanna/servers/flask/app.py +132 -0
  241. vanna/servers/flask/routes.py +137 -0
  242. vanna/tools/__init__.py +41 -0
  243. vanna/tools/agent_memory.py +322 -0
  244. vanna/tools/file_system.py +879 -0
  245. vanna/tools/python.py +222 -0
  246. vanna/tools/run_sql.py +165 -0
  247. vanna/tools/visualize_data.py +195 -0
  248. vanna/utils/__init__.py +0 -0
  249. vanna/web_components/__init__.py +44 -0
  250. vanna-2.0.0.dist-info/METADATA +485 -0
  251. vanna-2.0.0.dist-info/RECORD +289 -0
  252. vanna-2.0.0.dist-info/entry_points.txt +3 -0
  253. vanna/bedrock/__init__.py +0 -1
  254. vanna/cohere/__init__.py +0 -2
  255. vanna/faiss/__init__.py +0 -1
  256. vanna/mock/vectordb.py +0 -55
  257. vanna/ollama/ollama.py +0 -103
  258. vanna/opensearch/opensearch_vector.py +0 -392
  259. vanna/opensearch/opensearch_vector_semantic.py +0 -175
  260. vanna/oracle/oracle_vector.py +0 -585
  261. vanna/qianfan/Qianfan_Chat.py +0 -165
  262. vanna/qianfan/Qianfan_embeddings.py +0 -36
  263. vanna/qianwen/QianwenAI_chat.py +0 -133
  264. vanna-0.7.9.dist-info/METADATA +0 -408
  265. vanna-0.7.9.dist-info/RECORD +0 -79
  266. /vanna/{ZhipuAI → legacy/ZhipuAI}/ZhipuAI_Chat.py +0 -0
  267. /vanna/{ZhipuAI → legacy/ZhipuAI}/__init__.py +0 -0
  268. /vanna/{anthropic → legacy/anthropic}/__init__.py +0 -0
  269. /vanna/{azuresearch → legacy/azuresearch}/__init__.py +0 -0
  270. /vanna/{base → legacy/base}/__init__.py +0 -0
  271. /vanna/{chromadb → legacy/chromadb}/__init__.py +0 -0
  272. /vanna/{deepseek → legacy/deepseek}/__init__.py +0 -0
  273. /vanna/{exceptions → legacy/exceptions}/__init__.py +0 -0
  274. /vanna/{google → legacy/google}/__init__.py +0 -0
  275. /vanna/{hf → legacy/hf}/__init__.py +0 -0
  276. /vanna/{local.py → legacy/local.py} +0 -0
  277. /vanna/{marqo → legacy/marqo}/__init__.py +0 -0
  278. /vanna/{marqo → legacy/marqo}/marqo.py +0 -0
  279. /vanna/{milvus → legacy/milvus}/__init__.py +0 -0
  280. /vanna/{mistral → legacy/mistral}/__init__.py +0 -0
  281. /vanna/{mistral → legacy/mistral}/mistral.py +0 -0
  282. /vanna/{mock → legacy/mock}/__init__.py +0 -0
  283. /vanna/{mock → legacy/mock}/embedding.py +0 -0
  284. /vanna/{ollama → legacy/ollama}/__init__.py +0 -0
  285. /vanna/{openai → legacy/openai}/__init__.py +0 -0
  286. /vanna/{openai → legacy/openai}/openai_embeddings.py +0 -0
  287. /vanna/{opensearch → legacy/opensearch}/__init__.py +0 -0
  288. /vanna/{oracle → legacy/oracle}/__init__.py +0 -0
  289. /vanna/{pgvector → legacy/pgvector}/__init__.py +0 -0
  290. /vanna/{pinecone → legacy/pinecone}/__init__.py +0 -0
  291. /vanna/{pinecone → legacy/pinecone}/pinecone_vector.py +0 -0
  292. /vanna/{qdrant → legacy/qdrant}/__init__.py +0 -0
  293. /vanna/{qianfan → legacy/qianfan}/__init__.py +0 -0
  294. /vanna/{qianwen → legacy/qianwen}/QianwenAI_embeddings.py +0 -0
  295. /vanna/{qianwen → legacy/qianwen}/__init__.py +0 -0
  296. /vanna/{types → legacy/types}/__init__.py +0 -0
  297. /vanna/{vannadb → legacy/vannadb}/__init__.py +0 -0
  298. /vanna/{vllm → legacy/vllm}/__init__.py +0 -0
  299. /vanna/{weaviate → legacy/weaviate}/__init__.py +0 -0
  300. /vanna/{xinference → legacy/xinference}/__init__.py +0 -0
  301. {vanna-0.7.9.dist-info → vanna-2.0.0.dist-info}/WHEEL +0 -0
  302. {vanna-0.7.9.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
+ )