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,396 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mock rich components demonstration example.
|
|
3
|
+
|
|
4
|
+
This example shows how to create an agent that emits rich, stateful components
|
|
5
|
+
including cards, task lists, and tool execution displays using a mock LLM service.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
PYTHONPATH=. python vanna/examples/mock_rich_components_demo.py
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import asyncio
|
|
12
|
+
import time
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
from typing import AsyncGenerator, Optional
|
|
15
|
+
|
|
16
|
+
from vanna import (
|
|
17
|
+
AgentConfig,
|
|
18
|
+
Agent,
|
|
19
|
+
MemoryConversationStore,
|
|
20
|
+
MockLlmService,
|
|
21
|
+
User,
|
|
22
|
+
)
|
|
23
|
+
from vanna.core.components import UiComponent
|
|
24
|
+
from vanna.core.rich_components import (
|
|
25
|
+
StatusCardComponent,
|
|
26
|
+
ProgressDisplayComponent,
|
|
27
|
+
LogViewerComponent,
|
|
28
|
+
BadgeComponent,
|
|
29
|
+
IconTextComponent,
|
|
30
|
+
RichTextComponent,
|
|
31
|
+
Task,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class RichComponentsAgent(Agent):
|
|
36
|
+
"""Agent that demonstrates rich component capabilities."""
|
|
37
|
+
|
|
38
|
+
async def send_message(
|
|
39
|
+
self,
|
|
40
|
+
user: User,
|
|
41
|
+
message: str,
|
|
42
|
+
*,
|
|
43
|
+
conversation_id: Optional[str] = None,
|
|
44
|
+
) -> AsyncGenerator[UiComponent, None]:
|
|
45
|
+
"""Send message and yield UiComponent(rich_component=rich) components."""
|
|
46
|
+
|
|
47
|
+
# Welcome message using IconText
|
|
48
|
+
yield UiComponent(
|
|
49
|
+
rich_component=IconTextComponent(
|
|
50
|
+
id="welcome-message",
|
|
51
|
+
icon="👋",
|
|
52
|
+
text=f"Hello {user.username}! I'll demonstrate primitive components.",
|
|
53
|
+
variant="primary",
|
|
54
|
+
size="large",
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Status card showing we're processing
|
|
59
|
+
status_card = StatusCardComponent(
|
|
60
|
+
id="processing-status",
|
|
61
|
+
title="Processing Request",
|
|
62
|
+
status="running",
|
|
63
|
+
description="Processing your request...",
|
|
64
|
+
icon="⚙️",
|
|
65
|
+
)
|
|
66
|
+
yield UiComponent(rich_component=status_card)
|
|
67
|
+
|
|
68
|
+
# Simulate some processing time
|
|
69
|
+
await asyncio.sleep(1)
|
|
70
|
+
|
|
71
|
+
# Update status to success
|
|
72
|
+
yield UiComponent(
|
|
73
|
+
rich_component=status_card.set_status(
|
|
74
|
+
"success", "Request processed successfully!"
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Create a status card for overall demo progress
|
|
79
|
+
demo_card = StatusCardComponent(
|
|
80
|
+
id="demo-progress",
|
|
81
|
+
title="Demo Progress",
|
|
82
|
+
status="running",
|
|
83
|
+
description="Starting primitive components demonstration...",
|
|
84
|
+
icon="🎯",
|
|
85
|
+
)
|
|
86
|
+
yield UiComponent(rich_component=demo_card)
|
|
87
|
+
|
|
88
|
+
# Create badges for different stages
|
|
89
|
+
stages = [
|
|
90
|
+
("Initialize", "success", "✅"),
|
|
91
|
+
("Components", "running", "⚙️"),
|
|
92
|
+
("Progress", "pending", "⏳"),
|
|
93
|
+
("Logs", "pending", "📋"),
|
|
94
|
+
("Complete", "pending", "🎉"),
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
for stage_name, stage_status, stage_icon in stages:
|
|
98
|
+
yield UiComponent(
|
|
99
|
+
rich_component=BadgeComponent(
|
|
100
|
+
id=f"stage-{stage_name.lower()}",
|
|
101
|
+
text=stage_name,
|
|
102
|
+
variant=stage_status if stage_status != "pending" else "default",
|
|
103
|
+
icon=stage_icon,
|
|
104
|
+
size="md",
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Progress display
|
|
109
|
+
progress_display = ProgressDisplayComponent(
|
|
110
|
+
id="demo-progress-bar",
|
|
111
|
+
label="Overall Progress",
|
|
112
|
+
value=0.2,
|
|
113
|
+
description="Initializing demonstration...",
|
|
114
|
+
status="info",
|
|
115
|
+
animated=True,
|
|
116
|
+
)
|
|
117
|
+
yield UiComponent(rich_component=progress_display)
|
|
118
|
+
|
|
119
|
+
# Create log viewer for detailed progress
|
|
120
|
+
log_viewer = LogViewerComponent(id="demo-logs", title="Demo Activity Log")
|
|
121
|
+
yield UiComponent(rich_component=log_viewer)
|
|
122
|
+
|
|
123
|
+
# Simulate work with updates
|
|
124
|
+
for i in range(3):
|
|
125
|
+
await asyncio.sleep(1)
|
|
126
|
+
|
|
127
|
+
# Update progress
|
|
128
|
+
progress_value = 0.2 + (i + 1) * 0.2
|
|
129
|
+
step_name = ["Creating components", "Updating progress", "Finalizing demo"][
|
|
130
|
+
i
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
yield UiComponent(
|
|
134
|
+
rich_component=progress_display.update_progress(
|
|
135
|
+
progress_value, f"Step {i + 2} of 5: {step_name}..."
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Update demo card
|
|
140
|
+
yield UiComponent(
|
|
141
|
+
rich_component=demo_card.set_status(
|
|
142
|
+
"running",
|
|
143
|
+
f"Step {i + 2} of 5 completed. Progress: {int(progress_value * 100)}%",
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Add log entry
|
|
148
|
+
yield UiComponent(
|
|
149
|
+
rich_component=log_viewer.add_entry(
|
|
150
|
+
f"Completed step: {step_name}", "info"
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# Update stage badges
|
|
155
|
+
if i == 0:
|
|
156
|
+
yield UiComponent(
|
|
157
|
+
rich_component=BadgeComponent(
|
|
158
|
+
id="stage-components",
|
|
159
|
+
text="Components",
|
|
160
|
+
variant="success",
|
|
161
|
+
icon="✅",
|
|
162
|
+
size="md",
|
|
163
|
+
)
|
|
164
|
+
)
|
|
165
|
+
elif i == 1:
|
|
166
|
+
yield UiComponent(
|
|
167
|
+
rich_component=BadgeComponent(
|
|
168
|
+
id="stage-progress",
|
|
169
|
+
text="Progress",
|
|
170
|
+
variant="success",
|
|
171
|
+
icon="✅",
|
|
172
|
+
size="md",
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
yield UiComponent(
|
|
176
|
+
rich_component=BadgeComponent(
|
|
177
|
+
id="stage-logs",
|
|
178
|
+
text="Logs",
|
|
179
|
+
variant="running",
|
|
180
|
+
icon="📋",
|
|
181
|
+
size="md",
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Tool execution using primitive components
|
|
186
|
+
tool_status = StatusCardComponent(
|
|
187
|
+
id="demo-tool",
|
|
188
|
+
title="Analyze Data Tool",
|
|
189
|
+
status="running",
|
|
190
|
+
description="Running regression analysis on user_data.csv",
|
|
191
|
+
icon="🔬",
|
|
192
|
+
)
|
|
193
|
+
yield UiComponent(rich_component=tool_status)
|
|
194
|
+
|
|
195
|
+
# Tool progress
|
|
196
|
+
tool_progress = ProgressDisplayComponent(
|
|
197
|
+
id="tool-progress",
|
|
198
|
+
label="Tool Execution",
|
|
199
|
+
value=0.0,
|
|
200
|
+
description="Initializing tool...",
|
|
201
|
+
animated=True,
|
|
202
|
+
)
|
|
203
|
+
yield UiComponent(rich_component=tool_progress)
|
|
204
|
+
|
|
205
|
+
# Tool logs
|
|
206
|
+
tool_logs = LogViewerComponent(id="tool-logs", title="Tool Execution Log")
|
|
207
|
+
yield UiComponent(rich_component=tool_logs)
|
|
208
|
+
|
|
209
|
+
# Simulate tool execution steps
|
|
210
|
+
tool_steps = [
|
|
211
|
+
(0.2, "Loading dataset...", "info"),
|
|
212
|
+
(0.4, "Dataset loaded: 1000 rows, 5 columns", "info"),
|
|
213
|
+
(0.6, "Preprocessing data...", "info"),
|
|
214
|
+
(0.8, "Running regression analysis...", "info"),
|
|
215
|
+
(1.0, "Analysis complete!", "info"),
|
|
216
|
+
]
|
|
217
|
+
|
|
218
|
+
for progress_val, log_message, log_level in tool_steps:
|
|
219
|
+
await asyncio.sleep(0.5)
|
|
220
|
+
|
|
221
|
+
yield UiComponent(
|
|
222
|
+
rich_component=tool_progress.update_progress(
|
|
223
|
+
progress_val, f"Progress: {int(progress_val * 100)}%"
|
|
224
|
+
)
|
|
225
|
+
)
|
|
226
|
+
yield UiComponent(
|
|
227
|
+
rich_component=tool_logs.add_entry(log_message, log_level)
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# Complete tool execution
|
|
231
|
+
yield UiComponent(
|
|
232
|
+
rich_component=tool_status.set_status(
|
|
233
|
+
"success",
|
|
234
|
+
"Tool completed successfully. R² = 0.85, strong correlation found.",
|
|
235
|
+
)
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
# Show results using IconText
|
|
239
|
+
yield UiComponent(
|
|
240
|
+
rich_component=IconTextComponent(
|
|
241
|
+
id="tool-results",
|
|
242
|
+
icon="📊",
|
|
243
|
+
text="Analysis Results: R² = 0.85 (Strong correlation)",
|
|
244
|
+
variant="success",
|
|
245
|
+
size="medium",
|
|
246
|
+
)
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# Update final stage badge
|
|
250
|
+
yield UiComponent(
|
|
251
|
+
rich_component=BadgeComponent(
|
|
252
|
+
id="stage-logs", text="Logs", variant="success", icon="✅", size="md"
|
|
253
|
+
)
|
|
254
|
+
)
|
|
255
|
+
yield UiComponent(
|
|
256
|
+
rich_component=BadgeComponent(
|
|
257
|
+
id="stage-complete",
|
|
258
|
+
text="Complete",
|
|
259
|
+
variant="success",
|
|
260
|
+
icon="🎉",
|
|
261
|
+
size="md",
|
|
262
|
+
)
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
# Final updates
|
|
266
|
+
yield UiComponent(
|
|
267
|
+
rich_component=progress_display.update_progress(
|
|
268
|
+
1.0, "Demo completed successfully!"
|
|
269
|
+
)
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
yield UiComponent(
|
|
273
|
+
rich_component=demo_card.set_status(
|
|
274
|
+
"success", "Primitive components demonstration finished successfully!"
|
|
275
|
+
)
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# Add final log entry
|
|
279
|
+
yield UiComponent(
|
|
280
|
+
rich_component=tool_logs.add_entry("Demo completed successfully!", "info")
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# Add final text response
|
|
284
|
+
yield UiComponent(
|
|
285
|
+
rich_component=RichTextComponent(
|
|
286
|
+
content=f"""## Primitive Components Demo Complete!
|
|
287
|
+
|
|
288
|
+
I've demonstrated the new primitive component system:
|
|
289
|
+
|
|
290
|
+
- **Status Cards**: Domain-agnostic status displays that work for any process
|
|
291
|
+
- **Progress Displays**: Reusable progress indicators with animations
|
|
292
|
+
- **Log Viewers**: Structured log display for any activity
|
|
293
|
+
- **Badges**: Flexible status and category indicators
|
|
294
|
+
- **Icon Text**: Composable icon+text combinations
|
|
295
|
+
|
|
296
|
+
### Key Benefits of Primitive Components:
|
|
297
|
+
|
|
298
|
+
- **Separation of Concerns**: UI components are purely presentational
|
|
299
|
+
- **Reusability**: Components work across different domains and tools
|
|
300
|
+
- **Composability**: Tools build exactly the UI they need from primitives
|
|
301
|
+
- **Maintainability**: Business logic changes don't affect UI components
|
|
302
|
+
- **Extensibility**: New tools don't require new component types
|
|
303
|
+
|
|
304
|
+
**Primitive Components**: Compose UI from domain-agnostic building blocks
|
|
305
|
+
**After**: Tools compose UI from primitive `StatusCard` + `ProgressDisplay` + `LogViewer`
|
|
306
|
+
|
|
307
|
+
Your message was: "{message}"
|
|
308
|
+
""",
|
|
309
|
+
markdown=True,
|
|
310
|
+
)
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
# CLI compatibility alias
|
|
315
|
+
create_demo_agent = lambda: create_rich_demo_agent()
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def create_rich_demo_agent() -> RichComponentsAgent:
|
|
319
|
+
"""Create a primitive components demo agent.
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
Configured RichComponentsAgent instance
|
|
323
|
+
"""
|
|
324
|
+
llm_service = MockLlmService(response_content="Primitive components demo response")
|
|
325
|
+
|
|
326
|
+
return RichComponentsAgent(
|
|
327
|
+
llm_service=llm_service,
|
|
328
|
+
config=AgentConfig(
|
|
329
|
+
stream_responses=True,
|
|
330
|
+
include_thinking_indicators=False, # We'll use custom status cards
|
|
331
|
+
),
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
async def main() -> None:
|
|
336
|
+
"""Run the primitive components demo."""
|
|
337
|
+
|
|
338
|
+
# Create agent
|
|
339
|
+
agent = create_rich_demo_agent()
|
|
340
|
+
|
|
341
|
+
# Create a test user
|
|
342
|
+
user = User(
|
|
343
|
+
id="user123", username="demo_user", email="demo@example.com", permissions=[]
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
# Start a conversation
|
|
347
|
+
conversation_id = "primitive_demo_123"
|
|
348
|
+
user_message = "Show me the primitive components demo!"
|
|
349
|
+
|
|
350
|
+
print(f"User: {user_message}")
|
|
351
|
+
print("Agent response (primitive components):")
|
|
352
|
+
print("=" * 50)
|
|
353
|
+
|
|
354
|
+
# Send message and display components
|
|
355
|
+
component_count = 0
|
|
356
|
+
async for component in agent.send_message(
|
|
357
|
+
user=user, message=user_message, conversation_id=conversation_id
|
|
358
|
+
):
|
|
359
|
+
component_count += 1
|
|
360
|
+
rich_comp = component.rich_component
|
|
361
|
+
component_type = getattr(rich_comp, "type", rich_comp.__class__.__name__)
|
|
362
|
+
component_id = getattr(rich_comp, "id", "N/A")
|
|
363
|
+
lifecycle = getattr(rich_comp, "lifecycle", "N/A")
|
|
364
|
+
|
|
365
|
+
print(
|
|
366
|
+
f"[{component_count:2d}] {component_type} (id: {component_id[:8]}, lifecycle: {lifecycle})"
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
# Show some component details
|
|
370
|
+
if hasattr(rich_comp, "title"):
|
|
371
|
+
print(f" Title: {rich_comp.title}")
|
|
372
|
+
if hasattr(rich_comp, "content") and len(str(rich_comp.content)) < 100:
|
|
373
|
+
print(f" Content: {rich_comp.content}")
|
|
374
|
+
if hasattr(rich_comp, "status"):
|
|
375
|
+
print(f" Status: {rich_comp.status}")
|
|
376
|
+
if (
|
|
377
|
+
hasattr(rich_comp, "value")
|
|
378
|
+
and hasattr(rich_comp.type, "value")
|
|
379
|
+
and rich_comp.type.value == "progress_bar"
|
|
380
|
+
):
|
|
381
|
+
print(f" Progress: {rich_comp.value:.1%}")
|
|
382
|
+
|
|
383
|
+
print()
|
|
384
|
+
|
|
385
|
+
print("=" * 50)
|
|
386
|
+
print(f"Total components emitted: {component_count}")
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def run_interactive() -> None:
|
|
390
|
+
"""Entry point for interactive usage."""
|
|
391
|
+
print("Starting Primitive Components Demo...")
|
|
392
|
+
asyncio.run(main())
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
if __name__ == "__main__":
|
|
396
|
+
run_interactive()
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mock example showing how to use the SQL query tool with the Chinook database.
|
|
3
|
+
|
|
4
|
+
This example demonstrates using the RunSqlTool with SqliteRunner and a mock LLM service
|
|
5
|
+
that automatically executes sample SQL queries against the Chinook database.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
Template: Copy this file and modify for your custom database
|
|
9
|
+
Interactive: python -m vanna.examples.mock_sqlite_example
|
|
10
|
+
REPL: from vanna.examples.mock_sqlite_example import create_demo_agent
|
|
11
|
+
Server: python -m vanna.servers --example mock_sqlite_example
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
import os
|
|
16
|
+
import random
|
|
17
|
+
import uuid
|
|
18
|
+
from typing import AsyncGenerator, Dict, List, Optional, Type
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, Field
|
|
21
|
+
|
|
22
|
+
from vanna import (
|
|
23
|
+
AgentConfig,
|
|
24
|
+
Agent,
|
|
25
|
+
Tool,
|
|
26
|
+
ToolContext,
|
|
27
|
+
ToolRegistry,
|
|
28
|
+
ToolResult,
|
|
29
|
+
User,
|
|
30
|
+
UiComponent,
|
|
31
|
+
)
|
|
32
|
+
from vanna.core.interfaces import LlmService
|
|
33
|
+
from vanna.core.models import (
|
|
34
|
+
LlmRequest,
|
|
35
|
+
LlmResponse,
|
|
36
|
+
LlmStreamChunk,
|
|
37
|
+
ToolCall,
|
|
38
|
+
ToolSchema,
|
|
39
|
+
)
|
|
40
|
+
from vanna.core.rich_components import (
|
|
41
|
+
CardComponent,
|
|
42
|
+
NotificationComponent,
|
|
43
|
+
ComponentType,
|
|
44
|
+
)
|
|
45
|
+
from vanna.core.simple_components import (
|
|
46
|
+
SimpleTextComponent,
|
|
47
|
+
)
|
|
48
|
+
from vanna.tools import RunSqlTool
|
|
49
|
+
from vanna.integrations.sqlite import SqliteRunner
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class MockSqliteLlmService(LlmService):
|
|
53
|
+
"""LLM service that exercises the SQLite query tool with sample queries."""
|
|
54
|
+
|
|
55
|
+
def __init__(self, seed: Optional[int] = None):
|
|
56
|
+
self._random = random.Random(seed)
|
|
57
|
+
self._sample_queries = [
|
|
58
|
+
"SELECT name FROM sqlite_master WHERE type='table'",
|
|
59
|
+
"SELECT COUNT(*) as total_customers FROM Customer",
|
|
60
|
+
"SELECT FirstName, LastName FROM Customer LIMIT 5",
|
|
61
|
+
"SELECT Name, Composer FROM Track WHERE Composer IS NOT NULL LIMIT 5",
|
|
62
|
+
"SELECT COUNT(*) as album_count FROM Album",
|
|
63
|
+
"SELECT Name FROM Artist LIMIT 10",
|
|
64
|
+
"SELECT AVG(Total) as avg_invoice_total FROM Invoice",
|
|
65
|
+
"SELECT GenreId, COUNT(*) as track_count FROM Track GROUP BY GenreId LIMIT 5",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
async def send_request(self, request: LlmRequest) -> LlmResponse:
|
|
69
|
+
"""Handle non-streaming SQLite interactions."""
|
|
70
|
+
await asyncio.sleep(0.1)
|
|
71
|
+
return self._build_response(request)
|
|
72
|
+
|
|
73
|
+
async def stream_request(
|
|
74
|
+
self, request: LlmRequest
|
|
75
|
+
) -> AsyncGenerator[LlmStreamChunk, None]:
|
|
76
|
+
"""Provide streaming compatibility by yielding a single chunk."""
|
|
77
|
+
await asyncio.sleep(0.1)
|
|
78
|
+
response = self._build_response(request)
|
|
79
|
+
|
|
80
|
+
if response.tool_calls:
|
|
81
|
+
yield LlmStreamChunk(tool_calls=response.tool_calls)
|
|
82
|
+
if response.content is not None:
|
|
83
|
+
yield LlmStreamChunk(
|
|
84
|
+
content=response.content, finish_reason=response.finish_reason
|
|
85
|
+
)
|
|
86
|
+
else:
|
|
87
|
+
yield LlmStreamChunk(finish_reason=response.finish_reason)
|
|
88
|
+
|
|
89
|
+
async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
|
|
90
|
+
"""Mock validation - no errors."""
|
|
91
|
+
return []
|
|
92
|
+
|
|
93
|
+
def _build_response(self, request: LlmRequest) -> LlmResponse:
|
|
94
|
+
"""Create a response that either calls the tool or explains its result."""
|
|
95
|
+
last_message = request.messages[-1] if request.messages else None
|
|
96
|
+
|
|
97
|
+
if last_message and last_message.role == "tool":
|
|
98
|
+
# Respond to tool result
|
|
99
|
+
result = last_message.content or "No result provided"
|
|
100
|
+
return LlmResponse(
|
|
101
|
+
content=f"Here's what I found in the database:\n\n{result}",
|
|
102
|
+
finish_reason="stop",
|
|
103
|
+
usage={
|
|
104
|
+
"prompt_tokens": 40,
|
|
105
|
+
"completion_tokens": 20,
|
|
106
|
+
"total_tokens": 60,
|
|
107
|
+
},
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Generate a random SQL query
|
|
111
|
+
sql_query = self._random.choice(self._sample_queries)
|
|
112
|
+
tool_call = ToolCall(
|
|
113
|
+
id=f"call_{uuid.uuid4().hex[:8]}",
|
|
114
|
+
name="run_sql",
|
|
115
|
+
arguments={"sql": sql_query},
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return LlmResponse(
|
|
119
|
+
content="Let me query the Chinook database for you...",
|
|
120
|
+
tool_calls=[tool_call],
|
|
121
|
+
finish_reason="tool_calls",
|
|
122
|
+
usage={"prompt_tokens": 30, "completion_tokens": 10, "total_tokens": 40},
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def create_demo_agent() -> Agent:
|
|
127
|
+
"""Create a demo agent with SQLite query tool.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Configured Agent with SQLite tool and mock LLM
|
|
131
|
+
"""
|
|
132
|
+
# Get the path to the Chinook database
|
|
133
|
+
database_path = os.path.join(
|
|
134
|
+
os.path.dirname(__file__), "..", "..", "Chinook.sqlite"
|
|
135
|
+
)
|
|
136
|
+
database_path = os.path.abspath(database_path)
|
|
137
|
+
|
|
138
|
+
if not os.path.exists(database_path):
|
|
139
|
+
raise FileNotFoundError(
|
|
140
|
+
f"Chinook database not found at {database_path}. Please download it from https://vanna.ai/Chinook.sqlite"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
tool_registry = ToolRegistry()
|
|
144
|
+
sqlite_runner = SqliteRunner(database_path=database_path)
|
|
145
|
+
sql_tool = RunSqlTool(sql_runner=sqlite_runner)
|
|
146
|
+
tool_registry.register(sql_tool)
|
|
147
|
+
|
|
148
|
+
llm_service = MockSqliteLlmService()
|
|
149
|
+
|
|
150
|
+
return Agent(
|
|
151
|
+
llm_service=llm_service,
|
|
152
|
+
tool_registry=tool_registry,
|
|
153
|
+
config=AgentConfig(
|
|
154
|
+
stream_responses=False,
|
|
155
|
+
include_thinking_indicators=False,
|
|
156
|
+
),
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
async def main() -> None:
|
|
161
|
+
"""Run the mock SQLite example."""
|
|
162
|
+
|
|
163
|
+
# Create agent using factory function
|
|
164
|
+
agent = create_demo_agent()
|
|
165
|
+
tool_registry = agent.tool_registry
|
|
166
|
+
|
|
167
|
+
# Create a test user
|
|
168
|
+
user = User(id="user123", username="testuser", permissions=[])
|
|
169
|
+
|
|
170
|
+
# Test the tool directly
|
|
171
|
+
print("Testing SQL tool directly:")
|
|
172
|
+
tool_call = ToolCall(
|
|
173
|
+
id="test123",
|
|
174
|
+
name="run_sql",
|
|
175
|
+
arguments={"sql": "SELECT name FROM sqlite_master WHERE type='table'"},
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
context = ToolContext(user=user, conversation_id="test", request_id="test")
|
|
179
|
+
|
|
180
|
+
result = await tool_registry.execute(tool_call, context)
|
|
181
|
+
print(
|
|
182
|
+
f"Tables in database:\n{result.result_for_llm if result.success else result.error}"
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Show available tools
|
|
186
|
+
schemas = await tool_registry.get_schemas(user)
|
|
187
|
+
print(f"\nAvailable tools for user: {[schema.name for schema in schemas]}")
|
|
188
|
+
|
|
189
|
+
# Demonstrate the mock LLM triggering SQL queries
|
|
190
|
+
print("\n" + "=" * 50)
|
|
191
|
+
print("Agent conversation demo:")
|
|
192
|
+
print("=" * 50)
|
|
193
|
+
|
|
194
|
+
conversation_id = "sqlite-demo"
|
|
195
|
+
|
|
196
|
+
# Run multiple queries to show different results
|
|
197
|
+
for i in range(3):
|
|
198
|
+
print(f"\n--- Query {i + 1} ---")
|
|
199
|
+
async for component in agent.send_message(
|
|
200
|
+
user=user,
|
|
201
|
+
message=f"Show me some data from the database (query {i + 1})",
|
|
202
|
+
conversation_id=conversation_id,
|
|
203
|
+
):
|
|
204
|
+
if (
|
|
205
|
+
hasattr(component.rich_component, "content")
|
|
206
|
+
and component.rich_component.content
|
|
207
|
+
):
|
|
208
|
+
print(f"Assistant: {component.rich_component.content}")
|
|
209
|
+
elif component.simple_component and hasattr(
|
|
210
|
+
component.simple_component, "text"
|
|
211
|
+
):
|
|
212
|
+
print(f"Assistant: {component.simple_component.text}")
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def run_interactive() -> None:
|
|
216
|
+
"""Entry point for interactive usage."""
|
|
217
|
+
print("Starting mock SQLite example...")
|
|
218
|
+
print("This example uses the Chinook database to demonstrate SQL queries.")
|
|
219
|
+
asyncio.run(main())
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
if __name__ == "__main__":
|
|
223
|
+
run_interactive()
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OpenAI example using OpenAILlmService.
|
|
3
|
+
|
|
4
|
+
Loads environment from .env (via python-dotenv), uses model 'gpt-5' by default,
|
|
5
|
+
and sends a simple message through a Agent.
|
|
6
|
+
|
|
7
|
+
Run:
|
|
8
|
+
PYTHONPATH=. python vanna/examples/openai_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("OPENAI_API_KEY"):
|
|
29
|
+
print(
|
|
30
|
+
"[error] OPENAI_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
|
+
# Lazy import after env load to allow custom base_url/org via env
|
|
39
|
+
try:
|
|
40
|
+
from vanna.integrations.anthropic import OpenAILlmService
|
|
41
|
+
except ImportError as e:
|
|
42
|
+
print(
|
|
43
|
+
"[error] openai extra not installed. Install with: pip install -e .[openai]"
|
|
44
|
+
)
|
|
45
|
+
raise
|
|
46
|
+
|
|
47
|
+
from vanna import AgentConfig, Agent, User
|
|
48
|
+
from vanna.core.registry import ToolRegistry
|
|
49
|
+
from vanna.tools import ListFilesTool
|
|
50
|
+
|
|
51
|
+
# Default to 'gpt-5' for this demo; override via $OPENAI_MODEL if desired
|
|
52
|
+
model = os.getenv("OPENAI_MODEL", "gpt-5")
|
|
53
|
+
print(f"Using OpenAI model: {model}")
|
|
54
|
+
|
|
55
|
+
llm = OpenAILlmService(model=model)
|
|
56
|
+
|
|
57
|
+
# Create tool registry and register the list_files tool
|
|
58
|
+
tool_registry = ToolRegistry()
|
|
59
|
+
list_files_tool = ListFilesTool()
|
|
60
|
+
tool_registry.register(list_files_tool)
|
|
61
|
+
|
|
62
|
+
# Some models (e.g., reasoning/gpt-5) only support the default temperature=1.0
|
|
63
|
+
agent = Agent(
|
|
64
|
+
llm_service=llm,
|
|
65
|
+
config=AgentConfig(stream_responses=False, temperature=1.0),
|
|
66
|
+
tool_registry=tool_registry,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
user = User(id="demo-user", username="demo")
|
|
70
|
+
conversation_id = "openai-demo"
|
|
71
|
+
|
|
72
|
+
print("Sending: 'List the files in the current directory'\n")
|
|
73
|
+
async for component in agent.send_message(
|
|
74
|
+
user=user,
|
|
75
|
+
message="List the files in the current directory",
|
|
76
|
+
conversation_id=conversation_id,
|
|
77
|
+
):
|
|
78
|
+
if hasattr(component, "content") and component.content:
|
|
79
|
+
print("Assistant:", component.content)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if __name__ == "__main__":
|
|
83
|
+
asyncio.run(main())
|