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 @@
1
+ """Examples for using the Vanna Agents framework."""
@@ -0,0 +1,44 @@
1
+ """
2
+ Interactive example runner for Vanna Agents.
3
+ """
4
+
5
+ import sys
6
+ import importlib
7
+
8
+
9
+ def main() -> None:
10
+ """Run an example interactively."""
11
+ if len(sys.argv) < 2:
12
+ print("Available examples:")
13
+ print(" python -m vanna.examples mock_quickstart")
14
+ print(" python -m vanna.examples mock_custom_tool")
15
+ print(" python -m vanna.examples anthropic_quickstart")
16
+ print(" python -m vanna.examples openai_quickstart")
17
+ print(" python -m vanna.examples mock_quota_example")
18
+ print(" python -m vanna.examples mock_rich_components_demo")
19
+ print("")
20
+ print("Usage: python -m vanna.examples <example_name>")
21
+ return
22
+
23
+ example_name = sys.argv[1]
24
+ try:
25
+ module = importlib.import_module(f"vanna.examples.{example_name}")
26
+ if hasattr(module, "run_interactive"):
27
+ module.run_interactive()
28
+ elif hasattr(module, "main"):
29
+ import asyncio
30
+
31
+ if asyncio.iscoroutinefunction(module.main):
32
+ asyncio.run(module.main())
33
+ else:
34
+ module.main()
35
+ else:
36
+ print(f"Example '{example_name}' does not have a main function")
37
+ except ImportError:
38
+ print(f"Example '{example_name}' not found")
39
+ except Exception as e:
40
+ print(f"Error running example '{example_name}': {e}")
41
+
42
+
43
+ if __name__ == "__main__":
44
+ main()
@@ -0,0 +1,80 @@
1
+ """
2
+ Anthropic example using AnthropicLlmService.
3
+
4
+ Loads environment from .env (via python-dotenv), uses model 'claude-sonnet-4-20250514'
5
+ by default, and sends a simple message through a Agent.
6
+
7
+ Run:
8
+ PYTHONPATH=. python vanna/examples/anthropic_quickstart.py
9
+ """
10
+
11
+ import asyncio
12
+ import importlib.util
13
+ import os
14
+ import sys
15
+
16
+
17
+ def ensure_env() -> None:
18
+ if importlib.util.find_spec("dotenv") is not None:
19
+ from dotenv import load_dotenv
20
+
21
+ # Load from local .env without overriding existing env
22
+ load_dotenv(dotenv_path=os.path.join(os.getcwd(), ".env"), override=False)
23
+ else:
24
+ print(
25
+ "[warn] python-dotenv not installed; skipping .env load. Install with: pip install python-dotenv"
26
+ )
27
+
28
+ if not os.getenv("ANTHROPIC_API_KEY"):
29
+ print(
30
+ "[error] ANTHROPIC_API_KEY is not set. Add it to your environment or .env file."
31
+ )
32
+ sys.exit(1)
33
+
34
+
35
+ async def main() -> None:
36
+ ensure_env()
37
+
38
+ try:
39
+ from vanna.integrations.anthropic import AnthropicLlmService
40
+ except ImportError:
41
+ print(
42
+ "[error] anthropic extra not installed. Install with: pip install -e .[anthropic]"
43
+ )
44
+ raise
45
+
46
+ from vanna import AgentConfig, Agent, User
47
+ from vanna.core.registry import ToolRegistry
48
+ from vanna.tools import ListFilesTool
49
+
50
+ model = os.getenv("ANTHROPIC_MODEL", "claude-sonnet-4-20250514")
51
+ print(f"Using Anthropic model: {model}")
52
+
53
+ llm = AnthropicLlmService(model=model)
54
+
55
+ # Create tool registry and register the list_files tool
56
+ tool_registry = ToolRegistry()
57
+ list_files_tool = ListFilesTool()
58
+ tool_registry.register(list_files_tool)
59
+
60
+ agent = Agent(
61
+ llm_service=llm,
62
+ config=AgentConfig(stream_responses=False),
63
+ tool_registry=tool_registry,
64
+ )
65
+
66
+ user = User(id="demo-user", username="demo")
67
+ conversation_id = "anthropic-demo"
68
+
69
+ print("Sending: 'List the files in the current directory'\n")
70
+ async for component in agent.send_message(
71
+ user=user,
72
+ message="List the files in the current directory",
73
+ conversation_id=conversation_id,
74
+ ):
75
+ if hasattr(component, "content") and component.content:
76
+ print("Assistant:", component.content)
77
+
78
+
79
+ if __name__ == "__main__":
80
+ asyncio.run(main())
@@ -0,0 +1,293 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Example demonstrating the artifact system in Vanna Agents.
4
+
5
+ This script shows how agents can create interactive artifacts that can be
6
+ rendered externally by developers listening for the 'artifact-opened' event.
7
+ """
8
+
9
+ import asyncio
10
+ from typing import AsyncGenerator, Optional
11
+
12
+ from vanna import Agent, UiComponent, User, AgentConfig
13
+ from vanna.core.rich_components import ArtifactComponent
14
+ from vanna.integrations.anthropic.mock import MockLlmService
15
+ from vanna.core.interfaces import Agent, LlmService
16
+
17
+
18
+ class ArtifactDemoAgent(Agent):
19
+ """Demo agent that creates various types of artifacts."""
20
+
21
+ def __init__(self, llm_service: Optional[LlmService] = None) -> None:
22
+ if llm_service is None:
23
+ llm_service = MockLlmService(
24
+ "I'll help you create interactive artifacts! Try asking me to create a chart, dashboard, or interactive HTML widget."
25
+ )
26
+ super().__init__(
27
+ llm_service=llm_service,
28
+ config=AgentConfig(
29
+ stream_responses=True,
30
+ include_thinking_indicators=True,
31
+ ),
32
+ )
33
+
34
+ async def send_message(
35
+ self, user: User, message: str, *, conversation_id: Optional[str] = None
36
+ ) -> AsyncGenerator[UiComponent, None]:
37
+ """Handle user messages and create appropriate artifacts."""
38
+ # First send the normal response
39
+ async for component in super().send_message(
40
+ user, message, conversation_id=conversation_id
41
+ ):
42
+ yield component
43
+
44
+ # Then create artifacts based on message content
45
+ message_lower = message.lower()
46
+
47
+ if any(
48
+ word in message_lower for word in ["chart", "graph", "visualization", "d3"]
49
+ ):
50
+ async for component in self.create_d3_visualization():
51
+ yield component
52
+ elif any(
53
+ word in message_lower for word in ["dashboard", "analytics", "metrics"]
54
+ ):
55
+ async for component in self.create_dashboard_artifact():
56
+ yield component
57
+ elif any(
58
+ word in message_lower for word in ["html", "interactive", "widget", "demo"]
59
+ ):
60
+ async for component in self.create_html_artifact():
61
+ yield component
62
+
63
+ async def create_html_artifact(self) -> AsyncGenerator[UiComponent, None]:
64
+ """Create a simple HTML artifact."""
65
+ html_content = """
66
+ <div style="padding: 20px; font-family: Arial, sans-serif;">
67
+ <h2 style="color: #333;">Interactive HTML Artifact</h2>
68
+ <p>This is a simple HTML artifact that can be opened externally.</p>
69
+ <button onclick="alert('Hello from the artifact!')">Click me!</button>
70
+ <div style="margin-top: 20px;">
71
+ <input type="text" placeholder="Type something..." id="textInput">
72
+ <button onclick="document.getElementById('output').textContent = document.getElementById('textInput').value">
73
+ Update Text
74
+ </button>
75
+ </div>
76
+ <div id="output" style="margin-top: 10px; padding: 10px; background: #f0f0f0; border-radius: 4px;">
77
+ Output will appear here...
78
+ </div>
79
+ </div>
80
+ """
81
+
82
+ artifact = ArtifactComponent.create_html(
83
+ content=html_content,
84
+ title="Interactive HTML Demo",
85
+ description="A simple HTML artifact with interactive elements",
86
+ )
87
+
88
+ yield UiComponent(rich_component=artifact)
89
+
90
+ async def create_d3_visualization(self) -> AsyncGenerator[UiComponent, None]:
91
+ """Create a D3.js visualization artifact."""
92
+ d3_content = """
93
+ <div id="chart" style="width: 100%; height: 400px;"></div>
94
+ <script>
95
+ // Sample data
96
+ const data = [
97
+ {name: 'A', value: 30},
98
+ {name: 'B', value: 80},
99
+ {name: 'C', value: 45},
100
+ {name: 'D', value: 60},
101
+ {name: 'E', value: 20},
102
+ {name: 'F', value: 90}
103
+ ];
104
+
105
+ // Set up dimensions
106
+ const margin = {top: 20, right: 30, bottom: 40, left: 40};
107
+ const width = 800 - margin.left - margin.right;
108
+ const height = 400 - margin.top - margin.bottom;
109
+
110
+ // Create SVG
111
+ const svg = d3.select("#chart")
112
+ .append("svg")
113
+ .attr("width", width + margin.left + margin.right)
114
+ .attr("height", height + margin.top + margin.bottom)
115
+ .append("g")
116
+ .attr("transform", `translate(${margin.left},${margin.top})`);
117
+
118
+ // Create scales
119
+ const xScale = d3.scaleBand()
120
+ .domain(data.map(d => d.name))
121
+ .range([0, width])
122
+ .padding(0.1);
123
+
124
+ const yScale = d3.scaleLinear()
125
+ .domain([0, d3.max(data, d => d.value)])
126
+ .range([height, 0]);
127
+
128
+ // Create bars
129
+ svg.selectAll(".bar")
130
+ .data(data)
131
+ .enter().append("rect")
132
+ .attr("class", "bar")
133
+ .attr("x", d => xScale(d.name))
134
+ .attr("width", xScale.bandwidth())
135
+ .attr("y", d => yScale(d.value))
136
+ .attr("height", d => height - yScale(d.value))
137
+ .attr("fill", "#4CAF50")
138
+ .on("mouseover", function(event, d) {
139
+ d3.select(this).attr("fill", "#45a049");
140
+ })
141
+ .on("mouseout", function(event, d) {
142
+ d3.select(this).attr("fill", "#4CAF50");
143
+ });
144
+
145
+ // Add axes
146
+ svg.append("g")
147
+ .attr("transform", `translate(0,${height})`)
148
+ .call(d3.axisBottom(xScale));
149
+
150
+ svg.append("g")
151
+ .call(d3.axisLeft(yScale));
152
+ </script>
153
+ """
154
+
155
+ artifact = ArtifactComponent.create_d3(
156
+ content=d3_content,
157
+ title="D3.js Bar Chart",
158
+ description="An interactive bar chart built with D3.js",
159
+ )
160
+
161
+ yield UiComponent(rich_component=artifact)
162
+
163
+ async def create_dashboard_artifact(self) -> AsyncGenerator[UiComponent, None]:
164
+ """Create a dashboard-style artifact."""
165
+ dashboard_content = """
166
+ <div style="padding: 20px; font-family: Arial, sans-serif; background: #f5f5f5; min-height: 100vh;">
167
+ <h1 style="color: #333; margin-bottom: 30px;">Analytics Dashboard</h1>
168
+
169
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 30px;">
170
+ <div class="metric-card" style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
171
+ <h3 style="margin: 0; color: #666;">Total Users</h3>
172
+ <p style="font-size: 2em; font-weight: bold; color: #333; margin: 10px 0;">12,456</p>
173
+ <span style="color: #4CAF50;">↗ +5.2%</span>
174
+ </div>
175
+
176
+ <div class="metric-card" style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
177
+ <h3 style="margin: 0; color: #666;">Revenue</h3>
178
+ <p style="font-size: 2em; font-weight: bold; color: #333; margin: 10px 0;">$89,432</p>
179
+ <span style="color: #4CAF50;">↗ +12.3%</span>
180
+ </div>
181
+
182
+ <div class="metric-card" style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
183
+ <h3 style="margin: 0; color: #666;">Conversion Rate</h3>
184
+ <p style="font-size: 2em; font-weight: bold; color: #333; margin: 10px 0;">3.4%</p>
185
+ <span style="color: #f44336;">↘ -0.8%</span>
186
+ </div>
187
+ </div>
188
+
189
+ <div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
190
+ <h3 style="margin: 0 0 20px 0; color: #333;">Quick Actions</h3>
191
+ <div style="display: flex; gap: 10px; flex-wrap: wrap;">
192
+ <button onclick="alert('Export feature coming soon!')"
193
+ style="padding: 10px 20px; background: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer;">
194
+ Export Data
195
+ </button>
196
+ <button onclick="alert('Refresh complete!')"
197
+ style="padding: 10px 20px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer;">
198
+ Refresh
199
+ </button>
200
+ <button onclick="alert('Settings panel opened!')"
201
+ style="padding: 10px 20px; background: #FF9800; color: white; border: none; border-radius: 4px; cursor: pointer;">
202
+ Settings
203
+ </button>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ """
208
+
209
+ artifact = ArtifactComponent(
210
+ content=dashboard_content,
211
+ artifact_type="dashboard",
212
+ title="Analytics Dashboard",
213
+ description="A sample analytics dashboard with metrics and controls",
214
+ external_renderable=True,
215
+ fullscreen_capable=True,
216
+ )
217
+
218
+ yield UiComponent(rich_component=artifact)
219
+
220
+
221
+ def create_demo_agent() -> ArtifactDemoAgent:
222
+ """Create a demo agent for REPL and server usage.
223
+
224
+ Returns:
225
+ Configured ArtifactDemoAgent instance
226
+ """
227
+ return ArtifactDemoAgent()
228
+
229
+
230
+ async def main() -> None:
231
+ """Main demo function."""
232
+ print("🎨 Artifact Demo Agent")
233
+ print("This demo shows how to create different types of artifacts.")
234
+ print(
235
+ "In a real web application, developers can listen for 'artifact-opened' events."
236
+ )
237
+ print()
238
+
239
+ demo_agent = create_demo_agent()
240
+ user = User(id="demo_user", username="artifact_demo")
241
+
242
+ # Demo 1: HTML Artifact
243
+ print("1. Creating HTML Artifact...")
244
+ async for component in demo_agent.create_html_artifact():
245
+ artifact = component.rich_component
246
+ if isinstance(artifact, ArtifactComponent):
247
+ print(f" ✓ Created HTML artifact: {artifact.title}")
248
+ print(f" ✓ Artifact ID: {artifact.artifact_id}")
249
+ print(f" ✓ Type: {artifact.artifact_type}")
250
+ print(f" ✓ External renderable: {artifact.external_renderable}")
251
+ print()
252
+
253
+ # Demo 2: D3 Visualization
254
+ print("2. Creating D3.js Visualization...")
255
+ async for component in demo_agent.create_d3_visualization():
256
+ artifact = component.rich_component
257
+ if isinstance(artifact, ArtifactComponent):
258
+ print(f" ✓ Created D3 artifact: {artifact.title}")
259
+ print(f" ✓ Dependencies: {artifact.dependencies}")
260
+ print(f" ✓ Standalone HTML available via get_standalone_html()")
261
+ print()
262
+
263
+ # Demo 3: Dashboard
264
+ print("3. Creating Dashboard Artifact...")
265
+ async for component in demo_agent.create_dashboard_artifact():
266
+ artifact = component.rich_component
267
+ if isinstance(artifact, ArtifactComponent):
268
+ print(f" ✓ Created dashboard artifact: {artifact.title}")
269
+ print(f" ✓ Fullscreen capable: {artifact.fullscreen_capable}")
270
+ print()
271
+
272
+ print("🚀 Web Integration Example:")
273
+ print("""
274
+ In your web application, listen for the 'artifact-opened' event:
275
+
276
+ document.querySelector('vanna-chat').addEventListener('artifact-opened', (event) => {
277
+ const { artifactId, content, type, trigger } = event.detail;
278
+
279
+ if (trigger === 'created' && type === 'dashboard') {
280
+ // Auto-open dashboards in external window
281
+ const newWindow = window.open('', '_blank');
282
+ newWindow.document.write(event.detail.getStandaloneHTML());
283
+ newWindow.document.close();
284
+
285
+ // Prevent default rendering in chat
286
+ event.detail.preventDefault();
287
+ }
288
+ });
289
+ """)
290
+
291
+
292
+ if __name__ == "__main__":
293
+ asyncio.run(main())
@@ -0,0 +1,236 @@
1
+ """
2
+ Claude example using the SQL query tool with the Chinook database.
3
+
4
+ This example demonstrates using the RunSqlTool with SqliteRunner and Claude's AI
5
+ to intelligently query and analyze the Chinook database, with automatic visualization support.
6
+
7
+ Requirements:
8
+ - ANTHROPIC_API_KEY environment variable or .env file
9
+ - anthropic package: pip install -e .[anthropic]
10
+ - plotly package: pip install -e .[visualization]
11
+
12
+ Usage:
13
+ PYTHONPATH=. python vanna/examples/claude_sqlite_example.py
14
+ """
15
+
16
+ import asyncio
17
+ import importlib.util
18
+ import os
19
+ import sys
20
+ from typing import TYPE_CHECKING
21
+
22
+ if TYPE_CHECKING:
23
+ from vanna import Agent
24
+
25
+
26
+ def ensure_env() -> None:
27
+ if importlib.util.find_spec("dotenv") is not None:
28
+ from dotenv import load_dotenv
29
+
30
+ # Load from local .env without overriding existing env
31
+ load_dotenv(dotenv_path=os.path.join(os.getcwd(), ".env"), override=False)
32
+ else:
33
+ print(
34
+ "[warn] python-dotenv not installed; skipping .env load. Install with: pip install python-dotenv"
35
+ )
36
+
37
+ if not os.getenv("ANTHROPIC_API_KEY"):
38
+ print(
39
+ "[error] ANTHROPIC_API_KEY is not set. Add it to your environment or .env file."
40
+ )
41
+ sys.exit(1)
42
+
43
+
44
+ async def main() -> None:
45
+ ensure_env()
46
+
47
+ try:
48
+ from vanna.integrations.anthropic import AnthropicLlmService
49
+ except ImportError:
50
+ print(
51
+ "[error] anthropic extra not installed. Install with: pip install -e .[anthropic]"
52
+ )
53
+ raise
54
+
55
+ from vanna import AgentConfig, Agent
56
+ from vanna.core.registry import ToolRegistry
57
+ from vanna.core.user import CookieEmailUserResolver, RequestContext
58
+ from vanna.integrations.sqlite import SqliteRunner
59
+ from vanna.tools import (
60
+ RunSqlTool,
61
+ VisualizeDataTool,
62
+ LocalFileSystem,
63
+ )
64
+
65
+ # Get the path to the Chinook database
66
+ database_path = os.path.join(
67
+ os.path.dirname(__file__), "..", "..", "Chinook.sqlite"
68
+ )
69
+ database_path = os.path.abspath(database_path)
70
+
71
+ if not os.path.exists(database_path):
72
+ print(f"[error] Chinook database not found at {database_path}")
73
+ print(
74
+ "Please download it with: curl -o Chinook.sqlite https://vanna.ai/Chinook.sqlite"
75
+ )
76
+ sys.exit(1)
77
+
78
+ model = os.getenv("ANTHROPIC_MODEL", "claude-sonnet-4-20250514")
79
+ print(f"Using Anthropic model: {model}")
80
+ print(f"Using database: {database_path}")
81
+
82
+ llm = AnthropicLlmService(model=model)
83
+
84
+ # Create shared FileSystem for both tools
85
+ file_system = LocalFileSystem(working_directory="./claude_data")
86
+
87
+ # Create tool registry and register the SQL tool with SQLite runner
88
+ tool_registry = ToolRegistry()
89
+ sqlite_runner = SqliteRunner(database_path=database_path)
90
+ sql_tool = RunSqlTool(sql_runner=sqlite_runner, file_system=file_system)
91
+ tool_registry.register(sql_tool)
92
+
93
+ # Register visualization tool
94
+ try:
95
+ viz_tool = VisualizeDataTool(file_system=file_system)
96
+ tool_registry.register(viz_tool)
97
+ print("Visualization tool enabled")
98
+ except ImportError:
99
+ print(
100
+ "[warn] Plotly not installed. Visualization tool disabled. Install with: pip install -e .[visualization]"
101
+ )
102
+
103
+ user_resolver = CookieEmailUserResolver()
104
+
105
+ agent = Agent(
106
+ llm_service=llm,
107
+ config=AgentConfig(stream_responses=False),
108
+ tool_registry=tool_registry,
109
+ user_resolver=user_resolver,
110
+ )
111
+
112
+ # Simulate a logged-in demo user via cookie-based resolver
113
+ request_context = RequestContext(
114
+ cookies={user_resolver.cookie_name: "demo-user@example.com"},
115
+ metadata={"demo": True},
116
+ remote_addr="127.0.0.1",
117
+ )
118
+ conversation_id = "claude-sqlite-demo"
119
+
120
+ # Sample queries to demonstrate different capabilities
121
+ sample_questions = [
122
+ "What tables are in this database?",
123
+ "Show me the first 5 customers with their names",
124
+ "What's the total number of tracks in the database?",
125
+ "Find the top 5 artists by number of albums",
126
+ "What's the average invoice total?",
127
+ "Get data on the top 10 longest tracks and then visualize it",
128
+ ]
129
+
130
+ print("\n" + "=" * 60)
131
+ print("Claude SQLite Database Assistant Demo")
132
+ print("=" * 60)
133
+ print("This demo shows Claude querying the Chinook music database.")
134
+ print("Claude will intelligently construct SQL queries to answer questions")
135
+ print("and can create visualizations of the results.")
136
+ print()
137
+
138
+ for i, question in enumerate(sample_questions, 1):
139
+ print(f"\n--- Question {i}: {question} ---")
140
+
141
+ async for component in agent.send_message(
142
+ request_context=request_context,
143
+ message=question,
144
+ conversation_id=conversation_id,
145
+ ):
146
+ # Handle different component types
147
+ if hasattr(component, "simple_component") and component.simple_component:
148
+ if hasattr(component.simple_component, "text"):
149
+ print("Assistant:", component.simple_component.text)
150
+ elif hasattr(component, "rich_component") and component.rich_component:
151
+ if (
152
+ hasattr(component.rich_component, "content")
153
+ and component.rich_component.content
154
+ ):
155
+ print("Assistant:", component.rich_component.content)
156
+ elif hasattr(component, "content") and component.content:
157
+ print("Assistant:", component.content)
158
+
159
+ print() # Add spacing between questions
160
+
161
+ print("\n" + "=" * 60)
162
+ print("Demo complete! Claude successfully queried the database.")
163
+ print("=" * 60)
164
+
165
+
166
+ def create_demo_agent() -> "Agent":
167
+ """Create a demo agent with Claude and SQLite query tool.
168
+
169
+ This function is called by the vanna server framework.
170
+
171
+ Returns:
172
+ Configured Agent with Claude LLM and SQLite tool
173
+ """
174
+ ensure_env()
175
+
176
+ try:
177
+ from vanna.integrations.anthropic import AnthropicLlmService
178
+ except ImportError:
179
+ print(
180
+ "[error] anthropic extra not installed. Install with: pip install -e .[anthropic]"
181
+ )
182
+ raise
183
+
184
+ from vanna import AgentConfig, Agent
185
+ from vanna.core.registry import ToolRegistry
186
+ from vanna.core.user import CookieEmailUserResolver
187
+ from vanna.integrations.sqlite import SqliteRunner
188
+ from vanna.tools import (
189
+ RunSqlTool,
190
+ VisualizeDataTool,
191
+ LocalFileSystem,
192
+ )
193
+
194
+ # Get the path to the Chinook database
195
+ database_path = os.path.join(
196
+ os.path.dirname(__file__), "..", "..", "Chinook.sqlite"
197
+ )
198
+ database_path = os.path.abspath(database_path)
199
+
200
+ if not os.path.exists(database_path):
201
+ raise FileNotFoundError(
202
+ f"Chinook database not found at {database_path}. Please download it from https://vanna.ai/Chinook.sqlite"
203
+ )
204
+
205
+ model = os.getenv("ANTHROPIC_MODEL", "claude-sonnet-4-20250514")
206
+
207
+ llm = AnthropicLlmService(model=model)
208
+
209
+ # Create shared FileSystem for both tools
210
+ file_system = LocalFileSystem(working_directory="./claude_data")
211
+
212
+ # Create tool registry and register the SQL tool with SQLite runner
213
+ tool_registry = ToolRegistry()
214
+ sqlite_runner = SqliteRunner(database_path=database_path)
215
+ sql_tool = RunSqlTool(sql_runner=sqlite_runner, file_system=file_system)
216
+ tool_registry.register(sql_tool)
217
+
218
+ # Register visualization tool if available
219
+ try:
220
+ viz_tool = VisualizeDataTool(file_system=file_system)
221
+ tool_registry.register(viz_tool)
222
+ except ImportError:
223
+ pass # Visualization tool not available
224
+
225
+ user_resolver = CookieEmailUserResolver()
226
+
227
+ return Agent(
228
+ llm_service=llm,
229
+ config=AgentConfig(stream_responses=True), # Enable streaming for web interface
230
+ tool_registry=tool_registry,
231
+ user_resolver=user_resolver,
232
+ )
233
+
234
+
235
+ if __name__ == "__main__":
236
+ asyncio.run(main())