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,300 @@
1
+ """
2
+ Example coding agent using the vanna-agents framework.
3
+
4
+ This example demonstrates building an agent that can edit code files,
5
+ following the concepts from the "How to Build an Agent" article.
6
+ The agent includes tools for file operations and uses an LLM service
7
+ that can understand and modify code.
8
+
9
+ Usage:
10
+ PYTHONPATH=. python vanna/examples/coding_agent_example.py
11
+ """
12
+
13
+ import asyncio
14
+ import uuid
15
+ from typing import AsyncGenerator, List, Optional
16
+
17
+ from vanna import (
18
+ AgentConfig,
19
+ Agent,
20
+ ToolRegistry,
21
+ User,
22
+ )
23
+ from vanna.core.interfaces import LlmService
24
+ from vanna.core.models import (
25
+ LlmRequest,
26
+ LlmResponse,
27
+ LlmStreamChunk,
28
+ ToolCall,
29
+ ToolSchema,
30
+ )
31
+ from vanna.tools.file_system import create_file_system_tools
32
+ from vanna.tools.python import create_python_tools
33
+
34
+
35
+ class CodingLlmService(LlmService):
36
+ """
37
+ LLM service that simulates a coding assistant.
38
+
39
+ This demonstrates the minimal implementation needed for an agent
40
+ as described in the article - just needs to understand tool calls
41
+ and respond appropriately.
42
+ """
43
+
44
+ async def send_request(self, request: LlmRequest) -> LlmResponse:
45
+ """Handle non-streaming requests."""
46
+ await asyncio.sleep(0.1) # Simulate thinking time
47
+ return self._build_response(request)
48
+
49
+ async def stream_request(
50
+ self, request: LlmRequest
51
+ ) -> AsyncGenerator[LlmStreamChunk, None]:
52
+ """Handle streaming requests."""
53
+ await asyncio.sleep(0.1)
54
+ response = self._build_response(request)
55
+
56
+ if response.tool_calls:
57
+ yield LlmStreamChunk(tool_calls=response.tool_calls)
58
+ if response.content:
59
+ # Simulate streaming by chunking the response
60
+ words = response.content.split()
61
+ for i, word in enumerate(words):
62
+ chunk = word if i == 0 else f" {word}"
63
+ await asyncio.sleep(0.05) # Simulate streaming delay
64
+ yield LlmStreamChunk(content=chunk)
65
+
66
+ yield LlmStreamChunk(finish_reason=response.finish_reason)
67
+
68
+ async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
69
+ """Validate tools - no errors for this simple implementation."""
70
+ return []
71
+
72
+ def _build_response(self, request: LlmRequest) -> LlmResponse:
73
+ """Build a response based on the conversation context."""
74
+ last_message = request.messages[-1] if request.messages else None
75
+
76
+ # If we just got a tool result, respond to it
77
+ if last_message and last_message.role == "tool":
78
+ tool_result = last_message.content or "Tool executed"
79
+ return LlmResponse(
80
+ content=f"I've completed the operation. {tool_result}",
81
+ finish_reason="stop",
82
+ )
83
+
84
+ # If user is asking for file operations, use tools
85
+ if last_message and last_message.role == "user":
86
+ user_message = last_message.content.lower()
87
+
88
+ if "list files" in user_message or "show files" in user_message:
89
+ return LlmResponse(
90
+ content="I'll list the files for you.",
91
+ tool_calls=[
92
+ ToolCall(
93
+ id=f"call_{uuid.uuid4().hex[:8]}",
94
+ name="list_files",
95
+ arguments={},
96
+ )
97
+ ],
98
+ finish_reason="tool_calls",
99
+ )
100
+
101
+ elif "read" in user_message and (
102
+ "file" in user_message
103
+ or ".py" in user_message
104
+ or ".txt" in user_message
105
+ ):
106
+ filename = _extract_filename(user_message)
107
+
108
+ if filename:
109
+ return LlmResponse(
110
+ content=f"I'll read the file '{filename}' for you.",
111
+ tool_calls=[
112
+ ToolCall(
113
+ id=f"call_{uuid.uuid4().hex[:8]}",
114
+ name="read_file",
115
+ arguments={"filename": filename},
116
+ )
117
+ ],
118
+ finish_reason="tool_calls",
119
+ )
120
+
121
+ elif "create" in user_message or "write" in user_message:
122
+ # Suggest creating a simple example file
123
+ return LlmResponse(
124
+ content="I'll create an example Python file for you.",
125
+ tool_calls=[
126
+ ToolCall(
127
+ id=f"call_{uuid.uuid4().hex[:8]}",
128
+ name="write_file",
129
+ arguments={
130
+ "filename": "example.py",
131
+ "content": "# Example Python file\nprint('Hello from the coding agent!')\n\ndef greet(name):\n return f'Hello, {name}!'\n\nif __name__ == '__main__':\n print(greet('World'))\n",
132
+ "overwrite": True,
133
+ },
134
+ )
135
+ ],
136
+ finish_reason="tool_calls",
137
+ )
138
+
139
+ elif (
140
+ "run" in user_message or "execute" in user_message
141
+ ) and ".py" in user_message:
142
+ filename = _extract_filename(user_message)
143
+ if filename:
144
+ return LlmResponse(
145
+ content=f"I'll run the Python file '{filename}'.",
146
+ tool_calls=[
147
+ ToolCall(
148
+ id=f"call_{uuid.uuid4().hex[:8]}",
149
+ name="run_python_file",
150
+ arguments={
151
+ "filename": filename,
152
+ "arguments": [],
153
+ },
154
+ )
155
+ ],
156
+ finish_reason="tool_calls",
157
+ )
158
+
159
+ elif (
160
+ "edit" in user_message
161
+ or "update" in user_message
162
+ or "modify" in user_message
163
+ ):
164
+ return LlmResponse(
165
+ content="I'll update the greet function to make it more descriptive.",
166
+ tool_calls=[
167
+ ToolCall(
168
+ id=f"call_{uuid.uuid4().hex[:8]}",
169
+ name="edit_file",
170
+ arguments={
171
+ "filename": "example.py",
172
+ "edits": [
173
+ {
174
+ "start_line": 4,
175
+ "end_line": 5,
176
+ "new_content": (
177
+ "def greet(name):\n"
178
+ ' """Return a friendly greeting."""\n'
179
+ ' return f"Hello, {name}! Welcome to the coding agent."\n'
180
+ ),
181
+ }
182
+ ],
183
+ },
184
+ )
185
+ ],
186
+ finish_reason="tool_calls",
187
+ )
188
+
189
+ # Default response
190
+ return LlmResponse(
191
+ content=(
192
+ "I'm a coding assistant. I can help you list, read, write, edit, and run Python files. "
193
+ "Try asking me to 'list files', 'read example.py', 'create a Python file', 'run example.py', or 'update example.py'."
194
+ ),
195
+ finish_reason="stop",
196
+ )
197
+
198
+
199
+ def create_demo_agent() -> Agent:
200
+ """
201
+ Create a coding agent with file operation tools.
202
+
203
+ This follows the pattern from the article - minimal code
204
+ to create a powerful code-editing agent. Uses dependency injection
205
+ for file system operations with LocalFileSystem as default.
206
+ """
207
+ # Create tool registry and register file system tools
208
+ tool_registry = ToolRegistry()
209
+
210
+ # Use the convenience function to create tools with default LocalFileSystem
211
+ for tool in create_file_system_tools():
212
+ tool_registry.register(tool)
213
+
214
+ for tool in create_python_tools():
215
+ tool_registry.register(tool)
216
+
217
+ # Create LLM service
218
+ llm_service = CodingLlmService()
219
+
220
+ # Create agent with configuration
221
+ return Agent(
222
+ llm_service=llm_service,
223
+ tool_registry=tool_registry,
224
+ config=AgentConfig(
225
+ stream_responses=True,
226
+ include_thinking_indicators=True,
227
+ max_tool_iterations=3,
228
+ ),
229
+ )
230
+
231
+
232
+ async def main() -> None:
233
+ """
234
+ Demonstrate the coding agent in action.
235
+
236
+ As the article mentions: "300 lines of code and three tools and now
237
+ you're able to talk to an alien intelligence that edits your code."
238
+ """
239
+ print("šŸ¤– Starting Coding Agent Demo")
240
+ print("This demonstrates the concepts from 'How to Build an Agent'")
241
+ print("-" * 50)
242
+
243
+ # Create the agent
244
+ agent = create_demo_agent()
245
+
246
+ # Create a test user
247
+ user = User(id="coder123", username="developer", permissions=[])
248
+
249
+ # Show available tools
250
+ tools = await agent.get_available_tools(user)
251
+ print(f"Available tools: {[tool.name for tool in tools]}")
252
+ print()
253
+
254
+ # Demo conversation
255
+ conversation_id = "coding-session"
256
+
257
+ demos = [
258
+ "Hello! Can you list the files in this directory?",
259
+ "Can you create a simple Python file for me?",
260
+ "Now read the example.py file you just created",
261
+ "Please update the greet function to include a docstring and a friendlier message.",
262
+ "Run example.py so I can see its output.",
263
+ "Great, read example.py again to confirm the changes.",
264
+ ]
265
+
266
+ for i, message in enumerate(demos, 1):
267
+ print(f"Demo {i}: {message}")
268
+ print("Agent response:")
269
+
270
+ async for component in agent.send_message(
271
+ user=user, message=message, conversation_id=conversation_id
272
+ ):
273
+ if (
274
+ hasattr(component.rich_component, "content")
275
+ and component.rich_component.content
276
+ ):
277
+ print(f" šŸ“ {component.rich_component.content}")
278
+ elif hasattr(component.rich_component, "message"):
279
+ print(f" šŸ’¬ {component.rich_component.message}")
280
+ elif component.simple_component and hasattr(
281
+ component.simple_component, "text"
282
+ ):
283
+ print(f" šŸ“„ {component.simple_component.text}")
284
+
285
+ print("-" * 30)
286
+
287
+
288
+ def _extract_filename(message: str) -> Optional[str]:
289
+ """Extract a likely filename token from a user message."""
290
+
291
+ for token in message.replace("\n", " ").split():
292
+ cleaned = token.strip("'\".,;!?")
293
+ if "." in cleaned and not cleaned.startswith("."):
294
+ return cleaned
295
+
296
+ return None
297
+
298
+
299
+ if __name__ == "__main__":
300
+ asyncio.run(main())
@@ -0,0 +1,174 @@
1
+ """
2
+ Example demonstrating custom system prompt builder with dependency injection.
3
+
4
+ This example shows how to create a custom SystemPromptBuilder that dynamically
5
+ generates system prompts based on user context and available tools.
6
+
7
+ Usage:
8
+ python -m vanna.examples.custom_system_prompt_example
9
+ """
10
+
11
+ from typing import List, Optional
12
+
13
+ from vanna.core.interfaces import SystemPromptBuilder
14
+ from vanna.core.models import ToolSchema, User
15
+
16
+
17
+ class CustomSystemPromptBuilder(SystemPromptBuilder):
18
+ """Custom system prompt builder that personalizes prompts based on user."""
19
+
20
+ async def build_system_prompt(
21
+ self, user: User, tools: List[ToolSchema]
22
+ ) -> Optional[str]:
23
+ """Build a personalized system prompt.
24
+
25
+ Args:
26
+ user: The user making the request
27
+ tools: List of tools available to the user
28
+
29
+ Returns:
30
+ Personalized system prompt
31
+ """
32
+ # Build personalized greeting
33
+ username = user.username or user.id
34
+ greeting = f"Hello {username}! I'm your AI assistant."
35
+
36
+ # Add role-specific instructions based on user permissions
37
+ role_instructions = []
38
+ if "admin" in user.permissions:
39
+ role_instructions.append(
40
+ "As an admin user, you have access to all tools and capabilities."
41
+ )
42
+ elif "analyst" in user.permissions:
43
+ role_instructions.append(
44
+ "You're working as an analyst. I'll help you query and visualize data."
45
+ )
46
+ else:
47
+ role_instructions.append("I'm here to help you with your tasks.")
48
+
49
+ # List available tools
50
+ tool_info = []
51
+ if tools:
52
+ tool_info.append("\nAvailable tools:")
53
+ for tool in tools:
54
+ tool_info.append(f"- {tool.name}: {tool.description}")
55
+
56
+ # Combine all parts
57
+ parts = [greeting] + role_instructions + tool_info
58
+ return "\n".join(parts)
59
+
60
+
61
+ class SQLAssistantSystemPromptBuilder(SystemPromptBuilder):
62
+ """System prompt builder specifically for SQL database assistants."""
63
+
64
+ def __init__(self, database_name: str = "database"):
65
+ """Initialize with database context.
66
+
67
+ Args:
68
+ database_name: Name of the database being queried
69
+ """
70
+ self.database_name = database_name
71
+
72
+ async def build_system_prompt(
73
+ self, user: User, tools: List[ToolSchema]
74
+ ) -> Optional[str]:
75
+ """Build a SQL-focused system prompt.
76
+
77
+ Args:
78
+ user: The user making the request
79
+ tools: List of tools available to the user
80
+
81
+ Returns:
82
+ SQL-focused system prompt
83
+ """
84
+ prompt = f"""You are an expert SQL database assistant for the {self.database_name} database.
85
+
86
+ Your primary responsibilities:
87
+ 1. Write efficient, correct SQL queries
88
+ 2. Explain query results clearly
89
+ 3. Suggest optimizations when relevant
90
+ 4. Visualize data when appropriate
91
+
92
+ Guidelines:
93
+ - Always validate SQL syntax before execution
94
+ - Use appropriate JOINs and avoid Cartesian products
95
+ - Limit result sets to reasonable sizes by default
96
+ - Format numbers and dates for readability
97
+ """
98
+
99
+ # Add tool-specific instructions
100
+ has_viz_tool = any(tool.name == "visualize_data" for tool in tools)
101
+ if has_viz_tool:
102
+ prompt += "\n- Create visualizations for numerical data when it helps understanding"
103
+
104
+ return prompt
105
+
106
+
107
+ async def demo() -> None:
108
+ """Demonstrate custom system prompt builders."""
109
+ from vanna import Agent, User
110
+ from vanna.core.registry import ToolRegistry
111
+ from vanna.integrations.anthropic.mock import MockLlmService
112
+
113
+ # Example 1: Custom personalized system prompt
114
+ print("=" * 60)
115
+ print("Example 1: Custom Personalized System Prompt")
116
+ print("=" * 60)
117
+
118
+ custom_builder = CustomSystemPromptBuilder()
119
+ admin_user = User(id="user-1", username="Alice", permissions=["admin"])
120
+
121
+ # Simulate some tools
122
+ mock_tools = [
123
+ ToolSchema(
124
+ name="query_database", description="Query the SQL database", parameters={}
125
+ ),
126
+ ToolSchema(
127
+ name="visualize_data",
128
+ description="Create data visualizations",
129
+ parameters={},
130
+ ),
131
+ ]
132
+
133
+ prompt = await custom_builder.build_system_prompt(admin_user, mock_tools)
134
+ print("\nGenerated system prompt for admin user:")
135
+ print("-" * 60)
136
+ print(prompt)
137
+ print("-" * 60)
138
+
139
+ # Example 2: SQL-specific system prompt
140
+ print("\n" + "=" * 60)
141
+ print("Example 2: SQL Assistant System Prompt")
142
+ print("=" * 60)
143
+
144
+ sql_builder = SQLAssistantSystemPromptBuilder(database_name="Chinook")
145
+ analyst_user = User(id="user-2", username="Bob", permissions=["analyst"])
146
+
147
+ prompt = await sql_builder.build_system_prompt(analyst_user, mock_tools)
148
+ print("\nGenerated system prompt for SQL assistant:")
149
+ print("-" * 60)
150
+ print(prompt)
151
+ print("-" * 60)
152
+
153
+ # Example 3: Using custom builder with Agent
154
+ print("\n" + "=" * 60)
155
+ print("Example 3: Using Custom Builder with Agent")
156
+ print("=" * 60)
157
+
158
+ mock_llm = MockLlmService()
159
+ tool_registry = ToolRegistry()
160
+
161
+ agent = Agent(
162
+ llm_service=mock_llm,
163
+ tool_registry=tool_registry,
164
+ system_prompt_builder=sql_builder, # Inject custom builder here
165
+ )
166
+
167
+ print("\nAgent created with custom SQL system prompt builder!")
168
+ print("The agent will now use the SQL-focused system prompt for all interactions.")
169
+
170
+
171
+ if __name__ == "__main__":
172
+ import asyncio
173
+
174
+ asyncio.run(demo())
@@ -0,0 +1,208 @@
1
+ """
2
+ Example demonstrating the DefaultWorkflowHandler with setup health checking.
3
+
4
+ This example shows how the DefaultWorkflowHandler provides intelligent starter UI
5
+ that adapts based on available tools and helps users understand their setup status.
6
+
7
+ Run:
8
+ PYTHONPATH=. python vanna/examples/default_workflow_handler_example.py
9
+ """
10
+
11
+ import asyncio
12
+
13
+ from vanna import (
14
+ AgentConfig,
15
+ Agent,
16
+ MemoryConversationStore,
17
+ MockLlmService,
18
+ User,
19
+ DefaultWorkflowHandler,
20
+ )
21
+ from vanna.core.registry import ToolRegistry
22
+ from vanna.core.user.resolver import SimpleUserResolver
23
+ from vanna.tools import ListFilesTool
24
+
25
+
26
+ async def demonstrate_setup_scenarios():
27
+ """Demonstrate different setup scenarios with DefaultWorkflowHandler."""
28
+ print("šŸš€ Starting DefaultWorkflowHandler Setup Health Check Demo\n")
29
+
30
+ # Create basic components
31
+ llm_service = MockLlmService(response_content="I'm ready to help!")
32
+ conversation_store = MemoryConversationStore()
33
+ user_resolver = SimpleUserResolver()
34
+
35
+ # Create test user
36
+ user = User(
37
+ id="user1",
38
+ username="alice",
39
+ email="alice@example.com",
40
+ group_memberships=["user"],
41
+ )
42
+
43
+ print("=" * 60)
44
+ print("SCENARIO 1: Empty Setup (No Tools)")
45
+ print("=" * 60)
46
+
47
+ # Empty tool registry
48
+ empty_registry = ToolRegistry()
49
+
50
+ agent_empty = Agent(
51
+ llm_service=llm_service,
52
+ tool_registry=empty_registry,
53
+ user_resolver=user_resolver,
54
+ conversation_store=conversation_store,
55
+ config=AgentConfig(stream_responses=False),
56
+ workflow_handler=DefaultWorkflowHandler(),
57
+ )
58
+
59
+ print("šŸ“‹ Starter UI for empty setup:")
60
+ async for component in agent_empty.send_message(
61
+ request_context=user_resolver.create_request_context(
62
+ metadata={"starter_ui_request": True}
63
+ ),
64
+ message="",
65
+ conversation_id="empty-setup",
66
+ ):
67
+ if hasattr(component, "simple_component") and component.simple_component:
68
+ print(f" šŸ“„ {component.simple_component.text[:100]}...")
69
+ elif hasattr(component, "rich_component"):
70
+ comp = component.rich_component
71
+ if hasattr(comp, "title"):
72
+ print(f" šŸ“Š {comp.title}: {comp.status} - {comp.description}")
73
+ elif hasattr(comp, "content"):
74
+ print(f" šŸ“ {comp.content[:100]}...")
75
+
76
+ print("\n" + "=" * 60)
77
+ print("SCENARIO 2: Functional Setup (SQL + Basic Tools)")
78
+ print("=" * 60)
79
+
80
+ # Tool registry with SQL tool (simulated)
81
+ functional_registry = ToolRegistry()
82
+
83
+ # Register a mock SQL tool (we'll simulate by tool name)
84
+ list_tool = ListFilesTool()
85
+ list_tool.name = "run_sql" # Simulate SQL tool
86
+ functional_registry.register(list_tool)
87
+
88
+ agent_functional = Agent(
89
+ llm_service=llm_service,
90
+ tool_registry=functional_registry,
91
+ user_resolver=user_resolver,
92
+ conversation_store=conversation_store,
93
+ config=AgentConfig(stream_responses=False),
94
+ workflow_handler=DefaultWorkflowHandler(),
95
+ )
96
+
97
+ print("šŸ“‹ Starter UI for functional setup:")
98
+ async for component in agent_functional.send_message(
99
+ request_context=user_resolver.create_request_context(
100
+ metadata={"starter_ui_request": True}
101
+ ),
102
+ message="",
103
+ conversation_id="functional-setup",
104
+ ):
105
+ if hasattr(component, "simple_component") and component.simple_component:
106
+ print(f" šŸ“„ {component.simple_component.text[:100]}...")
107
+ elif hasattr(component, "rich_component"):
108
+ comp = component.rich_component
109
+ if hasattr(comp, "title"):
110
+ print(f" šŸ“Š {comp.title}: {comp.status} - {comp.description}")
111
+ elif hasattr(comp, "content"):
112
+ print(f" šŸ“ {comp.content[:100]}...")
113
+
114
+ print("\n" + "=" * 60)
115
+ print("SCENARIO 3: Complete Setup (SQL + Memory + Visualization)")
116
+ print("=" * 60)
117
+
118
+ # Complete tool registry
119
+ complete_registry = ToolRegistry()
120
+
121
+ # Mock SQL tool
122
+ sql_tool = ListFilesTool()
123
+ sql_tool.name = "run_sql"
124
+ complete_registry.register(sql_tool)
125
+
126
+ # Mock memory tools
127
+ search_tool = ListFilesTool()
128
+ search_tool.name = "search_saved_correct_tool_uses"
129
+ complete_registry.register(search_tool)
130
+
131
+ save_tool = ListFilesTool()
132
+ save_tool.name = "save_question_tool_args"
133
+ complete_registry.register(save_tool)
134
+
135
+ # Mock visualization tool
136
+ viz_tool = ListFilesTool()
137
+ viz_tool.name = "visualize_data"
138
+ complete_registry.register(viz_tool)
139
+
140
+ agent_complete = Agent(
141
+ llm_service=llm_service,
142
+ tool_registry=complete_registry,
143
+ user_resolver=user_resolver,
144
+ conversation_store=conversation_store,
145
+ config=AgentConfig(stream_responses=False),
146
+ workflow_handler=DefaultWorkflowHandler(),
147
+ )
148
+
149
+ print("šŸ“‹ Starter UI for complete setup:")
150
+ async for component in agent_complete.send_message(
151
+ request_context=user_resolver.create_request_context(
152
+ metadata={"starter_ui_request": True}
153
+ ),
154
+ message="",
155
+ conversation_id="complete-setup",
156
+ ):
157
+ if hasattr(component, "simple_component") and component.simple_component:
158
+ print(f" šŸ“„ {component.simple_component.text[:100]}...")
159
+ elif hasattr(component, "rich_component"):
160
+ comp = component.rich_component
161
+ if hasattr(comp, "title"):
162
+ print(f" šŸ“Š {comp.title}: {comp.status} - {comp.description}")
163
+ elif hasattr(comp, "content"):
164
+ print(f" šŸ“ {comp.content[:100]}...")
165
+
166
+ print("\n" + "=" * 60)
167
+ print("SCENARIO 4: Testing Commands")
168
+ print("=" * 60)
169
+
170
+ print("šŸ“‹ Testing /help command:")
171
+ async for component in agent_complete.send_message(
172
+ request_context=user_resolver.create_request_context(),
173
+ message="/help",
174
+ conversation_id="help-test",
175
+ ):
176
+ if hasattr(component, "rich_component") and hasattr(
177
+ component.rich_component, "content"
178
+ ):
179
+ print(f" šŸ“ Help: {component.rich_component.content[:200]}...")
180
+
181
+ print("\nšŸ“‹ Testing /status command:")
182
+ async for component in agent_complete.send_message(
183
+ request_context=user_resolver.create_request_context(),
184
+ message="/status",
185
+ conversation_id="status-test",
186
+ ):
187
+ if hasattr(component, "rich_component"):
188
+ comp = component.rich_component
189
+ if hasattr(comp, "title"):
190
+ print(f" šŸ“Š {comp.title}: {comp.status}")
191
+ elif hasattr(comp, "content"):
192
+ print(f" šŸ“ Status: {comp.content[:150]}...")
193
+
194
+ print("\nāœ… Demo complete! The DefaultWorkflowHandler provides:")
195
+ print(" • Smart setup health checking")
196
+ print(" • Contextual starter UI based on available tools")
197
+ print(" • Helpful error messages and setup guidance")
198
+ print(" • Built-in command handling (/help, /status)")
199
+ print(" • Automatic tool analysis and recommendations")
200
+
201
+
202
+ async def main():
203
+ """Run the DefaultWorkflowHandler demonstration."""
204
+ await demonstrate_setup_scenarios()
205
+
206
+
207
+ if __name__ == "__main__":
208
+ asyncio.run(main())