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,137 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Flask route implementations for Vanna Agents.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import json
|
|
7
|
+
import traceback
|
|
8
|
+
from typing import Any, AsyncGenerator, Dict, Generator, Optional, Union
|
|
9
|
+
|
|
10
|
+
from flask import Flask, Response, jsonify, request
|
|
11
|
+
|
|
12
|
+
from ..base import ChatHandler, ChatRequest
|
|
13
|
+
from ..base.templates import get_index_html
|
|
14
|
+
from ...core.user.request_context import RequestContext
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def register_chat_routes(
|
|
18
|
+
app: Flask, chat_handler: ChatHandler, config: Optional[Dict[str, Any]] = None
|
|
19
|
+
) -> None:
|
|
20
|
+
"""Register chat routes on Flask app.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
app: Flask application
|
|
24
|
+
chat_handler: Chat handler instance
|
|
25
|
+
config: Server configuration
|
|
26
|
+
"""
|
|
27
|
+
config = config or {}
|
|
28
|
+
|
|
29
|
+
@app.route("/")
|
|
30
|
+
def index() -> str:
|
|
31
|
+
"""Serve the main chat interface."""
|
|
32
|
+
dev_mode = config.get("dev_mode", False)
|
|
33
|
+
cdn_url = config.get("cdn_url", "https://img.vanna.ai/vanna-components.js")
|
|
34
|
+
api_base_url = config.get("api_base_url", "")
|
|
35
|
+
|
|
36
|
+
return get_index_html(
|
|
37
|
+
dev_mode=dev_mode, cdn_url=cdn_url, api_base_url=api_base_url
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
@app.route("/api/vanna/v2/chat_sse", methods=["POST"])
|
|
41
|
+
def chat_sse() -> Union[Response, tuple[Response, int]]:
|
|
42
|
+
"""Server-Sent Events endpoint for streaming chat."""
|
|
43
|
+
try:
|
|
44
|
+
data = request.get_json()
|
|
45
|
+
if not data:
|
|
46
|
+
return jsonify({"error": "JSON body required"}), 400
|
|
47
|
+
|
|
48
|
+
# Extract request context for user resolution
|
|
49
|
+
data["request_context"] = RequestContext(
|
|
50
|
+
cookies=dict(request.cookies),
|
|
51
|
+
headers=dict(request.headers),
|
|
52
|
+
remote_addr=request.remote_addr,
|
|
53
|
+
query_params=dict(request.args),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
chat_request = ChatRequest(**data)
|
|
57
|
+
except Exception as e:
|
|
58
|
+
traceback.print_stack()
|
|
59
|
+
traceback.print_exc()
|
|
60
|
+
return jsonify({"error": f"Invalid request: {str(e)}"}), 400
|
|
61
|
+
|
|
62
|
+
def generate() -> Generator[str, None, None]:
|
|
63
|
+
"""Generate SSE stream."""
|
|
64
|
+
loop = asyncio.new_event_loop()
|
|
65
|
+
asyncio.set_event_loop(loop)
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
|
|
69
|
+
async def async_generate() -> AsyncGenerator[str, None]:
|
|
70
|
+
async for chunk in chat_handler.handle_stream(chat_request):
|
|
71
|
+
chunk_json = chunk.model_dump_json()
|
|
72
|
+
yield f"data: {chunk_json}\n\n"
|
|
73
|
+
|
|
74
|
+
gen = async_generate()
|
|
75
|
+
try:
|
|
76
|
+
while True:
|
|
77
|
+
chunk = loop.run_until_complete(gen.__anext__())
|
|
78
|
+
yield chunk
|
|
79
|
+
except StopAsyncIteration:
|
|
80
|
+
yield "data: [DONE]\n\n"
|
|
81
|
+
finally:
|
|
82
|
+
loop.close()
|
|
83
|
+
|
|
84
|
+
return Response(
|
|
85
|
+
generate(),
|
|
86
|
+
mimetype="text/event-stream",
|
|
87
|
+
headers={
|
|
88
|
+
"Cache-Control": "no-cache",
|
|
89
|
+
"Connection": "keep-alive",
|
|
90
|
+
"X-Accel-Buffering": "no", # Disable nginx buffering
|
|
91
|
+
},
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
@app.route("/api/vanna/v2/chat_websocket")
|
|
95
|
+
def chat_websocket() -> tuple[Response, int]:
|
|
96
|
+
"""WebSocket endpoint placeholder."""
|
|
97
|
+
return jsonify(
|
|
98
|
+
{
|
|
99
|
+
"error": "WebSocket endpoint not implemented in basic Flask example",
|
|
100
|
+
"suggestion": "Use Flask-SocketIO for WebSocket support",
|
|
101
|
+
}
|
|
102
|
+
), 501
|
|
103
|
+
|
|
104
|
+
@app.route("/api/vanna/v2/chat_poll", methods=["POST"])
|
|
105
|
+
def chat_poll() -> Union[Response, tuple[Response, int]]:
|
|
106
|
+
"""Polling endpoint for chat."""
|
|
107
|
+
try:
|
|
108
|
+
data = request.get_json()
|
|
109
|
+
if not data:
|
|
110
|
+
return jsonify({"error": "JSON body required"}), 400
|
|
111
|
+
|
|
112
|
+
# Extract request context for user resolution
|
|
113
|
+
data["request_context"] = RequestContext(
|
|
114
|
+
cookies=dict(request.cookies),
|
|
115
|
+
headers=dict(request.headers),
|
|
116
|
+
remote_addr=request.remote_addr,
|
|
117
|
+
query_params=dict(request.args),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
chat_request = ChatRequest(**data)
|
|
121
|
+
except Exception as e:
|
|
122
|
+
traceback.print_stack()
|
|
123
|
+
traceback.print_exc()
|
|
124
|
+
return jsonify({"error": f"Invalid request: {str(e)}"}), 400
|
|
125
|
+
|
|
126
|
+
# Run async handler in new event loop
|
|
127
|
+
loop = asyncio.new_event_loop()
|
|
128
|
+
asyncio.set_event_loop(loop)
|
|
129
|
+
try:
|
|
130
|
+
result = loop.run_until_complete(chat_handler.handle_poll(chat_request))
|
|
131
|
+
return jsonify(result.model_dump())
|
|
132
|
+
except Exception as e:
|
|
133
|
+
traceback.print_stack()
|
|
134
|
+
traceback.print_exc()
|
|
135
|
+
return jsonify({"error": f"Chat failed: {str(e)}"}), 500
|
|
136
|
+
finally:
|
|
137
|
+
loop.close()
|
vanna/tools/__init__.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Built-in tool implementations."""
|
|
2
|
+
|
|
3
|
+
from .file_system import (
|
|
4
|
+
CommandResult,
|
|
5
|
+
FileSystem,
|
|
6
|
+
ListFilesTool,
|
|
7
|
+
LocalFileSystem,
|
|
8
|
+
ReadFileTool,
|
|
9
|
+
SearchFilesTool,
|
|
10
|
+
WriteFileTool,
|
|
11
|
+
create_file_system_tools,
|
|
12
|
+
)
|
|
13
|
+
from .python import (
|
|
14
|
+
PipInstallTool,
|
|
15
|
+
RunPythonFileTool,
|
|
16
|
+
create_python_tools,
|
|
17
|
+
)
|
|
18
|
+
from vanna.integrations.plotly import PlotlyChartGenerator
|
|
19
|
+
from .run_sql import RunSqlTool
|
|
20
|
+
from .visualize_data import VisualizeDataTool
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
# File system
|
|
24
|
+
"FileSystem",
|
|
25
|
+
"LocalFileSystem",
|
|
26
|
+
"ListFilesTool",
|
|
27
|
+
"SearchFilesTool",
|
|
28
|
+
"ReadFileTool",
|
|
29
|
+
"WriteFileTool",
|
|
30
|
+
"create_file_system_tools",
|
|
31
|
+
"CommandResult",
|
|
32
|
+
# Python tools
|
|
33
|
+
"RunPythonFileTool",
|
|
34
|
+
"PipInstallTool",
|
|
35
|
+
"create_python_tools",
|
|
36
|
+
# SQL
|
|
37
|
+
"RunSqlTool",
|
|
38
|
+
# Visualization
|
|
39
|
+
"PlotlyChartGenerator",
|
|
40
|
+
"VisualizeDataTool",
|
|
41
|
+
]
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent memory tools.
|
|
3
|
+
|
|
4
|
+
This module provides agent memory operations through an abstract AgentMemory interface,
|
|
5
|
+
allowing for different implementations (local vector DB, remote cloud service, etc.).
|
|
6
|
+
The tools access AgentMemory via ToolContext, which is populated by the Agent.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from typing import Any, Dict, List, Optional, Type
|
|
11
|
+
from pydantic import BaseModel, Field
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
from vanna.core.tool import Tool, ToolContext, ToolResult
|
|
16
|
+
from vanna.core.agent.config import UiFeature
|
|
17
|
+
from vanna.capabilities.agent_memory import AgentMemory
|
|
18
|
+
from vanna.components import (
|
|
19
|
+
UiComponent,
|
|
20
|
+
StatusBarUpdateComponent,
|
|
21
|
+
CardComponent,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SaveQuestionToolArgsParams(BaseModel):
|
|
26
|
+
"""Parameters for saving question-tool-argument combinations."""
|
|
27
|
+
|
|
28
|
+
question: str = Field(description="The original question that was asked")
|
|
29
|
+
tool_name: str = Field(
|
|
30
|
+
description="The name of the tool that was used successfully"
|
|
31
|
+
)
|
|
32
|
+
args: Dict[str, Any] = Field(
|
|
33
|
+
description="The arguments that were passed to the tool"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class SearchSavedCorrectToolUsesParams(BaseModel):
|
|
38
|
+
"""Parameters for searching saved tool usage patterns."""
|
|
39
|
+
|
|
40
|
+
question: str = Field(
|
|
41
|
+
description="The question to find similar tool usage patterns for"
|
|
42
|
+
)
|
|
43
|
+
limit: Optional[int] = Field(
|
|
44
|
+
default=10, description="Maximum number of results to return"
|
|
45
|
+
)
|
|
46
|
+
similarity_threshold: Optional[float] = Field(
|
|
47
|
+
default=0.7, description="Minimum similarity score for results (0.0-1.0)"
|
|
48
|
+
)
|
|
49
|
+
tool_name_filter: Optional[str] = Field(
|
|
50
|
+
default=None, description="Filter results to specific tool name"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class SaveTextMemoryParams(BaseModel):
|
|
55
|
+
"""Parameters for saving free-form text memories."""
|
|
56
|
+
|
|
57
|
+
content: str = Field(description="The text content to save as a memory")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class SaveQuestionToolArgsTool(Tool[SaveQuestionToolArgsParams]):
|
|
61
|
+
"""Tool for saving successful question-tool-argument combinations."""
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def name(self) -> str:
|
|
65
|
+
return "save_question_tool_args"
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def description(self) -> str:
|
|
69
|
+
return (
|
|
70
|
+
"Save a successful question-tool-argument combination for future reference"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def get_args_schema(self) -> Type[SaveQuestionToolArgsParams]:
|
|
74
|
+
return SaveQuestionToolArgsParams
|
|
75
|
+
|
|
76
|
+
async def execute(
|
|
77
|
+
self, context: ToolContext, args: SaveQuestionToolArgsParams
|
|
78
|
+
) -> ToolResult:
|
|
79
|
+
"""Save the tool usage pattern to agent memory."""
|
|
80
|
+
try:
|
|
81
|
+
await context.agent_memory.save_tool_usage(
|
|
82
|
+
question=args.question,
|
|
83
|
+
tool_name=args.tool_name,
|
|
84
|
+
args=args.args,
|
|
85
|
+
context=context,
|
|
86
|
+
success=True,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
success_msg = (
|
|
90
|
+
f"Successfully saved usage pattern for '{args.tool_name}' tool"
|
|
91
|
+
)
|
|
92
|
+
return ToolResult(
|
|
93
|
+
success=True,
|
|
94
|
+
result_for_llm=success_msg,
|
|
95
|
+
ui_component=UiComponent(
|
|
96
|
+
rich_component=StatusBarUpdateComponent(
|
|
97
|
+
status="success",
|
|
98
|
+
message="Saved to memory",
|
|
99
|
+
detail=f"Saved pattern for '{args.tool_name}'",
|
|
100
|
+
),
|
|
101
|
+
simple_component=None,
|
|
102
|
+
),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
except Exception as e:
|
|
106
|
+
error_message = f"Failed to save memory: {str(e)}"
|
|
107
|
+
return ToolResult(
|
|
108
|
+
success=False,
|
|
109
|
+
result_for_llm=error_message,
|
|
110
|
+
ui_component=UiComponent(
|
|
111
|
+
rich_component=StatusBarUpdateComponent(
|
|
112
|
+
status="error", message="Failed to save memory", detail=str(e)
|
|
113
|
+
),
|
|
114
|
+
simple_component=None,
|
|
115
|
+
),
|
|
116
|
+
error=str(e),
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class SearchSavedCorrectToolUsesTool(Tool[SearchSavedCorrectToolUsesParams]):
|
|
121
|
+
"""Tool for searching saved tool usage patterns."""
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def name(self) -> str:
|
|
125
|
+
return "search_saved_correct_tool_uses"
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def description(self) -> str:
|
|
129
|
+
return "Search for similar tool usage patterns based on a question"
|
|
130
|
+
|
|
131
|
+
def get_args_schema(self) -> Type[SearchSavedCorrectToolUsesParams]:
|
|
132
|
+
return SearchSavedCorrectToolUsesParams
|
|
133
|
+
|
|
134
|
+
async def execute(
|
|
135
|
+
self, context: ToolContext, args: SearchSavedCorrectToolUsesParams
|
|
136
|
+
) -> ToolResult:
|
|
137
|
+
"""Search for similar tool usage patterns."""
|
|
138
|
+
try:
|
|
139
|
+
results = await context.agent_memory.search_similar_usage(
|
|
140
|
+
question=args.question,
|
|
141
|
+
context=context,
|
|
142
|
+
limit=args.limit or 10,
|
|
143
|
+
similarity_threshold=args.similarity_threshold or 0.7,
|
|
144
|
+
tool_name_filter=args.tool_name_filter,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
if not results:
|
|
148
|
+
no_results_msg = (
|
|
149
|
+
"No similar tool usage patterns found for this question."
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# Check if user has access to detailed memory results
|
|
153
|
+
ui_features_available = context.metadata.get(
|
|
154
|
+
"ui_features_available", []
|
|
155
|
+
)
|
|
156
|
+
show_detailed_results = (
|
|
157
|
+
UiFeature.UI_FEATURE_SHOW_MEMORY_DETAILED_RESULTS
|
|
158
|
+
in ui_features_available
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Create UI component based on access level
|
|
162
|
+
if show_detailed_results:
|
|
163
|
+
# Admin view: Show card indicating 0 results
|
|
164
|
+
ui_component = UiComponent(
|
|
165
|
+
rich_component=CardComponent(
|
|
166
|
+
title="🧠 Memory Search: 0 Results",
|
|
167
|
+
content="No similar tool usage patterns found for this question.\n\nSearched agent memory with no matches.",
|
|
168
|
+
icon="🔍",
|
|
169
|
+
status="info",
|
|
170
|
+
collapsible=True,
|
|
171
|
+
collapsed=True,
|
|
172
|
+
markdown=True,
|
|
173
|
+
),
|
|
174
|
+
simple_component=None,
|
|
175
|
+
)
|
|
176
|
+
else:
|
|
177
|
+
# Non-admin view: Simple status message
|
|
178
|
+
ui_component = UiComponent(
|
|
179
|
+
rich_component=StatusBarUpdateComponent(
|
|
180
|
+
status="idle",
|
|
181
|
+
message="No similar patterns found",
|
|
182
|
+
detail="Searched agent memory",
|
|
183
|
+
),
|
|
184
|
+
simple_component=None,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
return ToolResult(
|
|
188
|
+
success=True,
|
|
189
|
+
result_for_llm=no_results_msg,
|
|
190
|
+
ui_component=ui_component,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Format results for LLM
|
|
194
|
+
results_text = f"Found {len(results)} similar tool usage pattern(s):\n\n"
|
|
195
|
+
for i, result in enumerate(results, 1):
|
|
196
|
+
memory = result.memory
|
|
197
|
+
results_text += f"{i}. {memory.tool_name} (similarity: {result.similarity_score:.2f})\n"
|
|
198
|
+
results_text += f" Question: {memory.question}\n"
|
|
199
|
+
results_text += f" Args: {memory.args}\n\n"
|
|
200
|
+
|
|
201
|
+
logger.info(f"Agent memory search results: {results_text.strip()}")
|
|
202
|
+
|
|
203
|
+
# Check if user has access to detailed memory results
|
|
204
|
+
ui_features_available = context.metadata.get("ui_features_available", [])
|
|
205
|
+
show_detailed_results = (
|
|
206
|
+
UiFeature.UI_FEATURE_SHOW_MEMORY_DETAILED_RESULTS
|
|
207
|
+
in ui_features_available
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# Create UI component based on access level
|
|
211
|
+
if show_detailed_results:
|
|
212
|
+
# Admin view: Show detailed results in collapsible card
|
|
213
|
+
detailed_content = "**Retrieved memories passed to LLM:**\n\n"
|
|
214
|
+
for i, result in enumerate(results, 1):
|
|
215
|
+
memory = result.memory
|
|
216
|
+
detailed_content += f"**{i}. {memory.tool_name}** (similarity: {result.similarity_score:.2f})\n"
|
|
217
|
+
detailed_content += f"- **Question:** {memory.question}\n"
|
|
218
|
+
detailed_content += f"- **Arguments:** `{memory.args}`\n"
|
|
219
|
+
if memory.timestamp:
|
|
220
|
+
detailed_content += f"- **Timestamp:** {memory.timestamp}\n"
|
|
221
|
+
if memory.memory_id:
|
|
222
|
+
detailed_content += f"- **ID:** `{memory.memory_id}`\n"
|
|
223
|
+
detailed_content += "\n"
|
|
224
|
+
|
|
225
|
+
ui_component = UiComponent(
|
|
226
|
+
rich_component=CardComponent(
|
|
227
|
+
title=f"🧠 Memory Search: {len(results)} Result(s)",
|
|
228
|
+
content=detailed_content.strip(),
|
|
229
|
+
icon="🔍",
|
|
230
|
+
status="info",
|
|
231
|
+
collapsible=True,
|
|
232
|
+
collapsed=True, # Start collapsed to avoid clutter
|
|
233
|
+
markdown=True, # Render content as markdown
|
|
234
|
+
),
|
|
235
|
+
simple_component=None,
|
|
236
|
+
)
|
|
237
|
+
else:
|
|
238
|
+
# Non-admin view: Simple status message
|
|
239
|
+
ui_component = UiComponent(
|
|
240
|
+
rich_component=StatusBarUpdateComponent(
|
|
241
|
+
status="success",
|
|
242
|
+
message=f"Found {len(results)} similar pattern(s)",
|
|
243
|
+
detail="Retrieved from agent memory",
|
|
244
|
+
),
|
|
245
|
+
simple_component=None,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
return ToolResult(
|
|
249
|
+
success=True,
|
|
250
|
+
result_for_llm=results_text.strip(),
|
|
251
|
+
ui_component=ui_component,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
except Exception as e:
|
|
255
|
+
error_message = f"Failed to search memories: {str(e)}"
|
|
256
|
+
return ToolResult(
|
|
257
|
+
success=False,
|
|
258
|
+
result_for_llm=error_message,
|
|
259
|
+
ui_component=UiComponent(
|
|
260
|
+
rich_component=StatusBarUpdateComponent(
|
|
261
|
+
status="error", message="Failed to search memory", detail=str(e)
|
|
262
|
+
),
|
|
263
|
+
simple_component=None,
|
|
264
|
+
),
|
|
265
|
+
error=str(e),
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class SaveTextMemoryTool(Tool[SaveTextMemoryParams]):
|
|
270
|
+
"""Tool for saving free-form text memories."""
|
|
271
|
+
|
|
272
|
+
@property
|
|
273
|
+
def name(self) -> str:
|
|
274
|
+
return "save_text_memory"
|
|
275
|
+
|
|
276
|
+
@property
|
|
277
|
+
def description(self) -> str:
|
|
278
|
+
return "Save free-form text memory for important insights, observations, or context"
|
|
279
|
+
|
|
280
|
+
def get_args_schema(self) -> Type[SaveTextMemoryParams]:
|
|
281
|
+
return SaveTextMemoryParams
|
|
282
|
+
|
|
283
|
+
async def execute(
|
|
284
|
+
self, context: ToolContext, args: SaveTextMemoryParams
|
|
285
|
+
) -> ToolResult:
|
|
286
|
+
"""Save a text memory to agent memory."""
|
|
287
|
+
try:
|
|
288
|
+
text_memory = await context.agent_memory.save_text_memory(
|
|
289
|
+
content=args.content, context=context
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
success_msg = (
|
|
293
|
+
f"Successfully saved text memory with ID: {text_memory.memory_id}"
|
|
294
|
+
)
|
|
295
|
+
return ToolResult(
|
|
296
|
+
success=True,
|
|
297
|
+
result_for_llm=success_msg,
|
|
298
|
+
ui_component=UiComponent(
|
|
299
|
+
rich_component=StatusBarUpdateComponent(
|
|
300
|
+
status="success",
|
|
301
|
+
message="Saved text memory",
|
|
302
|
+
detail=f"ID: {text_memory.memory_id}",
|
|
303
|
+
),
|
|
304
|
+
simple_component=None,
|
|
305
|
+
),
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
except Exception as e:
|
|
309
|
+
error_message = f"Failed to save text memory: {str(e)}"
|
|
310
|
+
return ToolResult(
|
|
311
|
+
success=False,
|
|
312
|
+
result_for_llm=error_message,
|
|
313
|
+
ui_component=UiComponent(
|
|
314
|
+
rich_component=StatusBarUpdateComponent(
|
|
315
|
+
status="error",
|
|
316
|
+
message="Failed to save text memory",
|
|
317
|
+
detail=str(e),
|
|
318
|
+
),
|
|
319
|
+
simple_component=None,
|
|
320
|
+
),
|
|
321
|
+
error=str(e),
|
|
322
|
+
)
|