vanna 0.7.9__py3-none-any.whl ā 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +461 -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.0.dist-info/METADATA +485 -0
- vanna-2.0.0.dist-info/RECORD +289 -0
- vanna-2.0.0.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.0.dist-info}/WHEEL +0 -0
- {vanna-0.7.9.dist-info ā vanna-2.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mock example showing how to create and use custom tools.
|
|
3
|
+
|
|
4
|
+
This example demonstrates creating a simple calculator tool
|
|
5
|
+
and registering it with an agent that uses a mock LLM service.
|
|
6
|
+
It now includes a `MockCalculatorLlmService` that automatically
|
|
7
|
+
invokes the calculator tool with random numbers before echoing
|
|
8
|
+
back the computed answer.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
Template: Copy this file and modify for your custom tools
|
|
12
|
+
Interactive: python -m vanna.examples.mock_custom_tool
|
|
13
|
+
REPL: from vanna.examples.mock_custom_tool import create_demo_agent
|
|
14
|
+
Server: python -m vanna.servers --example mock_custom_tool
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import asyncio
|
|
18
|
+
import random
|
|
19
|
+
import uuid
|
|
20
|
+
from typing import AsyncGenerator, Dict, List, Optional, Tuple, Type
|
|
21
|
+
|
|
22
|
+
from pydantic import BaseModel, Field
|
|
23
|
+
|
|
24
|
+
from vanna import (
|
|
25
|
+
AgentConfig,
|
|
26
|
+
Agent,
|
|
27
|
+
Tool,
|
|
28
|
+
ToolContext,
|
|
29
|
+
ToolRegistry,
|
|
30
|
+
ToolResult,
|
|
31
|
+
User,
|
|
32
|
+
UiComponent,
|
|
33
|
+
)
|
|
34
|
+
from vanna.core.interfaces import LlmService
|
|
35
|
+
from vanna.core.models import (
|
|
36
|
+
LlmRequest,
|
|
37
|
+
LlmResponse,
|
|
38
|
+
LlmStreamChunk,
|
|
39
|
+
ToolCall,
|
|
40
|
+
ToolSchema,
|
|
41
|
+
)
|
|
42
|
+
from vanna.core.rich_components import (
|
|
43
|
+
CardComponent,
|
|
44
|
+
NotificationComponent,
|
|
45
|
+
ComponentType,
|
|
46
|
+
)
|
|
47
|
+
from vanna.core.simple_components import (
|
|
48
|
+
SimpleTextComponent,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class CalculatorArgs(BaseModel):
|
|
53
|
+
"""Arguments for the calculator tool."""
|
|
54
|
+
|
|
55
|
+
operation: str = Field(
|
|
56
|
+
description="The operation to perform: add, subtract, multiply, divide"
|
|
57
|
+
)
|
|
58
|
+
a: float = Field(description="First number")
|
|
59
|
+
b: float = Field(description="Second number")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class CalculatorTool(Tool[CalculatorArgs]):
|
|
63
|
+
"""A simple calculator tool."""
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def name(self) -> str:
|
|
67
|
+
return "calculator"
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def description(self) -> str:
|
|
71
|
+
return "Perform basic arithmetic operations (add, subtract, multiply, divide)"
|
|
72
|
+
|
|
73
|
+
def get_args_schema(self) -> Type[CalculatorArgs]:
|
|
74
|
+
return CalculatorArgs
|
|
75
|
+
|
|
76
|
+
async def execute(self, context: ToolContext, args: CalculatorArgs) -> ToolResult:
|
|
77
|
+
"""Execute the calculator operation."""
|
|
78
|
+
symbol_map = {"add": "+", "subtract": "-", "multiply": "Ć", "divide": "Ć·"}
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
if args.operation == "add":
|
|
82
|
+
result = args.a + args.b
|
|
83
|
+
elif args.operation == "subtract":
|
|
84
|
+
result = args.a - args.b
|
|
85
|
+
elif args.operation == "multiply":
|
|
86
|
+
result = args.a * args.b
|
|
87
|
+
elif args.operation == "divide":
|
|
88
|
+
if args.b == 0:
|
|
89
|
+
message = "Cannot divide by zero"
|
|
90
|
+
await asyncio.sleep(3)
|
|
91
|
+
return ToolResult(
|
|
92
|
+
success=False,
|
|
93
|
+
result_for_llm=message,
|
|
94
|
+
ui_component=UiComponent(
|
|
95
|
+
rich_component=NotificationComponent(
|
|
96
|
+
type=ComponentType.NOTIFICATION,
|
|
97
|
+
level="error",
|
|
98
|
+
message=message,
|
|
99
|
+
),
|
|
100
|
+
simple_component=SimpleTextComponent(text=message),
|
|
101
|
+
),
|
|
102
|
+
error=message,
|
|
103
|
+
)
|
|
104
|
+
result = args.a / args.b
|
|
105
|
+
else:
|
|
106
|
+
message = f"Unknown operation: {args.operation}"
|
|
107
|
+
await asyncio.sleep(3)
|
|
108
|
+
return ToolResult(
|
|
109
|
+
success=False,
|
|
110
|
+
result_for_llm=message,
|
|
111
|
+
ui_component=UiComponent(
|
|
112
|
+
rich_component=NotificationComponent(
|
|
113
|
+
type=ComponentType.NOTIFICATION,
|
|
114
|
+
level="warning",
|
|
115
|
+
message=message,
|
|
116
|
+
),
|
|
117
|
+
simple_component=SimpleTextComponent(text=message),
|
|
118
|
+
),
|
|
119
|
+
error=message,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
await asyncio.sleep(3)
|
|
123
|
+
|
|
124
|
+
symbol = symbol_map.get(args.operation, args.operation)
|
|
125
|
+
expression = f"{args.a:g} {symbol} {args.b:g} = {result:g}"
|
|
126
|
+
return ToolResult(
|
|
127
|
+
success=True,
|
|
128
|
+
result_for_llm=str(result),
|
|
129
|
+
ui_component=UiComponent(
|
|
130
|
+
rich_component=CardComponent(
|
|
131
|
+
type=ComponentType.CARD,
|
|
132
|
+
title="Calculator Result",
|
|
133
|
+
content=expression,
|
|
134
|
+
),
|
|
135
|
+
simple_component=SimpleTextComponent(text=expression),
|
|
136
|
+
),
|
|
137
|
+
error=None,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
except Exception as e:
|
|
141
|
+
message = str(e)
|
|
142
|
+
await asyncio.sleep(3)
|
|
143
|
+
return ToolResult(
|
|
144
|
+
success=False,
|
|
145
|
+
result_for_llm=message,
|
|
146
|
+
ui_component=UiComponent(
|
|
147
|
+
rich_component=NotificationComponent(
|
|
148
|
+
type=ComponentType.NOTIFICATION,
|
|
149
|
+
level="error",
|
|
150
|
+
message=message,
|
|
151
|
+
),
|
|
152
|
+
simple_component=SimpleTextComponent(text=message),
|
|
153
|
+
),
|
|
154
|
+
error=message,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class MockCalculatorLlmService(LlmService):
|
|
159
|
+
"""LLM service that exercises the calculator tool before echoing the result."""
|
|
160
|
+
|
|
161
|
+
def __init__(self, seed: Optional[int] = None):
|
|
162
|
+
self._random = random.Random(seed)
|
|
163
|
+
|
|
164
|
+
async def send_request(self, request: LlmRequest) -> LlmResponse:
|
|
165
|
+
"""Handle non-streaming calculator interactions."""
|
|
166
|
+
await asyncio.sleep(0.05)
|
|
167
|
+
return self._build_response(request)
|
|
168
|
+
|
|
169
|
+
async def stream_request(
|
|
170
|
+
self, request: LlmRequest
|
|
171
|
+
) -> AsyncGenerator[LlmStreamChunk, None]:
|
|
172
|
+
"""Provide streaming compatibility by yielding a single chunk."""
|
|
173
|
+
await asyncio.sleep(0.05)
|
|
174
|
+
response = self._build_response(request)
|
|
175
|
+
|
|
176
|
+
if response.tool_calls:
|
|
177
|
+
yield LlmStreamChunk(tool_calls=response.tool_calls)
|
|
178
|
+
if response.content is not None:
|
|
179
|
+
yield LlmStreamChunk(
|
|
180
|
+
content=response.content, finish_reason=response.finish_reason
|
|
181
|
+
)
|
|
182
|
+
else:
|
|
183
|
+
yield LlmStreamChunk(finish_reason=response.finish_reason)
|
|
184
|
+
|
|
185
|
+
async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
|
|
186
|
+
"""Mock validation - no errors."""
|
|
187
|
+
return []
|
|
188
|
+
|
|
189
|
+
def _build_response(self, request: LlmRequest) -> LlmResponse:
|
|
190
|
+
"""Create a response that either calls the tool or echoes its result."""
|
|
191
|
+
last_message = request.messages[-1] if request.messages else None
|
|
192
|
+
|
|
193
|
+
if last_message and last_message.role == "tool":
|
|
194
|
+
answer = last_message.content or "No result provided"
|
|
195
|
+
return LlmResponse(
|
|
196
|
+
content=answer,
|
|
197
|
+
finish_reason="stop",
|
|
198
|
+
usage={
|
|
199
|
+
"prompt_tokens": 30,
|
|
200
|
+
"completion_tokens": 10,
|
|
201
|
+
"total_tokens": 40,
|
|
202
|
+
},
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
operation, a, b = self._random_operands()
|
|
206
|
+
tool_call = ToolCall(
|
|
207
|
+
id=f"call_{uuid.uuid4().hex[:8]}",
|
|
208
|
+
name="calculator",
|
|
209
|
+
arguments={"operation": operation, "a": a, "b": b},
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
return LlmResponse(
|
|
213
|
+
content="Let me ask my calculator friend for help...",
|
|
214
|
+
tool_calls=[tool_call],
|
|
215
|
+
finish_reason="tool_calls",
|
|
216
|
+
usage={"prompt_tokens": 30, "completion_tokens": 5, "total_tokens": 35},
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def _random_operands(self) -> Tuple[str, float, float]:
|
|
220
|
+
"""Generate operation and operands suited for the calculator tool."""
|
|
221
|
+
operation = self._random.choice(["add", "subtract", "multiply", "divide"])
|
|
222
|
+
|
|
223
|
+
if operation == "divide":
|
|
224
|
+
b = float(self._random.randint(1, 10))
|
|
225
|
+
multiplier = self._random.randint(1, 10)
|
|
226
|
+
a = float(b * multiplier)
|
|
227
|
+
elif operation == "subtract":
|
|
228
|
+
b = float(self._random.randint(1, 10))
|
|
229
|
+
a = b + float(self._random.randint(0, 10))
|
|
230
|
+
else:
|
|
231
|
+
a = float(self._random.randint(1, 12))
|
|
232
|
+
b = float(self._random.randint(1, 12))
|
|
233
|
+
|
|
234
|
+
return operation, a, b
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def create_demo_agent() -> Agent:
|
|
238
|
+
"""Create a demo agent with custom calculator tool.
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
Configured Agent with calculator tool and mock calculator LLM
|
|
242
|
+
"""
|
|
243
|
+
tool_registry = ToolRegistry()
|
|
244
|
+
calculator_tool = CalculatorTool()
|
|
245
|
+
tool_registry.register(calculator_tool)
|
|
246
|
+
|
|
247
|
+
llm_service = MockCalculatorLlmService()
|
|
248
|
+
|
|
249
|
+
return Agent(
|
|
250
|
+
llm_service=llm_service,
|
|
251
|
+
tool_registry=tool_registry,
|
|
252
|
+
config=AgentConfig(
|
|
253
|
+
stream_responses=False,
|
|
254
|
+
include_thinking_indicators=False,
|
|
255
|
+
),
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
async def main() -> None:
|
|
260
|
+
"""Run the mock custom tool example."""
|
|
261
|
+
|
|
262
|
+
# Create agent using factory function
|
|
263
|
+
agent = create_demo_agent()
|
|
264
|
+
tool_registry = agent.tool_registry
|
|
265
|
+
|
|
266
|
+
# Create a test user
|
|
267
|
+
user = User(id="user123", username="testuser", permissions=[])
|
|
268
|
+
|
|
269
|
+
# Test the tool directly
|
|
270
|
+
print("Testing calculator tool directly:")
|
|
271
|
+
tool_call = ToolCall(
|
|
272
|
+
id="test123", name="calculator", arguments={"operation": "add", "a": 5, "b": 3}
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
context = ToolContext(user=user, conversation_id="test", request_id="test")
|
|
276
|
+
|
|
277
|
+
result = await tool_registry.execute(tool_call, context)
|
|
278
|
+
print(f"5 + 3 = {result.result_for_llm if result.success else result.error}")
|
|
279
|
+
|
|
280
|
+
# Show available tools
|
|
281
|
+
schemas = await tool_registry.get_schemas(user)
|
|
282
|
+
print(f"\nAvailable tools for user: {[schema.name for schema in schemas]}")
|
|
283
|
+
|
|
284
|
+
# Demonstrate the mock LLM triggering a tool call
|
|
285
|
+
print("\nAgent conversation demo:")
|
|
286
|
+
conversation_id = "calc-demo"
|
|
287
|
+
async for component in agent.send_message(
|
|
288
|
+
user=user,
|
|
289
|
+
message="Can you compute something for me?",
|
|
290
|
+
conversation_id=conversation_id,
|
|
291
|
+
):
|
|
292
|
+
print(f"- Component type: {component.rich_component.type}")
|
|
293
|
+
if (
|
|
294
|
+
hasattr(component.rich_component, "content")
|
|
295
|
+
and component.rich_component.content
|
|
296
|
+
):
|
|
297
|
+
print(f"Assistant: {component.rich_component.content}")
|
|
298
|
+
elif component.simple_component and hasattr(component.simple_component, "text"):
|
|
299
|
+
print(f"Assistant: {component.simple_component.text}")
|
|
300
|
+
else:
|
|
301
|
+
print(f"- Component data: {component.rich_component.data}")
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def run_interactive() -> None:
|
|
305
|
+
"""Entry point for interactive usage."""
|
|
306
|
+
print("Starting mock custom tool example...")
|
|
307
|
+
asyncio.run(main())
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
if __name__ == "__main__":
|
|
311
|
+
run_interactive()
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mock quickstart example for the Vanna Agents framework.
|
|
3
|
+
|
|
4
|
+
This example shows how to create a basic agent with a mock LLM service
|
|
5
|
+
and have a simple conversation.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
Template: Copy this file and modify for your needs
|
|
9
|
+
Interactive: python -m vanna.examples.mock_quickstart
|
|
10
|
+
REPL: from vanna.examples.mock_quickstart import create_demo_agent
|
|
11
|
+
Server: python -m vanna.servers --example mock_quickstart
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
|
|
16
|
+
from vanna import (
|
|
17
|
+
AgentConfig,
|
|
18
|
+
Agent,
|
|
19
|
+
MemoryConversationStore,
|
|
20
|
+
MockLlmService,
|
|
21
|
+
User,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def create_demo_agent() -> Agent:
|
|
26
|
+
"""Create a demo agent for REPL and server usage.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Configured Agent instance
|
|
30
|
+
"""
|
|
31
|
+
llm_service = MockLlmService(
|
|
32
|
+
response_content="Hello! I'm a helpful AI assistant created using the Vanna Agents framework."
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
return Agent(
|
|
36
|
+
llm_service=llm_service,
|
|
37
|
+
config=AgentConfig(
|
|
38
|
+
stream_responses=True, # Enable streaming for better server experience
|
|
39
|
+
include_thinking_indicators=True,
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
async def main() -> None:
|
|
45
|
+
"""Run the mock quickstart example."""
|
|
46
|
+
|
|
47
|
+
# Create agent using factory function
|
|
48
|
+
agent = create_demo_agent()
|
|
49
|
+
|
|
50
|
+
# Create a test user
|
|
51
|
+
user = User(
|
|
52
|
+
id="user123", username="testuser", email="test@example.com", permissions=[]
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Start a conversation
|
|
56
|
+
conversation_id = "conversation123"
|
|
57
|
+
user_message = "Hello! Can you introduce yourself?"
|
|
58
|
+
|
|
59
|
+
print(f"User: {user_message}")
|
|
60
|
+
print("Agent: ", end="")
|
|
61
|
+
|
|
62
|
+
# Send message and collect response
|
|
63
|
+
async for component in agent.send_message(
|
|
64
|
+
user=user, message=user_message, conversation_id=conversation_id
|
|
65
|
+
):
|
|
66
|
+
if hasattr(component, "content"):
|
|
67
|
+
print(component.content, end="")
|
|
68
|
+
|
|
69
|
+
print()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def run_interactive() -> None:
|
|
73
|
+
"""Entry point for interactive usage."""
|
|
74
|
+
print("Starting Vanna Agents mock quickstart demo...")
|
|
75
|
+
asyncio.run(main())
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if __name__ == "__main__":
|
|
79
|
+
run_interactive()
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mock quota-based agent example using Mock LLM service.
|
|
3
|
+
|
|
4
|
+
This example demonstrates how to create a custom agent runner that
|
|
5
|
+
enforces user-based message quotas. It shows:
|
|
6
|
+
- Custom agent runner subclass
|
|
7
|
+
- Quota management and enforcement
|
|
8
|
+
- Error handling for quota exceeded cases
|
|
9
|
+
- Multiple users with different quotas
|
|
10
|
+
|
|
11
|
+
Run:
|
|
12
|
+
PYTHONPATH=. python vanna/examples/mock_quota_example.py
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import asyncio
|
|
16
|
+
|
|
17
|
+
from vanna import (
|
|
18
|
+
AgentConfig,
|
|
19
|
+
MemoryConversationStore,
|
|
20
|
+
MockLlmService,
|
|
21
|
+
User,
|
|
22
|
+
)
|
|
23
|
+
from vanna.core.registry import ToolRegistry
|
|
24
|
+
from vanna.tools import ListFilesTool
|
|
25
|
+
from vanna.examples.quota_agent import QuotaAgentRunner, QuotaExceededError
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async def demonstrate_quota_system() -> None:
|
|
29
|
+
"""Demonstrate the quota-based agent system."""
|
|
30
|
+
print("š Starting Mock Quota-based Agent Example\n")
|
|
31
|
+
|
|
32
|
+
# Create a mock LLM service
|
|
33
|
+
llm_service = MockLlmService(
|
|
34
|
+
response_content="Hello! I'm here to help you with your questions."
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Create tool registry with list_files tool
|
|
38
|
+
tool_registry = ToolRegistry()
|
|
39
|
+
list_files_tool = ListFilesTool()
|
|
40
|
+
tool_registry.register(list_files_tool)
|
|
41
|
+
|
|
42
|
+
# Create conversation store
|
|
43
|
+
conversation_store = MemoryConversationStore()
|
|
44
|
+
|
|
45
|
+
# Create the quota-based agent
|
|
46
|
+
agent = QuotaAgentRunner(
|
|
47
|
+
llm_service=llm_service,
|
|
48
|
+
tool_registry=tool_registry,
|
|
49
|
+
conversation_store=conversation_store,
|
|
50
|
+
config=AgentConfig(
|
|
51
|
+
stream_responses=False,
|
|
52
|
+
include_thinking_indicators=False,
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Create users with different quota settings
|
|
57
|
+
regular_user = User(
|
|
58
|
+
id="user1", username="alice", email="alice@example.com", permissions=[]
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
premium_user = User(
|
|
62
|
+
id="user2", username="bob", email="bob@example.com", permissions=["premium"]
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# Set custom quotas
|
|
66
|
+
agent.set_user_quota(regular_user.id, 3) # Alice gets 3 messages
|
|
67
|
+
agent.set_user_quota(premium_user.id, 5) # Bob gets 5 messages (premium)
|
|
68
|
+
|
|
69
|
+
print("š User Quotas:")
|
|
70
|
+
print(
|
|
71
|
+
f" ⢠{regular_user.username}: {agent.get_user_quota(regular_user.id)} messages"
|
|
72
|
+
)
|
|
73
|
+
print(
|
|
74
|
+
f" ⢠{premium_user.username}: {agent.get_user_quota(premium_user.id)} messages"
|
|
75
|
+
)
|
|
76
|
+
print()
|
|
77
|
+
|
|
78
|
+
# Test regular user within quota
|
|
79
|
+
print("š¬ Testing regular user (Alice) within quota:")
|
|
80
|
+
for i in range(1, 4): # Send 3 messages (within quota)
|
|
81
|
+
print(f" Message {i}/3:")
|
|
82
|
+
async for component in agent.send_message(
|
|
83
|
+
user=regular_user,
|
|
84
|
+
message=f"Hello, this is message {i}",
|
|
85
|
+
conversation_id="alice-conv",
|
|
86
|
+
):
|
|
87
|
+
if hasattr(component, "content") and component.content:
|
|
88
|
+
print(f" Agent: {component.content}")
|
|
89
|
+
print()
|
|
90
|
+
|
|
91
|
+
# Test regular user exceeding quota
|
|
92
|
+
print("ā ļø Testing regular user (Alice) exceeding quota:")
|
|
93
|
+
async for component in agent.send_message(
|
|
94
|
+
user=regular_user,
|
|
95
|
+
message="This message should be blocked",
|
|
96
|
+
conversation_id="alice-conv",
|
|
97
|
+
):
|
|
98
|
+
if hasattr(component, "content") and component.content:
|
|
99
|
+
print(f" Agent: {component.content}")
|
|
100
|
+
print()
|
|
101
|
+
|
|
102
|
+
# Test premium user with higher quota
|
|
103
|
+
print("ā Testing premium user (Bob) with higher quota:")
|
|
104
|
+
for i in range(1, 4): # Send 3 messages
|
|
105
|
+
print(f" Message {i}/5:")
|
|
106
|
+
async for component in agent.send_message(
|
|
107
|
+
user=premium_user,
|
|
108
|
+
message=f"Premium user message {i}",
|
|
109
|
+
conversation_id="bob-conv",
|
|
110
|
+
):
|
|
111
|
+
if hasattr(component, "content") and component.content:
|
|
112
|
+
print(f" Agent: {component.content}")
|
|
113
|
+
print()
|
|
114
|
+
|
|
115
|
+
# Demonstrate quota reset
|
|
116
|
+
print("š Resetting Alice's usage:")
|
|
117
|
+
agent.reset_user_usage(regular_user.id)
|
|
118
|
+
print(f" Alice's remaining messages: {agent.get_user_remaining(regular_user.id)}")
|
|
119
|
+
print()
|
|
120
|
+
|
|
121
|
+
print("ā
After reset, Alice can send messages again:")
|
|
122
|
+
async for component in agent.send_message(
|
|
123
|
+
user=regular_user,
|
|
124
|
+
message="This should work after reset",
|
|
125
|
+
conversation_id="alice-conv2",
|
|
126
|
+
):
|
|
127
|
+
if hasattr(component, "content") and component.content:
|
|
128
|
+
print(f" Agent: {component.content}")
|
|
129
|
+
|
|
130
|
+
print("\nš Final Usage Summary:")
|
|
131
|
+
print(
|
|
132
|
+
f" ⢠Alice: {agent.get_user_usage(regular_user.id)}/{agent.get_user_quota(regular_user.id)} used"
|
|
133
|
+
)
|
|
134
|
+
print(
|
|
135
|
+
f" ⢠Bob: {agent.get_user_usage(premium_user.id)}/{agent.get_user_quota(premium_user.id)} used"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
async def main() -> None:
|
|
140
|
+
"""Run the mock quota example."""
|
|
141
|
+
await demonstrate_quota_system()
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
if __name__ == "__main__":
|
|
145
|
+
asyncio.run(main())
|