vanna 0.7.9__py3-none-any.whl → 2.0.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vanna/__init__.py +167 -395
- vanna/agents/__init__.py +7 -0
- vanna/capabilities/__init__.py +17 -0
- vanna/capabilities/agent_memory/__init__.py +21 -0
- vanna/capabilities/agent_memory/base.py +103 -0
- vanna/capabilities/agent_memory/models.py +53 -0
- vanna/capabilities/file_system/__init__.py +14 -0
- vanna/capabilities/file_system/base.py +71 -0
- vanna/capabilities/file_system/models.py +25 -0
- vanna/capabilities/sql_runner/__init__.py +13 -0
- vanna/capabilities/sql_runner/base.py +37 -0
- vanna/capabilities/sql_runner/models.py +13 -0
- vanna/components/__init__.py +92 -0
- vanna/components/base.py +11 -0
- vanna/components/rich/__init__.py +83 -0
- vanna/components/rich/containers/__init__.py +7 -0
- vanna/components/rich/containers/card.py +20 -0
- vanna/components/rich/data/__init__.py +9 -0
- vanna/components/rich/data/chart.py +17 -0
- vanna/components/rich/data/dataframe.py +93 -0
- vanna/components/rich/feedback/__init__.py +21 -0
- vanna/components/rich/feedback/badge.py +16 -0
- vanna/components/rich/feedback/icon_text.py +14 -0
- vanna/components/rich/feedback/log_viewer.py +41 -0
- vanna/components/rich/feedback/notification.py +19 -0
- vanna/components/rich/feedback/progress.py +37 -0
- vanna/components/rich/feedback/status_card.py +28 -0
- vanna/components/rich/feedback/status_indicator.py +14 -0
- vanna/components/rich/interactive/__init__.py +21 -0
- vanna/components/rich/interactive/button.py +95 -0
- vanna/components/rich/interactive/task_list.py +58 -0
- vanna/components/rich/interactive/ui_state.py +93 -0
- vanna/components/rich/specialized/__init__.py +7 -0
- vanna/components/rich/specialized/artifact.py +20 -0
- vanna/components/rich/text.py +16 -0
- vanna/components/simple/__init__.py +15 -0
- vanna/components/simple/image.py +15 -0
- vanna/components/simple/link.py +15 -0
- vanna/components/simple/text.py +11 -0
- vanna/core/__init__.py +193 -0
- vanna/core/_compat.py +19 -0
- vanna/core/agent/__init__.py +10 -0
- vanna/core/agent/agent.py +1407 -0
- vanna/core/agent/config.py +123 -0
- vanna/core/audit/__init__.py +28 -0
- vanna/core/audit/base.py +299 -0
- vanna/core/audit/models.py +131 -0
- vanna/core/component_manager.py +329 -0
- vanna/core/components.py +53 -0
- vanna/core/enhancer/__init__.py +11 -0
- vanna/core/enhancer/base.py +94 -0
- vanna/core/enhancer/default.py +118 -0
- vanna/core/enricher/__init__.py +10 -0
- vanna/core/enricher/base.py +59 -0
- vanna/core/errors.py +47 -0
- vanna/core/evaluation/__init__.py +81 -0
- vanna/core/evaluation/base.py +186 -0
- vanna/core/evaluation/dataset.py +254 -0
- vanna/core/evaluation/evaluators.py +376 -0
- vanna/core/evaluation/report.py +289 -0
- vanna/core/evaluation/runner.py +313 -0
- vanna/core/filter/__init__.py +10 -0
- vanna/core/filter/base.py +67 -0
- vanna/core/lifecycle/__init__.py +10 -0
- vanna/core/lifecycle/base.py +83 -0
- vanna/core/llm/__init__.py +16 -0
- vanna/core/llm/base.py +40 -0
- vanna/core/llm/models.py +61 -0
- vanna/core/middleware/__init__.py +10 -0
- vanna/core/middleware/base.py +69 -0
- vanna/core/observability/__init__.py +11 -0
- vanna/core/observability/base.py +88 -0
- vanna/core/observability/models.py +47 -0
- vanna/core/recovery/__init__.py +11 -0
- vanna/core/recovery/base.py +84 -0
- vanna/core/recovery/models.py +32 -0
- vanna/core/registry.py +278 -0
- vanna/core/rich_component.py +156 -0
- vanna/core/simple_component.py +27 -0
- vanna/core/storage/__init__.py +14 -0
- vanna/core/storage/base.py +46 -0
- vanna/core/storage/models.py +46 -0
- vanna/core/system_prompt/__init__.py +13 -0
- vanna/core/system_prompt/base.py +36 -0
- vanna/core/system_prompt/default.py +157 -0
- vanna/core/tool/__init__.py +18 -0
- vanna/core/tool/base.py +70 -0
- vanna/core/tool/models.py +84 -0
- vanna/core/user/__init__.py +17 -0
- vanna/core/user/base.py +29 -0
- vanna/core/user/models.py +25 -0
- vanna/core/user/request_context.py +70 -0
- vanna/core/user/resolver.py +42 -0
- vanna/core/validation.py +164 -0
- vanna/core/workflow/__init__.py +12 -0
- vanna/core/workflow/base.py +254 -0
- vanna/core/workflow/default.py +789 -0
- vanna/examples/__init__.py +1 -0
- vanna/examples/__main__.py +44 -0
- vanna/examples/anthropic_quickstart.py +80 -0
- vanna/examples/artifact_example.py +293 -0
- vanna/examples/claude_sqlite_example.py +236 -0
- vanna/examples/coding_agent_example.py +300 -0
- vanna/examples/custom_system_prompt_example.py +174 -0
- vanna/examples/default_workflow_handler_example.py +208 -0
- vanna/examples/email_auth_example.py +340 -0
- vanna/examples/evaluation_example.py +269 -0
- vanna/examples/extensibility_example.py +262 -0
- vanna/examples/minimal_example.py +67 -0
- vanna/examples/mock_auth_example.py +227 -0
- vanna/examples/mock_custom_tool.py +311 -0
- vanna/examples/mock_quickstart.py +79 -0
- vanna/examples/mock_quota_example.py +145 -0
- vanna/examples/mock_rich_components_demo.py +396 -0
- vanna/examples/mock_sqlite_example.py +223 -0
- vanna/examples/openai_quickstart.py +83 -0
- vanna/examples/primitive_components_demo.py +305 -0
- vanna/examples/quota_lifecycle_example.py +139 -0
- vanna/examples/visualization_example.py +251 -0
- vanna/integrations/__init__.py +17 -0
- vanna/integrations/anthropic/__init__.py +9 -0
- vanna/integrations/anthropic/llm.py +270 -0
- vanna/integrations/azureopenai/__init__.py +9 -0
- vanna/integrations/azureopenai/llm.py +329 -0
- vanna/integrations/azuresearch/__init__.py +7 -0
- vanna/integrations/azuresearch/agent_memory.py +413 -0
- vanna/integrations/bigquery/__init__.py +5 -0
- vanna/integrations/bigquery/sql_runner.py +81 -0
- vanna/integrations/chromadb/__init__.py +104 -0
- vanna/integrations/chromadb/agent_memory.py +416 -0
- vanna/integrations/clickhouse/__init__.py +5 -0
- vanna/integrations/clickhouse/sql_runner.py +82 -0
- vanna/integrations/duckdb/__init__.py +5 -0
- vanna/integrations/duckdb/sql_runner.py +65 -0
- vanna/integrations/faiss/__init__.py +7 -0
- vanna/integrations/faiss/agent_memory.py +431 -0
- vanna/integrations/google/__init__.py +9 -0
- vanna/integrations/google/gemini.py +370 -0
- vanna/integrations/hive/__init__.py +5 -0
- vanna/integrations/hive/sql_runner.py +87 -0
- vanna/integrations/local/__init__.py +17 -0
- vanna/integrations/local/agent_memory/__init__.py +7 -0
- vanna/integrations/local/agent_memory/in_memory.py +285 -0
- vanna/integrations/local/audit.py +59 -0
- vanna/integrations/local/file_system.py +242 -0
- vanna/integrations/local/file_system_conversation_store.py +255 -0
- vanna/integrations/local/storage.py +62 -0
- vanna/integrations/marqo/__init__.py +7 -0
- vanna/integrations/marqo/agent_memory.py +354 -0
- vanna/integrations/milvus/__init__.py +7 -0
- vanna/integrations/milvus/agent_memory.py +458 -0
- vanna/integrations/mock/__init__.py +9 -0
- vanna/integrations/mock/llm.py +65 -0
- vanna/integrations/mssql/__init__.py +5 -0
- vanna/integrations/mssql/sql_runner.py +66 -0
- vanna/integrations/mysql/__init__.py +5 -0
- vanna/integrations/mysql/sql_runner.py +92 -0
- vanna/integrations/ollama/__init__.py +7 -0
- vanna/integrations/ollama/llm.py +252 -0
- vanna/integrations/openai/__init__.py +10 -0
- vanna/integrations/openai/llm.py +267 -0
- vanna/integrations/openai/responses.py +163 -0
- vanna/integrations/opensearch/__init__.py +7 -0
- vanna/integrations/opensearch/agent_memory.py +411 -0
- vanna/integrations/oracle/__init__.py +5 -0
- vanna/integrations/oracle/sql_runner.py +75 -0
- vanna/integrations/pinecone/__init__.py +7 -0
- vanna/integrations/pinecone/agent_memory.py +329 -0
- vanna/integrations/plotly/__init__.py +5 -0
- vanna/integrations/plotly/chart_generator.py +313 -0
- vanna/integrations/postgres/__init__.py +9 -0
- vanna/integrations/postgres/sql_runner.py +112 -0
- vanna/integrations/premium/agent_memory/__init__.py +7 -0
- vanna/integrations/premium/agent_memory/premium.py +186 -0
- vanna/integrations/presto/__init__.py +5 -0
- vanna/integrations/presto/sql_runner.py +107 -0
- vanna/integrations/qdrant/__init__.py +7 -0
- vanna/integrations/qdrant/agent_memory.py +439 -0
- vanna/integrations/snowflake/__init__.py +5 -0
- vanna/integrations/snowflake/sql_runner.py +147 -0
- vanna/integrations/sqlite/__init__.py +9 -0
- vanna/integrations/sqlite/sql_runner.py +65 -0
- vanna/integrations/weaviate/__init__.py +7 -0
- vanna/integrations/weaviate/agent_memory.py +428 -0
- vanna/{ZhipuAI → legacy/ZhipuAI}/ZhipuAI_embeddings.py +11 -11
- vanna/legacy/__init__.py +403 -0
- vanna/legacy/adapter.py +463 -0
- vanna/{advanced → legacy/advanced}/__init__.py +3 -1
- vanna/{anthropic → legacy/anthropic}/anthropic_chat.py +9 -7
- vanna/{azuresearch → legacy/azuresearch}/azuresearch_vector.py +79 -41
- vanna/{base → legacy/base}/base.py +224 -217
- vanna/legacy/bedrock/__init__.py +1 -0
- vanna/{bedrock → legacy/bedrock}/bedrock_converse.py +13 -12
- vanna/{chromadb → legacy/chromadb}/chromadb_vector.py +3 -1
- vanna/legacy/cohere/__init__.py +2 -0
- vanna/{cohere → legacy/cohere}/cohere_chat.py +19 -14
- vanna/{cohere → legacy/cohere}/cohere_embeddings.py +25 -19
- vanna/{deepseek → legacy/deepseek}/deepseek_chat.py +5 -6
- vanna/legacy/faiss/__init__.py +1 -0
- vanna/{faiss → legacy/faiss}/faiss.py +113 -59
- vanna/{flask → legacy/flask}/__init__.py +84 -43
- vanna/{flask → legacy/flask}/assets.py +5 -5
- vanna/{flask → legacy/flask}/auth.py +5 -4
- vanna/{google → legacy/google}/bigquery_vector.py +75 -42
- vanna/{google → legacy/google}/gemini_chat.py +7 -3
- vanna/{hf → legacy/hf}/hf.py +0 -1
- vanna/{milvus → legacy/milvus}/milvus_vector.py +58 -35
- vanna/{mock → legacy/mock}/llm.py +0 -1
- vanna/legacy/mock/vectordb.py +67 -0
- vanna/legacy/ollama/ollama.py +110 -0
- vanna/{openai → legacy/openai}/openai_chat.py +2 -6
- vanna/legacy/opensearch/opensearch_vector.py +369 -0
- vanna/legacy/opensearch/opensearch_vector_semantic.py +200 -0
- vanna/legacy/oracle/oracle_vector.py +584 -0
- vanna/{pgvector → legacy/pgvector}/pgvector.py +42 -13
- vanna/{qdrant → legacy/qdrant}/qdrant.py +2 -6
- vanna/legacy/qianfan/Qianfan_Chat.py +170 -0
- vanna/legacy/qianfan/Qianfan_embeddings.py +36 -0
- vanna/legacy/qianwen/QianwenAI_chat.py +132 -0
- vanna/{remote.py → legacy/remote.py} +28 -26
- vanna/{utils.py → legacy/utils.py} +6 -11
- vanna/{vannadb → legacy/vannadb}/vannadb_vector.py +115 -46
- vanna/{vllm → legacy/vllm}/vllm.py +5 -6
- vanna/{weaviate → legacy/weaviate}/weaviate_vector.py +59 -40
- vanna/{xinference → legacy/xinference}/xinference.py +6 -6
- vanna/py.typed +0 -0
- vanna/servers/__init__.py +16 -0
- vanna/servers/__main__.py +8 -0
- vanna/servers/base/__init__.py +18 -0
- vanna/servers/base/chat_handler.py +65 -0
- vanna/servers/base/models.py +111 -0
- vanna/servers/base/rich_chat_handler.py +141 -0
- vanna/servers/base/templates.py +331 -0
- vanna/servers/cli/__init__.py +7 -0
- vanna/servers/cli/server_runner.py +204 -0
- vanna/servers/fastapi/__init__.py +7 -0
- vanna/servers/fastapi/app.py +163 -0
- vanna/servers/fastapi/routes.py +183 -0
- vanna/servers/flask/__init__.py +7 -0
- vanna/servers/flask/app.py +132 -0
- vanna/servers/flask/routes.py +137 -0
- vanna/tools/__init__.py +41 -0
- vanna/tools/agent_memory.py +322 -0
- vanna/tools/file_system.py +879 -0
- vanna/tools/python.py +222 -0
- vanna/tools/run_sql.py +165 -0
- vanna/tools/visualize_data.py +195 -0
- vanna/utils/__init__.py +0 -0
- vanna/web_components/__init__.py +44 -0
- vanna-2.0.0rc1.dist-info/METADATA +868 -0
- vanna-2.0.0rc1.dist-info/RECORD +289 -0
- vanna-2.0.0rc1.dist-info/entry_points.txt +3 -0
- vanna/bedrock/__init__.py +0 -1
- vanna/cohere/__init__.py +0 -2
- vanna/faiss/__init__.py +0 -1
- vanna/mock/vectordb.py +0 -55
- vanna/ollama/ollama.py +0 -103
- vanna/opensearch/opensearch_vector.py +0 -392
- vanna/opensearch/opensearch_vector_semantic.py +0 -175
- vanna/oracle/oracle_vector.py +0 -585
- vanna/qianfan/Qianfan_Chat.py +0 -165
- vanna/qianfan/Qianfan_embeddings.py +0 -36
- vanna/qianwen/QianwenAI_chat.py +0 -133
- vanna-0.7.9.dist-info/METADATA +0 -408
- vanna-0.7.9.dist-info/RECORD +0 -79
- /vanna/{ZhipuAI → legacy/ZhipuAI}/ZhipuAI_Chat.py +0 -0
- /vanna/{ZhipuAI → legacy/ZhipuAI}/__init__.py +0 -0
- /vanna/{anthropic → legacy/anthropic}/__init__.py +0 -0
- /vanna/{azuresearch → legacy/azuresearch}/__init__.py +0 -0
- /vanna/{base → legacy/base}/__init__.py +0 -0
- /vanna/{chromadb → legacy/chromadb}/__init__.py +0 -0
- /vanna/{deepseek → legacy/deepseek}/__init__.py +0 -0
- /vanna/{exceptions → legacy/exceptions}/__init__.py +0 -0
- /vanna/{google → legacy/google}/__init__.py +0 -0
- /vanna/{hf → legacy/hf}/__init__.py +0 -0
- /vanna/{local.py → legacy/local.py} +0 -0
- /vanna/{marqo → legacy/marqo}/__init__.py +0 -0
- /vanna/{marqo → legacy/marqo}/marqo.py +0 -0
- /vanna/{milvus → legacy/milvus}/__init__.py +0 -0
- /vanna/{mistral → legacy/mistral}/__init__.py +0 -0
- /vanna/{mistral → legacy/mistral}/mistral.py +0 -0
- /vanna/{mock → legacy/mock}/__init__.py +0 -0
- /vanna/{mock → legacy/mock}/embedding.py +0 -0
- /vanna/{ollama → legacy/ollama}/__init__.py +0 -0
- /vanna/{openai → legacy/openai}/__init__.py +0 -0
- /vanna/{openai → legacy/openai}/openai_embeddings.py +0 -0
- /vanna/{opensearch → legacy/opensearch}/__init__.py +0 -0
- /vanna/{oracle → legacy/oracle}/__init__.py +0 -0
- /vanna/{pgvector → legacy/pgvector}/__init__.py +0 -0
- /vanna/{pinecone → legacy/pinecone}/__init__.py +0 -0
- /vanna/{pinecone → legacy/pinecone}/pinecone_vector.py +0 -0
- /vanna/{qdrant → legacy/qdrant}/__init__.py +0 -0
- /vanna/{qianfan → legacy/qianfan}/__init__.py +0 -0
- /vanna/{qianwen → legacy/qianwen}/QianwenAI_embeddings.py +0 -0
- /vanna/{qianwen → legacy/qianwen}/__init__.py +0 -0
- /vanna/{types → legacy/types}/__init__.py +0 -0
- /vanna/{vannadb → legacy/vannadb}/__init__.py +0 -0
- /vanna/{vllm → legacy/vllm}/__init__.py +0 -0
- /vanna/{weaviate → legacy/weaviate}/__init__.py +0 -0
- /vanna/{xinference → legacy/xinference}/__init__.py +0 -0
- {vanna-0.7.9.dist-info → vanna-2.0.0rc1.dist-info}/WHEEL +0 -0
- {vanna-0.7.9.dist-info → vanna-2.0.0rc1.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())
|