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.
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 +247 -223
  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.8.dist-info/METADATA +0 -408
  265. vanna-0.7.8.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.8.dist-info → vanna-2.0.0.dist-info}/WHEEL +0 -0
  302. {vanna-0.7.8.dist-info → vanna-2.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,27 @@
1
+ """Base classes for simple UI components."""
2
+
3
+ from typing import Any, Dict, Optional
4
+ from pydantic import BaseModel, Field
5
+ from enum import Enum
6
+
7
+
8
+ class SimpleComponentType(str, Enum):
9
+ TEXT = "text"
10
+ IMAGE = "image"
11
+ LINK = "link"
12
+
13
+
14
+ class SimpleComponent(BaseModel):
15
+ """A simple UI component with basic attributes."""
16
+
17
+ type: SimpleComponentType = Field(..., description="Type of the component.")
18
+ semantic_type: Optional[str] = Field(
19
+ default=None, description="Semantic type for better categorization."
20
+ )
21
+ metadata: Optional[Dict[str, Any]] = Field(
22
+ default=None, description="Additional metadata for the component."
23
+ )
24
+
25
+ def serialize_for_frontend(self) -> Dict[str, Any]:
26
+ """Serialize simple component for API consumption."""
27
+ return self.model_dump()
@@ -0,0 +1,14 @@
1
+ """
2
+ Storage domain.
3
+
4
+ This module provides the core abstractions for conversation storage in the Vanna Agents framework.
5
+ """
6
+
7
+ from .base import ConversationStore
8
+ from .models import Conversation, Message
9
+
10
+ __all__ = [
11
+ "ConversationStore",
12
+ "Conversation",
13
+ "Message",
14
+ ]
@@ -0,0 +1,46 @@
1
+ """
2
+ Storage domain interface.
3
+
4
+ This module contains the abstract base class for conversation storage.
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+ from typing import List, Optional
9
+
10
+ from .models import Conversation
11
+ from ..user.models import User
12
+
13
+
14
+ class ConversationStore(ABC):
15
+ """Abstract base class for conversation storage."""
16
+
17
+ @abstractmethod
18
+ async def create_conversation(
19
+ self, conversation_id: str, user: User, initial_message: str
20
+ ) -> Conversation:
21
+ """Create a new conversation with the specified ID."""
22
+ pass
23
+
24
+ @abstractmethod
25
+ async def get_conversation(
26
+ self, conversation_id: str, user: User
27
+ ) -> Optional[Conversation]:
28
+ """Get conversation by ID, scoped to user."""
29
+ pass
30
+
31
+ @abstractmethod
32
+ async def update_conversation(self, conversation: Conversation) -> None:
33
+ """Update conversation with new messages."""
34
+ pass
35
+
36
+ @abstractmethod
37
+ async def delete_conversation(self, conversation_id: str, user: User) -> bool:
38
+ """Delete conversation."""
39
+ pass
40
+
41
+ @abstractmethod
42
+ async def list_conversations(
43
+ self, user: User, limit: int = 50, offset: int = 0
44
+ ) -> List[Conversation]:
45
+ """List conversations for user."""
46
+ pass
@@ -0,0 +1,46 @@
1
+ """
2
+ Storage domain models.
3
+
4
+ This module contains data models for conversation storage.
5
+ """
6
+
7
+ from datetime import datetime
8
+ from typing import Any, Dict, List, Optional
9
+
10
+ from pydantic import BaseModel, Field
11
+
12
+ from ..tool.models import ToolCall
13
+ from ..user.models import User
14
+
15
+
16
+ class Message(BaseModel):
17
+ """Single message in a conversation."""
18
+
19
+ role: str = Field(description="Message role (user/assistant/system/tool)")
20
+ content: str = Field(description="Message content")
21
+ timestamp: datetime = Field(default_factory=datetime.utcnow)
22
+ metadata: Dict[str, Any] = Field(default_factory=dict)
23
+ tool_calls: Optional[List[ToolCall]] = Field(default=None)
24
+ tool_call_id: Optional[str] = Field(
25
+ default=None, description="ID if this is a tool response"
26
+ )
27
+
28
+
29
+ class Conversation(BaseModel):
30
+ """Conversation containing multiple messages."""
31
+
32
+ id: str = Field(description="Unique conversation identifier")
33
+ user: User = Field(description="User this conversation belongs to")
34
+ messages: List[Message] = Field(
35
+ default_factory=list, description="Messages in conversation"
36
+ )
37
+ created_at: datetime = Field(default_factory=datetime.utcnow)
38
+ updated_at: datetime = Field(default_factory=datetime.utcnow)
39
+ metadata: Dict[str, Any] = Field(
40
+ default_factory=dict, description="Additional conversation metadata"
41
+ )
42
+
43
+ def add_message(self, message: Message) -> None:
44
+ """Add a message to the conversation."""
45
+ self.messages.append(message)
46
+ self.updated_at = datetime.utcnow()
@@ -0,0 +1,13 @@
1
+ """
2
+ System prompt domain.
3
+
4
+ This module provides the core abstractions for building system prompts in the Vanna Agents framework.
5
+ """
6
+
7
+ from .base import SystemPromptBuilder
8
+ from .default import DefaultSystemPromptBuilder
9
+
10
+ __all__ = [
11
+ "SystemPromptBuilder",
12
+ "DefaultSystemPromptBuilder",
13
+ ]
@@ -0,0 +1,36 @@
1
+ """
2
+ System prompt builder interface.
3
+
4
+ This module contains the abstract base class for system prompt builders.
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+ from typing import TYPE_CHECKING, List, Optional
9
+
10
+ if TYPE_CHECKING:
11
+ from ..tool.models import ToolSchema
12
+ from ..user.models import User
13
+
14
+
15
+ class SystemPromptBuilder(ABC):
16
+ """Abstract base class for system prompt builders.
17
+
18
+ Subclasses should implement the build_system_prompt method to generate
19
+ system prompts based on user context and available tools.
20
+ """
21
+
22
+ @abstractmethod
23
+ async def build_system_prompt(
24
+ self, user: "User", tools: List["ToolSchema"]
25
+ ) -> Optional[str]:
26
+ """
27
+ Build a system prompt based on user context and available tools.
28
+
29
+ Args:
30
+ user: The user making the request
31
+ tools: List of tools available to the user
32
+
33
+ Returns:
34
+ System prompt string, or None if no system prompt should be used
35
+ """
36
+ pass
@@ -0,0 +1,157 @@
1
+ """
2
+ Default system prompt builder implementation with memory workflow support.
3
+
4
+ This module provides a default implementation of the SystemPromptBuilder interface
5
+ that automatically includes memory workflow instructions when memory tools are available.
6
+ """
7
+
8
+ from typing import TYPE_CHECKING, List, Optional
9
+ from datetime import datetime
10
+
11
+ from .base import SystemPromptBuilder
12
+
13
+ if TYPE_CHECKING:
14
+ from ..tool.models import ToolSchema
15
+ from ..user.models import User
16
+
17
+
18
+ class DefaultSystemPromptBuilder(SystemPromptBuilder):
19
+ """Default system prompt builder with automatic memory workflow integration.
20
+
21
+ Dynamically generates system prompts that include memory workflow
22
+ instructions when memory tools (search_saved_correct_tool_uses and
23
+ save_question_tool_args) are available.
24
+ """
25
+
26
+ def __init__(self, base_prompt: Optional[str] = None):
27
+ """Initialize with an optional base prompt.
28
+
29
+ Args:
30
+ base_prompt: Optional base system prompt. If not provided, uses a default.
31
+ """
32
+ self.base_prompt = base_prompt
33
+
34
+ async def build_system_prompt(
35
+ self, user: "User", tools: List["ToolSchema"]
36
+ ) -> Optional[str]:
37
+ """
38
+ Build a system prompt with memory workflow instructions.
39
+
40
+ Args:
41
+ user: The user making the request
42
+ tools: List of tools available to the user
43
+
44
+ Returns:
45
+ System prompt string with memory workflow instructions if applicable
46
+ """
47
+ if self.base_prompt is not None:
48
+ return self.base_prompt
49
+
50
+ # Check which memory tools are available
51
+ tool_names = [tool.name for tool in tools]
52
+ has_search = "search_saved_correct_tool_uses" in tool_names
53
+ has_save = "save_question_tool_args" in tool_names
54
+ has_text_memory = "save_text_memory" in tool_names
55
+
56
+ # Get today's date
57
+ today_date = datetime.now().strftime("%Y-%m-%d")
58
+
59
+ # Base system prompt
60
+ prompt_parts = [
61
+ f"You are Vanna, an AI data analyst assistant created to help users with data analysis tasks. Today's date is {today_date}.",
62
+ "",
63
+ "Response Guidelines:",
64
+ "- Any summary of what you did or observations should be the final step.",
65
+ "- Use the available tools to help the user accomplish their goals.",
66
+ "- When you execute a query, that raw result is shown to the user outside of your response so YOU DO NOT need to include it in your response. Focus on summarizing and interpreting the results.",
67
+ ]
68
+
69
+ if tools:
70
+ prompt_parts.append(
71
+ f"\nYou have access to the following tools: {', '.join(tool_names)}"
72
+ )
73
+
74
+ # Add memory workflow instructions based on available tools
75
+ if has_search or has_save or has_text_memory:
76
+ prompt_parts.append("\n" + "=" * 60)
77
+ prompt_parts.append("MEMORY SYSTEM:")
78
+ prompt_parts.append("=" * 60)
79
+
80
+ if has_search or has_save:
81
+ prompt_parts.append("\n1. TOOL USAGE MEMORY (Structured Workflow):")
82
+ prompt_parts.append("-" * 50)
83
+
84
+ if has_search:
85
+ prompt_parts.extend(
86
+ [
87
+ "",
88
+ "• BEFORE executing any tool (run_sql, visualize_data, or calculator), you MUST first call search_saved_correct_tool_uses with the user's question to check if there are existing successful patterns for similar questions.",
89
+ "",
90
+ "• Review the search results (if any) to inform your approach before proceeding with other tool calls.",
91
+ ]
92
+ )
93
+
94
+ if has_save:
95
+ prompt_parts.extend(
96
+ [
97
+ "",
98
+ "• AFTER successfully executing a tool that produces correct and useful results, you MUST call save_question_tool_args to save the successful pattern for future use.",
99
+ ]
100
+ )
101
+
102
+ if has_search or has_save:
103
+ prompt_parts.extend(
104
+ [
105
+ "",
106
+ "Example workflow:",
107
+ " • User asks a question",
108
+ f' • First: Call search_saved_correct_tool_uses(question="user\'s question")'
109
+ if has_search
110
+ else "",
111
+ " • Then: Execute the appropriate tool(s) based on search results and the question",
112
+ f' • Finally: If successful, call save_question_tool_args(question="user\'s question", tool_name="tool_used", args={{the args you used}})'
113
+ if has_save
114
+ else "",
115
+ "",
116
+ "Do NOT skip the search step, even if you think you know how to answer. Do NOT forget to save successful executions."
117
+ if has_search
118
+ else "",
119
+ "",
120
+ "The only exceptions to searching first are:",
121
+ ' • When the user is explicitly asking about the tools themselves (like "list the tools")',
122
+ " • When the user is testing or asking you to demonstrate the save/search functionality itself",
123
+ ]
124
+ )
125
+
126
+ if has_text_memory:
127
+ prompt_parts.extend(
128
+ [
129
+ "",
130
+ "2. TEXT MEMORY (Domain Knowledge & Context):",
131
+ "-" * 50,
132
+ "",
133
+ "• save_text_memory: Save important context about the database, schema, or domain",
134
+ "",
135
+ "Use text memory to save:",
136
+ " • Database schema details (column meanings, data types, relationships)",
137
+ " • Company-specific terminology and definitions",
138
+ " • Query patterns or best practices for this database",
139
+ " • Domain knowledge about the business or data",
140
+ " • User preferences for queries or visualizations",
141
+ "",
142
+ "DO NOT save:",
143
+ " • Information already captured in tool usage memory",
144
+ " • One-time query results or temporary observations",
145
+ "",
146
+ "Examples:",
147
+ ' • save_text_memory(content="The status column uses 1 for active, 0 for inactive")',
148
+ ' • save_text_memory(content="MRR means Monthly Recurring Revenue in our schema")',
149
+ " • save_text_memory(content=\"Always exclude test accounts where email contains 'test'\")",
150
+ ]
151
+ )
152
+
153
+ if has_search or has_save or has_text_memory:
154
+ # Remove empty strings from the list
155
+ prompt_parts = [part for part in prompt_parts if part != ""]
156
+
157
+ return "\n".join(prompt_parts)
@@ -0,0 +1,18 @@
1
+ """
2
+ Tool domain.
3
+
4
+ This module provides the core abstractions for tools in the Vanna Agents framework.
5
+ """
6
+
7
+ from .base import T, Tool
8
+ from .models import ToolCall, ToolContext, ToolRejection, ToolResult, ToolSchema
9
+
10
+ __all__ = [
11
+ "Tool",
12
+ "T",
13
+ "ToolCall",
14
+ "ToolContext",
15
+ "ToolRejection",
16
+ "ToolResult",
17
+ "ToolSchema",
18
+ ]
@@ -0,0 +1,70 @@
1
+ """
2
+ Tool domain interface.
3
+
4
+ This module contains the abstract base class for tools.
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+ from typing import Generic, List, Type, TypeVar
9
+
10
+ from .models import ToolContext, ToolResult, ToolSchema
11
+
12
+ # Type variable for tool argument types
13
+ T = TypeVar("T")
14
+
15
+
16
+ class Tool(ABC, Generic[T]):
17
+ """Abstract base class for tools."""
18
+
19
+ @property
20
+ @abstractmethod
21
+ def name(self) -> str:
22
+ """Unique name for this tool."""
23
+ pass
24
+
25
+ @property
26
+ @abstractmethod
27
+ def description(self) -> str:
28
+ """Description of what this tool does."""
29
+ pass
30
+
31
+ @property
32
+ def access_groups(self) -> List[str]:
33
+ """Groups permitted to access this tool."""
34
+ return []
35
+
36
+ @abstractmethod
37
+ def get_args_schema(self) -> Type[T]:
38
+ """Return the Pydantic model for arguments."""
39
+ pass
40
+
41
+ @abstractmethod
42
+ async def execute(self, context: ToolContext, args: T) -> ToolResult:
43
+ """Execute the tool with validated arguments.
44
+
45
+ Args:
46
+ context: Execution context containing user, conversation_id, and request_id
47
+ args: Validated tool arguments
48
+
49
+ Returns:
50
+ ToolResult with success status, result for LLM, and optional UI component
51
+ """
52
+ pass
53
+
54
+ def get_schema(self) -> ToolSchema:
55
+ """Generate tool schema for LLM."""
56
+ from typing import Any, cast
57
+
58
+ args_model = self.get_args_schema()
59
+ # Get the schema - args_model should be a Pydantic model class
60
+ schema = (
61
+ cast(Any, args_model).model_json_schema()
62
+ if hasattr(args_model, "model_json_schema")
63
+ else {}
64
+ )
65
+ return ToolSchema(
66
+ name=self.name,
67
+ description=self.description,
68
+ parameters=schema,
69
+ access_groups=self.access_groups,
70
+ )
@@ -0,0 +1,84 @@
1
+ """
2
+ Tool domain models.
3
+
4
+ This module contains data models for tool execution.
5
+ """
6
+
7
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional
8
+
9
+ from pydantic import BaseModel, Field
10
+
11
+ # Import AgentMemory at runtime for Pydantic model resolution
12
+ from vanna.capabilities.agent_memory import AgentMemory
13
+
14
+ if TYPE_CHECKING:
15
+ from ..components import UiComponent
16
+ from ..user.models import User
17
+ from ..observability import ObservabilityProvider
18
+
19
+
20
+ class ToolCall(BaseModel):
21
+ """Represents a tool call from the LLM."""
22
+
23
+ id: str = Field(description="Unique identifier for this tool call")
24
+ name: str = Field(description="Name of the tool to execute")
25
+ arguments: Dict[str, Any] = Field(description="Raw arguments from LLM")
26
+
27
+
28
+ class ToolContext(BaseModel):
29
+ """Context passed to all tool executions."""
30
+
31
+ user: "User" # Forward reference to avoid circular import
32
+ conversation_id: str
33
+ request_id: str = Field(description="Unique request identifier for tracing")
34
+ agent_memory: AgentMemory = Field(
35
+ description="Agent memory for tool usage learning"
36
+ )
37
+ metadata: Dict[str, Any] = Field(default_factory=dict)
38
+ observability_provider: Optional["ObservabilityProvider"] = Field(
39
+ default=None,
40
+ description="Optional observability provider for metrics and spans",
41
+ )
42
+
43
+ class Config:
44
+ arbitrary_types_allowed = True
45
+
46
+
47
+ class ToolResult(BaseModel):
48
+ """Result from tool execution.
49
+
50
+ Changes:
51
+ - `result_for_llm`: string that will be sent back to the LLM.
52
+ - `ui_component`: optional UI payload for rendering in clients.
53
+ """
54
+
55
+ success: bool = Field(description="Whether execution succeeded")
56
+ result_for_llm: str = Field(description="String content to send back to the LLM")
57
+ ui_component: Optional["UiComponent"] = Field(
58
+ default=None, description="Optional UI component for rendering"
59
+ )
60
+ error: Optional[str] = Field(default=None, description="Error message if failed")
61
+ metadata: Dict[str, Any] = Field(default_factory=dict)
62
+
63
+
64
+ class ToolSchema(BaseModel):
65
+ """Schema describing a tool for LLM consumption."""
66
+
67
+ name: str = Field(description="Tool name")
68
+ description: str = Field(description="What this tool does")
69
+ parameters: Dict[str, Any] = Field(description="JSON Schema of parameters")
70
+ access_groups: List[str] = Field(
71
+ default_factory=list, description="Groups permitted to access this tool"
72
+ )
73
+
74
+
75
+ class ToolRejection(BaseModel):
76
+ """Indicates tool execution should be rejected with a message.
77
+
78
+ Used by transform_args to reject tool execution when arguments
79
+ cannot be appropriately transformed for the user's context.
80
+ """
81
+
82
+ reason: str = Field(
83
+ description="Explanation of why the tool execution was rejected"
84
+ )
@@ -0,0 +1,17 @@
1
+ """
2
+ User domain.
3
+
4
+ This module provides the core abstractions for user management in the Vanna Agents framework.
5
+ """
6
+
7
+ from .base import UserService
8
+ from .models import User
9
+ from .resolver import UserResolver
10
+ from .request_context import RequestContext
11
+
12
+ __all__ = [
13
+ "UserService",
14
+ "User",
15
+ "UserResolver",
16
+ "RequestContext",
17
+ ]
@@ -0,0 +1,29 @@
1
+ """
2
+ User domain interface.
3
+
4
+ This module contains the abstract base class for user services.
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+ from typing import Any, Dict, Optional
9
+
10
+ from .models import User
11
+
12
+
13
+ class UserService(ABC):
14
+ """Service for user management and authentication."""
15
+
16
+ @abstractmethod
17
+ async def get_user(self, user_id: str) -> Optional[User]:
18
+ """Get user by ID."""
19
+ pass
20
+
21
+ @abstractmethod
22
+ async def authenticate(self, credentials: Dict[str, Any]) -> Optional[User]:
23
+ """Authenticate user and return User object if successful."""
24
+ pass
25
+
26
+ @abstractmethod
27
+ async def has_permission(self, user: User, permission: str) -> bool:
28
+ """Check if user has specific permission."""
29
+ pass
@@ -0,0 +1,25 @@
1
+ """
2
+ User domain models.
3
+
4
+ This module contains data models for user management.
5
+ """
6
+
7
+ from typing import Any, Dict, List, Optional
8
+
9
+ from pydantic import BaseModel, ConfigDict, Field
10
+
11
+
12
+ class User(BaseModel):
13
+ """User model for authentication and scoping."""
14
+
15
+ id: str = Field(description="Unique user identifier")
16
+ username: Optional[str] = Field(default=None, description="Username")
17
+ email: Optional[str] = Field(default=None, description="User email")
18
+ metadata: Dict[str, Any] = Field(
19
+ default_factory=dict, description="Additional user metadata"
20
+ )
21
+ group_memberships: List[str] = Field(
22
+ default_factory=list, description="Groups the user belongs to"
23
+ )
24
+
25
+ model_config = ConfigDict(extra="allow")
@@ -0,0 +1,70 @@
1
+ """
2
+ Request context for user resolution.
3
+
4
+ This module provides the RequestContext model for passing web request
5
+ information to UserResolver implementations.
6
+ """
7
+
8
+ from typing import Any, Dict, Optional
9
+
10
+ from pydantic import BaseModel, Field
11
+
12
+
13
+ class RequestContext(BaseModel):
14
+ """Context from a web request for user resolution.
15
+
16
+ This structured object replaces raw dictionaries for passing request
17
+ data to UserResolver implementations, making it easier to access
18
+ cookies, headers, and other request metadata.
19
+
20
+ Example:
21
+ context = RequestContext(
22
+ cookies={'vanna_email': 'alice@example.com'},
23
+ headers={'Authorization': 'Bearer token'},
24
+ remote_addr='127.0.0.1'
25
+ )
26
+ user = await resolver.resolve_user(context)
27
+ """
28
+
29
+ cookies: Dict[str, str] = Field(default_factory=dict, description="Request cookies")
30
+
31
+ headers: Dict[str, str] = Field(default_factory=dict, description="Request headers")
32
+
33
+ remote_addr: Optional[str] = Field(default=None, description="Remote IP address")
34
+
35
+ query_params: Dict[str, str] = Field(
36
+ default_factory=dict, description="Query parameters"
37
+ )
38
+
39
+ metadata: Dict[str, Any] = Field(
40
+ default_factory=dict, description="Additional framework-specific metadata"
41
+ )
42
+
43
+ def get_cookie(self, name: str, default: Optional[str] = None) -> Optional[str]:
44
+ """Get cookie value by name.
45
+
46
+ Args:
47
+ name: Cookie name
48
+ default: Default value if cookie not found
49
+
50
+ Returns:
51
+ Cookie value or default
52
+ """
53
+ return self.cookies.get(name, default)
54
+
55
+ def get_header(self, name: str, default: Optional[str] = None) -> Optional[str]:
56
+ """Get header value by name (case-insensitive).
57
+
58
+ Args:
59
+ name: Header name
60
+ default: Default value if header not found
61
+
62
+ Returns:
63
+ Header value or default
64
+ """
65
+ # Case-insensitive header lookup
66
+ name_lower = name.lower()
67
+ for key, value in self.headers.items():
68
+ if key.lower() == name_lower:
69
+ return value
70
+ return default