Full Code of vanna-ai/vanna for AI

main 365d0617c1a4 cached
355 files
2.3 MB
619.3k tokens
2076 symbols
1 requests
Download .txt
Showing preview only (2,469K chars total). Download the full file or copy to clipboard to get everything.
Repository: vanna-ai/vanna
Branch: main
Commit: 365d0617c1a4
Files: 355
Total size: 2.3 MB

Directory structure:
gitextract_qmlqs8x4/

├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   └── workflows/
│       ├── python-publish.yaml
│       └── tests.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTING.md
├── LICENSE
├── MIGRATION_GUIDE.md
├── README.md
├── README_LEGACY.md
├── examples/
│   ├── chromadb_gpu_example.py
│   └── transform_args_example.py
├── frontends/
│   └── webcomponent/
│       ├── .storybook/
│       │   ├── main.ts
│       │   ├── preview-head.html
│       │   └── preview.ts
│       ├── TEST_README.md
│       ├── package.json
│       ├── requirements-test.txt
│       ├── scripts/
│       │   └── sync-version.js
│       ├── src/
│       │   ├── components/
│       │   │   ├── button.stories.ts
│       │   │   ├── dataframe-component.stories.ts
│       │   │   ├── plotly-chart.stories.ts
│       │   │   ├── plotly-chart.ts
│       │   │   ├── rich-card.stories.ts
│       │   │   ├── rich-card.ts
│       │   │   ├── rich-component-system.stories.ts
│       │   │   ├── rich-component-system.ts
│       │   │   ├── rich-progress-bar.stories.ts
│       │   │   ├── rich-progress-bar.ts
│       │   │   ├── rich-task-list.stories.ts
│       │   │   ├── rich-task-list.ts
│       │   │   ├── vanna-chat.stories.ts
│       │   │   ├── vanna-chat.ts
│       │   │   ├── vanna-message.stories.ts
│       │   │   ├── vanna-message.ts
│       │   │   ├── vanna-progress-tracker.stories.ts
│       │   │   ├── vanna-progress-tracker.ts
│       │   │   ├── vanna-status-bar.stories.ts
│       │   │   └── vanna-status-bar.ts
│       │   ├── index.ts
│       │   ├── services/
│       │   │   └── api-client.ts
│       │   ├── styles/
│       │   │   ├── rich-component-styles.ts
│       │   │   └── vanna-design-tokens.ts
│       │   └── vite-env.d.ts
│       ├── test-comprehensive.html
│       ├── test_backend.py
│       ├── tsconfig.json
│       └── vite.config.ts
├── notebooks/
│   └── quickstart.ipynb
├── papers/
│   └── ai-sql-accuracy-2023-08-17.md
├── pyproject.toml
├── setup.cfg
├── src/
│   ├── evals/
│   │   ├── benchmarks/
│   │   │   └── llm_comparison.py
│   │   └── datasets/
│   │       └── sql_generation/
│   │           └── basic.yaml
│   └── vanna/
│       ├── __init__.py
│       ├── agents/
│       │   └── __init__.py
│       ├── capabilities/
│       │   ├── __init__.py
│       │   ├── agent_memory/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── file_system/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   └── sql_runner/
│       │       ├── __init__.py
│       │       ├── base.py
│       │       └── models.py
│       ├── components/
│       │   ├── __init__.py
│       │   ├── base.py
│       │   ├── rich/
│       │   │   ├── __init__.py
│       │   │   ├── containers/
│       │   │   │   ├── __init__.py
│       │   │   │   └── card.py
│       │   │   ├── data/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── chart.py
│       │   │   │   └── dataframe.py
│       │   │   ├── feedback/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── badge.py
│       │   │   │   ├── icon_text.py
│       │   │   │   ├── log_viewer.py
│       │   │   │   ├── notification.py
│       │   │   │   ├── progress.py
│       │   │   │   ├── status_card.py
│       │   │   │   └── status_indicator.py
│       │   │   ├── interactive/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── button.py
│       │   │   │   ├── task_list.py
│       │   │   │   └── ui_state.py
│       │   │   ├── specialized/
│       │   │   │   ├── __init__.py
│       │   │   │   └── artifact.py
│       │   │   └── text.py
│       │   └── simple/
│       │       ├── __init__.py
│       │       ├── image.py
│       │       ├── link.py
│       │       └── text.py
│       ├── core/
│       │   ├── __init__.py
│       │   ├── _compat.py
│       │   ├── agent/
│       │   │   ├── __init__.py
│       │   │   ├── agent.py
│       │   │   └── config.py
│       │   ├── audit/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── component_manager.py
│       │   ├── components.py
│       │   ├── enhancer/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── default.py
│       │   ├── enricher/
│       │   │   ├── __init__.py
│       │   │   └── base.py
│       │   ├── errors.py
│       │   ├── evaluation/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   ├── dataset.py
│       │   │   ├── evaluators.py
│       │   │   ├── report.py
│       │   │   └── runner.py
│       │   ├── filter/
│       │   │   ├── __init__.py
│       │   │   └── base.py
│       │   ├── lifecycle/
│       │   │   ├── __init__.py
│       │   │   └── base.py
│       │   ├── llm/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── middleware/
│       │   │   ├── __init__.py
│       │   │   └── base.py
│       │   ├── observability/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── recovery/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── registry.py
│       │   ├── rich_component.py
│       │   ├── simple_component.py
│       │   ├── storage/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── system_prompt/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── default.py
│       │   ├── tool/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── user/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   ├── models.py
│       │   │   ├── request_context.py
│       │   │   └── resolver.py
│       │   ├── validation.py
│       │   └── workflow/
│       │       ├── __init__.py
│       │       ├── base.py
│       │       └── default.py
│       ├── examples/
│       │   ├── __init__.py
│       │   ├── __main__.py
│       │   ├── anthropic_quickstart.py
│       │   ├── artifact_example.py
│       │   ├── claude_sqlite_example.py
│       │   ├── coding_agent_example.py
│       │   ├── custom_system_prompt_example.py
│       │   ├── default_workflow_handler_example.py
│       │   ├── email_auth_example.py
│       │   ├── evaluation_example.py
│       │   ├── extensibility_example.py
│       │   ├── minimal_example.py
│       │   ├── mock_auth_example.py
│       │   ├── mock_custom_tool.py
│       │   ├── mock_quickstart.py
│       │   ├── mock_quota_example.py
│       │   ├── mock_rich_components_demo.py
│       │   ├── mock_sqlite_example.py
│       │   ├── openai_quickstart.py
│       │   ├── primitive_components_demo.py
│       │   ├── quota_lifecycle_example.py
│       │   └── visualization_example.py
│       ├── integrations/
│       │   ├── __init__.py
│       │   ├── anthropic/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── azureopenai/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── azuresearch/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── bigquery/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── chromadb/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── clickhouse/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── duckdb/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── faiss/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── google/
│       │   │   ├── __init__.py
│       │   │   └── gemini.py
│       │   ├── hive/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── local/
│       │   │   ├── __init__.py
│       │   │   ├── agent_memory/
│       │   │   │   ├── __init__.py
│       │   │   │   └── in_memory.py
│       │   │   ├── audit.py
│       │   │   ├── file_system.py
│       │   │   ├── file_system_conversation_store.py
│       │   │   └── storage.py
│       │   ├── marqo/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── milvus/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── mock/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── mssql/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── mysql/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── ollama/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── openai/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   └── responses.py
│       │   ├── opensearch/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── oracle/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── pinecone/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── plotly/
│       │   │   ├── __init__.py
│       │   │   └── chart_generator.py
│       │   ├── postgres/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── premium/
│       │   │   └── agent_memory/
│       │   │       ├── __init__.py
│       │   │       └── premium.py
│       │   ├── presto/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── qdrant/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── snowflake/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── sqlite/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   └── weaviate/
│       │       ├── __init__.py
│       │       └── agent_memory.py
│       ├── legacy/
│       │   ├── ZhipuAI/
│       │   │   ├── ZhipuAI_Chat.py
│       │   │   ├── ZhipuAI_embeddings.py
│       │   │   └── __init__.py
│       │   ├── __init__.py
│       │   ├── adapter.py
│       │   ├── advanced/
│       │   │   └── __init__.py
│       │   ├── anthropic/
│       │   │   ├── __init__.py
│       │   │   └── anthropic_chat.py
│       │   ├── azuresearch/
│       │   │   ├── __init__.py
│       │   │   └── azuresearch_vector.py
│       │   ├── base/
│       │   │   ├── __init__.py
│       │   │   └── base.py
│       │   ├── bedrock/
│       │   │   ├── __init__.py
│       │   │   └── bedrock_converse.py
│       │   ├── chromadb/
│       │   │   ├── __init__.py
│       │   │   └── chromadb_vector.py
│       │   ├── cohere/
│       │   │   ├── __init__.py
│       │   │   ├── cohere_chat.py
│       │   │   └── cohere_embeddings.py
│       │   ├── deepseek/
│       │   │   ├── __init__.py
│       │   │   └── deepseek_chat.py
│       │   ├── exceptions/
│       │   │   └── __init__.py
│       │   ├── faiss/
│       │   │   ├── __init__.py
│       │   │   └── faiss.py
│       │   ├── flask/
│       │   │   ├── __init__.py
│       │   │   ├── assets.py
│       │   │   └── auth.py
│       │   ├── google/
│       │   │   ├── __init__.py
│       │   │   ├── bigquery_vector.py
│       │   │   └── gemini_chat.py
│       │   ├── hf/
│       │   │   ├── __init__.py
│       │   │   └── hf.py
│       │   ├── local.py
│       │   ├── marqo/
│       │   │   ├── __init__.py
│       │   │   └── marqo.py
│       │   ├── milvus/
│       │   │   ├── __init__.py
│       │   │   └── milvus_vector.py
│       │   ├── mistral/
│       │   │   ├── __init__.py
│       │   │   └── mistral.py
│       │   ├── mock/
│       │   │   ├── __init__.py
│       │   │   ├── embedding.py
│       │   │   ├── llm.py
│       │   │   └── vectordb.py
│       │   ├── ollama/
│       │   │   ├── __init__.py
│       │   │   └── ollama.py
│       │   ├── openai/
│       │   │   ├── __init__.py
│       │   │   ├── openai_chat.py
│       │   │   └── openai_embeddings.py
│       │   ├── opensearch/
│       │   │   ├── __init__.py
│       │   │   ├── opensearch_vector.py
│       │   │   └── opensearch_vector_semantic.py
│       │   ├── oracle/
│       │   │   ├── __init__.py
│       │   │   └── oracle_vector.py
│       │   ├── pgvector/
│       │   │   ├── __init__.py
│       │   │   └── pgvector.py
│       │   ├── pinecone/
│       │   │   ├── __init__.py
│       │   │   └── pinecone_vector.py
│       │   ├── qdrant/
│       │   │   ├── __init__.py
│       │   │   └── qdrant.py
│       │   ├── qianfan/
│       │   │   ├── Qianfan_Chat.py
│       │   │   ├── Qianfan_embeddings.py
│       │   │   └── __init__.py
│       │   ├── qianwen/
│       │   │   ├── QianwenAI_chat.py
│       │   │   ├── QianwenAI_embeddings.py
│       │   │   └── __init__.py
│       │   ├── remote.py
│       │   ├── types/
│       │   │   └── __init__.py
│       │   ├── utils.py
│       │   ├── vannadb/
│       │   │   ├── __init__.py
│       │   │   └── vannadb_vector.py
│       │   ├── vllm/
│       │   │   ├── __init__.py
│       │   │   └── vllm.py
│       │   ├── weaviate/
│       │   │   ├── __init__.py
│       │   │   └── weaviate_vector.py
│       │   └── xinference/
│       │       ├── __init__.py
│       │       └── xinference.py
│       ├── py.typed
│       ├── servers/
│       │   ├── __init__.py
│       │   ├── __main__.py
│       │   ├── base/
│       │   │   ├── __init__.py
│       │   │   ├── chat_handler.py
│       │   │   ├── models.py
│       │   │   ├── rich_chat_handler.py
│       │   │   └── templates.py
│       │   ├── cli/
│       │   │   ├── __init__.py
│       │   │   └── server_runner.py
│       │   ├── fastapi/
│       │   │   ├── __init__.py
│       │   │   ├── app.py
│       │   │   └── routes.py
│       │   └── flask/
│       │       ├── __init__.py
│       │       ├── app.py
│       │       └── routes.py
│       ├── tools/
│       │   ├── __init__.py
│       │   ├── agent_memory.py
│       │   ├── file_system.py
│       │   ├── python.py
│       │   ├── run_sql.py
│       │   └── visualize_data.py
│       ├── utils/
│       │   └── __init__.py
│       └── web_components/
│           └── __init__.py
├── tests/
│   ├── conftest.py
│   ├── test_agent_memory.py
│   ├── test_agent_memory_sanity.py
│   ├── test_agents.py
│   ├── test_azureopenai_llm.py
│   ├── test_chromadb_persistence_fix.py
│   ├── test_database_sanity.py
│   ├── test_gemini_integration.py
│   ├── test_legacy_adapter.py
│   ├── test_llm_context_enhancer.py
│   ├── test_memory_tools.py
│   ├── test_ollama_direct.py
│   ├── test_tool_permissions.py
│   └── test_workflow.py
└── tox.ini

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
*.ipynb linguist-detectable=false


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ["bug"]
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Error logs/Screenshots**
If applicable, add logs/screenshots to give more information about the issue.

**Desktop (please complete the following information where):**
 - OS: [e.g. Ubuntu]
 - Version: [e.g. 20.04]
 - Python: [3.9]
 - Vanna: [2.8.0]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ["enhancements"]
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/workflows/python-publish.yaml
================================================
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Upload Python Package

on:
  release:
    types: [published]

permissions:
  contents: read

jobs:
  deploy:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python
      uses: actions/setup-python@v3
      with:
        python-version: '3.x'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install build
    - name: Build package
      run: python -m build
    - name: Publish package
      uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}

================================================
FILE: .github/workflows/tests.yml
================================================
name: Basic Integration Tests

on:
  push:
    branches:
      - main

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python 3.11
      uses: actions/setup-python@v5
      with:
        python-version: "3.11"
    - name: Install pip
      run: |
        python -m pip install --upgrade pip
        pip install tox
    - name: Run tests
      env:
        PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION: python
        VANNA_API_KEY: ${{ secrets.VANNA_API_KEY }}
        OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
        ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
        SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
        SNOWFLAKE_USERNAME: ${{ secrets.SNOWFLAKE_USERNAME }}
        SNOWFLAKE_PASSWORD: ${{ secrets.SNOWFLAKE_PASSWORD }}
      run: tox


================================================
FILE: .gitignore
================================================
build
**.egg-info
venn
.DS_Store
tests/__pycache__
__pycache__/
.idea
.coverage
docs/*.html
.ipynb_checkpoints/
.tox/
notebooks/chroma.sqlite3
dist
.env
*.sqlite
htmlcov
chroma.sqlite3
*.bin
.coverage.*
milvus.db
.milvus.db.lock

# Frontend builds and dependencies
frontends/**/node_modules/
frontends/**/static/
frontends/**/.storybook-static/
frontends/**/package-lock.json
frontends/**/.mypy_cache/


================================================
FILE: .pre-commit-config.yaml
================================================
exclude: 'docs|node_modules|migrations|.git|.tox|assets.py'
default_stages: [ commit ]
fail_fast: true

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v3.2.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-merge-conflict
      - id: debug-statements
      - id: mixed-line-ending

  - repo: https://github.com/pycqa/isort
    rev: 5.12.0
    hooks:
      - id: isort
        args: [ "--profile", "black", "--filter-files" ]


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Vanna

Thank you for your interest in contributing to Vanna! This guide will help you get started with contributing to the Vanna 2.0+ codebase.

## Table of Contents

- [Getting Started](#getting-started)
- [Development Setup](#development-setup)
- [Code Standards](#code-standards)
- [Testing](#testing)
- [Pull Request Process](#pull-request-process)
- [Architecture Overview](#architecture-overview)
- [Adding New Features](#adding-new-features)

---

## Getting Started

### Prerequisites

- Python 3.11 or higher
- Git
- A GitHub account

### Fork and Clone

1. Fork the repository on GitHub
2. Clone your fork locally:
   ```bash
   git clone https://github.com/YOUR_USERNAME/vanna.git
   cd vanna
   ```

3. Add the upstream repository:
   ```bash
   git remote add upstream https://github.com/vanna-ai/vanna.git
   ```

---

## Development Setup

### 1. Create a Virtual Environment

```bash
python3 -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
```

### 2. Install Dependencies

```bash
# Install the package in editable mode with all extras
pip install -e ".[all]"

# Install development tools
pip install tox ruff mypy pytest pytest-asyncio
```

### 3. Verify Installation

```bash
# Run unit tests
tox -e py311-unit

# Run type checking
tox -e mypy

# Run format checking
tox -e ruff
```

---

## Code Standards

### Formatting

We use [ruff](https://github.com/astral-sh/ruff) for code formatting and linting.

```bash
# Check formatting
ruff format --check src/vanna/ tests/

# Apply formatting
ruff format src/vanna/ tests/

# Run linting
ruff check src/vanna/ tests/
```

### Type Checking

We use mypy with strict mode for type checking:

```bash
tox -e mypy
```

All new code should include type hints.

### Code Style Guidelines

- Follow PEP 8 style guidelines
- Use descriptive variable and function names
- Add docstrings to all public functions and classes
- Keep functions focused and single-purpose
- Avoid circular imports by using `TYPE_CHECKING`

**Example:**

```python
"""Module docstring explaining the purpose."""

from typing import TYPE_CHECKING, Optional

if TYPE_CHECKING:
    from vanna.core.user import User

class MyClass:
    """Class docstring explaining what this class does."""

    async def my_method(self, user: "User", count: int = 10) -> Optional[str]:
        """Method docstring explaining parameters and return value.

        Args:
            user: The user making the request
            count: Maximum number of items to return

        Returns:
            Result string if found, None otherwise
        """
        pass
```

---

## Testing

### Test Organization

Tests are organized in the `tests/` directory:

- `test_tool_permissions.py` - Tool access control tests
- `test_llm_context_enhancer.py` - LLM enhancer tests
- `test_legacy_adapter.py` - Legacy compatibility tests
- `test_agent_memory.py` - Agent memory tests
- `test_database_sanity.py` - Database integration tests
- `test_agents.py` - End-to-end agent tests

### Running Tests

```bash
# Run all unit tests (no external dependencies)
tox -e py311-unit

# Run specific test file
pytest tests/test_tool_permissions.py -v

# Run tests with a specific marker
pytest tests/ -v -m anthropic

# Run legacy adapter tests
tox -e py311-legacy
```

### Writing Tests

1. **Unit tests** should not require external dependencies (databases, APIs, etc.)
2. Use **pytest markers** for tests that require external services:
   ```python
   @pytest.mark.anthropic
   @pytest.mark.asyncio
   async def test_with_anthropic():
       # Test code here
       pass
   ```

3. **Mock external dependencies** in unit tests:
   ```python
   class MockLlmService(LlmService):
       async def send_request(self, request):
           # Mock implementation
           pass
   ```

4. **Test both success and failure cases**
5. **Use descriptive test names** that explain what is being tested

### Test Coverage

When adding new features, ensure:
- Core functionality is covered by unit tests
- Integration points are tested
- Error handling is validated
- Edge cases are considered

---

## Pull Request Process

### 1. Create a Feature Branch

```bash
git checkout -b feature/my-new-feature
# or
git checkout -b fix/bug-description
```

### 2. Make Your Changes

- Write your code following the code standards
- Add tests for your changes
- Update documentation as needed

### 3. Run All Checks

```bash
# Format code
ruff format src/vanna/ tests/

# Run linting
ruff check src/vanna/ tests/

# Run type checking
tox -e mypy

# Run tests
tox -e py311-unit
```

### 4. Commit Your Changes

Use clear, descriptive commit messages:

```bash
git add .
git commit -m "feat: add new LLM context enhancer for RAG

- Implements TextMemoryEnhancer class
- Adds tests for memory retrieval
- Updates documentation"
```

**Commit message format:**
- `feat:` - New feature
- `fix:` - Bug fix
- `docs:` - Documentation changes
- `test:` - Adding or updating tests
- `refactor:` - Code refactoring
- `chore:` - Maintenance tasks

### 5. Push and Create PR

```bash
git push origin feature/my-new-feature
```

Then create a pull request on GitHub with:
- Clear title describing the change
- Description of what was changed and why
- Link to any related issues
- Screenshots or examples if applicable

### 6. Code Review

- Address review feedback promptly
- Keep discussions focused and professional
- Be open to suggestions and alternative approaches

---

## Architecture Overview

### Core Components

Vanna 2.0+ is built around several key abstractions:

#### 1. **Agent** (`vanna.core.agent`)
The main orchestrator that coordinates tools, memory, and LLM interactions.

#### 2. **Tools** (`vanna.tools`, `vanna.core.tool`)
Modular capabilities that the agent can use. Each tool:
- Has a schema defining its inputs
- Implements an `execute()` method
- Declares access control via `access_groups`

#### 3. **Tool Registry** (`vanna.core.registry`)
Manages tool registration and access control.

#### 4. **Agent Memory** (`vanna.capabilities.agent_memory`)
Stores and retrieves tool usage patterns and documentation.

#### 5. **LLM Services** (`vanna.core.llm`)
Abstract interface for different LLM providers (Anthropic, OpenAI, etc.).

#### 6. **SQL Runners** (`vanna.capabilities.sql_runner`)
Abstract interface for executing SQL against different databases.

#### 7. **Components** (`vanna.components`)
Rich UI components for rendering results (tables, charts, status cards, etc.).

### Data Flow

```
User Request → Agent → LLM Service → Tool Selection → Tool Execution → Response Components
                ↓                                           ↓
          Agent Memory                              SQL Runner / Other Capabilities
```

---

## Adding New Features

### Adding a New Tool

1. **Create the tool class** in `src/vanna/tools/`:

```python
from vanna.core.tool import Tool, ToolContext, ToolResult
from pydantic import BaseModel, Field

class MyToolArgs(BaseModel):
    """Arguments for my tool."""
    query: str = Field(description="The query to process")

class MyTool(Tool[MyToolArgs]):
    """Tool that does something useful."""

    @property
    def name(self) -> str:
        return "my_tool"

    @property
    def description(self) -> str:
        return "Does something useful with a query"

    def get_args_schema(self) -> type[MyToolArgs]:
        return MyToolArgs

    async def execute(
        self,
        context: ToolContext,
        args: MyToolArgs
    ) -> ToolResult:
        # Implement your tool logic
        result = f"Processed: {args.query}"

        return ToolResult(
            success=True,
            result_for_llm=result,
            ui_component=None
        )
```

2. **Add tests** in `tests/test_my_tool.py`

3. **Register the tool** in examples or documentation

### Adding a New Database Integration

1. **Implement SqlRunner** in `src/vanna/integrations/mydb/`:

```python
from vanna.capabilities.sql_runner import SqlRunner, RunSqlToolArgs
from vanna.core.tool import ToolContext
import pandas as pd

class MyDbRunner(SqlRunner):
    """SQL runner for MyDB database."""

    def __init__(self, connection_string: str):
        self.connection_string = connection_string
        # Initialize your DB connection

    async def run_sql(
        self,
        args: RunSqlToolArgs,
        context: ToolContext
    ) -> pd.DataFrame:
        # Execute SQL and return DataFrame
        pass
```

2. **Add sanity tests** in `tests/test_database_sanity.py`

3. **Add tox target** in `tox.ini`

4. **Update documentation**

### Adding a New LLM Integration

1. **Implement LlmService** in `src/vanna/integrations/myllm/`:

```python
from vanna.core.llm.base import LlmService
from vanna.core.llm.models import LlmRequest, LlmResponse, LlmStreamChunk
from typing import AsyncGenerator

class MyLlmService(LlmService):
    """LLM service for MyLLM provider."""

    def __init__(self, api_key: str, model: str = "default"):
        self.api_key = api_key
        self.model = model

    async def send_request(self, request: LlmRequest) -> LlmResponse:
        # Implement API call
        pass

    async def stream_request(
        self,
        request: LlmRequest
    ) -> AsyncGenerator[LlmStreamChunk, None]:
        # Implement streaming API call
        yield LlmStreamChunk(...)

    async def validate_tools(self, tools) -> list[str]:
        # Validate tool schemas
        return []
```

2. **Add tests** with the `@pytest.mark.myllm` marker

3. **Add tox target** for integration tests

### Adding a New Agent Memory Backend

1. **Implement AgentMemory** in `src/vanna/integrations/mystore/`:

```python
from vanna.capabilities.agent_memory import (
    AgentMemory,
    ToolMemory,
    ToolMemorySearchResult,
    TextMemory,
    TextMemorySearchResult
)
from vanna.core.tool import ToolContext

class MyStoreMemory(AgentMemory):
    """Agent memory using MyStore vector database."""

    async def save_tool_usage(self, question, tool_name, args, context, success=True, metadata=None):
        # Implement storage
        pass

    async def search_similar_usage(self, question, context, *, limit=10, similarity_threshold=0.7, tool_name_filter=None):
        # Implement search
        pass

    # Implement other AgentMemory methods...
```

2. **Add tests** in `tests/test_agent_memory.py`

3. **Add to extras** in `pyproject.toml`

---

## Legacy Compatibility

If you're working on legacy VannaBase compatibility:

- The `LegacyVannaAdapter` bridges legacy code with Vanna 2.0+
- Add tests to `tests/test_legacy_adapter.py`
- See `src/vanna/legacy/adapter.py` for examples

---

## Getting Help

- **Documentation**: https://vanna.ai/docs/
- **GitHub Issues**: https://github.com/vanna-ai/vanna/issues
- **Discussions**: https://github.com/vanna-ai/vanna/discussions

---

## License

By contributing to Vanna, you agree that your contributions will be licensed under the MIT License.

---

Thank you for contributing to Vanna! 🎉


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2024 Vanna.AI

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: MIGRATION_GUIDE.md
================================================
# Migration Guide: Vanna 0.x to Vanna 2.0+

This guide will help you migrate from Vanna 0.x (legacy) to Vanna 2.0+, the new user-aware agent framework.

## Table of Contents
- [Overview of Changes](#overview-of-changes)
- [Quick Migration Path](#quick-migration-path)
- [Migration Strategies](#migration-strategies)
  - [Strategy 1: Using the Legacy Adapter (Recommended for Quick Migration)](#strategy-1-using-the-legacy-adapter-recommended-for-quick-migration)
  - [Strategy 2: Full Migration to New Architecture](#strategy-2-full-migration-to-new-architecture)
- [Key Architectural Differences](#key-architectural-differences)
- [API Mapping](#api-mapping)
- [Common Migration Scenarios](#common-migration-scenarios)
- [Breaking Changes](#breaking-changes)
- [FAQ](#faq)

---

## Overview of Changes

Vanna 2.0+ represents a fundamental architectural shift from a simple LLM wrapper to a full-fledged **user-aware agent framework**. Here are the major changes:

### What's New in 2.0+
- ✅ **User awareness** - Identity and permissions flow through every layer
- ✅ **Web component** - Pre-built UI with streaming responses
- ✅ **Tool registry** - Modular, extensible tool system
- ✅ **Rich UI components** - Tables, charts, status cards (not just text)
- ✅ **Streaming by default** - Progressive responses via SSE
- ✅ **Enterprise features** - Audit logs, rate limiting, observability
- ✅ **FastAPI/Flask servers** - Production-ready backends included

### What Changed from 0.x
- ❌ Direct method calls (`vn.ask()`) → Agent-based workflow
- ❌ Monolithic `VannaBase` class → Modular tool system
- ❌ No user context → User-aware at every layer
- ❌ Simple text responses → Rich streaming UI components

---

## Quick Migration Path

**Can't migrate immediately?** Use the Legacy Adapter to get started quickly:

```python
# Assume you already have a working vn object from your Vanna 0.x code:
# vn = MyVanna(config={"model": "gpt-4"})
# vn.connect_to_postgres(...)
# vn.train(ddl="...")

# NEW: Just add these imports and wrap your existing vn object
from vanna import Agent, AgentConfig
from vanna.servers.fastapi import VannaFastAPIServer
from vanna.core.user import UserResolver, User, RequestContext
from vanna.legacy.adapter import LegacyVannaAdapter
from vanna.integrations.anthropic import AnthropicLlmService

# Define simple user resolver
class SimpleUserResolver(UserResolver):
    async def resolve_user(self, request_context: RequestContext) -> User:
        user_email = request_context.get_cookie('vanna_email')
        return User(id=user_email, email=user_email, group_memberships=['user'])

# Wrap your existing vn with the adapter
tools = LegacyVannaAdapter(vn)

# Create agent with new LLM service
llm = AnthropicLlmService(model="claude-haiku-4-5")
agent = Agent(llm_service=llm, tool_registry=tools, user_resolver=SimpleUserResolver())

# Run server
server = VannaFastAPIServer(agent)
server.run(host='0.0.0.0', port=8000)

# Now it works with the new Agent framework!
# (See Strategy 1 below for complete example)
```

---

## Migration Strategies

### Strategy 1: Using the Legacy Adapter (Recommended for Quick Migration)

**Best for:** Teams that want to adopt Vanna 2.0+ gradually while maintaining existing code.

#### Step 1: Install Vanna 2.0+

```bash
pip install 'vanna[flask,anthropic]'
```

#### Step 2: Wrap Your Existing VannaBase Instance

```python
from vanna import Agent, AgentConfig
from vanna.servers.fastapi import VannaFastAPIServer
from vanna.core.user import UserResolver, User, RequestContext
from vanna.legacy.adapter import LegacyVannaAdapter
from vanna.integrations.anthropic import AnthropicLlmService

# Assume you already have a working vn object from your existing code:
# vn = MyVanna(config={'model': 'gpt-4', 'api_key': 'your-key'})
# vn.connect_to_postgres(...)
# vn.train(ddl="...")
# etc.

# NEW: Define user resolution (required in 2.0+)
class SimpleUserResolver(UserResolver):
    async def resolve_user(self, request_context: RequestContext) -> User:
        user_email = request_context.get_cookie('vanna_email')
        if not user_email:
            raise ValueError("Missing 'vanna_email' cookie")

        # Admin users get 'admin' group membership
        if user_email == "admin@example.com":
            return User(id="admin_user", email=user_email, group_memberships=['admin'])

        # Regular users get 'user' group membership
        return User(id=user_email, email=user_email, group_memberships=['user'])

# NEW: Wrap with legacy adapter
# This automatically registers run_sql and memory tools from your VannaBase instance
tools = LegacyVannaAdapter(vn)

# NEW: Set up LLM for the new Agent framework
llm = AnthropicLlmService(
    model="claude-haiku-4-5",
    api_key="YOUR_ANTHROPIC_API_KEY"
)

# NEW: Create agent with legacy adapter as tool registry
agent = Agent(
    llm_service=llm,
    tool_registry=tools,  # LegacyVannaAdapter is a ToolRegistry
    user_resolver=SimpleUserResolver(),
    config=AgentConfig()
)

# NEW: Create and run server
server = VannaFastAPIServer(agent)

if __name__ == "__main__":
    # Run with: python your_script.py
    # Or: uvicorn your_module:server --host 0.0.0.0 --port 8000
    server.run(host='0.0.0.0', port=8000)
```

**What the LegacyVannaAdapter does:**
- Automatically wraps `vn.run_sql()` as the `run_sql` tool (available to 'user' and 'admin' groups)
- Exposes training data from `vn.get_training_data()` as searchable memory (via `search_saved_correct_tool_uses` tool)
- Optionally allows saving new training data (via `save_question_tool_args` tool - admin only)
- Maintains your existing database connection and training data

**Pros:**
- ✅ Minimal code changes
- ✅ Preserve existing training data
- ✅ Gradual migration path
- ✅ Get new features (web UI, streaming) immediately

**Cons:**
- ⚠️ Limited user awareness (all requests use same VannaBase instance)
- ⚠️ Can't leverage row-level security
- ⚠️ Missing some advanced features

---

### Strategy 2: Full Migration to New Architecture

**Best for:** New projects or teams ready for a complete rewrite.

#### Before (Vanna 0.x)

```python
from vanna import VannaBase
from vanna.openai_chat import OpenAI_Chat
from vanna.chromadb import ChromaDB_VectorStore

class MyVanna(ChromaDB_VectorStore, OpenAI_Chat):
    def __init__(self, config=None):
        ChromaDB_VectorStore.__init__(self, config=config)
        OpenAI_Chat.__init__(self, config=config)

vn = MyVanna(config={'model': 'gpt-4', 'api_key': 'your-key'})
vn.connect_to_postgres(...)

# Train
vn.train(ddl="CREATE TABLE customers ...")
vn.train(question="Top customers?", sql="SELECT ...")

# Ask
sql = vn.generate_sql("Who are the top customers?")
df = vn.run_sql(sql)
print(df)
```

#### After (Vanna 2.0+)

```python
from vanna import Agent, AgentConfig
from vanna.servers.fastapi import VannaFastAPIServer
from vanna.core.registry import ToolRegistry
from vanna.core.user import UserResolver, User, RequestContext
from vanna.integrations.anthropic import AnthropicLlmService
from vanna.tools import RunSqlTool
from vanna.integrations.postgres import PostgresRunner

# 1. Define user resolution
class MyUserResolver(UserResolver):
    async def resolve_user(self, request_context: RequestContext) -> User:
        # Extract from your auth system (JWT, cookies, etc.)
        token = request_context.get_header('Authorization')
        user_data = await self.validate_token(token)

        return User(
            id=user_data['id'],
            email=user_data['email'],
            permissions=user_data['permissions'],
            metadata={'role': user_data['role']}
        )

# 2. Set up tools
tools = ToolRegistry()
postgres_runner = PostgresRunner(
    host="localhost",
    dbname="mydb",
    user="user",
    password="password",
    port=5432
)
tools.register_local_tool(
    RunSqlTool(sql_runner=postgres_runner),
    access_groups=['user', 'admin']
)

# 3. Create agent
llm = AnthropicLlmService(model="claude-sonnet-4-5")
agent = Agent(
    llm_service=llm,
    tool_registry=tools,
    user_resolver=MyUserResolver(),
    config=AgentConfig(stream_responses=True)
)

# 4. Create server
server = VannaFastAPIServer(agent)
app = server.create_app()

# Run with: uvicorn main:app --host 0.0.0.0 --port 8000
# Visit http://localhost:8000 for web UI
```

**Pros:**
- ✅ Full access to new features
- ✅ True user awareness
- ✅ Better security and permissions
- ✅ Production-ready architecture

**Cons:**
- ⚠️ Requires rewriting code
- ⚠️ Need to migrate training data approach
- ⚠️ Steeper learning curve

---

## Key Architectural Differences

| Feature | Vanna 0.x | Vanna 2.0+ |
|---------|-----------|------------|
| **User Context** | None | `User` object with permissions flows through entire system |
| **Interaction Model** | Direct method calls (`vn.ask()`) | Agent-based with streaming components |
| **Tools** | Monolithic methods | Modular `Tool` classes with schemas |
| **Responses** | Plain text/DataFrames | Rich UI components (tables, charts, code) |
| **Training** | `vn.train()` with vector DB | System prompts, context enrichers, RAG tools |
| **Database Connection** | `vn.connect_to_postgres()` | `SqlRunner` implementations as dependencies |
| **Web UI** | None (custom implementation) | Built-in web component + backend |
| **Streaming** | None | Server-Sent Events by default |
| **Permissions** | None | Group-based access control on tools |
| **Audit Logs** | None | Built-in audit logging system |

---

## Summary

| If you want to... | Use this strategy |
|-------------------|-------------------|
| Migrate quickly with minimal changes | **Strategy 1: Legacy Adapter** |
| Get full access to new features | **Strategy 2: Full Migration** |
| Support both legacy and new code | **Strategy 1** initially, then gradual migration |
| Start a new project | **Strategy 2: Full Migration** |

**Recommended Path:**
1. Start with Legacy Adapter for quick migration
2. Gradually rewrite critical paths to native 2.0+ architecture
3. Eventually remove Legacy Adapter once fully migrated

Good luck with your migration! 🚀


================================================
FILE: README.md
================================================
# Vanna 2.0: Turn Questions into Data Insights

**Natural language → SQL → Answers.** Now with enterprise security and user-aware permissions.

[![Python](https://img.shields.io/badge/python-3.8+-blue.svg)](https://python.org)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)

https://github.com/user-attachments/assets/476cd421-d0b0-46af-8b29-0f40c73d6d83


![Vanna2 Demo](img/architecture.png)

---

## What's New in 2.0

🔐 **User-Aware at Every Layer** — Queries automatically filtered per user permissions

🎨 **Modern Web Interface** — Beautiful pre-built `<vanna-chat>` component

⚡ **Streaming Responses** — Real-time tables, charts, and progress updates

🔒 **Enterprise Security** — Row-level security, audit logs, rate limiting

🔄 **Production-Ready** — FastAPI integration, observability, lifecycle hooks

> **Upgrading from 0.x?** See the [Migration Guide](MIGRATION_GUIDE.md) | [What changed?](#migration-notes)

---

## Get Started

### Try it with Sample Data

[Quickstart](https://vanna.ai/docs/quick-start)

### Configure

[Configure](https://vanna.ai/docs/configure)

### Web Component

```html
<!-- Drop into any existing webpage -->
<script src="https://img.vanna.ai/vanna-components.js"></script>
<vanna-chat
  sse-endpoint="https://your-api.com/chat"
  theme="dark">
</vanna-chat>
```

Uses your existing cookies/JWTs. Works with React, Vue, or plain HTML.

---

## What You Get

Ask a question in natural language and get back:

**1. Streaming Progress Updates**

**2. SQL Code Block (By default only shown to "admin" users)**

**3. Interactive Data Table**

**4. Charts** (Plotly visualizations)

**5. Natural Language Summary**

All streamed in real-time to your web component.

---

## Why Vanna 2.0?

### ✅ Get Started Instantly
* Production chat interface
* Custom agent with your database
* Embed in any webpage

### ✅ Enterprise-Ready Security
**User-aware at every layer** — Identity flows through system prompts, tool execution, and SQL filtering
**Row-level security** — Queries automatically filtered per user permissions
**Audit logs** — Every query tracked per user for compliance
**Rate limiting** — Per-user quotas via lifecycle hooks

### ✅ Beautiful Web UI Included
**Pre-built `<vanna-chat>` component** — No need to build your own chat interface
**Streaming tables & charts** — Rich components, not just text
**Responsive & customizable** — Works on mobile, desktop, light/dark themes
**Framework-agnostic** — React, Vue, plain HTML

### ✅ Works With Your Stack
**Any LLM:** OpenAI, Anthropic, Ollama, Azure, Google Gemini, AWS Bedrock, Mistral, Others
**Any Database:** PostgreSQL, MySQL, Snowflake, BigQuery, Redshift, SQLite, Oracle, SQL Server, DuckDB, ClickHouse, Others
**Your Auth System:** Bring your own — cookies, JWTs, OAuth tokens
**Your Framework:** FastAPI, Flask

### ✅ Extensible But Opinionated
**Custom tools** — Extend the `Tool` base class
**Lifecycle hooks** — Quota checking, logging, content filtering
**LLM middlewares** — Caching, prompt engineering
**Observability** — Built-in tracing and metrics

---

## Architecture

![Vanna2 Diagram](img/vanna2.svg)

---

## How It Works

```mermaid
sequenceDiagram
    participant U as 👤 User
    participant W as 🌐 <vanna-chat>
    participant S as 🐍 Your Server
    participant A as 🤖 Agent
    participant T as 🧰 Tools

    U->>W: "Show Q4 sales"
    W->>S: POST /api/vanna/v2/chat_sse (with auth)
    S->>A: User(id=alice, groups=[read_sales])
    A->>T: Execute SQL tool (user-aware)
    T->>T: Apply row-level security
    T->>A: Filtered results
    A->>W: Stream: Table → Chart → Summary
    W->>U: Display beautiful UI
```

**Key Concepts:**

1. **User Resolver** — You define how to extract user identity from requests (cookies, JWTs, etc.)
2. **User-Aware Tools** — Tools automatically check permissions based on user's group memberships
3. **Streaming Components** — Backend streams structured UI components (tables, charts) to frontend
4. **Built-in Web UI** — Pre-built `<vanna-chat>` component renders everything beautifully

---

## Production Setup with Your Auth

Here's a complete example integrating Vanna with your existing FastAPI app and authentication:

```python
from fastapi import FastAPI
from vanna import Agent
from vanna.servers.fastapi.routes import register_chat_routes
from vanna.servers.base import ChatHandler
from vanna.core.user import UserResolver, User, RequestContext
from vanna.integrations.anthropic import AnthropicLlmService
from vanna.tools import RunSqlTool
from vanna.integrations.sqlite import SqliteRunner
from vanna.core.registry import ToolRegistry

# Your existing FastAPI app
app = FastAPI()

# 1. Define your user resolver (using YOUR auth system)
class MyUserResolver(UserResolver):
    async def resolve_user(self, request_context: RequestContext) -> User:
        # Extract from cookies, JWTs, or session
        token = request_context.get_header('Authorization')
        user_data = self.decode_jwt(token)  # Your existing logic

        return User(
            id=user_data['id'],
            email=user_data['email'],
            group_memberships=user_data['groups']  # Used for permissions
        )

# 2. Set up agent with tools
llm = AnthropicLlmService(model="claude-sonnet-4-5")
tools = ToolRegistry()
tools.register(RunSqlTool(sql_runner=SqliteRunner("./data.db")))

agent = Agent(
    llm_service=llm,
    tool_registry=tools,
    user_resolver=MyUserResolver()
)

# 3. Add Vanna routes to your app
chat_handler = ChatHandler(agent)
register_chat_routes(app, chat_handler)

# Now you have:
# - POST /api/vanna/v2/chat_sse (streaming endpoint)
# - GET / (optional web UI)
```

**Then in your frontend:**
```html
<vanna-chat sse-endpoint="/api/vanna/v2/chat_sse"></vanna-chat>
```

See [Full Documentation](https://vanna.ai/docs) for custom tools, lifecycle hooks, and advanced configuration

---

## Custom Tools

Extend Vanna with custom tools for your specific use case:

```python
from vanna.core.tool import Tool, ToolContext, ToolResult
from pydantic import BaseModel, Field
from typing import Type

class EmailArgs(BaseModel):
    recipient: str = Field(description="Email recipient")
    subject: str = Field(description="Email subject")

class EmailTool(Tool[EmailArgs]):
    @property
    def name(self) -> str:
        return "send_email"

    @property
    def access_groups(self) -> list[str]:
        return ["send_email"]  # Permission check

    def get_args_schema(self) -> Type[EmailArgs]:
        return EmailArgs

    async def execute(self, context: ToolContext, args: EmailArgs) -> ToolResult:
        user = context.user  # Automatically injected

        # Your business logic
        await self.email_service.send(
            from_email=user.email,
            to=args.recipient,
            subject=args.subject
        )

        return ToolResult(success=True, result_for_llm=f"Email sent to {args.recipient}")

# Register your tool
tools.register(EmailTool())
```

---

## Advanced Features

Vanna 2.0 includes powerful enterprise features for production use:

**Lifecycle Hooks** — Add quota checking, custom logging, content filtering at key points in the request lifecycle

**LLM Middlewares** — Implement caching, prompt engineering, or cost tracking around LLM calls

**Conversation Storage** — Persist and retrieve conversation history per user

**Observability** — Built-in tracing and metrics integration

**Context Enrichers** — Add RAG, memory, or documentation to enhance agent responses

**Agent Configuration** — Control streaming, temperature, max iterations, and more

---

## Use Cases

**Vanna is ideal for:**
- 📊 Data analytics applications with natural language interfaces
- 🔐 Multi-tenant SaaS needing user-aware permissions
- 🎨 Teams wanting a pre-built web component + backend
- 🏢 Enterprise environments with security/audit requirements
- 📈 Applications needing rich streaming responses (tables, charts, SQL)
- 🔄 Integrating with existing authentication systems

---

## Community & Support

- 📖 **[Full Documentation](https://vanna.ai/docs)** — Complete guides and API reference
- 💡 **[GitHub Discussions](https://github.com/vanna-ai/vanna/discussions)** — Feature requests and Q&A
- 🐛 **[GitHub Issues](https://github.com/vanna-ai/vanna/issues)** — Bug reports
- 📧 **Enterprise Support** — support@vanna.ai

---

## Migration Notes

**Upgrading from Vanna 0.x?**

Vanna 2.0 is a complete rewrite focused on user-aware agents and production deployments. Key changes:

- **New API**: Agent-based instead of `VannaBase` class methods
- **User-aware**: Every component now knows the user identity
- **Streaming**: Rich UI components instead of text/dataframes
- **Web-first**: Built-in `<vanna-chat>` component and server

**Migration path:**

1. **Quick wrap** — Use `LegacyVannaAdapter` to wrap your existing Vanna 0.x instance and get the new web UI immediately
2. **Gradual migration** — Incrementally move to the new Agent API and tools

See the complete [Migration Guide](MIGRATION_GUIDE.md) for step-by-step instructions.

---

## License

MIT License — See [LICENSE](LICENSE) for details.

---

**Built with ❤️ by the Vanna team** | [Website](https://vanna.ai) | [Docs](https://vanna.ai/docs) | [Discussions](https://github.com/vanna-ai/vanna/discussions)


================================================
FILE: README_LEGACY.md
================================================


| GitHub | PyPI | Documentation | Gurubase |
| ------ | ---- | ------------- | -------- |
| [![GitHub](https://img.shields.io/badge/GitHub-vanna-blue?logo=github)](https://github.com/vanna-ai/vanna) | [![PyPI](https://img.shields.io/pypi/v/vanna?logo=pypi)](https://pypi.org/project/vanna/) | [![Documentation](https://img.shields.io/badge/Documentation-vanna-blue?logo=read-the-docs)](https://vanna.ai/docs/) | [![Gurubase](https://img.shields.io/badge/Gurubase-Ask%20Vanna%20Guru-006BFF)](https://gurubase.io/g/vanna) |

# Vanna
Vanna is an MIT-licensed open-source Python RAG (Retrieval-Augmented Generation) framework for SQL generation and related functionality.

https://github.com/vanna-ai/vanna/assets/7146154/1901f47a-515d-4982-af50-f12761a3b2ce

![vanna-quadrants](https://github.com/vanna-ai/vanna/assets/7146154/1c7c88ba-c144-4ecf-a028-cf5ba7344ca2)

## How Vanna works

![Screen Recording 2024-01-24 at 11 21 37 AM](https://github.com/vanna-ai/vanna/assets/7146154/1d2718ad-12a8-4a76-afa2-c61754462f93)


Vanna works in two easy steps - train a RAG "model" on your data, and then ask questions which will return SQL queries that can be set up to automatically run on your database.

1. **Train a RAG "model" on your data**.
2. **Ask questions**.

![](img/vanna-readme-diagram.png)

If you don't know what RAG is, don't worry -- you don't need to know how this works under the hood to use it. You just need to know that you "train" a model, which stores some metadata and then use it to "ask" questions.

See the [base class](https://github.com/vanna-ai/vanna/blob/main/src/vanna/base/base.py) for more details on how this works under the hood.

## User Interfaces
These are some of the user interfaces that we've built using Vanna. You can use these as-is or as a starting point for your own custom interface.

- [Jupyter Notebook](https://vanna.ai/docs/postgres-openai-vanna-vannadb/)
- [vanna-ai/vanna-streamlit](https://github.com/vanna-ai/vanna-streamlit)
- [vanna-ai/vanna-flask](https://github.com/vanna-ai/vanna-flask)
- [vanna-ai/vanna-slack](https://github.com/vanna-ai/vanna-slack)

## Supported LLMs

- [OpenAI](https://github.com/vanna-ai/vanna/tree/main/src/vanna/openai)
- [Anthropic](https://github.com/vanna-ai/vanna/tree/main/src/vanna/anthropic)
- [Gemini](https://github.com/vanna-ai/vanna/blob/main/src/vanna/google/gemini_chat.py)
- [HuggingFace](https://github.com/vanna-ai/vanna/blob/main/src/vanna/hf/hf.py)
- [AWS Bedrock](https://github.com/vanna-ai/vanna/tree/main/src/vanna/bedrock)
- [Ollama](https://github.com/vanna-ai/vanna/tree/main/src/vanna/ollama)
- [Qianwen](https://github.com/vanna-ai/vanna/tree/main/src/vanna/qianwen)
- [Qianfan](https://github.com/vanna-ai/vanna/tree/main/src/vanna/qianfan)
- [Zhipu](https://github.com/vanna-ai/vanna/tree/main/src/vanna/ZhipuAI)

## Supported VectorStores

- [AzureSearch](https://github.com/vanna-ai/vanna/tree/main/src/vanna/azuresearch)
- [Opensearch](https://github.com/vanna-ai/vanna/tree/main/src/vanna/opensearch)
- [PgVector](https://github.com/vanna-ai/vanna/tree/main/src/vanna/pgvector)
- [PineCone](https://github.com/vanna-ai/vanna/tree/main/src/vanna/pinecone)
- [ChromaDB](https://github.com/vanna-ai/vanna/tree/main/src/vanna/chromadb)
- [FAISS](https://github.com/vanna-ai/vanna/tree/main/src/vanna/faiss)
- [Marqo](https://github.com/vanna-ai/vanna/tree/main/src/vanna/marqo)
- [Milvus](https://github.com/vanna-ai/vanna/tree/main/src/vanna/milvus)
- [Qdrant](https://github.com/vanna-ai/vanna/tree/main/src/vanna/qdrant)
- [Weaviate](https://github.com/vanna-ai/vanna/tree/main/src/vanna/weaviate)
- [Oracle](https://github.com/vanna-ai/vanna/tree/main/src/vanna/oracle)

## Supported Databases

- [PostgreSQL](https://www.postgresql.org/)
- [MySQL](https://www.mysql.com/)
- [PrestoDB](https://prestodb.io/)
- [Apache Hive](https://hive.apache.org/)
- [ClickHouse](https://clickhouse.com/)
- [Snowflake](https://www.snowflake.com/en/)
- [Oracle](https://www.oracle.com/)
- [Microsoft SQL Server](https://www.microsoft.com/en-us/sql-server/sql-server-downloads)
- [BigQuery](https://cloud.google.com/bigquery)
- [SQLite](https://www.sqlite.org/)
- [DuckDB](https://duckdb.org/)


## Getting started
See the [documentation](https://vanna.ai/docs/) for specifics on your desired database, LLM, etc.

If you want to get a feel for how it works after training, you can try this [Colab notebook](https://vanna.ai/docs/app/).


### Install
```bash
pip install vanna
```

There are a number of optional packages that can be installed so see the [documentation](https://vanna.ai/docs/) for more details.

### Import
See the [documentation](https://vanna.ai/docs/) if you're customizing the LLM or vector database.

```python
# The import statement will vary depending on your LLM and vector database. This is an example for OpenAI + ChromaDB

from vanna.openai.openai_chat import OpenAI_Chat
from vanna.chromadb.chromadb_vector import ChromaDB_VectorStore

class MyVanna(ChromaDB_VectorStore, OpenAI_Chat):
    def __init__(self, config=None):
        ChromaDB_VectorStore.__init__(self, config=config)
        OpenAI_Chat.__init__(self, config=config)

vn = MyVanna(config={'api_key': 'sk-...', 'model': 'gpt-4-...'})

# See the documentation for other options

```


## Training
You may or may not need to run these `vn.train` commands depending on your use case. See the [documentation](https://vanna.ai/docs/) for more details.

These statements are shown to give you a feel for how it works.

### Train with DDL Statements
DDL statements contain information about the table names, columns, data types, and relationships in your database.

```python
vn.train(ddl="""
    CREATE TABLE IF NOT EXISTS my-table (
        id INT PRIMARY KEY,
        name VARCHAR(100),
        age INT
    )
""")
```

### Train with Documentation
Sometimes you may want to add documentation about your business terminology or definitions.

```python
vn.train(documentation="Our business defines XYZ as ...")
```

### Train with SQL
You can also add SQL queries to your training data. This is useful if you have some queries already laying around. You can just copy and paste those from your editor to begin generating new SQL.

```python
vn.train(sql="SELECT name, age FROM my-table WHERE name = 'John Doe'")
```


## Asking questions
```python
vn.ask("What are the top 10 customers by sales?")
```

You'll get SQL
```sql
SELECT c.c_name as customer_name,
        sum(l.l_extendedprice * (1 - l.l_discount)) as total_sales
FROM   snowflake_sample_data.tpch_sf1.lineitem l join snowflake_sample_data.tpch_sf1.orders o
        ON l.l_orderkey = o.o_orderkey join snowflake_sample_data.tpch_sf1.customer c
        ON o.o_custkey = c.c_custkey
GROUP BY customer_name
ORDER BY total_sales desc limit 10;
```

If you've connected to a database, you'll get the table:
<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>CUSTOMER_NAME</th>
      <th>TOTAL_SALES</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>Customer#000143500</td>
      <td>6757566.0218</td>
    </tr>
    <tr>
      <th>1</th>
      <td>Customer#000095257</td>
      <td>6294115.3340</td>
    </tr>
    <tr>
      <th>2</th>
      <td>Customer#000087115</td>
      <td>6184649.5176</td>
    </tr>
    <tr>
      <th>3</th>
      <td>Customer#000131113</td>
      <td>6080943.8305</td>
    </tr>
    <tr>
      <th>4</th>
      <td>Customer#000134380</td>
      <td>6075141.9635</td>
    </tr>
    <tr>
      <th>5</th>
      <td>Customer#000103834</td>
      <td>6059770.3232</td>
    </tr>
    <tr>
      <th>6</th>
      <td>Customer#000069682</td>
      <td>6057779.0348</td>
    </tr>
    <tr>
      <th>7</th>
      <td>Customer#000102022</td>
      <td>6039653.6335</td>
    </tr>
    <tr>
      <th>8</th>
      <td>Customer#000098587</td>
      <td>6027021.5855</td>
    </tr>
    <tr>
      <th>9</th>
      <td>Customer#000064660</td>
      <td>5905659.6159</td>
    </tr>
  </tbody>
</table>
</div>

You'll also get an automated Plotly chart:
![](img/top-10-customers.png)

## RAG vs. Fine-Tuning
RAG
- Portable across LLMs
- Easy to remove training data if any of it becomes obsolete
- Much cheaper to run than fine-tuning
- More future-proof -- if a better LLM comes out, you can just swap it out

Fine-Tuning
- Good if you need to minimize tokens in the prompt
- Slow to get started
- Expensive to train and run (generally)

## Why Vanna?

1. **High accuracy on complex datasets.**
    - Vanna’s capabilities are tied to the training data you give it
    - More training data means better accuracy for large and complex datasets
2. **Secure and private.**
    - Your database contents are never sent to the LLM or the vector database
    - SQL execution happens in your local environment
3. **Self learning.**
    - If using via Jupyter, you can choose to "auto-train" it on the queries that were successfully executed
    - If using via other interfaces, you can have the interface prompt the user to provide feedback on the results
    - Correct question to SQL pairs are stored for future reference and make the future results more accurate
4. **Supports any SQL database.**
    - The package allows you to connect to any SQL database that you can otherwise connect to with Python
5. **Choose your front end.**
    - Most people start in a Jupyter Notebook.
    - Expose to your end users via Slackbot, web app, Streamlit app, or a custom front end.

## Extending Vanna
Vanna is designed to connect to any database, LLM, and vector database. There's a [VannaBase](https://github.com/vanna-ai/vanna/blob/main/src/vanna/base/base.py) abstract base class that defines some basic functionality. The package provides implementations for use with OpenAI and ChromaDB. You can easily extend Vanna to use your own LLM or vector database. See the [documentation](https://vanna.ai/docs/) for more details.

## Vanna in 100 Seconds

https://github.com/vanna-ai/vanna/assets/7146154/eb90ee1e-aa05-4740-891a-4fc10e611cab

## More resources
 - [Full Documentation](https://vanna.ai/docs/)
 - [Website](https://vanna.ai)
 - [Discord group for support](https://discord.gg/qUZYKHremx)


================================================
FILE: examples/chromadb_gpu_example.py
================================================
"""
Example: Using ChromaDB AgentMemory with GPU acceleration

This example demonstrates how to use ChromaAgentMemory with intelligent
device selection for GPU acceleration when available.
"""

from vanna.integrations.chromadb import (
    ChromaAgentMemory,
    get_device,
    create_sentence_transformer_embedding_function
)


def example_default_usage():
    """Example 1: Use default embedding function (no GPU, no sentence-transformers required)"""
    print("Example 1: Default ChromaDB embedding (CPU-only, no extra dependencies)")

    memory = ChromaAgentMemory(
        persist_directory="./chroma_memory_default"
    )

    print("✓ ChromaAgentMemory created with default embedding function")
    print()


def example_auto_gpu():
    """Example 2: Automatic GPU detection with SentenceTransformers"""
    print("Example 2: Automatic GPU detection")

    # Detect the best available device
    device = get_device()
    print(f"Detected device: {device}")

    # Create embedding function with automatic device selection
    embedding_fn = create_sentence_transformer_embedding_function()

    memory = ChromaAgentMemory(
        persist_directory="./chroma_memory_gpu",
        embedding_function=embedding_fn
    )

    print(f"✓ ChromaAgentMemory created with SentenceTransformer on {device}")
    print()


def example_explicit_cuda():
    """Example 3: Explicitly use CUDA"""
    print("Example 3: Explicitly request CUDA")

    # Explicitly request CUDA
    embedding_fn = create_sentence_transformer_embedding_function(device="cuda")

    memory = ChromaAgentMemory(
        persist_directory="./chroma_memory_cuda",
        embedding_function=embedding_fn
    )

    print("✓ ChromaAgentMemory created with SentenceTransformer on CUDA")
    print()


def example_custom_model_gpu():
    """Example 4: Use a larger model with GPU"""
    print("Example 4: Custom model with GPU acceleration")

    # Use a larger, more accurate model with GPU
    embedding_fn = create_sentence_transformer_embedding_function(
        model_name="sentence-transformers/all-mpnet-base-v2"
    )

    memory = ChromaAgentMemory(
        persist_directory="./chroma_memory_large",
        embedding_function=embedding_fn
    )

    print("✓ ChromaAgentMemory created with all-mpnet-base-v2 model")
    print()


def example_manual_chromadb():
    """Example 5: Manually configure ChromaDB embedding function"""
    print("Example 5: Manual ChromaDB embedding function configuration")

    from chromadb.utils import embedding_functions

    # Manually create and configure the embedding function
    device = get_device()
    embedding_fn = embedding_functions.SentenceTransformerEmbeddingFunction(
        model_name="sentence-transformers/all-MiniLM-L6-v2",
        device=device
    )

    memory = ChromaAgentMemory(
        persist_directory="./chroma_memory_manual",
        embedding_function=embedding_fn
    )

    print(f"✓ ChromaAgentMemory created with manual configuration on {device}")
    print()


if __name__ == "__main__":
    print("=" * 70)
    print("ChromaDB AgentMemory GPU Acceleration Examples")
    print("=" * 70)
    print()

    # Example 1: Default (no GPU, no sentence-transformers needed)
    example_default_usage()

    # Examples 2-5 require sentence-transformers to be installed
    try:
        import sentence_transformers

        example_auto_gpu()

        # Only run CUDA example if CUDA is available
        device = get_device()
        if device == "cuda":
            example_explicit_cuda()

        example_custom_model_gpu()
        example_manual_chromadb()

    except ImportError:
        print("⚠️  sentence-transformers not installed")
        print("    Install with: pip install sentence-transformers")
        print("    Examples 2-5 require this package for GPU acceleration")
        print()

    print("=" * 70)
    print("Summary:")
    print("- Example 1 works without sentence-transformers (CPU only)")
    print("- Examples 2-5 require sentence-transformers for GPU support")
    print("- GPU acceleration automatically detected when available")
    print("=" * 70)


================================================
FILE: examples/transform_args_example.py
================================================
"""
Example demonstrating how to use ToolRegistry.transform_args for user-specific
argument transformation, such as applying row-level security (RLS) to SQL queries.

This example shows:
1. Creating a custom ToolRegistry subclass that overrides transform_args
2. Applying RLS transformation to SQL queries based on user context
3. Rejecting tool execution when validation fails
"""

from typing import Union
from pydantic import BaseModel

from vanna.core import ToolRegistry
from vanna.core.tool import Tool, ToolContext, ToolRejection, ToolResult
from vanna.core.user import User


# Example: SQL execution tool arguments
class SQLExecutionArgs(BaseModel):
    query: str
    database: str = "default"


class SQLExecutionTool(Tool[SQLExecutionArgs]):
    @property
    def name(self) -> str:
        return "execute_sql"

    @property
    def description(self) -> str:
        return "Execute a SQL query against the database"

    def get_args_schema(self):
        return SQLExecutionArgs

    async def execute(self, context: ToolContext, args: SQLExecutionArgs) -> ToolResult:
        # Execute the SQL query (implementation not shown)
        return ToolResult(
            success=True,
            result_for_llm=f"Executed query: {args.query[:50]}...",
        )


class RLSToolRegistry(ToolRegistry):
    """Custom ToolRegistry that applies row-level security to SQL queries."""

    async def transform_args(
        self,
        tool: Tool,
        args,
        user: User,
        context: ToolContext,
    ) -> Union[SQLExecutionArgs, ToolRejection]:
        """Apply row-level security transformation to SQL queries."""

        # Only transform SQL execution tools
        if tool.name == "execute_sql" and isinstance(args, SQLExecutionArgs):
            original_query = args.query.strip()

            # Example 1: Reject queries that try to access restricted tables
            if "restricted_table" in original_query.lower():
                return ToolRejection(
                    reason="Access to 'restricted_table' is not permitted for your user group"
                )

            # Example 2: Apply RLS by modifying the WHERE clause
            # This is a simplified example - real RLS would be more sophisticated
            if "SELECT" in original_query.upper() and "users" in original_query.lower():
                # Add a WHERE clause to filter by user's organization
                user_org_id = user.metadata.get("organization_id")

                if user_org_id:
                    # Simple RLS: append WHERE clause for organization filtering
                    if "WHERE" in original_query.upper():
                        transformed_query = original_query.replace(
                            "WHERE",
                            f"WHERE organization_id = {user_org_id} AND",
                            1
                        )
                    else:
                        # Add WHERE clause before ORDER BY, LIMIT, etc.
                        transformed_query = original_query.rstrip(";")
                        transformed_query += f" WHERE organization_id = {user_org_id}"

                    # Return transformed arguments
                    return args.model_copy(update={"query": transformed_query})

            # Example 3: Validate required parameters
            if not args.database:
                return ToolRejection(
                    reason="Database parameter is required for SQL execution"
                )

        # For all other tools or if no transformation needed, pass through
        return args


# Usage example
async def example_usage():
    """Demonstrate using the RLS-enabled ToolRegistry."""
    from vanna.capabilities.agent_memory import AgentMemory

    # Create registry and register tool
    registry = RLSToolRegistry()
    sql_tool = SQLExecutionTool()
    registry.register_local_tool(sql_tool, access_groups=[])

    # Create a user with organization context
    user = User(
        user_id="user123",
        metadata={"organization_id": 42}
    )

    # Create tool context
    context = ToolContext(
        user=user,
        conversation_id="conv123",
        request_id="req123",
        agent_memory=AgentMemory(),
    )

    # Example 1: Query that will be transformed with RLS
    from vanna.core.tool import ToolCall

    tool_call = ToolCall(
        id="call1",
        name="execute_sql",
        arguments={
            "query": "SELECT * FROM users",
            "database": "production"
        }
    )

    result = await registry.execute(tool_call, context)
    print(f"Result: {result.result_for_llm}")
    # The query will be transformed to: SELECT * FROM users WHERE organization_id = 42

    # Example 2: Query that will be rejected
    tool_call_rejected = ToolCall(
        id="call2",
        name="execute_sql",
        arguments={
            "query": "SELECT * FROM restricted_table",
            "database": "production"
        }
    )

    result = await registry.execute(tool_call_rejected, context)
    print(f"Rejected: {result.error}")
    # Will return: "Access to 'restricted_table' is not permitted for your user group"


if __name__ == "__main__":
    import asyncio
    asyncio.run(example_usage())


================================================
FILE: frontends/webcomponent/.storybook/main.ts
================================================
import type { StorybookConfig } from '@storybook/web-components-vite';

const config: StorybookConfig = {
  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-actions',
    '@storybook/addon-controls',
    '@storybook/addon-docs',
  ],
  framework: {
    name: '@storybook/web-components-vite',
    options: {},
  },
  typescript: {
    check: false,
    reactDocgen: 'react-docgen-typescript',
    reactDocgenTypescriptOptions: {
      shouldExtractLiteralValuesFromEnum: true,
      propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
    },
  },
};

export default config;

================================================
FILE: frontends/webcomponent/.storybook/preview-head.html
================================================
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
  href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;500;600;700&family=Signika:wght@300;400;500;600;700&family=Space+Mono:wght@400;700&display=swap"
  rel="stylesheet"
/>


================================================
FILE: frontends/webcomponent/.storybook/preview.ts
================================================
import type { Preview } from '@storybook/web-components';

const preview: Preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
    docs: {
      autodocs: 'tag',
    },
  },
};

export default preview;

================================================
FILE: frontends/webcomponent/TEST_README.md
================================================
# Vanna Webcomponent Comprehensive Test Suite

This test suite validates all component types and update patterns in the vanna-webcomponent before pruning unused code.

## Overview

The test suite consists of:
- **`test_backend.py`**: Real Python backend that streams all component types
- **`test-comprehensive.html`**: Browser-based test interface with visual validation
- **Two test modes**: Rapid (stress test) and Realistic (with delays)

## Quick Start

### 1. Install Dependencies

```bash
cd submodule/vanna-webcomponent
pip install -r requirements-test.txt
```

### 2. Build the Webcomponent

```bash
npm run build
```

### 3. Start the Test Backend

```bash
# Realistic mode (with delays between components)
python test_backend.py --mode realistic

# Rapid mode (fast stress test)
python test_backend.py --mode rapid
```

The backend will start on `http://localhost:5555` and automatically serve the test page.

### 4. Open Test Interface

Simply open your browser to:
```
http://localhost:5555
```

The test page will load automatically!

### 5. Run the Test

1. Click **"Run Comprehensive Test"** button in the sidebar
2. Watch components render in real-time
3. Monitor the checklist - items check off as components render
4. Watch the console log for any errors

## Test Coverage

### Component Types Tested

The test exercises **all** rich component types with **19 different components**:

#### Primitive Components
- ✓ Text (with markdown)
- ✓ Badge
- ✓ Icon Text

#### Feedback Components
- ✓ Status Card (with all states: pending, running, completed, failed)
- ✓ Progress Display (0% → 50% → 100%)
- ✓ Progress Bar
- ✓ Status Indicator (with pulse animation)
- ✓ Notification (info, success, warning, error levels)
- ✓ Log Viewer (with info, warning, error logs)

#### Data Components
- ✓ Card (with buttons and actions)
- ✓ Task List (with status updates)
- ✓ **DataFrame** (tabular data with search/sort/filter/export)
- ✓ **Table** (structured data with explicit column definitions)
- ✓ **Chart** (Plotly charts: bar, line, scatter)
- ✓ **Code Block** (syntax highlighted code: Python, SQL, etc.)

#### Specialized Components
- ✓ **Artifact** (HTML/SVG interactive content)

#### Container Components
- ✓ **Container** (groups components in rows/columns)

#### Interactive Components
- ✓ Button (single)
- ✓ Button Group (horizontal/vertical)
- ✓ Button actions (click → backend response)

#### UI State Updates
- ✓ Status Bar Update (updates status bar above input)
- ✓ Task Tracker Update (adds/updates tasks in sidebar)
- ✓ Chat Input Update (changes placeholder/state)

### Update Operations Tested

For each component type, the test validates:

1. **Create** (`lifecycle: create`) - Initial component rendering
2. **Update** (`lifecycle: update`) - Incremental property updates
3. **Replace** - Full component replacement
4. **Remove** - Component removal from DOM

### Interactive Features Tested

- **Button Actions**: Clicking buttons sends actions to backend
- **Action Handling**: Backend receives actions and responds with new components
- **Round-trip Communication**: Full interaction loop validation

## Test Modes

### Realistic Mode (Default)

```bash
python test_backend.py --mode realistic
```

- Includes delays between component updates (0.2-0.5s)
- Simulates real conversation flow
- Easier to observe rendering behavior
- **Recommended for initial validation**

### Rapid Mode

```bash
python test_backend.py --mode rapid
```

- Minimal delays (0.05-0.1s)
- Stress tests rendering performance
- Validates no race conditions
- **Use for performance testing**

## Validation Checklist

The test interface provides real-time validation:

### ✅ Visual Checklist
- Automatically checks off components as they render
- Shows 19 component types
- Green checkmark = successfully rendered

### 📊 Metrics
- **Components Rendered**: Total unique component types
- **Updates Processed**: Total number of updates (create + update + replace)
- **Errors**: Console errors detected

### 🔴 Console Monitor
- Real-time console log display
- Errors highlighted in red
- Warnings in yellow
- Info messages in blue

### 🟢 Status Indicators
- **Backend Status**: Green = connected, Red = disconnected
- **Console Status**: Green = no errors, Red = errors detected

## Using for Webcomponent Pruning

The test suite is designed to validate that pruning doesn't break functionality:

### Pruning Workflow

1. **Run baseline test**:
   ```bash
   python test_backend.py --mode realistic

   # Browser: Open http://localhost:5555 and run test
   # Verify: All 19 components render, 0 errors
   ```

2. **Identify cruft to remove**:
   - Unused imports
   - Dead code paths
   - Deprecated components
   - Development-only utilities

3. **Remove one piece of cruft**:
   ```bash
   # Example: Remove unused import from vanna-chat.ts
   # or delete unused utility file
   ```

4. **Rebuild**:
   ```bash
   npm run build
   ```

5. **Refresh browser test**:
   - Press F5 to reload test page
   - Click "Run Comprehensive Test" again
   - Check console for errors
   - Verify all 12 components still render

6. **If green → continue; if red → investigate**:
   - Green (no errors): Commit the change, continue pruning
   - Red (errors): Revert change, that code was actually needed

7. **Repeat until clean**: Continue removing cruft until webcomponent is minimal

### What to Prune

Look for these common types of cruft:

- ❌ **Unused imports**: Components imported but never used
- ❌ **Development utilities**: Debug helpers, test mocks in production code
- ❌ **Deprecated components**: Old component versions no longer referenced
- ❌ **Unused CSS**: Styles for removed components
- ❌ **Dead code paths**: Conditional logic that's never executed
- ❌ **Commented code**: Old implementations that are commented out
- ❌ **Storybook-only code**: Utilities only used in stories, not production

### What NOT to Prune

Be careful with these:

- ✅ **Base component renderers**: Even if rarely used, may be needed
- ✅ **ComponentRegistry entries**: Needed for dynamic component lookup
- ✅ **Shadow DOM utilities**: Required for web components
- ✅ **Event handlers**: May be used by runtime events
- ✅ **Type definitions**: Used at compile time even if not runtime

## Customizing the Test

### Add More Component Tests

Edit `test_backend.py` and add new test functions:

```python
async def test_my_component(conversation_id: str, request_id: str, mode: str):
    """Test my custom component."""
    my_component = MyComponent(
        id=str(uuid.uuid4()),
        # ... component properties
    )
    yield await yield_chunk(my_component, conversation_id, request_id)
    await delay(mode)

# Then add to run_comprehensive_test():
async for chunk in test_my_component(conversation_id, request_id, mode):
    yield chunk
```

### Modify Test Delays

In `test_backend.py`, adjust the `delay()` function:

```python
async def delay(mode: str, short: float = 0.1, long: float = 0.5):
    if mode == "realistic":
        await asyncio.sleep(long)  # Adjust long delay here
    elif mode == "rapid":
        await asyncio.sleep(short)  # Adjust short delay here
```

### Add Custom Validation

Edit `test-comprehensive.html` and add custom validation logic:

```javascript
// Add to MutationObserver callback
const componentType = node.getAttribute('data-component-type');
if (componentType === 'my_component') {
    // Custom validation for my_component
    console.log('My component rendered!');
}
```

## Troubleshooting

### Backend won't start

**Error**: `ModuleNotFoundError: No module named 'vanna'`

**Solution**: Make sure vanna is in the Python path:
```bash
cd submodule/vanna-webcomponent
python test_backend.py  # Already adds ../vanna/src to sys.path
```

### Frontend shows "Backend not responding"

**Solutions**:
1. Check backend is running: `curl http://localhost:5555/health`
2. Check CORS is enabled (should be by default)
3. Verify port 5555 is not in use: `lsof -i :5555`

### Components not rendering

**Check**:
1. Browser console for errors (F12)
2. Webcomponent is built: `ls dist/`
3. Test HTML is loading: `<script type="module" src="./dist/index.js"></script>`

### Test page is blank

**Solutions**:
1. Check you're serving from the right directory:
   ```bash
   cd submodule/vanna-webcomponent
   python -m http.server 8080
   ```
2. Open correct URL: `http://localhost:8080/test-comprehensive.html`
3. Check browser console for 404 errors

### Checklist not updating

The checklist tracks components by their `data-component-type` attribute. If components don't have this attribute, they won't be tracked.

**Verify**: Open browser DevTools and inspect rendered components for `data-component-type`.

## Advanced Usage

### Run Backend on Different Port

```bash
python test_backend.py --port 8000
```

Then update `test-comprehensive.html`:
```html
<vanna-chat
    api-url="http://localhost:8000"
    ...
></vanna-chat>
```

### Enable Debug Logging

Add to `test_backend.py`:

```python
import logging
logging.basicConfig(level=logging.DEBUG)
```

### Run Type Checking

Validate the backend code with mypy:

```bash
python -m mypy test_backend.py
```

This catches type errors before runtime (e.g., wrong field names in Pydantic models).

### Test Specific Component Only

Modify `run_comprehensive_test()` to only run specific tests:

```python
async def run_comprehensive_test(conversation_id, request_id, mode):
    # Comment out tests you don't want to run
    async for chunk in test_status_card(conversation_id, request_id, mode):
        yield chunk

    # async for chunk in test_progress_display(...):  # Disabled
    #     yield chunk
```

## Architecture

### Backend Flow

1. FastAPI receives POST to `/api/vanna/v2/chat_sse`
2. `chat_sse()` creates async generator
3. Generator yields components wrapped in `ChatStreamChunk`
4. Each chunk serialized to SSE format: `data: {json}\n\n`
5. Stream ends with `data: [DONE]\n\n`

### Frontend Flow

1. `<vanna-chat>` web component connects to backend
2. Opens SSE connection to `/api/vanna/v2/chat_sse`
3. Receives chunks, parses JSON
4. `ComponentManager` processes updates
5. `ComponentRegistry` renders HTML elements
6. Elements appended to shadow DOM container
7. MutationObserver detects new components
8. Checklist updates automatically

### Button Action Flow

1. User clicks button in frontend
2. Button's `action` property sent as new message
3. Backend receives message via `/api/vanna/v2/chat_sse` POST
4. `handle_action_message()` processes action
5. Response components streamed back
6. Frontend renders response

## Files

- **`test_backend.py`** - Python FastAPI backend (400 lines)
- **`test-comprehensive.html`** - Browser test interface (500 lines)
- **`requirements-test.txt`** - Python dependencies
- **`TEST_README.md`** - This documentation

## Next Steps

After validating the webcomponent with this test suite:

1. **Run baseline test** - Verify all components work before pruning
2. **Identify cruft** - Find unused code in the webcomponent
3. **Prune iteratively** - Remove one piece at a time, test after each change
4. **Commit clean code** - Once pruned, commit the cleaned webcomponent
5. **Copy to vanna package** - Integrate cleaned webcomponent into vanna Python package

## Support

If you encounter issues with the test suite:

1. Check this README's Troubleshooting section
2. Verify all dependencies are installed
3. Ensure you're in the correct directory
4. Check browser and terminal console output

---

**Happy Testing!** 🧪


================================================
FILE: frontends/webcomponent/package.json
================================================
{
  "name": "@vanna/webcomponent",
  "version": "2.0.0",
  "description": "Lit-based web components for Vanna User Agents",
  "main": "dist/vanna-components.js",
  "scripts": {
    "sync-version": "node scripts/sync-version.js",
    "dev": "vite",
    "build": "npm run sync-version && tsc && vite build",
    "preview": "vite preview",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "vanna",
    "ai",
    "sql",
    "web-components",
    "lit",
    "chat",
    "llm",
    "natural-language"
  ],
  "author": "Zain Hoda <zain@vanna.ai>",
  "license": "MIT",
  "type": "commonjs",
  "repository": {
    "type": "git",
    "url": "https://github.com/vanna-ai/vanna.git",
    "directory": "frontends/webcomponent"
  },
  "homepage": "https://github.com/vanna-ai/vanna",
  "bugs": {
    "url": "https://github.com/vanna-ai/vanna/issues"
  },
  "files": [
    "dist",
    "src"
  ],
  "dependencies": {
    "lit": "^3.3.1",
    "plotly.js-dist-min": "^3.1.0"
  },
  "devDependencies": {
    "@storybook/addon-actions": "^8.6.14",
    "@storybook/addon-controls": "^8.6.14",
    "@storybook/addon-docs": "^8.6.14",
    "@storybook/addon-essentials": "^8.6.14",
    "@storybook/web-components": "^8.6.14",
    "@storybook/web-components-vite": "^8.6.14",
    "@types/plotly.js-dist-min": "^2.3.4",
    "storybook": "^8.6.14",
    "typescript": "^5.9.2",
    "vite": "^7.1.5"
  }
}


================================================
FILE: frontends/webcomponent/requirements-test.txt
================================================
# Test backend requirements for vanna-webcomponent comprehensive testing

fastapi>=0.115.0
uvicorn[standard]>=0.32.0
pydantic>=2.0.0

# Note: The vanna package itself will be imported from ../vanna/src
# No need to install it separately for local testing


================================================
FILE: frontends/webcomponent/scripts/sync-version.js
================================================
/**
 * Sync version from pyproject.toml to package.json
 *
 * This ensures the webcomponent version always matches the Python package version.
 * Single source of truth: pyproject.toml
 *
 * Usage: node scripts/sync-version.js
 */

const fs = require('fs');
const path = require('path');

// Paths relative to this script
const PYPROJECT_PATH = path.join(__dirname, '../../../pyproject.toml');
const PACKAGE_JSON_PATH = path.join(__dirname, '../package.json');

function extractVersionFromPyproject(content) {
  // Match: version = "2.0.0"
  const match = content.match(/^version\s*=\s*"([^"]+)"/m);
  if (!match) {
    throw new Error('Could not find version in pyproject.toml');
  }
  return match[1];
}

function updatePackageJsonVersion(packageJsonPath, newVersion) {
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
  const oldVersion = packageJson.version;

  packageJson.version = newVersion;

  fs.writeFileSync(
    packageJsonPath,
    JSON.stringify(packageJson, null, 2) + '\n',
    'utf8'
  );

  return { oldVersion, newVersion };
}

function main() {
  try {
    // Read pyproject.toml
    const pyprojectContent = fs.readFileSync(PYPROJECT_PATH, 'utf8');
    const version = extractVersionFromPyproject(pyprojectContent);

    // Update package.json
    const { oldVersion, newVersion } = updatePackageJsonVersion(PACKAGE_JSON_PATH, version);

    if (oldVersion !== newVersion) {
      console.log(`✓ Version synced: ${oldVersion} → ${newVersion}`);
    } else {
      console.log(`✓ Version already in sync: ${newVersion}`);
    }

    process.exit(0);
  } catch (error) {
    console.error(`✗ Version sync failed: ${error.message}`);
    process.exit(1);
  }
}

main();


================================================
FILE: frontends/webcomponent/src/components/button.stories.ts
================================================
import type { Meta, StoryObj } from '@storybook/web-components';
import { ComponentManager, ComponentUpdate } from './rich-component-system';
import { vannaDesignTokens } from '../styles/vanna-design-tokens.js';

const meta: Meta = {
  title: 'Rich Components/Buttons',
  parameters: {
    layout: 'padded',
    backgrounds: {
      default: 'dark',
      values: [
        { name: 'light', value: '#f5f7fa' },
        { name: 'dark', value: 'rgb(11, 15, 25)' },
      ],
    },
  },
};

export default meta;
type Story = StoryObj;

const ensureTokenStyles = () => {
  if (document.getElementById('vanna-token-style')) {
    return;
  }

  const style = document.createElement('style');
  style.id = 'vanna-token-style';
  style.textContent = vannaDesignTokens.cssText.replace(/:host/g, '.vanna-tokens');
  document.head.appendChild(style);
};

const createContainer = () => {
  ensureTokenStyles();

  const container = document.createElement('div');
  container.className = 'vanna-tokens';
  container.style.cssText = `
    padding: var(--vanna-space-5, 20px);
    max-width: 800px;
    margin: 0 auto;
    background: var(--vanna-background-default);
    border-radius: var(--vanna-border-radius-lg);
    box-shadow: var(--vanna-shadow-md);
  `;

  return container;
};

const createManager = (container: HTMLElement) => new ComponentManager(container);

const renderComponent = (manager: ComponentManager, component: any) => {
  const update: ComponentUpdate = {
    operation: 'create',
    target_id: component.id,
    component,
    timestamp: new Date().toISOString(),
  } as ComponentUpdate;

  manager.processUpdate(update);
};

const withDefaults = (component: any) => ({
  layout: { position: 'append', size: {}, z_index: 0, classes: [] },
  theme: {},
  lifecycle: 'create',
  ...component,
});

const addMockVannaChat = (container: HTMLElement) => {
  // Create a mock vanna-chat element with sendMessage method
  const mockVannaChat = document.createElement('div');
  mockVannaChat.setAttribute('id', 'mock-vanna-chat');

  // Store the original querySelector
  const originalQuerySelector = document.querySelector.bind(document);

  // Override querySelector to return our mock when looking for vanna-chat
  document.querySelector = function(selector: string) {
    if (selector === 'vanna-chat') {
      return mockVannaChat as any;
    }
    return originalQuerySelector(selector);
  } as any;

  // Add sendMessage method that logs to console and shows in UI
  (mockVannaChat as any).sendMessage = (message: string) => {
    console.log('📤 Button clicked - Message:', message);

    // Show a visual feedback in the storybook
    const feedback = document.createElement('div');
    feedback.style.cssText = `
      position: fixed;
      top: 20px;
      right: 20px;
      background: #4CAF50;
      color: white;
      padding: 12px 20px;
      border-radius: 8px;
      box-shadow: 0 4px 6px rgba(0,0,0,0.3);
      font-family: monospace;
      z-index: 10000;
      animation: slideIn 0.3s ease-out;
    `;
    feedback.textContent = `Message sent: ${message}`;

    // Add animation
    const style = document.createElement('style');
    style.textContent = `
      @keyframes slideIn {
        from {
          transform: translateX(100%);
          opacity: 0;
        }
        to {
          transform: translateX(0);
          opacity: 1;
        }
      }
    `;
    document.head.appendChild(style);

    document.body.appendChild(feedback);

    setTimeout(() => {
      feedback.style.opacity = '0';
      feedback.style.transition = 'opacity 0.3s ease-out';
      setTimeout(() => feedback.remove(), 300);
    }, 2000);
  };

  container.appendChild(mockVannaChat);
  return mockVannaChat;
};

export const SingleButtons: Story = {
  render: () => {
    const container = createContainer();
    const manager = createManager(container);
    addMockVannaChat(container);

    // Add title
    const title = document.createElement('h2');
    title.textContent = 'Single Button Components';
    title.style.cssText = 'margin-bottom: 20px; color: var(--vanna-text-primary);';
    container.appendChild(title);

    const buttons = [
      withDefaults({
        id: 'primary-button',
        type: 'button',
        data: {
          label: 'Primary Action',
          action: 'primary_action',
          variant: 'primary',
          size: 'medium',
        },
      }),
      withDefaults({
        id: 'secondary-button',
        type: 'button',
        data: {
          label: 'Save Draft',
          action: 'save_draft',
          variant: 'secondary',
          size: 'medium',
          icon: '💾',
          icon_position: 'left',
        },
      }),
      withDefaults({
        id: 'success-button',
        type: 'button',
        data: {
          label: 'Approve',
          action: 'approve',
          variant: 'success',
          size: 'medium',
          icon: '✓',
        },
      }),
      withDefaults({
        id: 'warning-button',
        type: 'button',
        data: {
          label: 'Caution',
          action: 'warning',
          variant: 'warning',
          size: 'medium',
          icon: '⚠️',
        },
      }),
      withDefaults({
        id: 'error-button',
        type: 'button',
        data: {
          label: 'Delete',
          action: 'delete',
          variant: 'error',
          size: 'medium',
          icon: '🗑️',
        },
      }),
      withDefaults({
        id: 'ghost-button',
        type: 'button',
        data: {
          label: 'Ghost Style',
          action: 'ghost',
          variant: 'ghost',
          icon: '👻',
        },
      }),
      withDefaults({
        id: 'link-button',
        type: 'button',
        data: {
          label: 'Learn More',
          action: 'learn_more',
          variant: 'link',
        },
      }),
      withDefaults({
        id: 'loading-button',
        type: 'button',
        data: {
          label: 'Processing...',
          action: 'loading',
          variant: 'primary',
          loading: true,
        },
      }),
      withDefaults({
        id: 'disabled-button',
        type: 'button',
        data: {
          label: 'Disabled',
          action: 'disabled',
          variant: 'secondary',
          disabled: true,
        },
      }),
    ];

    buttons.forEach((component) => {
      renderComponent(manager, component);
      // Add some spacing
      const spacer = document.createElement('div');
      spacer.style.height = '12px';
      container.appendChild(spacer);
    });

    // Add instruction
    const instruction = document.createElement('p');
    instruction.textContent = 'Click any button to see the message it sends (wrapped in square brackets)';
    instruction.style.cssText = 'margin-top: 20px; color: var(--vanna-text-secondary); font-style: italic;';
    container.appendChild(instruction);

    return container;
  },
};

export const ButtonSizes: Story = {
  render: () => {
    const container = createContainer();
    const manager = createManager(container);
    addMockVannaChat(container);

    const title = document.createElement('h2');
    title.textContent = 'Button Sizes';
    title.style.cssText = 'margin-bottom: 20px; color: var(--vanna-text-primary);';
    container.appendChild(title);

    const sizes = ['small', 'medium', 'large'];

    sizes.forEach((size) => {
      const button = withDefaults({
        id: `button-${size}`,
        type: 'button',
        data: {
          label: `${size.charAt(0).toUpperCase() + size.slice(1)} Button`,
          action: `${size}_action`,
          variant: 'primary',
          size,
          icon: '⭐',
        },
      });

      renderComponent(manager, button);

      const spacer = document.createElement('div');
      spacer.style.height = '12px';
      container.appendChild(spacer);
    });

    return container;
  },
};

export const ButtonGroups: Story = {
  render: () => {
    const container = createContainer();
    const manager = createManager(container);
    addMockVannaChat(container);

    const title = document.createElement('h2');
    title.textContent = 'Button Group Components';
    title.style.cssText = 'margin-bottom: 20px; color: var(--vanna-text-primary);';
    container.appendChild(title);

    // Horizontal action group
    const actionGroup = withDefaults({
      id: 'action-group',
      type: 'button_group',
      data: {
        buttons: [
          {
            label: 'Accept',
            action: 'accept',
            variant: 'success',
            icon: '✓',
          },
          {
            label: 'Reject',
            action: 'reject',
            variant: 'error',
            icon: '✗',
          },
          {
            label: 'Cancel',
            action: 'cancel',
            variant: 'secondary',
          },
        ],
        orientation: 'horizontal',
        spacing: 'medium',
        align: 'left',
      },
    });

    const sectionTitle1 = document.createElement('h3');
    sectionTitle1.textContent = 'Horizontal Action Group';
    sectionTitle1.style.cssText = 'margin: 20px 0 10px 0; color: var(--vanna-text-primary); font-size: 16px;';
    container.appendChild(sectionTitle1);
    renderComponent(manager, actionGroup);

    // Centered navigation
    const navigationGroup = withDefaults({
      id: 'navigation-group',
      type: 'button_group',
      data: {
        buttons: [
          {
            label: 'Back',
            action: 'back',
            variant: 'ghost',
            icon: '←',
          },
          {
            label: 'Continue',
            action: 'continue',
            variant: 'primary',
            icon: '→',
            icon_position: 'right',
          },
        ],
        orientation: 'horizontal',
        spacing: 'large',
        align: 'center',
      },
    });

    const sectionTitle2 = document.createElement('h3');
    sectionTitle2.textContent = 'Centered Navigation';
    sectionTitle2.style.cssText = 'margin: 20px 0 10px 0; color: var(--vanna-text-primary); font-size: 16px;';
    container.appendChild(sectionTitle2);
    renderComponent(manager, navigationGroup);

    // Vertical options
    const verticalGroup = withDefaults({
      id: 'vertical-group',
      type: 'button_group',
      data: {
        buttons: [
          { label: 'Option 1', action: 'option1', variant: 'secondary' },
          { label: 'Option 2', action: 'option2', variant: 'secondary' },
          { label: 'Option 3', action: 'option3', variant: 'secondary' },
        ],
        orientation: 'vertical',
        spacing: 'small',
        align: 'left',
      },
    });

    const sectionTitle3 = document.createElement('h3');
    sectionTitle3.textContent = 'Vertical Options';
    sectionTitle3.style.cssText = 'margin: 20px 0 10px 0; color: var(--vanna-text-primary); font-size: 16px;';
    container.appendChild(sectionTitle3);
    renderComponent(manager, verticalGroup);

    // Toolbar
    const toolbarGroup = withDefaults({
      id: 'toolbar-group',
      type: 'button_group',
      data: {
        buttons: [
          {
            label: 'New',
            action: 'new',
            variant: 'primary',
            icon: '➕',
            size: 'small',
          },
          {
            label: 'Edit',
            action: 'edit',
            variant: 'secondary',
            icon: '✏️',
            size: 'small',
          },
          {
            label: 'Delete',
            action: 'delete',
            variant: 'error',
            icon: '🗑️',
            size: 'small',
          },
          {
            label: 'Share',
            action: 'share',
            variant: 'ghost',
            icon: '🔗',
            size: 'small',
          },
        ],
        orientation: 'horizontal',
        spacing: 'small',
        align: 'left',
      },
    });

    const sectionTitle4 = document.createElement('h3');
    sectionTitle4.textContent = 'Toolbar (Small Buttons)';
    sectionTitle4.style.cssText = 'margin: 20px 0 10px 0; color: var(--vanna-text-primary); font-size: 16px;';
    container.appendChild(sectionTitle4);
    renderComponent(manager, toolbarGroup);

    // Full width confirmation
    const confirmationGroup = withDefaults({
      id: 'confirmation-group',
      type: 'button_group',
      data: {
        buttons: [
          { label: 'Yes', action: 'yes', variant: 'success' },
          { label: 'No', action: 'no', variant: 'error' },
        ],
        orientation: 'horizontal',
        spacing: 'medium',
        align: 'space-between',
        full_width: true,
      },
    });

    const sectionTitle5 = document.createElement('h3');
    sectionTitle5.textContent = 'Full Width Confirmation';
    sectionTitle5.style.cssText = 'margin: 20px 0 10px 0; color: var(--vanna-text-primary); font-size: 16px;';
    container.appendChild(sectionTitle5);
    renderComponent(manager, confirmationGroup);

    // Add instruction
    const instruction = document.createElement('p');
    instruction.textContent = 'Click any button in the groups to see the message it sends';
    instruction.style.cssText = 'margin-top: 20px; color: var(--vanna-text-secondary); font-style: italic;';
    container.appendChild(instruction);

    return container;
  },
};

export const InteractiveDemo: Story = {
  render: () => {
    const container = createContainer();
    const manager = createManager(container);
    addMockVannaChat(container);

    const title = document.createElement('h2');
    title.textContent = 'Interactive Button Demo';
    title.style.cssText = 'margin-bottom: 20px; color: var(--vanna-text-primary);';
    container.appendChild(title);

    const description = document.createElement('p');
    description.textContent = 'This demo shows how buttons send messages with their labels wrapped in square brackets.';
    description.style.cssText = 'margin-bottom: 20px; color: var(--vanna-text-secondary);';
    container.appendChild(description);

    // Simple choice buttons
    const choiceGroup = withDefaults({
      id: 'choice-group',
      type: 'button_group',
      data: {
        buttons: [
          { label: 'Okay', action: 'okay', variant: 'primary' },
          { label: 'Not now', action: 'not_now', variant: 'secondary' },
          { label: 'Never', action: 'never', variant: 'ghost' },
        ],
        orientation: 'horizontal',
        spacing: 'medium',
        align: 'center',
      },
    });

    renderComponent(manager, choiceGroup);

    const codeExample = document.createElement('pre');
    codeExample.textContent = `// When you click "Okay", the message sent is: [Okay]
// When you click "Not now", the message sent is: [Not now]
// When you click "Never", the message sent is: [Never]`;
    codeExample.style.cssText = `
      margin-top: 20px;
      padding: 12px;
      background: rgba(0, 0, 0, 0.3);
      border-radius: 6px;
      color: #a0aec0;
      font-size: 12px;
      font-family: 'Courier New', monospace;
      overflow-x: auto;
    `;
    container.appendChild(codeExample);

    return container;
  },
};


================================================
FILE: frontends/webcomponent/src/components/dataframe-component.stories.ts
================================================
import type { Meta, StoryObj } from '@storybook/web-components';
import { ComponentManager, ComponentUpdate } from './rich-component-system';
import { vannaDesignTokens } from '../styles/vanna-design-tokens.js';
import { richComponentStyleText } from '../styles/rich-component-styles.js';

const meta: Meta = {
  title: 'Rich Components/DataFrame',
  parameters: {
    layout: 'padded',
    backgrounds: {
      default: 'light',
      values: [
        { name: 'light', value: '#f5f7fa' },
        { name: 'dark', value: 'rgb(11, 15, 25)' },
      ],
    },
  },
  argTypes: {
    theme: {
      control: { type: 'select' },
      options: ['light', 'dark'],
    },
    striped: {
      control: { type: 'boolean' },
    },
    bordered: {
      control: { type: 'boolean' },
    },
    compact: {
      control: { type: 'boolean' },
    },
    searchable: {
      control: { type: 'boolean' },
    },
    sortable: {
      control: { type: 'boolean' },
    },
    exportable: {
      control: { type: 'boolean' },
    },
  },
};

export default meta;
type Story = StoryObj;

const ensureTokenStyles = () => {
  if (document.getElementById('vanna-token-style')) {
    return;
  }

  const style = document.createElement('style');
  style.id = 'vanna-token-style';
  style.textContent = vannaDesignTokens.cssText.replace(/:host/g, '.vanna-tokens');
  document.head.appendChild(style);
};

const ensureRichComponentStyles = () => {
  if (document.getElementById('vanna-rich-component-styles')) {
    return;
  }

  const style = document.createElement('style');
  style.id = 'vanna-rich-component-styles';
  style.textContent = richComponentStyleText;
  document.head.appendChild(style);
};

const createContainer = () => {
  ensureTokenStyles();
  ensureRichComponentStyles();

  const container = document.createElement('div');
  container.className = 'vanna-tokens';
  container.style.cssText = `
    padding: var(--vanna-space-5, 20px);
    max-width: 1200px;
    margin: 0 auto;
    background: var(--vanna-background-default, #0b0f19);
    border-radius: var(--vanna-border-radius-lg, 8px);
    box-shadow: var(--vanna-shadow-md, 0 4px 6px rgba(0, 0, 0, 0.1));
    color: var(--vanna-foreground-default, #ffffff);
  `;

  // Add some additional DataFrame-specific debugging styles
  const additionalStyles = document.createElement('style');
  additionalStyles.textContent = `
    /* Ensure DataFrame styles are applied with higher specificity */
    .vanna-tokens {
      font-family: var(--vanna-font-family-default, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif) !important;
    }

    .vanna-tokens .rich-dataframe {
      background: var(--vanna-background-default, #0b0f19) !important;
      border: 1px solid var(--vanna-outline-default, #333) !important;
      border-radius: var(--vanna-border-radius-lg, 8px) !important;
      overflow: hidden !important;
      font-family: var(--vanna-font-family-default, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif) !important;
    }

    .vanna-tokens .dataframe-table {
      width: 100% !important;
      border-collapse: collapse !important;
      font-size: 0.875rem !important;
      color: var(--vanna-foreground-default, #ffffff) !important;
      font-family: var(--vanna-font-family-default, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif) !important;
    }

    .vanna-tokens .dataframe-table th {
      background: var(--vanna-background-higher, #1a1f2e) !important;
      color: var(--vanna-foreground-default, #ffffff) !important;
      font-weight: 600 !important;
      text-align: left !important;
      padding: 12px 16px !important;
      border-bottom: 2px solid var(--vanna-outline-default, #333) !important;
      font-family: var(--vanna-font-family-default, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif) !important;
    }

    .vanna-tokens .dataframe-table td {
      padding: 12px 16px !important;
      border-bottom: 1px solid var(--vanna-outline-dimmer, #222) !important;
      color: var(--vanna-foreground-default, #ffffff) !important;
      font-family: var(--vanna-font-family-default, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif) !important;
    }

    .vanna-tokens .dataframe-table.striped tbody tr:nth-child(even) {
      background: rgba(255, 255, 255, 0.02) !important;
    }

    .vanna-tokens .dataframe-header {
      padding: 16px 20px !important;
      background: var(--vanna-background-higher, #1a1f2e) !important;
      border-bottom: 1px solid var(--vanna-outline-default, #333) !important;
      font-family: var(--vanna-font-family-default, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif) !important;
    }

    .vanna-tokens .dataframe-title {
      font-family: var(--vanna-font-family-default, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif) !important;
      color: var(--vanna-foreground-default, #ffffff) !important;
      font-weight: 600 !important;
    }

    .vanna-tokens .dataframe-description {
      font-family: var(--vanna-font-family-default, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif) !important;
      color: var(--vanna-foreground-dimmer, #b1bac4) !important;
    }

    .vanna-tokens .dataframe-actions {
      padding: 12px 20px !important;
      background: var(--vanna-background-default, #0b0f19) !important;
      border-bottom: 1px solid var(--vanna-outline-dimmer, #222) !important;
      display: flex !important;
      justify-content: space-between !important;
      align-items: center !important;
      gap: 12px !important;
    }

    .vanna-tokens .search-input {
      width: 100% !important;
      padding: 8px 12px !important;
      border: 1px solid var(--vanna-outline-default, #333) !important;
      border-radius: 6px !important;
      background: var(--vanna-background-default, #0b0f19) !important;
      color: var(--vanna-foreground-default, #ffffff) !important;
      font-size: 0.875rem !important;
      font-family: var(--vanna-font-family-default, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif) !important;
    }

    .vanna-tokens .export-btn {
      padding: 8px 12px !important;
      border: 1px solid var(--vanna-outline-default, #333) !important;
      border-radius: 6px !important;
      background: var(--vanna-background-default, #0b0f19) !important;
      color: var(--vanna-foreground-default, #ffffff) !important;
      cursor: pointer !important;
      font-size: 0.875rem !important;
      font-family: var(--vanna-font-family-default, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif) !important;
    }
  `;
  document.head.appendChild(additionalStyles);

  return container;
};

const createManager = (container: HTMLElement) => new ComponentManager(container);

const renderComponent = (manager: ComponentManager, component: any) => {
  const update: ComponentUpdate = {
    operation: 'create',
    target_id: component.id,
    component,
    timestamp: new Date().toISOString(),
  } as ComponentUpdate;

  manager.processUpdate(update);
};

const withDefaults = (component: any) => ({
  layout: { position: 'append', size: {}, z_index: 0, classes: [] },
  theme: {},
  lifecycle: 'create',
  timestamp: new Date().toISOString(),
  visible: true,
  interactive: false,
  children: [],
  ...component,
});

// Sample data sets
const employeeData = [
  { id: 1, name: 'Alice Johnson', email: 'alice@example.com', age: 28, city: 'New York', salary: 75000, active: true, department: 'Engineering' },
  { id: 2, name: 'Bob Smith', email: 'bob@example.com', age: 34, city: 'San Francisco', salary: 85000, active: true, department: 'Product' },
  { id: 3, name: 'Carol Davis', email: 'carol@example.com', age: 29, city: 'Chicago', salary: 70000, active: false, department: 'Design' },
  { id: 4, name: 'David Wilson', email: 'david@example.com', age: 42, city: 'Austin', salary: 90000, active: true, department: 'Engineering' },
  { id: 5, name: 'Eve Brown', email: 'eve@example.com', age: 31, city: 'Seattle', salary: 80000, active: true, department: 'Marketing' },
  { id: 6, name: 'Frank Miller', email: 'frank@example.com', age: 38, city: 'Boston', salary: 95000, active: false, department: 'Sales' },
  { id: 7, name: 'Grace Lee', email: 'grace@example.com', age: 26, city: 'Denver', salary: 65000, active: true, department: 'HR' },
  { id: 8, name: 'Henry Taylor', email: 'henry@example.com', age: 33, city: 'Portland', salary: 72000, active: true, department: 'Engineering' },
  { id: 9, name: 'Ivy Chen', email: 'ivy@example.com', age: 27, city: 'Los Angeles', salary: 78000, active: true, department: 'Product' },
  { id: 10, name: 'Jack Anderson', email: 'jack@example.com', age: 35, city: 'Miami', salary: 82000, active: false, department: 'Finance' },
];

const sqlQueryData = [
  { TrackId: 1, Name: 'For Those About To Rock (We Salute You)', AlbumId: 1, MediaTypeId: 1, GenreId: 1, Composer: 'Angus Young, Malcolm Young, Brian Johnson', Milliseconds: 343719, Bytes: 11170334, UnitPrice: 0.99 },
  { TrackId: 2, Name: 'Balls to the Wall', AlbumId: 2, MediaTypeId: 2, GenreId: 1, Composer: null, Milliseconds: 342562, Bytes: 5510424, UnitPrice: 0.99 },
  { TrackId: 3, Name: 'Fast As a Shark', AlbumId: 3, MediaTypeId: 2, GenreId: 1, Composer: 'F. Baltes, S. Kaufman, U. Dirkscneider & W. Hoffman', Milliseconds: 230619, Bytes: 3990994, UnitPrice: 0.99 },
  { TrackId: 4, Name: 'Restless and Wild', AlbumId: 3, MediaTypeId: 2, GenreId: 1, Composer: 'F. Baltes, R.A. Smith-Diesel, S. Kaufman, U. Dirkscneider & W. Hoffman', Milliseconds: 252051, Bytes: 4331779, UnitPrice: 0.99 },
  { TrackId: 5, Name: 'Princess of the Dawn', AlbumId: 3, MediaTypeId: 2, GenreId: 1, Composer: 'Deaffy & R.A. Smith-Diesel', Milliseconds: 375418, Bytes: 6290521, UnitPrice: 0.99 },
  { TrackId: 6, Name: 'Put The Finger On You', AlbumId: 1, MediaTypeId: 1, GenreId: 1, Composer: 'Angus Young, Malcolm Young, Brian Johnson', Milliseconds: 205662, Bytes: 6713451, UnitPrice: 0.99 },
  { TrackId: 7, Name: "Let's Get It Up", AlbumId: 1, MediaTypeId: 1, GenreId: 1, Composer: 'Angus Young, Malcolm Young, Brian Johnson', Milliseconds: 233926, Bytes: 7636561, UnitPrice: 0.99 },
  { TrackId: 8, Name: 'Inject The Venom', AlbumId: 1, MediaTypeId: 1, GenreId: 1, Composer: 'Angus Young, Malcolm Young, Brian Johnson', Milliseconds: 210834, Bytes: 6852860, UnitPrice: 0.99 },
];

export const BasicDataFrame: Story = {
  render: (args) => {
    const container = createContainer();
    const manager = createManager(container);

    const component = withDefaults({
      id: 'basic-dataframe',
      type: 'dataframe',
      data: {
        data: employeeData.slice(0, 5),
        columns: ['id', 'name', 'email', 'age', 'city', 'department'],
        title: 'Employee Records',
        description: 'Basic employee data with essential information',
        row_count: 5,
        column_count: 6,
        striped: args.striped ?? true,
        bordered: args.bordered ?? true,
        compact: args.compact ?? false,
        searchable: args.searchable ?? false,
        sortable: args.sortable ?? false,
        exportable: args.exportable ?? false,
        column_types: {
          id: 'number',
          name: 'string',
          email: 'string',
          age: 'number',
          city: 'string',
          department: 'string'
        }
      },
    });

    renderComponent(manager, component);
    return container;
  },
  args: {
    striped: true,
    bordered: true,
    compact: false,
    searchable: false,
    sortable: false,
    exportable: false,
  },
};

export const InteractiveDataFrame: Story = {
  render: (args) => {
    const container = createContainer();
    const manager = createManager(container);

    const component = withDefaults({
      id: 'interactive-dataframe',
      type: 'dataframe',
      data: {
        data: employeeData,
        columns: ['id', 'name', 'email', 'age', 'city', 'salary', 'active', 'department'],
        title: 'Interactive Employee Database',
        description: 'Full dataset with search, sort, and export functionality',
        row_count: employeeData.length,
        column_count: 8,
        striped: args.striped ?? true,
        bordered: args.bordered ?? true,
        compact: args.compact ?? false,
        searchable: args.searchable ?? true,
        sortable: args.sortable ?? true,
        exportable: args.exportable ?? true,
        max_rows_displayed: 8,
        column_types: {
          id: 'number',
          name: 'string',
          email: 'string',
          age: 'number',
          city: 'string',
          salary: 'number',
          active: 'boolean',
          department: 'string'
        }
      },
    });

    renderComponent(manager, component);
    return container;
  },
  args: {
    striped: true,
    bordered: true,
    compact: false,
    searchable: true,
    sortable: true,
    exportable: true,
  },
};

export const SQLQueryResults: Story = {
  render: (args) => {
    const container = createContainer();
    const manager = createManager(container);

    const component = withDefaults({
      id: 'sql-dataframe',
      type: 'dataframe',
      data: {
        data: sqlQueryData,
        columns: ['TrackId', 'Name', 'AlbumId', 'MediaTypeId', 'GenreId', 'Composer', 'Milliseconds', 'Bytes', 'UnitPrice'],
        title: 'SQL Query Results',
        description: 'SELECT * FROM Track LIMIT 8',
        row_count: sqlQueryData.length,
        column_count: 9,
        striped: args.striped ?? true,
        bordered: args.bordered ?? true,
        compact: args.compact ?? false,
        searchable: args.searchable ?? true,
        sortable: args.sortable ?? true,
        exportable: args.exportable ?? true,
        column_types: {
          TrackId: 'number',
          Name: 'string',
          AlbumId: 'number',
          MediaTypeId: 'number',
          GenreId: 'number',
          Composer: 'string',
          Milliseconds: 'number',
          Bytes: 'number',
          UnitPrice: 'number'
        }
      },
    });

    renderComponent(manager, component);
    return container;
  },
  args: {
    striped: true,
    bordered: true,
    compact: false,
    searchable: true,
    sortable: true,
    exportable: true,
  },
};

export const CompactView: Story = {
  render: (args) => {
    const container = createContainer();
    const manager = createManager(container);

    const component = withDefaults({
      id: 'compact-dataframe',
      type: 'dataframe',
      data: {
        data: employeeData.slice(0, 6),
        columns: ['id', 'name', 'city', 'active'],
        title: 'Compact Employee View',
        description: 'Space-efficient display with essential columns only',
        row_count: 6,
        column_count: 4,
        striped: args.striped ?? true,
        bordered: args.bordered ?? false,
        compact: args.compact ?? true,
        searchable: args.searchable ?? false,
        sortable: args.sortable ?? true,
        exportable: args.exportable ?? false,
        column_types: {
          id: 'number',
          name: 'string',
          city: 'string',
          active: 'boolean'
        }
      },
    });

    renderComponent(manager, component);
    return container;
  },
  args: {
    striped: true,
    bordered: false,
    compact: true,
    searchable: false,
    sortable: true,
    exportable: false,
  },
};

export const EmptyDataFrame: Story = {
  render: () => {
    const container = createContainer();
    const manager = createManager(container);

    const component = withDefaults({
      id: 'empty-dataframe',
      type: 'dataframe',
      data: {
        data: [],
        columns: [],
        title: 'No Data Available',
        description: 'This dataset contains no records',
        row_count: 0,
        column_count: 0,
      },
    });

    renderComponent(manager, component);
    return container;
  },
};

export const LargeDataset: Story = {
  render: (args) => {
    const container = createContainer();
    const manager = createManager(container);

    // Generate a larger dataset
    const largeData = Array.from({ length: 50 }, (_, i) => ({
      id: i + 1,
      name: `User ${i + 1}`,
      email: `user${i + 1}@example.com`,
      score: Math.floor(Math.random() * 100),
      category: ['A', 'B', 'C'][i % 3],
      active: Math.random() > 0.3,
      created_date: new Date(2024, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1).toISOString().split('T')[0]
    }));

    const component = withDefaults({
      id: 'large-dataframe',
      type: 'dataframe',
      data: {
        data: largeData,
        columns: ['id', 'name', 'email', 'score', 'category', 'active', 'created_date'],
        title: 'Large Dataset',
        description: '50 records with pagination and search',
        row_count: largeData.length,
        column_count: 7,
        striped: args.striped ?? true,
        bordered: args.bordered ?? true,
        compact: args.compact ?? false,
        searchable: args.searchable ?? true,
        sortable: args.sortable ?? true,
        exportable: args.exportable ?? true,
        max_rows_displayed: 15,
        column_types: {
          id: 'number',
          name: 'string',
          email: 'string',
          score: 'number',
          category: 'string',
          active: 'boolean',
          created_date: 'date'
        }
      },
    });

    renderComponent(manager, component);
    return container;
  },
  args: {
    striped: true,
    bordered: true,
    compact: false,
    searchable: true,
    sortable: true,
    exportable: true,
  },
};

export const DataTypesShowcase: Story = {
  render: () => {
    const container = createContainer();
    const manager = createManager(container);

    const typesData = [
      {
        id: 1,
        name: 'Alice',
        score: 95.5,
        active: true,
        created: '2024-01-15',
        notes: 'Excellent performance',
        tags: null
      },
      {
        id: 2,
        name: 'Bob',
        score: 87.2,
        active: false,
        created: '2024-02-20',
        notes: 'Good but needs improvement',
        tags: 'priority,review'
      },
      {
        id: 3,
        name: 'Carol',
        score: 92.8,
        active: true,
        created: '2024-03-10',
        notes: null,
        tags: 'star-performer'
      },
    ];

    const component = withDefaults({
      id: 'types-dataframe',
      type: 'dataframe',
      data: {
        data: typesData,
        columns: ['id', 'name', 'score', 'active', 'created', 'notes', 'tags'],
        title: 'Data Types Showcase',
        description: 'Demonstrates different column data types and null handling',
        row_count: typesData.length,
        column_count: 7,
        striped: true,
        bordered: true,
        searchable: true,
        sortable: true,
        exportable: true,
        column_types: {
          id: 'number',
          name: 'string',
          score: 'number',
          active: 'boolean',
          created: 'date',
          notes: 'string',
          tags: 'string'
        }
      },
    });

    renderComponent(manager, component);
    return container;
  },
};

================================================
FILE: frontends/webcomponent/src/components/plotly-chart.stories.ts
================================================
import type { Meta, StoryObj } from '@storybook/web-components';
import { html } from 'lit';
import './plotly-chart';

const meta: Meta = {
  title: 'Rich Components/Plotly Chart',
  component: 'plotly-chart',
  parameters: {
    layout: 'padded',
    backgrounds: {
      default: 'light',
      values: [
        { name: 'dark', value: 'rgb(11, 15, 25)' },
        { name: 'light', value: '#f5f7fa' },
      ],
    },
  },
  argTypes: {
    theme: {
      control: 'select',
      options: ['light', 'dark']
    },
    loading: { control: 'boolean' },
    error: { control: 'text' },
  },
};

export default meta;
type Story = StoryObj;

export const LineChart: Story = {
  args: {
    theme: 'light',
    loading: false,
    error: '',
  },
  render: (args) => html`
    <div style="max-width: 800px; margin: 0 auto;">
      <plotly-chart
        theme=${args.theme}
        ?loading=${args.loading}
        error=${args.error}
        .data=${[
          {
            x: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
            y: [20, 14, 23, 25, 22, 16],
            type: 'scatter',
            mode: 'lines+markers',
            name: 'Sales',
            line: { color: 'rgb(0, 123, 255)' }
          }
        ]}
        .layout=${{
          xaxis: { title: 'Month' },
          yaxis: { title: 'Sales (in thousands)' }
        }}>
      </plotly-chart>
    </div>
  `,
};

export const BarChart: Story = {
  args: {
    theme: 'light',
  },
  render: (args) => html`
    <div style="max-width: 800px; margin: 0 auto;">
      <plotly-chart
        theme=${args.theme}
        .data=${[
          {
            x: ['Product A', 'Product B', 'Product C', 'Product D'],
            y: [45, 32, 28, 35],
            type: 'bar',
            name: 'Revenue',
            marker: {
              color: ['rgb(16, 185, 129)', 'rgb(0, 123, 255)', 'rgb(245, 158, 11)', 'rgb(239, 68, 68)']
            }
          }
        ]}
        .layout=${{
          xaxis: { title: 'Products' },
          yaxis: { title: 'Revenue ($M)' }
        }}>
      </plotly-chart>
    </div>
  `,
};

export const ScatterPlot: Story = {
  args: {
    theme: 'light',
  },
  render: (args) => html`
    <div style="max-width: 800px; margin: 0 auto;">
      <plotly-chart
        theme=${args.theme}
        .data=${[
          {
            x: [85, 78, 92, 88, 76, 95, 82, 89, 93, 79],
            y: [450, 320, 580, 490, 280, 650, 380, 520, 610, 310],
            type: 'scatter',
            mode: 'markers',
            name: 'Business Units',
            marker: {
              size: 12,
              color: 'rgb(0, 123, 255)',
              opacity: 0.7
            }
          }
        ]}
        .layout=${{
          xaxis: { title: 'Customer Satisfaction Score' },
          yaxis: { title: 'Revenue ($K)' }
        }}>
      </plotly-chart>
    </div>
  `,
};

export const MultipleLines: Story = {
  args: {
    theme: 'light',
  },
  render: (args) => html`
    <div style="max-width: 800px; margin: 0 auto;">
      <plotly-chart
        theme=${args.theme}
        .data=${[
          {
            x: ['Q1', 'Q2', 'Q3', 'Q4'],
            y: [85, 88, 92, 89],
            type: 'scatter',
            mode: 'lines+markers',
            name: 'User Engagement',
            line: { color: 'rgb(16, 185, 129)' }
          },
          {
            x: ['Q1', 'Q2', 'Q3', 'Q4'],
            y: [65, 72, 78, 81],
            type: 'scatter',
            mode: 'lines+markers',
            name: 'Conversion Rate',
            line: { color: 'rgb(0, 123, 255)' }
          },
          {
            x: ['Q1', 'Q2', 'Q3', 'Q4'],
            y: [42, 48, 55, 58],
            type: 'scatter',
            mode: 'lines+markers',
            name: 'Customer Retention',
            line: { color: 'rgb(245, 158, 11)' }
          }
        ]}
        .layout=${{
          xaxis: { title: 'Quarter' },
          yaxis: { title: 'Percentage (%)' }
        }}>
      </plotly-chart>
    </div>
  `,
};

export const LoadingState: Story = {
  args: {
    theme: 'light',
    loading: true,
  },
  render: (args) => html`
    <div style="max-width: 800px; margin: 0 auto;">
      <plotly-chart
        theme=${args.theme}
        ?loading=${args.loading}
        .data=${[]}>
      </plotly-chart>
    </div>
  `,
};

export const ErrorState: Story = {
  args: {
    theme: 'light',
    error: 'Failed to load chart data from API',
  },
  render: (args) => html`
    <div style="max-width: 800px; margin: 0 auto;">
      <plotly-chart
        theme=${args.theme}
        error=${args.error}
        .data=${[]}>
      </plotly-chart>
    </div>
  `,
};

export const LightTheme: Story = {
  args: {
    theme: 'light',
  },
  parameters: {
    backgrounds: { default: 'light' }
  },
  render: (args) => html`
    <div style="max-width: 800px; margin: 0 auto;">
      <plotly-chart
        theme=${args.theme}
        .data=${[
          {
            x: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
            y: [20, 14, 23, 25, 22, 16],
            type: 'scatter',
            mode: 'lines+markers',
            name: 'Sales',
            line: { color: 'rgb(0, 123, 255)' }
          }
        ]}
        .layout=${{
          xaxis: { title: 'Month' },
          yaxis: { title: 'Sales (in thousands)' }
        }}>
      </plotly-chart>
    </div>
  `,
};

export const CustomLayout: Story = {
  args: {
    theme: 'light',
  },
  render: (args) => html`
    <div style="max-width: 800px; margin: 0 auto;">
      <plotly-chart
        theme=${args.theme}
        .data=${[
          {
            x: [1, 2, 3, 4, 5],
            y: [10, 11, 12, 13, 14],
            type: 'scatter',
            mode: 'lines',
            name: 'Trend A',
            line: { color: 'rgb(16, 185, 129)', width: 3 }
          },
          {
            x: [1, 2, 3, 4, 5],
            y: [8, 9, 10, 11, 12],
            type: 'scatter',
            mode: 'lines',
            name: 'Trend B',
            line: { color: 'rgb(239, 68, 68)', width: 3, dash: 'dash' }
          }
        ]}
        .layout=${{
          title: {
            text: 'Custom Styled Chart',
            font: { size: 18 }
          },
          xaxis: {
            title: 'Time Period',
            gridcolor: 'rgba(255, 255, 255, 0.1)'
          },
          yaxis: {
            title: 'Value',
            gridcolor: 'rgba(255, 255, 255, 0.1)'
          },
          height: 500,
          showlegend: true
        }}>
      </plotly-chart>
    </div>
  `,
};



================================================
FILE: frontends/webcomponent/src/components/plotly-chart.ts
================================================
import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { vannaDesignTokens } from '../styles/vanna-design-tokens.js';
import Plotly from 'plotly.js-dist-min';

export interface PlotlyData {
  x?: any[];
  y?: any[];
  type?: any;
  mode?: any;
  name?: string;
  marker?: any;
  line?: any;
  [key: string]: any;
}

export interface PlotlyLayout {
  title?: any;
  xaxis?: any;
  yaxis?: any;
  font?: any;
  paper_bgcolor?: string;
  plot_bgcolor?: string;
  margin?: any;
  showlegend?: boolean;
  height?: number;
  width?: number;
  modebar?: any;
  [key: string]: any;
}

@customElement('plotly-chart')
export class PlotlyChart extends LitElement {
  static styles = [
    vannaDesignTokens,
    css`
      :host {
        display: block;
        font-family: var(--vanna-font-family-default);
        width: 100%;
        height: 100%;
      }

      .plotly-div {
        width: 100%;
        min-height: 400px;
      }

      /* Plotly layering fix for Shadow DOM */
      .plotly-div,
      .plotly-div .js-plotly-plot,
      .plotly-div .plot-container,
      .plotly-div .svg-container {
        position: relative;
        width: 100%;
        height: 100%;
      }

      .plotly-div svg.main-svg {
        position: absolute;
        top: 0;
        left: 0;
      }

      .plotly-div .hoverlayer {
        pointer-events: none;
      }

      .error-message {
        padding: var(--vanna-space-4);
        color: var(--vanna-accent-negative-default);
        text-align: center;
        font-style: italic;
      }

      .loading-message {
        padding: var(--vanna-space-4);
        color: var(--vanna-foreground-dimmer);
        text-align: center;
        font-style: italic;
      }
    `
  ];

  @property({ type: Array }) data: PlotlyData[] = [];
  @property({ type: Object }) layout: PlotlyLayout = {};
  @property({ type: Object }) config = {};
  @property({ type: Boolean }) loading = false;
  @property() error = '';
  @property() theme: 'light' | 'dark' = 'dark';

  private plotlyDiv?: HTMLElement;
  private resizeObserver?: ResizeObserver;

  firstUpdated() {
    this.plotlyDiv = this.shadowRoot?.querySelector('.plotly-div') as HTMLElement;
    this._renderChart();
    this._setupResizeObserver();
  }

  disconnectedCallback() {
    super.disconnectedCallback();
    this.resizeObserver?.disconnect();
  }

  private _setupResizeObserver() {
    if (!this.plotlyDiv) return;

    this.resizeObserver = new ResizeObserver(() => {
      if (this.plotlyDiv && this.data.length > 0) {
        const width = this.plotlyDiv.offsetWidth;
        Plotly.relayout(this.plotlyDiv, { width });
      }
    });

    this.resizeObserver.observe(this.plotlyDiv);
  }

  updated(changedProperties: Map<string | number | symbol, unknown>) {
    if (changedProperties.has('data') || changedProperties.has('layout') || changedProperties.has('theme')) {
      this._renderChart();
    }
  }

  private _getDefaultLayout(): PlotlyLayout {
    const isDark = this.theme === 'dark';

    // Start with layout from backend (which may include white background)
    const mergedLayout = {
      ...this.layout,
      // Only add font/modebar if not already set by backend
      font: this.layout.font || {
        family: 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
        color: isDark ? 'rgb(242, 244, 247)' : 'rgb(17, 24, 39)',
        size: 12
      },
      modebar: this.layout.modebar || {
        bgcolor: isDark ? 'rgba(21, 26, 38, 0.8)' : 'rgba(255, 255, 255, 0.8)',
        color: isDark ? 'rgb(177, 186, 196)' : 'rgb(75, 85, 99)',
        activecolor: isDark ? 'rgb(242, 244, 247)' : 'rgb(17, 24, 39)',
        orientation: 'h'
      },
      // Set explicit dimensions for Shadow DOM compatibility
      autosize: false,
      width: this.layout.width || undefined,
      height: this.layout.height || 400,
    };

    // If backend didn't set background colors, use transparent
    if (!this.layout.paper_bgcolor) {
      mergedLayout.paper_bgcolor = 'transparent';
    }
    if (!this.layout.plot_bgcolor) {
      mergedLayout.plot_bgcolor = 'transparent';
    }

    return mergedLayout;
  }

  private _getDefaultConfig() {
    return {
      responsive: true,
      displayModeBar: false,
      ...this.config
    };
  }

  private async _renderChart() {
    if (!this.plotlyDiv || this.loading || this.error || this.data.length === 0) {
      return;
    }

    try {
      const layout = this._getDefaultLayout();
      const config = this._getDefaultConfig();

      await Plotly.newPlot(this.plotlyDiv, this.data, layout, config);
    } catch (err) {
      this.error = err instanceof Error ? err.message : 'Failed to render chart';
      console.error('Plotly chart error:', err);
    }
  }

  render() {
    return html`
      ${this.loading ? html`
        <div class="loading-message">Loading chart...</div>
      ` : this.error ? html`
        <div class="error-message">Error: ${this.error}</div>
      ` : html`
        <div class="plotly-div"></div>
      `}
    `;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'plotly-chart': PlotlyChart;
  }
}

================================================
FILE: frontends/webcomponent/src/components/rich-card.stories.ts
================================================
import type { Meta, StoryObj } from '@storybook/web-components';
import { html } from 'lit';
import './rich-card';

const meta: Meta = {
  title: 'Rich Components/Rich Card',
  component: 'rich-card',
  parameters: {
    layout: 'padded',
    backgrounds: {
      default: 'light',
      values: [
        { name: 'dark', value: 'rgb(11, 15, 25)' },
        { name: 'light', value: '#f5f7fa' },
      ],
    },
  },
  argTypes: {
    title: { control: 'text' },
    subtitle: { control: 'text' },
    content: { control: 'text' },
    icon: { control: 'text' },
    status: {
      control: 'select',
      options: ['info', 'success', 'warning', 'error']
    },
    collapsible: { control: 'boolean' },
    collapsed: { control: 'boolean' },
  },
};

export default meta;
type Story = StoryObj;

export const Default: Story = {
  args: {
    title: 'Sample Card',
    subtitle: 'This is a subtitle',
    content: 'This is the content of the card. It can contain any text or HTML.',
    status: 'info',
    collapsible: false,
    collapsed: false,
  },
  render: (args) => html`
    <div style="max-width: 600px; margin: 0 auto;">
      <rich-card
        title=${args.title}
        subtitle=${args.subtitle}
        content=${args.content}
        icon=${args.icon}
        status=${args.status}
        ?collapsible=${args.collapsible}
        ?collapsed=${args.collapsed}>
      </rich-card>
    </div>
  `,
};

export const WithIcon: Story = {
  args: {
    title: 'Card with Icon',
    subtitle: 'Featuring an emoji icon',
    content: 'This card demonstrates how icons work with the rich card component.',
    icon: '🚀',
    status: 'success',
    collapsible: false,
  },
  render: (args) => html`
    <div style="max-width: 600px; margin: 0 auto;">
      <rich-card
        title=${args.title}
        subtitle=${args.subtitle}
        content=${args.content}
        icon=${args.icon}
        status=${args.status}
        ?collapsible=${args.collapsible}>
      </rich-card>
    </div>
  `,
};

export const WithActions: Story = {
  args: {
    title: 'Interactive Card',
    subtitle: 'With action buttons',
    content: 'This card includes action buttons that can trigger events.',
    status: 'info',
    collapsible: false,
  },
  render: (args) => html`
    <div style="max-width: 600px; margin: 0 auto;">
      <rich-card
        title=${args.title}
        subtitle=${args.subtitle}
        content=${args.content}
        status=${args.status}
        ?collapsible=${args.collapsible}
        .actions=${[
          { label: 'Primary Action', action: 'primary', variant: 'primary' },
          { label: 'Secondary Action', action: 'secondary', variant: 'secondary' }
        ]}
        @card-action=${(e: CustomEvent) => {
          console.log('Card action:', e.detail.action);
          alert(`Action triggered: ${e.detail.action}`);
        }}>
      </rich-card>
    </div>
  `,
};

export const Collapsible: Story = {
  args: {
    title: 'Collapsible Card',
    subtitle: 'Click to expand/collapse',
    content: 'This content can be hidden by clicking the toggle button in the header.',
    status: 'warning',
    collapsible: true,
    collapsed: false,
  },
  render: (args) => html`
    <div style="max-width: 600px; margin: 0 auto;">
      <rich-card
        title=${args.title}
        subtitle=${args.subtitle}
        content=${args.content}
        status=${args.status}
        ?collapsible=${args.collapsible}
        ?collapsed=${args.collapsed}>
      </rich-card>
    </div>
  `,
};

export const StatusVariants: Story = {
  render: () => html`
    <div style="max-width: 600px; margin: 0 auto; display: flex; flex-direction: column; gap: 16px;">
      <rich-card
        title="Info Status"
        content="This card shows the info status variant."
        status="info">
      </rich-card>

      <rich-card
        title="Success Status"
        content="This card shows the success status variant."
        status="success">
      </rich-card>

      <rich-card
        title="Warning Status"
        content="This card shows the warning status variant."
        status="warning">
      </rich-card>

      <rich-card
        title="Error Status"
        content="This card shows the error status variant."
        status="error">
      </rich-card>
    </div>
  `,
};

export const LightTheme: Story = {
  args: {
    title: 'Light Theme Card',
    subtitle: 'Styled for light backgrounds',
    content: 'This card is displayed with the light theme variant.',
    icon: '☀️',
    status: 'success',
  },
  parameters: {
    backgrounds: { default: 'light' }
  },
  render: (args) => html`
    <div style="max-width: 600px; margin: 0 auto;">
      <rich-card
        theme="light"
        title=${args.title}
        subtitle=${args.subtitle}
        content=${args.content}
        icon=${args.icon}
        status=${args.status}>
      </rich-card>
    </div>
  `,
};

================================================
FILE: frontends/webcomponent/src/components/rich-card.ts
================================================
import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { vannaDesignTokens } from '../styles/vanna-design-tokens.js';

export interface CardAction {
  label: string;
  action: string;
  variant?: 'primary' | 'secondary';
}

@customElement('rich-card')
export class RichCard extends LitElement {
  static styles = [
    vannaDesignTokens,
    css`
      :host {
        display: block;
        margin-bottom: var(--vanna-space-4);
        font-family: var(--vanna-font-family-default);
      }

      .card {
        border: 1px solid var(--vanna-outline-default);
        border-radius: var(--vanna-border-radius-lg);
        background: var(--vanna-background-default);
        box-shadow: var(--vanna-shadow-sm);
        overflow: hidden;
        transition: box-shadow var(--vanna-duration-200) ease;
      }

      .card:hover {
        box-shadow: var(--vanna-shadow-md);
      }

      .card-header {
        display: flex;
        align-items: center;
        padding: var(--vanna-space-4) var(--vanna-space-5);
        background: var(--vanna-background-higher);
        border-bottom: 1px solid var(--vanna-outline-default);
        gap: var(--vanna-space-3);
      }

      .card-header.collapsible {
        cursor: pointer;
      }

      .card-icon {
        font-size: 1.25rem;
        display: flex;
        align-items: center;
      }

      .card-title-section {
        flex: 1;
      }

      .card-title {
        margin: 0;
        font-size: 1rem;
        font-weight: 600;
        color: var(--vanna-foreground-default);
      }

      .card-subtitle {
        margin: var(--vanna-space-1) 0 0 0;
        font-size: 0.875rem;
        color: var(--vanna-foreground-dimmer);
      }

      .card-status {
        padding: var(--vanna-space-1) var(--vanna-space-2);
        border-radius: var(--vanna-border-radius-md);
        font-size: 0.75rem;
        font-weight: 600;
        text-transform: uppercase;
      }

      .card-status.status-success {
        background: #d4edda;
        color: #155724;
      }

      .card-status.status-warning {
        background: #fff3cd;
        color: #856404;
      }

      .card-status.status-error {
        background: #f8d7da;
        color: #721c24;
      }

      .card-status.status-info {
        background: #d1ecf1;
        color: #0c5460;
      }

      .card-toggle {
        background: none;
        border: none;
        cursor: pointer;
        font-size: 1rem;
        color: var(--vanna-foreground-dimmer);
        padding: var(--vanna-space-1);
        border-radius: var(--vanna-border-radius-sm);
        transition: background-color var(--vanna-duration-200) ease;
      }

      .card-toggle:hover {
        background: var(--vanna-background-root);
      }

      .card-content {
        padding: var(--vanna-space-4) var(--vanna-space-5);
        line-height: 1.5;
        color: var(--vanna-foreground-default);
        transition: all var(--vanna-duration-200) ease;
        overflow: hidden;
      }

      .card-content.collapsed {
        max-height: 0;
        padding-top: 0;
        padding-bottom: 0;
      }

      .card-content h1,
      .card-content h2,
      .card-content h3 {
        margin: var(--vanna-space-2) 0;
        font-weight: 600;
      }

      .card-content h1 {
        font-size: 1.5rem;
      }

      .card-content h2 {
        font-size: 1.25rem;
      }

      .card-content h3 {
        font-size: 1.125rem;
      }

      .card-content p {
        margin: var(--vanna-space-2) 0;
      }

      .card-content ul {
        margin: var(--vanna-space-2) 0;
        padding-left: var(--vanna-space-5);
      }

      .card-content li {
        margin: var(--vanna-space-1) 0;
      }

      .card-content code {
        background: var(--vanna-background-higher);
        padding: var(--vanna-space-1) var(--vanna-space-2);
        border-radius: var(--vanna-border-radius-sm);
        font-family: monospace;
        font-size: 0.875em;
      }

      .card-content strong {
        font-weight: 600;
      }

      .card-actions {
        padding: var(--vanna-space-3) var(--vanna-space-5);
        background: var(--vanna-background-root);
        border-top: 1px solid var(--vanna-outline-default);
        display: flex;
        gap: var(--vanna-space-2);
      }

      .card-action {
        padding: var(--vanna-space-2) var(--vanna-space-4);
        border-radius: var(--vanna-border-radius-md);
        border: 1px solid var(--vanna-outline-default);
        background: var(--vanna-background-default);
        color: var(--vanna-foreground-default);
        cursor: pointer;
        font-size: 0.875rem;
        font-weight: 500;
        transition: all var(--vanna-duration-200) ease;
      }

      .card-action:hover {
        background: var(--vanna-background-higher);
      }

      .card-action.primary {
        background: var(--vanna-accent-primary-default);
        color: white;
        border-color: var(--vanna-accent-primary-default);
      }

      .card-action.primary:hover {
        background: var(--vanna-accent-primary-stronger);
      }
    `
  ];

  @property() title = '';
  @property() subtitle = '';
  @property() content = '';
  @property() icon = '';
  @property() status: 'info' | 'success' | 'warning' | 'error' = 'info';
  @property({ type: Array }) actions: CardAction[] = [];
  @property({ type: Boolean }) collapsible = false;
  @property({ type: Boolean }) collapsed = false;
  @property({ type: Boolean }) markdown = false;
  @property() theme: 'light' | 'dark' = 'dark';

  private _toggleCollapsed() {
    if (this.collapsible) {
      this.collapsed = !this.collapsed;
    }
  }

  private _renderMarkdown(text: string): string {
    // Simple markdown rendering - basic formatting
    return text
      .replace(/^### (.*$)/gm, '<h3>$1</h3>')
      .replace(/^## (.*$)/gm, '<h2>$1</h2>')
      .replace(/^# (.*$)/gm, '<h1>$1</h1>')
      .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
      .replace(/\*(.*?)\*/g, '<em>$1</em>')
      .replace(/`([^`]+)`/g, '<code>$1</code>')
      .replace(/^- (.*$)/gm, '<li>$1</li>')
      .replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>')
      .replace(/\n\n/g, '</p><p>')
      .replace(/^(?!<[h|u|l|p])(.+)$/gm, '<p>$1</p>');
  }

  render() {
    const contentHtml = this.markdown
      ? html`<div class="card-content ${this.collapsed ? 'collapsed' : ''}" .innerHTML=${this._renderMarkdown(this.content)}></div>`
      : html`<div class="card-content ${this.collapsed ? 'collapsed' : ''}">${this.content}</div>`;

    return html`
      <div class="card">
        <div class="card-header ${this.collapsible ? 'collapsible' : ''}"
             @click=${this._toggleCollapsed}>
          ${this.icon ? html`<span class="card-icon">${this.icon}</span>` : ''}
          <div class="card-title-section">
            <h3 class="card-title">${this.title}</h3>
            ${this.subtitle ? html`<p class="card-subtitle">${this.subtitle}</p>` : ''}
          </div>
          ${this.status ? html`<span class="card-status status-${this.status}">${this.status}</span>` : ''}
          ${this.collapsible ? html`
            <button class="card-toggle">${this.collapsed ? '▶' : '▼'}</button>
          ` : ''}
        </div>
        ${contentHtml}
        ${this.actions.length > 0 ? html`
          <div class="card-actions">
            ${this.actions.map(action => html`
              <button class="card-action ${action.variant || 'secondary'}"
                      @click=${() => this._handleAction(action.action)}>
                ${action.label}
              </button>
            `)}
          </div>
        ` : ''}
      </div>
    `;
  }

  private async _handleAction(action: string) {
    console.log('🔘 Card action button clicked (rich-card)');
    console.log('   Action:', action);

    // Dispatch event for any listeners
    this.dispatchEvent(new CustomEvent('card-action', {
      detail: { action },
      bubbles: true,
      composed: true
    }));

    // Also directly send to vanna-chat
    const vannaChat = document.querySelector('vanna-chat') as any;
    if (vannaChat && typeof vannaChat.sendMessage === 'function') {
      console.log('   Found vanna-chat, sending message...');
      try {
        const success = await vannaChat.sendMessage(action);
        if (success) {
          console.log('   ✅ Action sent successfully');
        } else {
          console.error('   ❌ Failed to send action');
        }
      } catch (error) {
        console.error('   ❌ Error sending action:', error);
      }
    } else {
      console.warn('   ⚠️ vanna-chat component not found or sendMessage not available');
    }
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'rich-card': RichCard;
  }
}

================================================
FILE: frontends/webcomponent/src/components/rich-component-system.stories.ts
================================================
import type { Meta, StoryObj } from '@storybook/web-components';
import { ComponentManager, ComponentUpdate } from './rich-component-system';
import { vannaDesignTokens } from '../styles/vanna-design-tokens.js';

const meta: Meta = {
  title: 'Rich Components/Component System',
  parameters: {
    layout: 'padded',
    backgrounds: {
      default: 'light',
      values: [
        { name: 'light', value: '#f5f7fa' },
        { name: 'dark', value: 'rgb(11, 15, 25)' },
      ],
    },
  },
};

export default meta;
type Story = StoryObj;

const ensureTokenStyles = () => {
  if (document.getElementById('vanna-token-style')) {
    return;
  }

  const style = document.createElement('style');
  style.id = 'vanna-token-style';
  style.textContent = vannaDesignTokens.cssText.replace(/:host/g, '.vanna-tokens');
  document.head.appendChild(style);
};

const createContainer = () => {
  ensureTokenStyles();

  const container = document.createElement('div');
  container.className = 'vanna-tokens';
  container.style.cssText = `
    padding: var(--vanna-space-5, 20px);
    max-width: 800px;
    margin: 0 auto;
    background: var(--vanna-background-default);
    border-radius: var(--vanna-border-radius-lg);
    box-shadow: var(--vanna-shadow-md);
  `;

  return container;
};

const createManager = (container: HTMLElement) => new ComponentManager(container);

const renderComponent = (manager: ComponentManager, component: any) => {
  const update: ComponentUpdate = {
    operation: 'create',
    target_id: component.id,
    component,
    timestamp: new Date().toISOString(),
  } as ComponentUpdate;

  manager.processUpdate(update);
};

const withDefaults = (component: any) => ({
  layout: { position: 'append', size: {}, z_index: 0, classes: [] },
  theme: {},
  lifecycle: 'create',
  ...component,
});

export const NotificationComponents: Story = {
  render: () => {
    const container = createContainer();
    const manager = createManager(container);

    const components = [
      withDefaults({
        id: 'info-notification',
        type: 'notification',
        data: {
          message: 'This is an informational message',
          title: 'Information',
          level: 'info',
          dismissible: true,
          actions: [],
        },
      }),
      withDefaults({
        id: 'success-notification',
        type: 'notification',
        data: {
          message: 'Operation completed successfully!',
          title: 'Success',
          level: 'success',
          dismissible: true,
          actions: [
            { label: 'View Details', action: 'view', variant: 'primary' },
            { label: 'Dismiss', action: 'dismiss', variant: 'secondary' },
          ],
        },
      }),
      withDefaults({
        id: 'warning-notification',
        type: 'notification',
        data: {
          message: 'Please review the configuration before proceeding',
          title: 'Warning',
          level: 'warning',
          dismissible: true,
          actions: [],
        },
      }),
      withDefaults({
        id: 'error-notification',
        type: 'notification',
        data: {
          message: 'Failed to connect to the database. Please check your connection.',
          title: 'Connection Error',
          level: 'error',
          dismissible: true,
          actions: [
            { label: 'Retry', action: 'retry', variant: 'primary' },
            { label: 'Cancel', action: 'cancel', variant: 'secondary' },
          ],
        },
      }),
    ];

    components.forEach((component) => renderComponent(manager, component));

    return container;
  },
};

export const StatusIndicatorComponents: Story = {
  render: () => {
    const container = createContainer();
    const manager = createManager(container);

    const statuses = [
      { status: 'loading', message: 'Processing your request...', pulse: true },
      { status: 'success', message: 'Request completed successfully', pulse: false },
      { status: 'warning', message: 'Operation completed with warnings', pulse: false },
      { status: 'error', message: 'Request failed - please try again', pulse: false },
    ];

    statuses.forEach((statusData, index) => {
      const component = withDefaults({
        id: `status-${index}`,
        type: 'status_indicator',
        data: statusData,
      });

      renderComponent(manager, component);
    });

    return container;
  },
};

export const TextComponents: Story = {
  render: () => {
    const container = createContainer();
    const manager = createManager(container);

    const plainText = withDefaults({
      id: 'plain-text',
      type: 'text',
      data: {
        content: 'This is a plain text component with some sample content to demonstrate text rendering.',
        markdown: false,
      },
    });

    const markdownText = withDefaults({
      id: 'markdown-text',
      type: 'text',
      data: {
        content: `# Rich Components Demo\n\nThis is a **markdown** text component with various formatting:\n\n- **Bold text** for emphasis\n- *Italic text* for style\n- Lists for organization\n\n## Features\n\nThe text component supports:\n- Plain text rendering\n- Basic markdown formatting\n- Code syntax highlighting`,
        markdown: true,
      },
    });

    [plainText, markdownText].forEach((component) => renderComponent(manager, component));

    return container;
  },
};

export const DataFrameComponents: Story = {
  render: () => {
    const container = createContainer();
    const manager = createManager(container);

    // Sample data for different scenarios
    const sampleData = [
      { id: 1, name: 'Alice Johnson', email: 'alice@example.com', age: 28, city: 'New York', salary: 75000, active: true },
      { id: 2, name: 'Bob Smith', email: 'bob@example.com', age: 34, city: 'San Francisco', salary: 85000, active: true },
      { id: 3, name: 'Carol Davis', email: 'carol@example.com', age: 29, city: 'Chicago', salary: 70000, active: false },
      { id: 4, name: 'David Wilson', email: 'david@example.com', age: 42, city: 'Austin', salary: 90000, active: true },
      { id: 5, name: 'Eve Brown', email: 'eve@example.com', age: 31, city: 'Seattle', salary: 80000, active: true },
      { id: 6, name: 'Frank Miller', email: 'frank@example.com', age: 38, city: 'Boston', salary: 95000, active: false },
      { id: 7, name: 'Grace Lee', email: 'grace@example.com', age: 26, city: 'Denver', salary: 65000, active: true },
      { id: 8, name: 'Henry Taylor', email: 'henry@example.com', age: 33, city: 'Portland', salary: 72000, active: true },
    ];

    const columns = ['id', 'name', 'email', 'age', 'city', 'salary', 'active'];

    // Basic DataFrame
    const basicDataFrame = withDefaults({
      id: 'basic-dataframe',
      type: 'dataframe',
      data: {
        data: sampleData.slice(0, 5),
        columns: columns,
        title: 'Employee Records',
        description: 'Sample employee data with various fields',
        row_count: 5,
        column_count: columns.length,
        column_types: {
          id: 'number',
          name: 'string',
          email: 'string',
          age: 'number',
          city: 'string',
          salary: 'number',
          active: 'boolean'
        }
      },
    });

    // Large DataFrame with all features
    const fullDataFrame = withDefaults({
      id: 'full-dataframe',
      type: 'dataframe',
      data: {
        data: sampleData,
        columns: columns,
        title: 'Complete Employee Database',
        description: 'Full dataset with search, sort, and export functionality',
        row_count: sampleData.length,
        column_count: columns.length,
        searchable: true,
        sortable: true,
        filterable: true,
        exportable: true,
        striped: true,
        bordered: true,
        max_rows_displayed: 6,
        column_types: {
          id: 'number',
          name: 'string',
          email: 'string',
          age: 'number',
          city: 'string',
          salary: 'number',
          active: 'boolean'
        }
      },
    });

    // Empty DataFrame
    const emptyDataFrame = withDefaults({
      id: 'empty-dataframe',
      type: 'dataframe',
      data: {
        data: [],
        columns: [],
        title: 'Empty Dataset',
        description: 'No data available to display',
        row_count: 0,
        column_count: 0,
      },
    });

    // Compact DataFrame
    const compactDataFrame = withDefaults({
      id: 'compact-dataframe',
      type: 'dataframe',
      data: {
        data: sampleData.slice(0, 4),
        columns: ['id', 'name', 'city', 'active'],
        title: 'Compact View',
        description: 'Space-efficient display with essential columns only',
        row_count: 4,
        column_count: 4,
        compact: true,
        searchable: false,
        exportable: false,
        column_types: {
          id: 'number',
          name: 'string',
          city: 'string',
          active: 'boolean'
        }
      },
    });

    [basicDataFrame, fullDataFrame, emptyDataFrame, compactDataFrame].forEach((component) => {
      renderComponent(manager, component);
    });

    return container;
  },
};

export const SQLQueryDataFrame: Story = {
  render: () => {
    const container = createContainer();
    const manager = createManager(container);

    // SQL query result simulation
    const sqlResultData = [
      { TrackId: 1, Name: 'For Those About To Rock (We Salute You)', AlbumId: 1, MediaTypeId: 1, GenreId: 1, Composer: 'Angus Young, Malcolm Young, Brian Johnson', Milliseconds: 343719, Bytes: 11170334, UnitPrice: 0.99 },
      { TrackId: 2, Name: 'Balls to the Wall', AlbumId: 2, MediaTypeId: 2, GenreId: 1, Composer: null, Milliseconds: 342562, Bytes: 5510424, UnitPrice: 0.99 },
      { TrackId: 3, Name: 'Fast As a Shark', AlbumId: 3, MediaTypeId: 2, GenreId: 1, Composer: 'F. Baltes, S. Kaufman, U. Dirkscneider & W. Hoffman', Milliseconds: 230619, Bytes: 3990994, UnitPrice: 0.99 },
      { TrackId: 4, Name: 'Restless and Wild', AlbumId: 3, MediaTypeId: 2, GenreId: 1, Composer: 'F. Baltes, R.A. Smith-Diesel, S. Kaufman, U. Dirkscneider & W. Hoffman', Milliseconds: 252051, Bytes: 4331779, UnitPrice: 0.99 },
      { TrackId: 5, Name: 'Princess of the Dawn', AlbumId: 3, MediaTypeId: 2, GenreId: 1, Composer: 'Deaffy & R.A. Smith-Diesel', Milliseconds: 375418, Bytes: 6290521, UnitPrice: 0.99 },
    ];

    const sqlColumns = ['TrackId', 'Name', 'AlbumId', 'MediaTypeId', 'GenreId', 'Composer', 'Milliseconds', 'Bytes', 'UnitPrice'];

    const sqlDataFrame = withDefaults({
      id: 'sql-dataframe',
      type: 'dataframe',
      data: {
        data: sqlResultData,
        columns: sqlColumns,
        title: 'Query Results',
        description: 'SELECT * FROM Track LIMIT 5',
        row_count: sqlResultData.length,
        column_count: sqlColumns.length,
        searchable: true,
        sortable: true,
        exportable: true,
        column_types: {
          TrackId: 'number',
          Name: 'string',
          AlbumId: 'number',
          MediaTypeId: 'number',
          GenreId: 'number',
          Composer: 'string',
          Milliseconds: 'number',
          Bytes: 'number',
          UnitPrice: 'number'
        }
      },
    });

    renderComponent(manager, sqlDataFrame);

    return container;
  },
};


================================================
FILE: frontends/webcomponent/src/components/rich-component-system.ts
================================================
/**
 * Rich Component System for Vanna Agents
 *
 * Provides a generic component registry and rendering system that can display
 * any rich component sent from the Python backend.
 */

import { richComponentStyleText } from '../styles/rich-component-styles.js';

// Component interfaces matching Python backend
export interface RichComponent {
  id: string;
  type: string;
  lifecycle: 'create' | 'update' | 'replace' | 'remove';
  data: Record<string, any>;
  children: string[];
  timestamp: string;
  visible: boolean;
  interactive: boolean;
}

// Artifact event interfaces
export interface ArtifactOpenedEventDetail {
  // Core identification
  artifactId: string;

  // Artifact content
  content: string; // Full HTML/SVG/JS content
  type: 'html' | 'svg' | 'visualization' | 'interactive' | 'd3' | 'threejs';
  title?: string;
  description?: string;

  // Trigger context
  trigger: 'created' | 'user-action'; // How this event was fired

  // Control
  preventDefault: () => void; // Prevent default behavior

  // Helpers
  getStandaloneHTML: () => string; // Full page HTML with dependencies

  // Metadata
  timestamp: string;
}

declare global {
  interface GlobalEventHandlersEventMap {
    'artifact-opened': CustomEvent<ArtifactOpenedEventDetail>;
  }
}


const RICH_COMPONENT_STYLE_ATTR = 'data-vanna-rich-component-styles';

function ensureRichComponentStyles(container: HTMLElement): void {
  const doc = container.ownerDocument;
  if (!doc) {
    return;
  }

  if (container.querySelector(`style[${RICH_COMPONENT_STYLE_ATTR}]`)) {
    return;
  }

  const styleEl = doc.createElement('style');
  styleEl.setAttribute(RICH_COMPONENT_STYLE_ATTR, 'true');
  styleEl.textContent = richComponentStyleText;
  container.prepend(styleEl);
}

export interface ComponentUpdate {
  operation: 'create' | 'update' | 'replace' | 'remove' | 'reorder' | 'bulk_update';
  target_id: string;
  component?: RichComponent;
  updates?: Record<string, any>;
  position?: any;
  timestamp: string;
  batch_id?: string;
}

// Component renderer interface
export interface ComponentRenderer {
  render(component: RichComponent): HTMLElement;
  update(element: HTMLElement, component: RichComponent, updates?: Record<string, any>): void;
  remove(element: HTMLElement): void;
}

// Base component renderer with common functionality
export abstract class BaseComponentRenderer implements ComponentRenderer {
  abstract render(component: RichComponent): HTMLElement;

  update(element: HTMLElement, component: RichComponent, _updates?: Record<string, any>): void {
    // Default implementation - re-render completely
    const newElement = this.render(component);
    element.parentNode?.replaceChild(newElement, element);
  }

  remove(element: HTMLElement): void {
    element.remove();
  }

}

// Card component renderer
export class CardComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    console.log('🎴 CardComponentRenderer.render() called', {
      componentId: component.id,
      componentData: component.data,
      actions: component.data?.actions
    });

    const card = document.createElement('div');
    card.className = 'rich-component rich-card';
    card.dataset.componentId = component.id;

    const { title, content, subtitle, icon, status, actions = [], collapsible, collapsed } = component.data;

    console.log('🎴 Extracted actions:', actions, 'Length:', actions?.length);

    card.innerHTML = `
      <div class="card-header ${collapsible ? 'collapsible' : ''}">
        ${icon ? `<span class="card-icon">${icon}</span>` : ''}
        <div class="card-title-section">
          <h3 class="card-title">${title}</h3>
          ${subtitle ? `<p class="card-subtitle">${subtitle}</p>` : ''}
        </div>
        ${status ? `<span class="card-status status-${status}">${status}</span>` : ''}
        ${collapsible ? `<button class="card-toggle">${collapsed ? '▶' : '▼'}</button>` : ''}
      </div>
      <div class="card-content ${collapsed ? 'collapsed' : ''}">
        ${content}
      </div>
      ${actions && actions.length > 0 ? `
        <div class="card-actions">
          ${actions.map((action: any) => `
            <button class="card-action ${action.variant || 'secondary'}" data-action="${action.action}">
              ${action.label}
            </button>
          `).join('')}
        </div>
      ` : ''}
    `;


    // Add collapsible functionality
    if (collapsible) {
      const toggle = card.querySelector('.card-toggle') as HTMLButtonElement;
      const content = card.querySelector('.card-content') as HTMLElement;

      toggle?.addEventListener('click', () => {
        content.classList.toggle('collapsed');
        toggle.textContent = content.classList.contains('collapsed') ? '▶' : '▼';
      });
    }

    // Add click handlers for action buttons
    console.log('🎴 Checking if should add click handlers:', {
      hasActions: !!actions,
      actionsLength: actions?.length
    });

    if (actions && actions.length > 0) {
      const actionButtons = card.querySelectorAll('.card-action') as NodeListOf<HTMLButtonElement>;
      console.log('🎴 Found action buttons:', actionButtons.length);

      actionButtons.forEach((button, index) => {
        const action = actions[index];
        console.log(`🎴 Setting up listener for button ${index}:`, {
          hasAction: !!action,
          hasActionProperty: !!action?.action,
          action: action
        });

        if (action && action.action) {
          console.log('🎴 Adding click listener to button:', button);
          button.addEventListener('click', async () => {
            console.log('🔘 Card action button clicked:', action.label);
            console.log('   Sending action:', action.action);

            // Apply visual feedback
            button.disabled = true;
            button.classList.add('button-transitioning', 'button-clicked');

            // Find vanna-chat component and send message
            const vannaChat = document.querySelector('vanna-chat') as any;

            if (vannaChat && typeof vannaChat.sendMessage === 'function') {
              try {
                const success = await vannaChat.sendMessage(action.action);

                if (success) {
                  console.log('✅ Card action sent successfully');
                  // Keep button disabled after successful action
                } else {
                  console.error('❌ Failed to send card action');
                  // Re-enable button on failure
                  button.disabled = false;
                  button.classList.remove('button-transitioning', 'button-clicked');
                }
              } catch (error) {
                console.error('❌ Error sending card action:', error);
                // Re-enable button on error
                button.disabled = false;
                button.classList.remove('button-transitioning', 'button-clicked');
              }
            } else {
              console.warn('⚠️ vanna-chat component not found or sendMessage not available');
              button.disabled = false;
              button.classList.remove('button-transitioning', 'button-clicked');
            }
          });
        }
      });
    }

    return card;
  }

  update(element: HTMLElement, component: RichComponent, updates?: Record<string, any>): void {
    if (!updates) return super.update(element, component);

    // Optimized updates for common properties
    if (updates.title) {
      const titleEl = element.querySelector('.card-title');
      if (titleEl) titleEl.textContent = updates.title;
    }

    if (updates.content) {
      const contentEl = element.querySelector('.card-content');
      if (contentEl) contentEl.innerHTML = updates.content;
    }

    if (updates.status) {
      const statusEl = element.querySelector('.card-status');
      if (statusEl) {
        statusEl.className = `card-status status-${updates.status}`;
        statusEl.textContent = updates.status;
      }
    }

    // For complex updates, fall back to full re-render
    if (updates.actions || updates.collapsible) {
      super.update(element, component);
    }
  }
}

// Task list component renderer
export class TaskListComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = 'rich-component rich-task-list';
    container.dataset.componentId = component.id;

    const { title, tasks = [], show_progress, show_timestamps } = component.data;

    const completedTasks = tasks.filter((task: any) => task.status === 'completed').length;
    const progress = tasks.length > 0 ? (completedTasks / tasks.length) * 100 : 0;

    container.innerHTML = `
      <div class="task-list-header">
        <h3 class="task-list-title">${title}</h3>
        ${show_progress ? `
          <div class="task-list-progress">
            <span class="progress-text">${completedTasks}/${tasks.length} completed</span>
            <div class="progress-bar">
              <div class="progress-fill" style="width: ${progress}%"></div>
            </div>
          </div>
        ` : ''}
      </div>
      <div class="task-list-items">
        ${tasks.map((task: any) => this.renderTask(task, show_timestamps)).join('')}
      </div>
    `;


    return container;
  }

  private renderTask(task: any, showTimestamps: boolean): string {
    const statusIcon = this.getStatusIcon(task.status);
    const progressBar = task.progress !== null && task.progress !== undefined ? `
      <div class="task-progress">
        <div class="task-progress-bar">
          <div class="task-progress-fill" style="width: ${task.progress * 100}%"></div>
        </div>
        <span class="task-progress-text">${Math.round(task.progress * 100)}%</span>
      </div>
    ` : '';

    return `
      <div class="task-item status-${task.status}" data-task-id="${task.id}">
        <div class="task-icon">${statusIcon}</div>
        <div class="task-content">
          <div class="task-title">${task.title}</div>
          ${task.description ? `<div class="task-description">${task.description}</div>` : ''}
          ${progressBar}
          ${showTimestamps && task.created_at ? `
            <div class="task-timestamp">
              Created: ${new Date(task.created_at).toLocaleString()}
            </div>
          ` : ''}
        </div>
      </div>
    `;
  }

  private getStatusIcon(status: string): string {
    switch (status) {
      case 'completed': return '✅';
      case 'running': return '🔄';
      case 'failed': return '❌';
      default: return '⭕';
    }
  }
}

// Progress bar component renderer
export class ProgressBarComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = 'rich-component rich-progress-bar';
    container.dataset.componentId = component.id;

    const { value, label, show_percentage, status, animated } = component.data;
    const percentage = Math.round(value * 100);

    container.innerHTML = `
      <div class="progress-header">
        ${label ? `<span class="progress-label">${label}</span>` : ''}
        ${show_percentage ? `<span class="progress-percentage">${percentage}%</span>` : ''}
      </div>
      <div class="progress-track">
        <div class="progress-fill ${animated ? 'animated' : ''} ${status ? `status-${status}` : ''}"
             style="width: ${percentage}%"></div>
      </div>
    `;


    return container;
  }

  update(element: HTMLElement, component: RichComponent, updates?: Record<string, any>): void {
    if (!updates) return super.update(element, component);

    if (updates.value !== undefined) {
      const fill = element.querySelector('.progress-fill') as HTMLElement;
      const percentage = Math.round(updates.value * 100);

      if (fill) {
        fill.style.width = `${percentage}%`;
      }

      const percentageEl = element.querySelector('.progress-percentage');
      if (percentageEl) {
        percentageEl.textContent = `${percentage}%`;
      }
    }

    if (updates.label) {
      const labelEl = element.querySelector('.progress-label');
      if (labelEl) labelEl.textContent = updates.label;
    }

    if (updates.status) {
      const fill = element.querySelector('.progress-fill') as HTMLElement;
      if (fill) {
        fill.className = fill.className.replace(/status-\w+/, `status-${updates.status}`);
      }
    }
  }
}

// Notification component renderer
export class NotificationComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = 'rich-component rich-notification';
    container.dataset.componentId = component.id;

    const { message, title, level = 'info', icon, dismissible, auto_dismiss, actions = [] } = component.data;

    const levelIcon = icon || this.getLevelIcon(level);
    const dismissButton = dismissible ? `
      <button class="notification-dismiss" onclick="this.parentElement.remove()">×</button>
    ` : '';

    container.innerHTML = `
      <div class="notification-content level-${level}">
        ${levelIcon ? `<span class="notification-icon">${levelIcon}</span>` : ''}
        <div class="notification-body">
          ${title ? `<div class="notification-title">${title}</div>` : ''}
          <div class="notification-message">${message}</div>
        </div>
        ${actions.length > 0 ? `
          <div class="notification-actions">
            ${actions.map((action: any) => `
              <button class="notification-action ${action.variant || 'secondary'}" data-action="${action.action}">
                ${action.label}
              </button>
            `).join('')}
          </div>
        ` : ''}
        ${dismissButton}
      </div>
    `;

    // Auto-dismiss functionality
    if (auto_dismiss && component.data.auto_dismiss_delay) {
      setTimeout(() => {
        if (container.parentElement) {
          container.remove();
        }
      }, component.data.auto_dismiss_delay);
    }


    return container;
  }

  private getLevelIcon(level: string): string {
    switch (level) {
      case 'success': return '✅';
      case 'warning': return '⚠️';
      case 'error': return '❌';
      case 'info':
      default: return 'ℹ️';
    }
  }
}

// Status indicator component renderer
export class StatusIndicatorComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = 'rich-component rich-status-indicator';
    container.dataset.componentId = component.id;

    const { status, message, icon, pulse } = component.data;

    const statusIcon = icon || this.getStatusIcon(status);
    const pulseClass = pulse ? 'pulse' : '';

    container.innerHTML = `
      <div class="status-indicator-content status-${status} ${pulseClass}">
        <span class="status-icon">${statusIcon}</span>
        <span class="status-message">${message}</span>
      </div>
    `;


    return container;
  }

  private getStatusIcon(status: string): string {
    switch (status) {
      case 'loading': return '🔄';
      case 'success': return '✅';
      case 'warning': return '⚠️';
      case 'error': return '❌';
      default: return 'ℹ️';
    }
  }

  update(element: HTMLElement, component: RichComponent, updates?: Record<string, any>): void {
    if (!updates) return super.update(element, component);

    const content = element.querySelector('.status-indicator-content');
    if (content && updates.status) {
      content.className = content.className.replace(/status-\w+/, `status-${updates.status}`);
    }

    if (updates.pulse !== undefined) {
      const content = element.querySelector('.status-indicator-content');
      if (content) {
        if (updates.pulse) {
          content.classList.add('pulse');
        } else {
          content.classList.remove('pulse');
        }
      }
    }

    if (updates.message) {
      const messageEl = element.querySelector('.status-message');
      if (messageEl) {
        messageEl.textContent = updates.message;
      }
    }
  }
}

// DataFrame component renderer
export class DataFrameComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = 'rich-component rich-dataframe';
    container.dataset.componentId = component.id;

    const {
      data = [],
      columns = [],
      title,
      description,
      row_count = 0,
      column_count = 0,
      max_rows_displayed = 100,
      searchable = true,
      sortable = true,
      filterable = true,
      exportable = true,
      striped = true,
      bordered = true,
      compact = false,
      column_types = {}
    } = component.data;

    // Limit displayed rows
    const displayedData = data.slice(0, max_rows_displayed);
    const hasMoreRows = data.length > max_rows_displayed;

    let headerHTML = '';
    if (title || description) {
      headerHTML = `
        <div class="dataframe-header">
          ${title ? `<h3 class="dataframe-title">${title}</h3>` : ''}
          ${description ? `<p class="dataframe-description">${description}</p>` : ''}
          <div class="dataframe-meta">
            <span class="row-count">${row_count} rows</span>
            <span class="column-count">${column_count} columns</span>
          </div>
        </div>
      `;
    }

    let actionsHTML = '';
    if (searchable || exportable || filterable) {
      actionsHTML = `
        <div class="dataframe-actions">
          ${searchable ? `
            <div class="dataframe-search">
              <input type="text" placeholder="Search..." class="search-input">
            </div>
          ` : ''}
          ${exportable ? `
            <button class="export-btn" title="Export to CSV">📥 Export</button>
          ` : ''}
        </div>
      `;
    }

    let tableHTML = '';
    if (columns.length > 0 && displayedData.length > 0) {
      const tableClasses = [
        'dataframe-table',
        striped ? 'striped' : '',
        bordered ? 'bordered' : '',
        compact ? 'compact' : ''
      ].filter(Boolean).join(' ');

      tableHTML = `
        <div class="dataframe-table-container">
          <table class="${tableClasses}">
            <thead>
              <tr>
                ${columns.map((col: string) => `
                  <th class="${sortable ? 'sortable' : ''}" data-column="${col}">
                    ${col}
                    ${sortable ? '<span class="sort-indicator"></span>' : ''}
                  </th>
                `).join('')}
              </tr>
            </thead>
            <tbody>
              ${displayedData.map((row: any) => `
                <tr>
                  ${columns.map((col: string) => {
                    const value = row[col];
                    const columnType = column_types[col] || 'string';
                    const formattedValue = this.formatCellValue(value, columnType);
                    return `<td class="cell-${columnType}">${formattedValue}</td>`;
                  }).join('')}
                </tr>
              `).join('')}
            </tbody>
          </table>
          ${hasMoreRows ? `
            <div class="dataframe-truncated">
              <em>Showing ${max_rows_displayed} of ${row_count} rows</em>
            </div>
          ` : ''}
        </div>
      `;
    } else {
      tableHTML = `
        <div class="dataframe-empty">
          <p>No data to display</p>
        </div>
      `;
    }

    container.innerHTML = `
      ${headerHTML}
      ${actionsHTML}
      ${tableHTML}
    `;


    // Add event listeners
    this.attachEventListeners(container, displayedData, columns);

    return container;
  }

  private formatCellValue(value: any, columnType: string): string {
    if (value === null || value === undefined) {
      return '<em class="null-value">NULL</em>';
    }

    switch (columnType) {
      case 'number':
        return typeof value === 'number' ? value.toLocaleString() : String(value);
      case 'date':
        try {
          return new Date(value).toLocaleDateString();
        } catch {
          return String(value);
        }
      case 'boolean':
        return value ? '✓' : '✗';
      default:
        return this.escapeHtml(String(value));
    }
  }

  private escapeHtml(text: string): string {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
  }

  private attachEventListeners(container: HTMLElement, data: any[], columns: string[]): void {
    // Search functionality
    const searchInput = container.querySelector('.search-input') as HTMLInputElement;
    if (searchInput) {
      searchInput.addEventListener('input', (e) => {
        const searchTerm = (e.target as HTMLInputElement).value.toLowerCase();
        this.filterTable(container, data, columns, searchTerm);
      });
    }

    // Export functionality
    const exportBtn = container.querySelector('.export-btn') as HTMLButtonElement;
    if (exportBtn) {
      exportBtn.addEventListener('click', () => {
        this.exportToCSV(data, columns);
      });
    }

    // Sort functionality
    const sortableHeaders = container.querySelectorAll('th.sortable');
    sortableHeaders.forEach(header => {
      header.addEventListener('click', (e) => {
        const column = (e.currentTarget as HTMLElement).dataset.column;
        if (column) {
          this.sortTable(container, data, columns, column);
        }
      });
    });
  }

  private filterTable(container: HTMLElement, data: any[], columns: string[], searchTerm: string): void {
    const tbody = container.querySelector('tbody');
    if (!tbody) return;

    const filteredData = data.filter(row => {
      return columns.some(col => {
        const value = String(row[col] || '').toLowerCase();
        return value.includes(searchTerm);
      });
    });

    tbody.innerHTML = filteredData.map(row => `
      <tr>
        ${columns.map(col => {
          const value = row[col];
          const formattedValue = this.formatCellValue(value, 'string');
          return `<td>${formattedValue}</td>`;
        }).join('')}
      </tr>
    `).join('');
  }

  private sortTable(container: HTMLElement, data: any[], columns: string[], column: string): void {
    const tbody = container.querySelector('tbody');
    const header = container.querySelector(`th[data-column="${column}"]`) as HTMLElement;
    if (!tbody || !header) return;

    // Determine sort direction
    const currentSort = header.dataset.sortDirection || 'none';
    const newSort = currentSort === 'asc' ? 'desc' : 'asc';

    // Clear all sort indicators
    container.querySelectorAll('th[data-sort-direction]').forEach(h => {
      (h as HTMLElement).removeAttribute('data-sort-direction');
      const indicator = h.querySelector('.sort-indicator');
      if (indicator) indicator.textContent = '';
    });

    // Set new sort direction
    header.dataset.sortDirection = newSort;
    const indicator = header.querySelector('.sort-indicator');
    if (indicator) {
      indicator.textContent = newSort === 'asc' ? '↑' : '↓';
    }

    // Sort data
    const sortedData = [...data].sort((a, b) => {
      const aVal = a[column];
      const bVal = b[column];

      if (aVal === null || aVal === undefined) return 1;
      if (bVal === null || bVal === undefined) return -1;

      if (typeof aVal === 'number' && typeof bVal === 'number') {
        return newSort === 'asc' ? aVal - bVal : bVal - aVal;
      }

      const aStr = String(aVal).toLowerCase();
      const bStr = String(bVal).toLowerCase();
      const comparison = aStr.localeCompare(bStr);
      return newSort === 'asc' ? comparison : -comparison;
    });

    // Update table
    tbody.innerHTML = sortedData.map(row => `
      <tr>
        ${columns.map(col => {
          const value = row[col];
          const formattedValue = this.formatCellValue(value, 'string');
          return `<td>${formattedValue}</td>`;
        }).join('')}
      </tr>
    `).join('');
  }

  private exportToCSV(data: any[], columns: string[]): void {
    const csvContent = [
      columns.join(','),
      ...data.map(row =>
        columns.map(col => {
          const value = row[col];
          const strValue = value === null || value === undefined ? '' : String(value);
          // Escape quotes and wrap in quotes if contains comma, quote, or newline
          if (strValue.includes(',') || strValue.includes('"') || strValue.includes('\n')) {
            return `"${strValue.replace(/"/g, '""')}"`;
          }
          return strValue;
        }).join(',')
      )
    ].join('\n');

    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
    const link = document.createElement('a');
    const url = URL.createObjectURL(blob);
    link.setAttribute('href', url);
    link.setAttribute('download', 'data.csv');
    link.style.visibility = 'hidden';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }
}

// Text component renderer
export class TextComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = 'rich-component rich-text';
    container.dataset.componentId = component.id;

    const {
      content,
      markdown = false,
      code_language,
      font_size,
      font_weight,
      text_align
    } = component.data;

    // Apply text styling
    let textStyle = '';
    if (font_size) textStyle += `font-size: ${font_size}; `;
    if (font_weight) textStyle += `font-weight: ${font_weight}; `;
    if (text_align) textStyle += `text-align: ${text_align}; `;

    if (code_language) {
      // Code block
      container.innerHTML = `
        <pre class="text-code" style="${textStyle}"><code class="language-${code_language}">${this.escapeHtml(content)}</code></pre>
      `;
    } else if (markdown) {
      // Markdown text (simple implementation)
      container.innerHTML = `
        <div class="text-markdown" style="${textStyle}">${this.renderMarkdown(content)}</div>
      `;
    } else {
      // Plain text
      container.innerHTML = `
        <div class="text-content" style="${textStyle}">${this.escapeHtml(content)}</div>
      `;
    }


    return container;
  }

  private escapeHtml(text: string): string {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
  }

  private renderMarkdown(text: string): string {
    // Simple markdown rendering - just basic formatting
    return text
      .replace(/^## (.*$)/gm, '<h2>$1</h2>')
      .replace(/^# (.*$)/gm, '<h1>$1</h1>')
      .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
      .replace(/\*(.*?)\*/g, '<em>$1</em>')
      .replace(/^- (.*$)/gm, '<li>$1</li>')
      .replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>')
      .replace(/\n\n/g, '</p><p>')
      .replace(/^(?!<[h|u|l])(.+)$/gm, '<p>$1</p>');
  }
}

// Primitive Component Renderers (Domain-Agnostic)

// Status card component renderer
export class StatusCardComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = 'rich-component rich-status-card';
    container.dataset.componentId = component.id;

    const { title, status, description, icon, actions = [], collapsible, collapsed, metadata = {} } = component.data;

    const statusIcon = icon || this.getStatusIcon(status);
    const hasMetadata = Object.keys(metadata).length > 0;

    container.innerHTML = `
      <div class="status-card-header ${collapsible ? 'collapsible' : ''}">
        <div class="status-card-icon">${statusIcon}</div>
        <div class="status-card-title-section">
          <h3 class="status-card-title">${title}</h3>
          <span class="status-card-badge status-${status}">${status}</span>
        </div>
        ${collapsible ? `<button class="status-card-toggle">${collapsed ? '▶' : '▼'}</button>` : ''}
      </div>
      ${description ? `
        <div class="status-card-content ${collapsed ? 'collapsed' : ''}">
          ${description}
        </div>
      ` : ''}
      ${hasMetadata ? `
        <details class="status-card-metadata">
          <summary class="status-card-metadata-summary">Parameters</summary>
          <div class="status-card-metadata-content">
            ${this.renderMetadataTable(metadata)}
          </div>
        </details>
      ` : ''}
      ${actions.length > 0 ? `
        <div class="status-card-actions">
          ${actions.map((action: any) => `
            <button class="status-card-action ${action.variant || 'secondary'}" data-action="${action.action}">
              ${action.label}
            </button>
          `).join('')}
        </div>
      ` : ''}
    `;

    // Add collapsible functionality
    if (collapsible) {
      const toggle = container.querySelector('.status-card-toggle') as HTMLButtonElement;
      const content = container.querySelector('.status-card-content') as HTMLElement;

      toggle?.addEventListener('click', () => {
        if (content) {
          content.classList.toggle('collapsed');
          toggle.textContent = content.classList.contains('collapsed') ? '▶' : '▼';
        }
      });
    }

    return container;
  }

  private renderMetadataTable(metadata: Record<string, any>): string {
    const rows = Object.entries(metadata).map(([key, value]) => {
      const formattedValue = this.formatMetadataValue(value);
      return `
        <tr>
          <td class="metadata-key">${this.escapeHtml(key)}</td>
          <td class="metadata-value">${formattedValue}</td>
        </tr>
      `;
    }).join('');

    return `
      <table class="metadata-table">
        <thead>
          <tr>
            <th>Parameter</th>
            <th>Value</th>
          </tr>
        </thead>
        <tbody>
          ${rows}
        </tbody>
      </table>
    `;
  }

  private formatMetadataValue(value: any): string {
    if (value === null) {
      return '<span class="metadata-null">null</span>';
    }
    if (value === undefined) {
      return '<span class="metadata-undefined">undefined</span>';
    }
    if (typeof value === 'boolean') {
      return `<span class="metadata-boolean">${value}</span>`;
    }
    if (typeof value === 'number') {
      return `<span class="metadata-number">${value}</span>`;
    }
    if (typeof value === 'string') {
      return `<span class="metadata-string">${this.escapeHtml(value)}</span>`;
    }
    if (Array.isArray(value) || typeof value === 'object') {
      return `<pre class="metadata-json">${JSON.stringify(value, null, 2)}</pre>`;
    }
    return this.escapeHtml(String(value));
  }

  private escapeHtml(text: string): string {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
  }

  private getStatusIcon(status: string): string {
    switch (status) {
      case 'pending': return '⏳';
      case 'running': return '⚙️';
      case 'completed': return '✅';
      case 'success': return '✅';
      case 'failed': return '❌';
      case 'error': return '❌';
      case 'warning': return '⚠️';
      default: return 'ℹ️';
    }
  }
}

// Progress display component renderer
export class ProgressDisplayComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = 'rich-component rich-progress-display';
    container.dataset.componentId = component.id;

    const { label, value, description, status, show_percentage, animated, indeterminate } = component.data;
    const percentage = Math.round(value * 100);

    container.innerHTML = `
      <div class="progress-display-container">
        <div class="progress-display-header">
          <span class="progress-display-label">${label}</span>
          ${show_percentage && !indeterminate ? `<span class="progress-display-percentage">${percentage}%</span>` : ''}
        </div>
        <div class="progress-display-track">
          <div class="progress-display-fill ${animated ? 'animated' : ''} ${status ? `status-${status}` : ''} ${indeterminate ? 'indeterminate' : ''}"
               style="width: ${indeterminate ? '100' : percentage}%"></div>
        </div>
        ${description ? `<div class="progress-display-description">${description}</div>` : ''}
      </div>
    `;

    return container;
  }
}

// Log viewer component renderer
export class LogViewerComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = 'rich-component rich-log-viewer';
    container.dataset.componentId = component.id;

    const { title, entries = [], searchable, show_timestamps, auto_scroll } = component.data;

    container.innerHTML = `
      <div class="log-viewer-container">
        <div class="log-viewer-header">
          <h3 class="log-viewer-title">${title}</h3>
          ${searchable ? `
            <div class="log-viewer-search">
              <input type="text" placeholder="Search logs..." class="log-search-input">
            </div>
          ` : ''}
        </div>
        <div class="log-viewer-content ${auto_scroll ? 'auto-scroll' : ''}">
          ${entries.map((entry: any) => `
            <div class="log-entry log-${entry.level}">
              ${show_timestamps ? `<span class="log-timestamp">${new Date(entry.timestamp).toLocaleTimeString()}</span>` : ''}
              <span class="log-level">[${entry.level.toUpperCase()}]</span>
              <span class="log-message">${entry.message}</span>
            </div>
          `).join('')}
        </div>
      </div>
    `;

    // Auto-scroll to bottom if enabled
    if (auto_scroll) {
      const content = container.querySelector('.log-viewer-content');
      if (content) {
        content.scrollTop = content.scrollHeight;
      }
    }

    return container;
  }
}

// Badge component renderer
export class BadgeComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('span');
    container.className = `rich-component rich-badge badge-${component.data.variant} badge-${component.data.size}`;
    container.dataset.componentId = component.id;

    const { text, icon } = component.data;

    container.innerHTML = `
      ${icon ? `<span class="badge-icon">${icon}</span>` : ''}
      <span class="badge-text">${text}</span>
    `;

    return container;
  }
}

// Icon text component renderer
export class IconTextComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = `rich-component rich-icon-text icon-text-${component.data.variant} icon-text-${component.data.size} icon-text-${component.data.alignment}`;
    container.dataset.componentId = component.id;

    const { icon, text } = component.data;

    container.innerHTML = `
      <span class="icon-text-icon">${icon}</span>
      <span class="icon-text-text">${text}</span>
    `;

    return container;
  }
}

// Button component renderer
export class ButtonComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const button = document.createElement('button');
    button.className = `rich-component rich-button button-${component.data.variant} button-${component.data.size}`;
    button.dataset.componentId = component.id;

    const { label, action, disabled, icon, icon_position, full_width, loading } = component.data;

    if (disabled || loading) {
      button.disabled = true;
    }

    if (full_width) {
      button.classList.add('button-full-width');
    }

    if (loading) {
      button.classList.add('button-loading');
    }

    // Build button content
    let buttonContent = '';
    if (loading) {
      buttonContent = `<span class="button-spinner">⏳</span><span class="button-label">${label}</span>`;
    } else if (icon) {
      if (icon_position === 'right') {
        buttonContent = `<span class="button-label">${label}</span><span class="button-icon">${icon}</span>`;
      } else {
        buttonContent = `<span class="button-icon">${icon}</span><span class="button-label">${label}</span>`;
      }
    } else {
      buttonContent = `<span class="button-label">${label}</span>`;
    }

    button.innerHTML = buttonContent;

    // Add click handler
    if (action && !disabled && !loading) {
      button.addEventListener('click', async () => {
        console.log('🔘 Button clicked:', label);
        console.log('   Sending action:', action);

        // Apply visual feedback immediately
        button.disabled = true;
        button.classList.add('button-transitioning', 'button-clicked');

        // Find vanna-chat component and send message with button action
        const vannaChat = document.querySelector('vanna-chat') as any;
        console.log('   Found vanna-chat:', !!vannaChat);

        if (vannaChat && typeof vannaChat.sendMessage === 'function') {
          console.log('   Calling sendMessage...');
          try {
            const success = await vannaChat.sendMessage(action);
            if (success) {
              console.log('   ✓ Message sent successfully');
            } else {
              console.log('   ✗ Message failed, restoring button state');
              // Restore button state if it wasn't originally disabled
              if (!disabled) {
                button.disabled = false;
              }
              button.classList.remove('button-transitioning', 'button-clicked');
            }
          } catch (error) {
            console.error('   ✗ Message failed with error:', error);
            // Restore button state if it wasn't originally disabled
            if (!disabled) {
              button.disabled = false;
            }
            button.classList.remove('button-transitioning', 'button-clicked');
          }
        } else {
          console.error('   ✗ vanna-chat not found or sendMessage not available');
          // Restore button state if it wasn't originally disabled
          if (!disabled) {
            button.disabled = false;
          }
          button.classList.remove('button-transitioning', 'button-clicked');
        }
      });
    }

    return button;
  }

  update(element: HTMLElement, component: RichComponent, updates?: Record<string, any>): void {
    if (!updates) return super.update(element, component);

    const button = element as HTMLButtonElement;

    if (updates.disabled !== undefined) {
      button.disabled = updates.disabled;
    }

    if (updates.loading !== undefined) {
      button.disabled = updates.loading;
      if (updates.loading) {
        button.classList.add('button-loading');
      } else {
        button.classList.remove('button-loading');
      }
    }

    if (updates.label || updates.icon || updates.icon_position) {
      // Re-render content
      super.update(element, component);
    }
  }
}

// Button group component renderer
export class ButtonGroupComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = `rich-component rich-button-group button-group-${component.data.orientation} button-group-spacing-${component.data.spacing} button-group-align-${component.data.align}`;
    container.dataset.componentId = component.id;

    const { buttons = [], full_width } = component.data;

    if (full_width) {
      container.classList.add('button-group-full-width');
    }

    // Render each button
    buttons.forEach((buttonConfig: any, index: number) => {
      const button = document.createElement('button');
      button.className = `rich-button button-${buttonConfig.variant || 'secondary'} button-${buttonConfig.size || 'medium'}`;
      button.dataset.buttonIndex = String(index);

      // Store original disabled state
      if (buttonConfig.disabled) {
        button.disabled = true;
        button.dataset.originallyDisabled = 'true';
      } else {
        button.dataset.originallyDisabled = 'false';
      }

      // Build button content
      let buttonContent = '';
      if (buttonConfig.icon) {
        if (buttonConfig.icon_position === 'right') {
          buttonContent = `<span class="button-label">${buttonConfig.label}</span><span class="button-icon">${buttonConfig.icon}</span>`;
        } else {
          buttonContent = `<span class="button-icon">${buttonConfig.icon}</span><span class="button-label">${buttonConfig.label}</span>`;
        }
      } else {
        buttonContent = `<span class="button-label">${buttonConfig.label}</span>`;
      }

      button.innerHTML = buttonContent;

      // Add click handler with enhanced functionality
      if (buttonConfig.action && !buttonConfig.disabled) {
        button.addEventListener('click', async () => {
          console.log('🔘 Button Group button clicked:', buttonConfig.label);
          console.log('   Button index:', index);
          console.log('   Sending action:', buttonConfig.action);

          // Immediately apply visual changes to all buttons in the group
          this.applyButtonGroupClickState(container, index);

          // Find vanna-chat component and send message with button action
          const vannaChat = document.querySelector('vanna-chat') as any;
          console.log('   Found vanna-chat:', !!vannaChat);

          if (vannaChat && typeof vannaChat.sendMessage === 'function') {
            console.log('   Calling sendMessage...');
            try {
              const success = await vannaChat.sendMessage(buttonConfig.action);
              if (success) {
                console.log('   ✓ Message sent successfully');
              } else {
                console.log('   ✗ Message failed, restoring button state');
                this.restoreButtonGroupState(container);
              }
            } catch (error) {
              console.error('   ✗ Message failed with error:', error);
              this.restoreButtonGroupState(container);
            }
          } else {
            console.error('   ✗ vanna-chat not found or sendMessage not available');
            this.restoreButtonGroupState(container);
          }
        });
      }

      container.appendChild(button);
    });

    return container;
  }

  private applyButtonGroupClickState(container: HTMLElement, clickedIndex: number): void {
    const buttons = container.querySelectorAll('button') as NodeListOf<HTMLButtonElement>;
    
    buttons.forEach((button, index) => {
      // Disable all buttons
      button.disabled = true;
      
      // Add transition class for animation
      button.classList.add('button-transitioning');
      
      if (index === clickedIndex) {
        // Highlight the clicked button
        button.classList.add('button-clicked', 'button-highlighted');
      } else {
        // Gray out other buttons
        button.classList.add('button-grayed-out');
      }
    });
  }

  private restoreButtonGroupState(container: HTMLElement): void {
    const buttons = container.querySelectorAll('button') as NodeListOf<HTMLButtonElement>;
    
    buttons.forEach((button) => {
      // Re-enable buttons (unless they were originally disabled)
      const originallyDisabled = button.dataset.originallyDisabled === 'true';
      if (!originallyDisabled) {
        button.disabled = false;
      }
      
      // Remove all state classes
      button.classList.remove(
        'button-clicked', 
        'button-highlighted', 
        'button-grayed-out',
        'button-transitioning'
      );
    });
  }
}

// Chart component renderer (for Plotly charts)
export class ChartComponentRenderer extends BaseComponentRenderer {
  render(component: RichComponent): HTMLElement {
    const container = document.createElement('div');
    container.className = 'rich-component rich-chart';
    container.dataset.componentId = component.id;

    // The ChartComponent.data field contains the Plotly figure directly
    // Structure: component.data = { data: [...traces...], layout: {...}, title: "...", config: {...} }
    const { data: plotlyData, layout, title, config = {} } = component.data;

    console.log('ChartComponentRenderer: Received component.data:', component.data);
    console.log('ChartComponentRenderer: plotlyData:', plotlyData);
    console.log('ChartComponentRenderer: layout:', layout);

    // Check if we have a valid Plotly figure structure
    if (plotlyData && Array.isArray(plotlyData) && layout) {
      // Create plotly-chart web component
      const chartElement = document.createElement('plotly-chart') as any;

      // Set theme to match current theme
      const vannaChat = document.querySelector('vanna-chat');
      if (vannaChat) {
        chartElement.theme = vannaChat.getAttribute('theme') || 'dark';
      }

      // Wrap in container with optional title
      if (title) {
        container.innerHTML = `
          <div class="chart-header">
            <h3 class="chart-title">${title}</h3>
          </div>
          <div class="chart-content"></div>
        `;
        container.querySelector('.chart-content')?.appendChild(chartElement);
      } else {
        container.appendChild(chartElement);
      }

      // Set data AFTER the element is in the DOM
      // This ensures the web component is fully initialized
      requestAnimationFrame(() => {
        chartElement.data = plotlyData; // Plotly traces (array)
        chartElement.layout = layout; // Plotly layout (object)
        chartElement.config = config;

        console.log('ChartComponentRenderer: Set properties after DOM attachment');
        console.log('ChartComponentRenderer: chartElement.data:', chartElement.data);
        console.log('ChartComponentRenderer: chartElement.layout:', chartElement.layout);
      });
    } else {
      // Fallback for invalid chart data
      container.innerHTML = `
        <div class="chart-error">
          <p>Invalid chart data format</p>
          <pre>${JSON.stringify(component.data, null, 2).substring(0, 200)}...</pre>
        </div>
      `;
    }

    return container;
  }
}

// Artifact component renderer
export class ArtifactComponentRenderer extends BaseComponentRenderer {
  private defaultPrevented = false;

  render(component: RichComponent): HTMLElement {
    console.log('🔧 ArtifactComponentRenderer.render called with:', component);

    const container = document.createElement('div');
    container.className = 'rich-component rich-artifact';
    container.dataset.componentId = component.id;
    container.dataset.artifactId = component.data.artifact_id;

    const {
      content,
      artifact_type,
      title,
      description,
      editable,
      fullscreen_capable,
      external_renderable
    } = component.data;

    // Create artifact preview and controls
    container.innerHTML = `
      <div class="artifact-header">
        <div class="artifact-meta">
          <h3 class="artifact-title">${title || 'Artifact'}</h3>
          ${description ? `<p class="artifact-description">${description}</p>` : ''}
          <span class="artifact-type-badge">${artifact_type}</span>
        </div>
        <div class="artifact-controls">
          ${editable ? '<button class="artifact-btn edit-btn" title="Edit">✏️</button>' : ''}
          ${fullscreen_capable ? '<button class="artifact-btn fullscreen-btn" title="Fullscreen">⛶</button>' : ''}
          ${external_renderable ? '<button class="artifact-btn external-btn" title="Open External">🔗</button>' : ''}
        </div>
      </div>
      <div class="artifact-preview">
        <iframe class="artifact-iframe" sandbox="allow-scripts allow-same-origin" srcdoc="${this.escapeHtml(content)}"></iframe>
      </div>
    `;

    // Attach event listeners
    this.attachEventListeners(container, component);

    // Fire artifact-opened event for creation
    const shouldRenderInChat = this.fireArtifactOpenedEvent(component, 'created', container);

    // If default was prevented, show a placeholder instead
    if (!shouldRenderInChat) {
      container.innerHTML = `
        <div class="artifact-placeholder">
          <div class="placeholder-content">
            <span class="placeholder-icon">🎨</span>
            <div class="placeholder-text">
              <strong>${title || 'Artifact'}</strong> opened externally
              <div class="placeholder-type">${artifact_type}</div>
            </div>
            <button class="placeholder-reopen" title="Reopen">↗</button>
          </div>
        </div>
      `;

      // Add reopen functionality
      const reopenBtn = container.querySelector('.placeholder-reopen') as HTMLButtonElement;
      if (reopenBtn) {
        reopenBtn.addEventListener('click', () => {
          this.fireArtifactOpenedEvent(component, 'user-action', container);
        });
      }
    }

    return container;
  }

  private attachEventListeners(container: HTMLElement, component: RichComponent): void {
    // External button click
    const externalBtn = container.querySelector('.external-btn') as HTMLButtonElement;
    if (externalBtn) {
      externalBtn.addEventListener('click', () => {
        this.fireArtifactOpenedEvent(component, 'user-action', container);
      });
    }

    // Fullscreen button click
    const fullscreenBtn = container.querySelector('.fullscreen-btn') as HTMLButtonElement;
    if (fullscreenBtn) {
      fullscreenBtn.addEventListener('click', () => {
        this.openFullscreen(component);
      });
    }

    // Edit button click (placeholder for future implementation)
    const editBtn = container.querySelector('.edit-btn') as HTMLButtonElement;
    if (editBtn) {
      editBtn.addEventListener('click', () => {
        this.openEditor(component);
      });
    }
  }

  private fireArtifactOpenedEvent(component: RichComponent, trigger: 'created' | 'user-action', container: HTMLElement): boolean {
    console.log('🎯 fireArtifactOpenedEvent called:', { trigger, artifactId: component.data.artifact_id });

    this.defaultPrevented = false;

    const eventDetail: ArtifactOpenedEventDetail = {
      artifactId: component.data.artifact_id,
      content: component.data.content,
      type: component.data.artifact_type,
      title: component.data.title,
      description: component.data.description,
      trigger,
      preventDefault: () => {
        console.log('🛑 preventDefault called!');
        this.defaultPrevented = true;
      },
      getStandaloneHTML: () => this.generateStandaloneHTML(component),
      timestamp: new Date().toISOString()
    };

    const event = new CustomEvent('artifact-opened', {
      detail: eventDetail,
      bubbles: true,
      cancelable: true
    });

    console.log('📡 Dispatching artifact-opened event:', event);

    // Fire the event from the container element (should bubble up to vanna-chat)
    container.dispatchEvent(event);

    // Also dispatch directly on the vanna-chat element as backup
    const vannaChat = container.closest('vanna-chat');
    if (vannaChat) {
      console.log('📡 Also dispatching on vanna-chat element');
      vannaChat.dispatchEvent(new CustomEvent('artifact-opened', {
        detail: eventDetail,
        bubbles: true,
        cancelable: true
      }));
    }

    console.log('📨 Event dispatched. defaultPrevented:', this.defaultPrevented);

    // Handle default behavior if not prevented and user triggered
    if (!this.defaultPrevented && trigger === 'user-action') {
      this.handleDefaultAction(c
Download .txt
gitextract_qmlqs8x4/

├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   └── workflows/
│       ├── python-publish.yaml
│       └── tests.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTING.md
├── LICENSE
├── MIGRATION_GUIDE.md
├── README.md
├── README_LEGACY.md
├── examples/
│   ├── chromadb_gpu_example.py
│   └── transform_args_example.py
├── frontends/
│   └── webcomponent/
│       ├── .storybook/
│       │   ├── main.ts
│       │   ├── preview-head.html
│       │   └── preview.ts
│       ├── TEST_README.md
│       ├── package.json
│       ├── requirements-test.txt
│       ├── scripts/
│       │   └── sync-version.js
│       ├── src/
│       │   ├── components/
│       │   │   ├── button.stories.ts
│       │   │   ├── dataframe-component.stories.ts
│       │   │   ├── plotly-chart.stories.ts
│       │   │   ├── plotly-chart.ts
│       │   │   ├── rich-card.stories.ts
│       │   │   ├── rich-card.ts
│       │   │   ├── rich-component-system.stories.ts
│       │   │   ├── rich-component-system.ts
│       │   │   ├── rich-progress-bar.stories.ts
│       │   │   ├── rich-progress-bar.ts
│       │   │   ├── rich-task-list.stories.ts
│       │   │   ├── rich-task-list.ts
│       │   │   ├── vanna-chat.stories.ts
│       │   │   ├── vanna-chat.ts
│       │   │   ├── vanna-message.stories.ts
│       │   │   ├── vanna-message.ts
│       │   │   ├── vanna-progress-tracker.stories.ts
│       │   │   ├── vanna-progress-tracker.ts
│       │   │   ├── vanna-status-bar.stories.ts
│       │   │   └── vanna-status-bar.ts
│       │   ├── index.ts
│       │   ├── services/
│       │   │   └── api-client.ts
│       │   ├── styles/
│       │   │   ├── rich-component-styles.ts
│       │   │   └── vanna-design-tokens.ts
│       │   └── vite-env.d.ts
│       ├── test-comprehensive.html
│       ├── test_backend.py
│       ├── tsconfig.json
│       └── vite.config.ts
├── notebooks/
│   └── quickstart.ipynb
├── papers/
│   └── ai-sql-accuracy-2023-08-17.md
├── pyproject.toml
├── setup.cfg
├── src/
│   ├── evals/
│   │   ├── benchmarks/
│   │   │   └── llm_comparison.py
│   │   └── datasets/
│   │       └── sql_generation/
│   │           └── basic.yaml
│   └── vanna/
│       ├── __init__.py
│       ├── agents/
│       │   └── __init__.py
│       ├── capabilities/
│       │   ├── __init__.py
│       │   ├── agent_memory/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── file_system/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   └── sql_runner/
│       │       ├── __init__.py
│       │       ├── base.py
│       │       └── models.py
│       ├── components/
│       │   ├── __init__.py
│       │   ├── base.py
│       │   ├── rich/
│       │   │   ├── __init__.py
│       │   │   ├── containers/
│       │   │   │   ├── __init__.py
│       │   │   │   └── card.py
│       │   │   ├── data/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── chart.py
│       │   │   │   └── dataframe.py
│       │   │   ├── feedback/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── badge.py
│       │   │   │   ├── icon_text.py
│       │   │   │   ├── log_viewer.py
│       │   │   │   ├── notification.py
│       │   │   │   ├── progress.py
│       │   │   │   ├── status_card.py
│       │   │   │   └── status_indicator.py
│       │   │   ├── interactive/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── button.py
│       │   │   │   ├── task_list.py
│       │   │   │   └── ui_state.py
│       │   │   ├── specialized/
│       │   │   │   ├── __init__.py
│       │   │   │   └── artifact.py
│       │   │   └── text.py
│       │   └── simple/
│       │       ├── __init__.py
│       │       ├── image.py
│       │       ├── link.py
│       │       └── text.py
│       ├── core/
│       │   ├── __init__.py
│       │   ├── _compat.py
│       │   ├── agent/
│       │   │   ├── __init__.py
│       │   │   ├── agent.py
│       │   │   └── config.py
│       │   ├── audit/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── component_manager.py
│       │   ├── components.py
│       │   ├── enhancer/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── default.py
│       │   ├── enricher/
│       │   │   ├── __init__.py
│       │   │   └── base.py
│       │   ├── errors.py
│       │   ├── evaluation/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   ├── dataset.py
│       │   │   ├── evaluators.py
│       │   │   ├── report.py
│       │   │   └── runner.py
│       │   ├── filter/
│       │   │   ├── __init__.py
│       │   │   └── base.py
│       │   ├── lifecycle/
│       │   │   ├── __init__.py
│       │   │   └── base.py
│       │   ├── llm/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── middleware/
│       │   │   ├── __init__.py
│       │   │   └── base.py
│       │   ├── observability/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── recovery/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── registry.py
│       │   ├── rich_component.py
│       │   ├── simple_component.py
│       │   ├── storage/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── system_prompt/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── default.py
│       │   ├── tool/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── models.py
│       │   ├── user/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   ├── models.py
│       │   │   ├── request_context.py
│       │   │   └── resolver.py
│       │   ├── validation.py
│       │   └── workflow/
│       │       ├── __init__.py
│       │       ├── base.py
│       │       └── default.py
│       ├── examples/
│       │   ├── __init__.py
│       │   ├── __main__.py
│       │   ├── anthropic_quickstart.py
│       │   ├── artifact_example.py
│       │   ├── claude_sqlite_example.py
│       │   ├── coding_agent_example.py
│       │   ├── custom_system_prompt_example.py
│       │   ├── default_workflow_handler_example.py
│       │   ├── email_auth_example.py
│       │   ├── evaluation_example.py
│       │   ├── extensibility_example.py
│       │   ├── minimal_example.py
│       │   ├── mock_auth_example.py
│       │   ├── mock_custom_tool.py
│       │   ├── mock_quickstart.py
│       │   ├── mock_quota_example.py
│       │   ├── mock_rich_components_demo.py
│       │   ├── mock_sqlite_example.py
│       │   ├── openai_quickstart.py
│       │   ├── primitive_components_demo.py
│       │   ├── quota_lifecycle_example.py
│       │   └── visualization_example.py
│       ├── integrations/
│       │   ├── __init__.py
│       │   ├── anthropic/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── azureopenai/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── azuresearch/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── bigquery/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── chromadb/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── clickhouse/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── duckdb/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── faiss/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── google/
│       │   │   ├── __init__.py
│       │   │   └── gemini.py
│       │   ├── hive/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── local/
│       │   │   ├── __init__.py
│       │   │   ├── agent_memory/
│       │   │   │   ├── __init__.py
│       │   │   │   └── in_memory.py
│       │   │   ├── audit.py
│       │   │   ├── file_system.py
│       │   │   ├── file_system_conversation_store.py
│       │   │   └── storage.py
│       │   ├── marqo/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── milvus/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── mock/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── mssql/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── mysql/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── ollama/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── openai/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   └── responses.py
│       │   ├── opensearch/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── oracle/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── pinecone/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── plotly/
│       │   │   ├── __init__.py
│       │   │   └── chart_generator.py
│       │   ├── postgres/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── premium/
│       │   │   └── agent_memory/
│       │   │       ├── __init__.py
│       │   │       └── premium.py
│       │   ├── presto/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── qdrant/
│       │   │   ├── __init__.py
│       │   │   └── agent_memory.py
│       │   ├── snowflake/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   ├── sqlite/
│       │   │   ├── __init__.py
│       │   │   └── sql_runner.py
│       │   └── weaviate/
│       │       ├── __init__.py
│       │       └── agent_memory.py
│       ├── legacy/
│       │   ├── ZhipuAI/
│       │   │   ├── ZhipuAI_Chat.py
│       │   │   ├── ZhipuAI_embeddings.py
│       │   │   └── __init__.py
│       │   ├── __init__.py
│       │   ├── adapter.py
│       │   ├── advanced/
│       │   │   └── __init__.py
│       │   ├── anthropic/
│       │   │   ├── __init__.py
│       │   │   └── anthropic_chat.py
│       │   ├── azuresearch/
│       │   │   ├── __init__.py
│       │   │   └── azuresearch_vector.py
│       │   ├── base/
│       │   │   ├── __init__.py
│       │   │   └── base.py
│       │   ├── bedrock/
│       │   │   ├── __init__.py
│       │   │   └── bedrock_converse.py
│       │   ├── chromadb/
│       │   │   ├── __init__.py
│       │   │   └── chromadb_vector.py
│       │   ├── cohere/
│       │   │   ├── __init__.py
│       │   │   ├── cohere_chat.py
│       │   │   └── cohere_embeddings.py
│       │   ├── deepseek/
│       │   │   ├── __init__.py
│       │   │   └── deepseek_chat.py
│       │   ├── exceptions/
│       │   │   └── __init__.py
│       │   ├── faiss/
│       │   │   ├── __init__.py
│       │   │   └── faiss.py
│       │   ├── flask/
│       │   │   ├── __init__.py
│       │   │   ├── assets.py
│       │   │   └── auth.py
│       │   ├── google/
│       │   │   ├── __init__.py
│       │   │   ├── bigquery_vector.py
│       │   │   └── gemini_chat.py
│       │   ├── hf/
│       │   │   ├── __init__.py
│       │   │   └── hf.py
│       │   ├── local.py
│       │   ├── marqo/
│       │   │   ├── __init__.py
│       │   │   └── marqo.py
│       │   ├── milvus/
│       │   │   ├── __init__.py
│       │   │   └── milvus_vector.py
│       │   ├── mistral/
│       │   │   ├── __init__.py
│       │   │   └── mistral.py
│       │   ├── mock/
│       │   │   ├── __init__.py
│       │   │   ├── embedding.py
│       │   │   ├── llm.py
│       │   │   └── vectordb.py
│       │   ├── ollama/
│       │   │   ├── __init__.py
│       │   │   └── ollama.py
│       │   ├── openai/
│       │   │   ├── __init__.py
│       │   │   ├── openai_chat.py
│       │   │   └── openai_embeddings.py
│       │   ├── opensearch/
│       │   │   ├── __init__.py
│       │   │   ├── opensearch_vector.py
│       │   │   └── opensearch_vector_semantic.py
│       │   ├── oracle/
│       │   │   ├── __init__.py
│       │   │   └── oracle_vector.py
│       │   ├── pgvector/
│       │   │   ├── __init__.py
│       │   │   └── pgvector.py
│       │   ├── pinecone/
│       │   │   ├── __init__.py
│       │   │   └── pinecone_vector.py
│       │   ├── qdrant/
│       │   │   ├── __init__.py
│       │   │   └── qdrant.py
│       │   ├── qianfan/
│       │   │   ├── Qianfan_Chat.py
│       │   │   ├── Qianfan_embeddings.py
│       │   │   └── __init__.py
│       │   ├── qianwen/
│       │   │   ├── QianwenAI_chat.py
│       │   │   ├── QianwenAI_embeddings.py
│       │   │   └── __init__.py
│       │   ├── remote.py
│       │   ├── types/
│       │   │   └── __init__.py
│       │   ├── utils.py
│       │   ├── vannadb/
│       │   │   ├── __init__.py
│       │   │   └── vannadb_vector.py
│       │   ├── vllm/
│       │   │   ├── __init__.py
│       │   │   └── vllm.py
│       │   ├── weaviate/
│       │   │   ├── __init__.py
│       │   │   └── weaviate_vector.py
│       │   └── xinference/
│       │       ├── __init__.py
│       │       └── xinference.py
│       ├── py.typed
│       ├── servers/
│       │   ├── __init__.py
│       │   ├── __main__.py
│       │   ├── base/
│       │   │   ├── __init__.py
│       │   │   ├── chat_handler.py
│       │   │   ├── models.py
│       │   │   ├── rich_chat_handler.py
│       │   │   └── templates.py
│       │   ├── cli/
│       │   │   ├── __init__.py
│       │   │   └── server_runner.py
│       │   ├── fastapi/
│       │   │   ├── __init__.py
│       │   │   ├── app.py
│       │   │   └── routes.py
│       │   └── flask/
│       │       ├── __init__.py
│       │       ├── app.py
│       │       └── routes.py
│       ├── tools/
│       │   ├── __init__.py
│       │   ├── agent_memory.py
│       │   ├── file_system.py
│       │   ├── python.py
│       │   ├── run_sql.py
│       │   └── visualize_data.py
│       ├── utils/
│       │   └── __init__.py
│       └── web_components/
│           └── __init__.py
├── tests/
│   ├── conftest.py
│   ├── test_agent_memory.py
│   ├── test_agent_memory_sanity.py
│   ├── test_agents.py
│   ├── test_azureopenai_llm.py
│   ├── test_chromadb_persistence_fix.py
│   ├── test_database_sanity.py
│   ├── test_gemini_integration.py
│   ├── test_legacy_adapter.py
│   ├── test_llm_context_enhancer.py
│   ├── test_memory_tools.py
│   ├── test_ollama_direct.py
│   ├── test_tool_permissions.py
│   └── test_workflow.py
└── tox.ini
Download .txt
SYMBOL INDEX (2076 symbols across 222 files)

FILE: examples/chromadb_gpu_example.py
  function example_default_usage (line 15) | def example_default_usage():
  function example_auto_gpu (line 27) | def example_auto_gpu():
  function example_explicit_cuda (line 47) | def example_explicit_cuda():
  function example_custom_model_gpu (line 63) | def example_custom_model_gpu():
  function example_manual_chromadb (line 81) | def example_manual_chromadb():

FILE: examples/transform_args_example.py
  class SQLExecutionArgs (line 20) | class SQLExecutionArgs(BaseModel):
  class SQLExecutionTool (line 25) | class SQLExecutionTool(Tool[SQLExecutionArgs]):
    method name (line 27) | def name(self) -> str:
    method description (line 31) | def description(self) -> str:
    method get_args_schema (line 34) | def get_args_schema(self):
    method execute (line 37) | async def execute(self, context: ToolContext, args: SQLExecutionArgs) ...
  class RLSToolRegistry (line 45) | class RLSToolRegistry(ToolRegistry):
    method transform_args (line 48) | async def transform_args(
  function example_usage (line 100) | async def example_usage():

FILE: frontends/webcomponent/scripts/sync-version.js
  constant PYPROJECT_PATH (line 14) | const PYPROJECT_PATH = path.join(__dirname, '../../../pyproject.toml');
  constant PACKAGE_JSON_PATH (line 15) | const PACKAGE_JSON_PATH = path.join(__dirname, '../package.json');
  function extractVersionFromPyproject (line 17) | function extractVersionFromPyproject(content) {
  function updatePackageJsonVersion (line 26) | function updatePackageJsonVersion(packageJsonPath, newVersion) {
  function main (line 41) | function main() {

FILE: frontends/webcomponent/src/components/button.stories.ts
  type Story (line 20) | type Story = StoryObj;

FILE: frontends/webcomponent/src/components/dataframe-component.stories.ts
  type Story (line 45) | type Story = StoryObj;

FILE: frontends/webcomponent/src/components/plotly-chart.stories.ts
  type Story (line 29) | type Story = StoryObj;

FILE: frontends/webcomponent/src/components/plotly-chart.ts
  type PlotlyData (line 6) | interface PlotlyData {
  type PlotlyLayout (line 17) | interface PlotlyLayout {
  class PlotlyChart (line 33) | class PlotlyChart extends LitElement {
    method firstUpdated (line 95) | firstUpdated() {
    method disconnectedCallback (line 101) | disconnectedCallback() {
    method _setupResizeObserver (line 106) | private _setupResizeObserver() {
    method updated (line 119) | updated(changedProperties: Map<string | number | symbol, unknown>) {
    method _getDefaultLayout (line 125) | private _getDefaultLayout(): PlotlyLayout {
    method _getDefaultConfig (line 160) | private _getDefaultConfig() {
    method _renderChart (line 168) | private async _renderChart() {
    method render (line 184) | render() {
  type HTMLElementTagNameMap (line 198) | interface HTMLElementTagNameMap {

FILE: frontends/webcomponent/src/components/rich-card.stories.ts
  type Story (line 33) | type Story = StoryObj;

FILE: frontends/webcomponent/src/components/rich-card.ts
  type CardAction (line 5) | interface CardAction {
  class RichCard (line 12) | class RichCard extends LitElement {
    method _toggleCollapsed (line 219) | private _toggleCollapsed() {
    method _renderMarkdown (line 225) | private _renderMarkdown(text: string): string {
    method render (line 240) | render() {
    method _handleAction (line 274) | private async _handleAction(action: string) {
  type HTMLElementTagNameMap (line 306) | interface HTMLElementTagNameMap {

FILE: frontends/webcomponent/src/components/rich-component-system.stories.ts
  type Story (line 20) | type Story = StoryObj;

FILE: frontends/webcomponent/src/components/rich-component-system.ts
  type RichComponent (line 11) | interface RichComponent {
  type ArtifactOpenedEventDetail (line 23) | interface ArtifactOpenedEventDetail {
  type GlobalEventHandlersEventMap (line 47) | interface GlobalEventHandlersEventMap {
  constant RICH_COMPONENT_STYLE_ATTR (line 53) | const RICH_COMPONENT_STYLE_ATTR = 'data-vanna-rich-component-styles';
  function ensureRichComponentStyles (line 55) | function ensureRichComponentStyles(container: HTMLElement): void {
  type ComponentUpdate (line 71) | interface ComponentUpdate {
  type ComponentRenderer (line 82) | interface ComponentRenderer {
  method update (line 92) | update(element: HTMLElement, component: RichComponent, _updates?: Record...
  method remove (line 98) | remove(element: HTMLElement): void {
  class CardComponentRenderer (line 105) | class CardComponentRenderer extends BaseComponentRenderer {
    method render (line 106) | render(component: RichComponent): HTMLElement {
    method update (line 220) | update(element: HTMLElement, component: RichComponent, updates?: Recor...
  class TaskListComponentRenderer (line 250) | class TaskListComponentRenderer extends BaseComponentRenderer {
    method render (line 251) | render(component: RichComponent): HTMLElement {
    method renderTask (line 282) | private renderTask(task: any, showTimestamps: boolean): string {
    method getStatusIcon (line 310) | private getStatusIcon(status: string): string {
  class ProgressBarComponentRenderer (line 321) | class ProgressBarComponentRenderer extends BaseComponentRenderer {
    method render (line 322) | render(component: RichComponent): HTMLElement {
    method update (line 345) | update(element: HTMLElement, component: RichComponent, updates?: Recor...
  class NotificationComponentRenderer (line 377) | class NotificationComponentRenderer extends BaseComponentRenderer {
    method render (line 378) | render(component: RichComponent): HTMLElement {
    method getLevelIcon (line 423) | private getLevelIcon(level: string): string {
  class StatusIndicatorComponentRenderer (line 435) | class StatusIndicatorComponentRenderer extends BaseComponentRenderer {
    method render (line 436) | render(component: RichComponent): HTMLElement {
    method getStatusIcon (line 457) | private getStatusIcon(status: string): string {
    method update (line 467) | update(element: HTMLElement, component: RichComponent, updates?: Recor...
  class DataFrameComponentRenderer (line 496) | class DataFrameComponentRenderer extends BaseComponentRenderer {
    method render (line 497) | render(component: RichComponent): HTMLElement {
    method formatCellValue (line 617) | private formatCellValue(value: any, columnType: string): string {
    method escapeHtml (line 638) | private escapeHtml(text: string): string {
    method attachEventListeners (line 644) | private attachEventListeners(container: HTMLElement, data: any[], colu...
    method filterTable (line 674) | private filterTable(container: HTMLElement, data: any[], columns: stri...
    method sortTable (line 696) | private sortTable(container: HTMLElement, data: any[], columns: string...
    method exportToCSV (line 749) | private exportToCSV(data: any[], columns: string[]): void {
  class TextComponentRenderer (line 778) | class TextComponentRenderer extends BaseComponentRenderer {
    method render (line 779) | render(component: RichComponent): HTMLElement {
    method escapeHtml (line 820) | private escapeHtml(text: string): string {
    method renderMarkdown (line 826) | private renderMarkdown(text: string): string {
  class StatusCardComponentRenderer (line 843) | class StatusCardComponentRenderer extends BaseComponentRenderer {
    method render (line 844) | render(component: RichComponent): HTMLElement {
    method renderMetadataTable (line 903) | private renderMetadataTable(metadata: Record<string, any>): string {
    method formatMetadataValue (line 929) | private formatMetadataValue(value: any): string {
    method escapeHtml (line 951) | private escapeHtml(text: string): string {
    method getStatusIcon (line 957) | private getStatusIcon(status: string): string {
  class ProgressDisplayComponentRenderer (line 972) | class ProgressDisplayComponentRenderer extends BaseComponentRenderer {
    method render (line 973) | render(component: RichComponent): HTMLElement {
  class LogViewerComponentRenderer (line 1000) | class LogViewerComponentRenderer extends BaseComponentRenderer {
    method render (line 1001) | render(component: RichComponent): HTMLElement {
  class BadgeComponentRenderer (line 1043) | class BadgeComponentRenderer extends BaseComponentRenderer {
    method render (line 1044) | render(component: RichComponent): HTMLElement {
  class IconTextComponentRenderer (line 1061) | class IconTextComponentRenderer extends BaseComponentRenderer {
    method render (line 1062) | render(component: RichComponent): HTMLElement {
  class ButtonComponentRenderer (line 1079) | class ButtonComponentRenderer extends BaseComponentRenderer {
    method render (line 1080) | render(component: RichComponent): HTMLElement {
    method update (line 1165) | update(element: HTMLElement, component: RichComponent, updates?: Recor...
  class ButtonGroupComponentRenderer (line 1191) | class ButtonGroupComponentRenderer extends BaseComponentRenderer {
    method render (line 1192) | render(component: RichComponent): HTMLElement {
    method applyButtonGroupClickState (line 1272) | private applyButtonGroupClickState(container: HTMLElement, clickedInde...
    method restoreButtonGroupState (line 1292) | private restoreButtonGroupState(container: HTMLElement): void {
  class ChartComponentRenderer (line 1314) | class ChartComponentRenderer extends BaseComponentRenderer {
    method render (line 1315) | render(component: RichComponent): HTMLElement {
  class ArtifactComponentRenderer (line 1378) | class ArtifactComponentRenderer extends BaseComponentRenderer {
    method render (line 1381) | render(component: RichComponent): HTMLElement {
    method attachEventListeners (line 1451) | private attachEventListeners(container: HTMLElement, component: RichCo...
    method fireArtifactOpenedEvent (line 1477) | private fireArtifactOpenedEvent(component: RichComponent, trigger: 'cr...
    method generateStandaloneHTML (line 1530) | private generateStandaloneHTML(component: RichComponent): string {
    method handleDefaultAction (line 1573) | private handleDefaultAction(component: RichComponent): void {
    method openFullscreen (line 1582) | private openFullscreen(component: RichComponent): void {
    method openEditor (line 1649) | private openEditor(component: RichComponent): void {
    method escapeHtml (line 1654) | private escapeHtml(html: string): string {
  class UserMessageComponentRenderer (line 1662) | class UserMessageComponentRenderer extends BaseComponentRenderer {
    method render (line 1663) | render(component: RichComponent): HTMLElement {
  class AssistantMessageComponentRenderer (line 1678) | class AssistantMessageComponentRenderer extends BaseComponentRenderer {
    method render (line 1679) | render(component: RichComponent): HTMLElement {
  class ComponentRegistry (line 1694) | class ComponentRegistry {
    method constructor (line 1697) | constructor() {
    method register (line 1727) | register(type: string, renderer: ComponentRenderer): void {
    method render (line 1731) | render(component: RichComponent): HTMLElement {
    method getWebComponentTag (line 1746) | private getWebComponentTag(type: string): string | null {
    method renderWebComponent (line 1756) | private renderWebComponent(tagName: string, component: RichComponent):...
    method getCurrentTheme (line 1775) | private getCurrentTheme(): string {
    method update (line 1785) | update(element: HTMLElement, component: RichComponent, updates?: Recor...
    method remove (line 1792) | remove(element: HTMLElement): void {
    method renderFallback (line 1796) | private renderFallback(component: RichComponent): HTMLElement {
  class ComponentManager (line 1813) | class ComponentManager {
    method constructor (line 1830) | constructor(container: HTMLElement) {
    method processUpdate (line 1835) | processUpdate(update: ComponentUpdate): void {
    method createComponent (line 1858) | private createComponent(update: ComponentUpdate): void {
    method updateComponent (line 1870) | private updateComponent(update: ComponentUpdate): void {
    method replaceComponent (line 1881) | private replaceComponent(update: ComponentUpdate): void {
    method removeComponent (line 1901) | private removeComponent(update: ComponentUpdate): void {
    method positionComponent (line 1910) | private positionComponent(element: HTMLElement): void {
    method triggerScroll (line 1918) | private triggerScroll(): void {
    method clear (line 1931) | clear(): void {
    method getComponent (line 1938) | getComponent(id: string): RichComponent | undefined {
    method getAllComponents (line 1942) | getAllComponents(): RichComponent[] {
    method normalizeComponent (line 1946) | private normalizeComponent(component: RichComponent): RichComponent {
    method isUIStateUpdate (line 1964) | private isUIStateUpdate(component: RichComponent): boolean {
    method processUIStateUpdate (line 1970) | private processUIStateUpdate(component: RichComponent): void {
    method updateStatusBar (line 1986) | private updateStatusBar(component: RichComponent): void {
    method updateTaskTracker (line 2010) | private updateTaskTracker(component: RichComponent): void {
    method updateChatInput (line 2063) | private updateChatInput(component: RichComponent): void {

FILE: frontends/webcomponent/src/components/rich-progress-bar.stories.ts
  type Story (line 33) | type Story = StoryObj;

FILE: frontends/webcomponent/src/components/rich-progress-bar.ts
  class RichProgressBar (line 6) | class RichProgressBar extends LitElement {
    method percentage (line 148) | private get percentage(): number {
    method progressClasses (line 153) | private get progressClasses(): string {
    method render (line 171) | render() {
  type HTMLElementTagNameMap (line 199) | interface HTMLElementTagNameMap {

FILE: frontends/webcomponent/src/components/rich-task-list.stories.ts
  type Story (line 27) | type Story = StoryObj;

FILE: frontends/webcomponent/src/components/rich-task-list.ts
  type TaskItem (line 5) | interface TaskItem {
  class RichTaskList (line 15) | class RichTaskList extends LitElement {
    method completedTasks (line 201) | private get completedTasks(): number {
    method progressPercentage (line 205) | private get progressPercentage(): number {
    method getStatusIcon (line 209) | private getStatusIcon(status: string): string {
    method renderTask (line 219) | private renderTask(task: TaskItem) {
    method render (line 246) | render() {
  type HTMLElementTagNameMap (line 269) | interface HTMLElementTagNameMap {

FILE: frontends/webcomponent/src/components/vanna-chat.stories.ts
  type Story (line 35) | type Story = StoryObj;

FILE: frontends/webcomponent/src/components/vanna-chat.ts
  class VannaChat (line 14) | class VannaChat extends LitElement {
    method windowState (line 730) | get windowState() {
    method windowState (line 734) | set windowState(value: 'normal' | 'maximized' | 'minimized') {
    method constructor (line 747) | constructor() {
    method ensureApiClient (line 757) | private ensureApiClient() {
    method firstUpdated (line 774) | firstUpdated() {
    method requestStarterUI (line 811) | private async requestStarterUI(): Promise<void> {
    method disconnectedCallback (line 830) | disconnectedCallback() {
    method updated (line 840) | updated(changedProperties: Map<string, any>) {
    method handleInput (line 852) | private handleInput(e: Event) {
    method handleKeyPress (line 857) | private handleKeyPress(e: KeyboardEvent) {
    method sendMessage (line 868) | sendMessage(messageText?: string): Promise<boolean> {
    method _sendMessageInternal (line 885) | private async _sendMessageInternal(messageText: string): Promise<boole...
    method getTitleInitials (line 973) | private getTitleInitials(): string {
    method minimizeWindow (line 990) | private minimizeWindow(e?: Event) {
    method maximizeWindow (line 1005) | private maximizeWindow(e?: Event) {
    method restoreWindow (line 1018) | private restoreWindow(e?: Event) {
    method addMessage (line 1032) | addMessage(content: string, type: 'user' | 'assistant') {
    method setStatus (line 1059) | setStatus(status: typeof this.status, message: string, detail?: string) {
    method clearStatus (line 1065) | clearStatus() {
    method getProgressTracker (line 1071) | getProgressTracker(): HTMLElement | null {
    method handleStreamingResponse (line 1075) | private async handleStreamingResponse(request: any) {
    method processChunk (line 1118) | private async processChunk(chunk: ChatStreamChunk) {
    method getChunkTitle (line 1198) | private getChunkTitle(chunk: ChatStreamChunk): string {
    method generateId (line 1212) | private generateId(): string {
    method updateApiBaseUrl (line 1219) | updateApiBaseUrl(baseUrl: string) {
    method getApiClient (line 1227) | getApiClient(): VannaApiClient {
    method setCustomHeaders (line 1237) | setCustomHeaders(headers: Record<string, string>) {
    method updateEmptyState (line 1244) | private updateEmptyState() {
    method updateScrollIndicator (line 1258) | private updateScrollIndicator() {
    method scrollToLastMessage (line 1273) | scrollToLastMessage() {
    method clearMessages (line 1293) | clearMessages() {
    method addTestMessages (line 1304) | addTestMessages(count: number = 10) {
    method render (line 1314) | render() {

FILE: frontends/webcomponent/src/components/vanna-message.stories.ts
  type Story (line 22) | type Story = StoryObj;

FILE: frontends/webcomponent/src/components/vanna-message.ts
  class VannaMessage (line 6) | class VannaMessage extends LitElement {
    method formatTimestamp (line 204) | private formatTimestamp(timestamp: number): string {
    method render (line 211) | render() {

FILE: frontends/webcomponent/src/components/vanna-progress-tracker.stories.ts
  type Story (line 29) | type Story = StoryObj;

FILE: frontends/webcomponent/src/components/vanna-progress-tracker.ts
  type ProgressItem (line 5) | interface ProgressItem {
  class VannaProgressTracker (line 13) | class VannaProgressTracker extends LitElement {
    method addItem (line 183) | addItem(text: string, detail?: string, id?: string): string {
    method updateItem (line 194) | updateItem(id: string, status: ProgressItem['status'], detail?: string) {
    method clearItems (line 200) | clearItems() {
    method getStatusIcon (line 204) | private getStatusIcon(status: ProgressItem['status']) {
    method getProgressSummary (line 225) | private getProgressSummary() {
    method render (line 236) | render() {

FILE: frontends/webcomponent/src/components/vanna-status-bar.stories.ts
  type Story (line 34) | type Story = StoryObj;

FILE: frontends/webcomponent/src/components/vanna-status-bar.ts
  class VannaStatusBar (line 6) | class VannaStatusBar extends LitElement {
    method disconnectedCallback (line 349) | disconnectedCallback() {
    method updated (line 363) | updated(_changedProperties: Map<string | number | symbol, unknown>) {
    method render (line 426) | render() {

FILE: frontends/webcomponent/src/services/api-client.ts
  type ChatMessage (line 5) | interface ChatMessage {
  type ChatRequest (line 12) | interface ChatRequest {
  type ChatStreamChunk (line 20) | interface ChatStreamChunk {
  type ChatResponse (line 28) | interface ChatResponse {
  type ApiClientConfig (line 35) | interface ApiClientConfig {
  class VannaApiClient (line 44) | class VannaApiClient {
    method constructor (line 52) | constructor(config: ApiClientConfig = {}) {
    method setCustomHeaders (line 71) | setCustomHeaders(headers: Record<string, string>) {
    method getCustomHeaders (line 78) | getCustomHeaders(): Record<string, string> {
    method streamChat (line 85) | async *streamChat(request: ChatRequest): AsyncGenerator<ChatStreamChun...
    method createWebSocketConnection (line 152) | createWebSocketConnection(): Promise<WebSocket> {
    method sendWebSocketMessage (line 191) | async sendWebSocketMessage(
    method sendPollMessage (line 265) | async sendPollMessage(request: ChatRequest): Promise<ChatResponse> {
    method generateId (line 288) | generateId(): string {

FILE: frontends/webcomponent/test_backend.py
  class ChatRequest (line 61) | class ChatRequest(BaseModel):
  class UiComponent (line 69) | class UiComponent(BaseModel):
  function yield_chunk (line 82) | async def yield_chunk(component: RichComponent, conversation_id: str, re...
  function delay (line 93) | async def delay(mode: str, short: float = 0.1, long: float = 0.5):
  function test_text_component (line 101) | async def test_text_component(conversation_id: str, request_id: str, mod...
  function test_status_card (line 149) | async def test_status_card(conversation_id: str, request_id: str, mode: ...
  function test_progress_display (line 179) | async def test_progress_display(conversation_id: str, request_id: str, m...
  function test_card_component (line 208) | async def test_card_component(conversation_id: str, request_id: str, mod...
  function test_task_list (line 257) | async def test_task_list(conversation_id: str, request_id: str, mode: st...
  function test_progress_bar (line 296) | async def test_progress_bar(conversation_id: str, request_id: str, mode:...
  function test_notification (line 317) | async def test_notification(conversation_id: str, request_id: str, mode:...
  function test_status_indicator (line 330) | async def test_status_indicator(conversation_id: str, request_id: str, m...
  function test_badge (line 351) | async def test_badge(conversation_id: str, request_id: str, mode: str) -...
  function test_icon_text (line 362) | async def test_icon_text(conversation_id: str, request_id: str, mode: st...
  function test_buttons (line 373) | async def test_buttons(conversation_id: str, request_id: str, mode: str)...
  function test_dataframe (line 398) | async def test_dataframe(conversation_id: str, request_id: str, mode: st...
  function test_chart (line 450) | async def test_chart(conversation_id: str, request_id: str, mode: str) -...
  function test_artifact (line 511) | async def test_artifact(conversation_id: str, request_id: str, mode: str...
  function test_log_viewer (line 538) | async def test_log_viewer(conversation_id: str, request_id: str, mode: s...
  function test_ui_state_updates (line 573) | async def test_ui_state_updates(conversation_id: str, request_id: str, m...
  function run_comprehensive_test (line 640) | async def run_comprehensive_test(conversation_id: str, request_id: str, ...
  function handle_action_message (line 741) | async def handle_action_message(message: str, conversation_id: str, requ...
  function chat_sse (line 781) | async def chat_sse(chat_request: ChatRequest) -> StreamingResponse:
  function health (line 834) | async def health():
  function root (line 840) | async def root():

FILE: src/evals/benchmarks/llm_comparison.py
  function get_sql_tools (line 27) | def get_sql_tools() -> ToolRegistry:
  function compare_llms (line 37) | async def compare_llms():
  function main (line 159) | async def main():

FILE: src/vanna/capabilities/agent_memory/base.py
  class AgentMemory (line 23) | class AgentMemory(ABC):
    method save_tool_usage (line 27) | async def save_tool_usage(
    method save_text_memory (line 40) | async def save_text_memory(
    method search_similar_usage (line 47) | async def search_similar_usage(
    method search_text_memories (line 60) | async def search_text_memories(
    method get_recent_memories (line 72) | async def get_recent_memories(
    method get_recent_text_memories (line 79) | async def get_recent_text_memories(
    method delete_by_id (line 86) | async def delete_by_id(self, context: "ToolContext", memory_id: str) -...
    method delete_text_memory (line 91) | async def delete_text_memory(self, context: "ToolContext", memory_id: ...
    method clear_memories (line 96) | async def clear_memories(

FILE: src/vanna/capabilities/agent_memory/models.py
  class ToolMemory (line 10) | class ToolMemory(BaseModel):
  class TextMemory (line 22) | class TextMemory(BaseModel):
  class ToolMemorySearchResult (line 30) | class ToolMemorySearchResult(BaseModel):
  class TextMemorySearchResult (line 38) | class TextMemorySearchResult(BaseModel):
  class MemoryStats (line 46) | class MemoryStats(BaseModel):

FILE: src/vanna/capabilities/file_system/base.py
  class FileSystem (line 16) | class FileSystem(ABC):
    method list_files (line 20) | async def list_files(self, directory: str, context: "ToolContext") -> ...
    method read_file (line 25) | async def read_file(self, filename: str, context: "ToolContext") -> str:
    method write_file (line 30) | async def write_file(
    method exists (line 41) | async def exists(self, path: str, context: "ToolContext") -> bool:
    method is_directory (line 46) | async def is_directory(self, path: str, context: "ToolContext") -> bool:
    method search_files (line 51) | async def search_files(
    method run_bash (line 63) | async def run_bash(

FILE: src/vanna/capabilities/file_system/models.py
  class FileSearchMatch (line 12) | class FileSearchMatch:
  class CommandResult (line 20) | class CommandResult:

FILE: src/vanna/capabilities/sql_runner/base.py
  class SqlRunner (line 18) | class SqlRunner(ABC):
    method run_sql (line 22) | async def run_sql(

FILE: src/vanna/capabilities/sql_runner/models.py
  class RunSqlToolArgs (line 10) | class RunSqlToolArgs(BaseModel):

FILE: src/vanna/components/rich/containers/card.py
  class CardComponent (line 8) | class CardComponent(RichComponent):

FILE: src/vanna/components/rich/data/chart.py
  class ChartComponent (line 8) | class ChartComponent(RichComponent):

FILE: src/vanna/components/rich/data/dataframe.py
  class DataFrameComponent (line 8) | class DataFrameComponent(RichComponent):
    method __init__ (line 40) | def __init__(self, **kwargs: Any) -> None:
    method from_records (line 66) | def from_records(

FILE: src/vanna/components/rich/feedback/badge.py
  class BadgeComponent (line 7) | class BadgeComponent(RichComponent):

FILE: src/vanna/components/rich/feedback/icon_text.py
  class IconTextComponent (line 6) | class IconTextComponent(RichComponent):

FILE: src/vanna/components/rich/feedback/log_viewer.py
  class LogEntry (line 10) | class LogEntry(BaseModel):
  class LogViewerComponent (line 19) | class LogViewerComponent(RichComponent):
    method add_entry (line 30) | def add_entry(

FILE: src/vanna/components/rich/feedback/notification.py
  class NotificationComponent (line 8) | class NotificationComponent(RichComponent):

FILE: src/vanna/components/rich/feedback/progress.py
  class ProgressBarComponent (line 7) | class ProgressBarComponent(RichComponent):
  class ProgressDisplayComponent (line 18) | class ProgressDisplayComponent(RichComponent):
    method update_progress (line 30) | def update_progress(

FILE: src/vanna/components/rich/feedback/status_card.py
  class StatusCardComponent (line 8) | class StatusCardComponent(RichComponent):
    method set_status (line 21) | def set_status(

FILE: src/vanna/components/rich/feedback/status_indicator.py
  class StatusIndicatorComponent (line 7) | class StatusIndicatorComponent(RichComponent):

FILE: src/vanna/components/rich/interactive/button.py
  class ButtonComponent (line 7) | class ButtonComponent(RichComponent):
    method __init__ (line 31) | def __init__(
  class ButtonGroupComponent (line 57) | class ButtonGroupComponent(RichComponent):
    method __init__ (line 78) | def __init__(

FILE: src/vanna/components/rich/interactive/task_list.py
  class Task (line 10) | class Task(BaseModel):
  class TaskListComponent (line 23) | class TaskListComponent(RichComponent):
    method add_task (line 34) | def add_task(self, task: Task) -> "TaskListComponent":
    method update_task (line 39) | def update_task(self, task_id: str, **updates: Any) -> "TaskListCompon...
    method complete_task (line 51) | def complete_task(self, task_id: str) -> "TaskListComponent":

FILE: src/vanna/components/rich/interactive/ui_state.py
  class StatusBarUpdateComponent (line 9) | class StatusBarUpdateComponent(RichComponent):
    method __init__ (line 17) | def __init__(self, **kwargs: Any) -> None:
  class TaskOperation (line 23) | class TaskOperation(str, Enum):
  class TaskTrackerUpdateComponent (line 32) | class TaskTrackerUpdateComponent(RichComponent):
    method __init__ (line 43) | def __init__(self, **kwargs: Any) -> None:
    method add_task (line 49) | def add_task(cls, task: Task) -> "TaskTrackerUpdateComponent":
    method update_task (line 54) | def update_task(
    method remove_task (line 71) | def remove_task(cls, task_id: str) -> "TaskTrackerUpdateComponent":
    method clear_tasks (line 76) | def clear_tasks(cls) -> "TaskTrackerUpdateComponent":
  class ChatInputUpdateComponent (line 81) | class ChatInputUpdateComponent(RichComponent):
    method __init__ (line 90) | def __init__(self, **kwargs: Any) -> None:

FILE: src/vanna/components/rich/specialized/artifact.py
  class ArtifactComponent (line 9) | class ArtifactComponent(RichComponent):

FILE: src/vanna/components/rich/text.py
  class RichTextComponent (line 7) | class RichTextComponent(RichComponent):

FILE: src/vanna/components/simple/image.py
  class SimpleImageComponent (line 8) | class SimpleImageComponent(SimpleComponent):

FILE: src/vanna/components/simple/link.py
  class SimpleLinkComponent (line 8) | class SimpleLinkComponent(SimpleComponent):

FILE: src/vanna/components/simple/text.py
  class SimpleTextComponent (line 7) | class SimpleTextComponent(SimpleComponent):

FILE: src/vanna/core/_compat.py
  class StrEnum (line 13) | class StrEnum(str, Enum):  # type: ignore[no-redef]

FILE: src/vanna/core/agent/agent.py
  class Agent (line 56) | class Agent:
    method __init__ (line 82) | def __init__(
    method send_message (line 142) | async def send_message(
    method _send_message (line 231) | async def _send_message(
    method get_available_tools (line 1156) | async def get_available_tools(self, user: User) -> List[ToolSchema]:
    method _build_llm_request (line 1160) | async def _build_llm_request(
    method _send_llm_request (line 1241) | async def _send_llm_request(self, request: LlmRequest) -> LlmResponse:
    method _handle_streaming_response (line 1315) | async def _handle_streaming_response(self, request: LlmRequest) -> Llm...

FILE: src/vanna/core/agent/config.py
  class UiFeature (line 17) | class UiFeature(StrEnum):
  class UiFeatures (line 35) | class UiFeatures(BaseModel):
    method can_user_access_feature (line 49) | def can_user_access_feature(self, feature_name: str, user: "User") -> ...
    method register_feature (line 75) | def register_feature(self, name: str, access_groups: List[str]) -> None:
  class AuditConfig (line 85) | class AuditConfig(BaseModel):
  class AgentConfig (line 113) | class AgentConfig(BaseModel):

FILE: src/vanna/core/audit/base.py
  class AuditLogger (line 27) | class AuditLogger(ABC):
    method log_event (line 51) | async def log_event(self, event: AuditEvent) -> None:
    method log_tool_access_check (line 62) | async def log_tool_access_check(
    method log_tool_invocation (line 95) | async def log_tool_invocation(
    method log_tool_result (line 133) | async def log_tool_result(
    method log_ui_feature_access (line 171) | async def log_ui_feature_access(
    method log_ai_response (line 203) | async def log_ai_response(
    method query_events (line 243) | async def query_events(
    method _sanitize_parameters (line 266) | def _sanitize_parameters(

FILE: src/vanna/core/audit/models.py
  class AuditEventType (line 16) | class AuditEventType(StrEnum):
  class AuditEvent (line 37) | class AuditEvent(BaseModel):
  class ToolAccessCheckEvent (line 63) | class ToolAccessCheckEvent(AuditEvent):
  class ToolInvocationEvent (line 73) | class ToolInvocationEvent(AuditEvent):
  class ToolResultEvent (line 88) | class ToolResultEvent(AuditEvent):
  class UiFeatureAccessCheckEvent (line 103) | class UiFeatureAccessCheckEvent(AuditEvent):
  class AiResponseEvent (line 112) | class AiResponseEvent(AuditEvent):

FILE: src/vanna/core/component_manager.py
  class UpdateOperation (line 15) | class UpdateOperation(str, Enum):
  class Position (line 26) | class Position(BaseModel):
  class ComponentUpdate (line 34) | class ComponentUpdate(BaseModel):
    method serialize_for_frontend (line 45) | def serialize_for_frontend(self) -> Dict[str, Any]:
  class ComponentNode (line 58) | class ComponentNode(BaseModel):
    method find_child (line 65) | def find_child(self, component_id: str) -> Optional["ComponentNode"]:
    method remove_child (line 75) | def remove_child(self, component_id: str) -> bool:
    method get_all_ids (line 85) | def get_all_ids(self) -> Set[str]:
  class ComponentTree (line 93) | class ComponentTree(BaseModel):
    method add_component (line 99) | def add_component(
    method update_component (line 121) | def update_component(
    method replace_component (line 145) | def replace_component(
    method remove_component (line 164) | def remove_component(self, component_id: str) -> Optional[ComponentUpd...
    method get_component (line 184) | def get_component(self, component_id: str) -> Optional[RichComponent]:
    method _find_parent (line 189) | def _find_parent(self, position: Optional[Position]) -> Optional[Compo...
  class ComponentManager (line 211) | class ComponentManager:
    method __init__ (line 214) | def __init__(self) -> None:
    method emit (line 220) | def emit(self, component: RichComponent) -> Optional[ComponentUpdate]:
    method update_component (line 249) | def update_component(
    method replace_component (line 263) | def replace_component(
    method remove_component (line 278) | def remove_component(self, component_id: str) -> Optional[ComponentUpd...
    method get_component (line 290) | def get_component(self, component_id: str) -> Optional[RichComponent]:
    method get_all_components (line 294) | def get_all_components(self) -> List[RichComponent]:
    method start_batch (line 298) | def start_batch(self) -> str:
    method end_batch (line 303) | def end_batch(self) -> Optional[str]:
    method get_updates_since (line 309) | def get_updates_since(
    method clear_history (line 327) | def clear_history(self) -> None:

FILE: src/vanna/core/components.py
  class UiComponent (line 14) | class UiComponent(BaseModel):
    method validate_components (line 33) | def validate_components(self) -> "UiComponent":

FILE: src/vanna/core/enhancer/base.py
  class LlmContextEnhancer (line 16) | class LlmContextEnhancer(ABC):
    method enhance_system_prompt (line 54) | async def enhance_system_prompt(
    method enhance_user_messages (line 75) | async def enhance_user_messages(

FILE: src/vanna/core/enhancer/default.py
  class DefaultLlmContextEnhancer (line 17) | class DefaultLlmContextEnhancer(LlmContextEnhancer):
    method __init__ (line 32) | def __init__(self, agent_memory: Optional["AgentMemory"] = None):
    method enhance_system_prompt (line 41) | async def enhance_system_prompt(
    method enhance_user_messages (line 103) | async def enhance_user_messages(

FILE: src/vanna/core/enricher/base.py
  class ToolContextEnricher (line 15) | class ToolContextEnricher(ABC):
    method enrich_context (line 46) | async def enrich_context(self, context: "ToolContext") -> "ToolContext":

FILE: src/vanna/core/errors.py
  class AgentError (line 8) | class AgentError(Exception):
  class ToolExecutionError (line 14) | class ToolExecutionError(AgentError):
  class ToolNotFoundError (line 20) | class ToolNotFoundError(AgentError):
  class PermissionError (line 26) | class PermissionError(AgentError):
  class ConversationNotFoundError (line 32) | class ConversationNotFoundError(AgentError):
  class LlmServiceError (line 38) | class LlmServiceError(AgentError):
  class ValidationError (line 44) | class ValidationError(AgentError):

FILE: src/vanna/core/evaluation/base.py
  class ExpectedOutcome (line 17) | class ExpectedOutcome(BaseModel):
  class TestCase (line 40) | class TestCase(BaseModel):
  class AgentResult (line 61) | class AgentResult:
    method get_final_answer (line 77) | def get_final_answer(self) -> str:
    method get_tool_names_called (line 92) | def get_tool_names_called(self) -> List[str]:
  class EvaluationResult (line 97) | class EvaluationResult(BaseModel):
  class TestCaseResult (line 120) | class TestCaseResult:
    method overall_passed (line 128) | def overall_passed(self) -> bool:
    method overall_score (line 132) | def overall_score(self) -> float:
  class AgentVariant (line 140) | class AgentVariant:
  class Evaluator (line 157) | class Evaluator(ABC):
    method name (line 167) | def name(self) -> str:
    method evaluate (line 172) | async def evaluate(

FILE: src/vanna/core/evaluation/dataset.py
  class EvaluationDataset (line 17) | class EvaluationDataset:
    method __init__ (line 33) | def __init__(self, name: str, test_cases: List[TestCase], description:...
    method from_yaml (line 46) | def from_yaml(cls, path: str) -> "EvaluationDataset":
    method from_json (line 61) | def from_json(cls, path: str) -> "EvaluationDataset":
    method _from_dict (line 76) | def _from_dict(cls, data: Dict[str, Any]) -> "EvaluationDataset":
    method _parse_test_case (line 97) | def _parse_test_case(cls, data: Dict[str, Any]) -> TestCase:
    method save_yaml (line 139) | def save_yaml(self, path: str) -> None:
    method save_json (line 149) | def save_json(self, path: str) -> None:
    method _to_dict (line 159) | def _to_dict(self) -> Dict[str, Any]:
    method _test_case_to_dict (line 173) | def _test_case_to_dict(self, test_case: TestCase) -> Dict[str, Any]:
    method filter_by_metadata (line 225) | def filter_by_metadata(self, **kwargs: Any) -> "EvaluationDataset":
    method __len__ (line 246) | def __len__(self) -> int:
    method __repr__ (line 250) | def __repr__(self) -> str:

FILE: src/vanna/core/evaluation/evaluators.py
  class TrajectoryEvaluator (line 18) | class TrajectoryEvaluator(Evaluator):
    method name (line 26) | def name(self) -> str:
    method evaluate (line 29) | async def evaluate(
  class OutputEvaluator (line 93) | class OutputEvaluator(Evaluator):
    method name (line 101) | def name(self) -> str:
    method evaluate (line 104) | async def evaluate(
  class LLMAsJudgeEvaluator (line 171) | class LLMAsJudgeEvaluator(Evaluator):
    method __init__ (line 178) | def __init__(self, judge_llm: LlmService, criteria: str):
    method name (line 189) | def name(self) -> str:
    method evaluate (line 192) | async def evaluate(
    method _parse_score (line 265) | def _parse_score(self, judgment: str) -> float:
    method _parse_passed (line 276) | def _parse_passed(self, judgment: str) -> bool:
    method _parse_reasoning (line 284) | def _parse_reasoning(self, judgment: str) -> str:
  class EfficiencyEvaluator (line 292) | class EfficiencyEvaluator(Evaluator):
    method __init__ (line 298) | def __init__(
    method name (line 316) | def name(self) -> str:
    method evaluate (line 319) | async def evaluate(

FILE: src/vanna/core/evaluation/report.py
  class EvaluationReport (line 17) | class EvaluationReport:
    method pass_rate (line 34) | def pass_rate(self) -> float:
    method average_score (line 41) | def average_score(self) -> float:
    method average_time (line 47) | def average_time(self) -> float:
    method total_tokens (line 53) | def total_tokens(self) -> int:
    method get_failures (line 57) | def get_failures(self) -> List[TestCaseResult]:
    method print_summary (line 61) | def print_summary(self) -> None:
  class ComparisonReport (line 89) | class ComparisonReport:
    method print_summary (line 106) | def print_summary(self) -> None:
    method get_best_variant (line 132) | def get_best_variant(self, metric: str = "score") -> str:
    method save_csv (line 150) | def save_csv(self, path: str) -> None:
    method save_html (line 194) | def save_html(self, path: str) -> None:
    method _generate_html (line 206) | def _generate_html(self) -> str:

FILE: src/vanna/core/evaluation/runner.py
  class EvaluationRunner (line 29) | class EvaluationRunner:
    method __init__ (line 47) | def __init__(
    method run_evaluation (line 65) | async def run_evaluation(
    method compare_agents (line 89) | async def compare_agents(
    method compare_agents_streaming (line 135) | async def compare_agents_streaming(
    method _run_agent_variant (line 175) | async def _run_agent_variant(
    method _run_test_cases_parallel (line 214) | async def _run_test_cases_parallel(
    method _run_single_test_case (line 234) | async def _run_single_test_case(
    method _execute_agent (line 267) | async def _execute_agent(

FILE: src/vanna/core/filter/base.py
  class ConversationFilter (line 15) | class ConversationFilter(ABC):
    method filter_messages (line 54) | async def filter_messages(self, messages: List["Message"]) -> List["Me...

FILE: src/vanna/core/lifecycle/base.py
  class LifecycleHook (line 17) | class LifecycleHook(ABC):
    method before_message (line 39) | async def before_message(self, user: "User", message: str) -> Optional...
    method after_message (line 54) | async def after_message(self, result: Any) -> None:
    method before_tool (line 62) | async def before_tool(self, tool: "Tool[Any]", context: "ToolContext")...
    method after_tool (line 74) | async def after_tool(self, result: "ToolResult") -> Optional["ToolResu...

FILE: src/vanna/core/llm/base.py
  class LlmService (line 13) | class LlmService(ABC):
    method send_request (line 17) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 22) | async def stream_request(
    method validate_tools (line 38) | async def validate_tools(self, tools: List[Any]) -> List[str]:

FILE: src/vanna/core/llm/models.py
  class LlmMessage (line 15) | class LlmMessage(BaseModel):
  class LlmRequest (line 24) | class LlmRequest(BaseModel):
  class LlmResponse (line 41) | class LlmResponse(BaseModel):
    method is_tool_call (line 50) | def is_tool_call(self) -> bool:
  class LlmStreamChunk (line 55) | class LlmStreamChunk(BaseModel):

FILE: src/vanna/core/middleware/base.py
  class LlmMiddleware (line 15) | class LlmMiddleware(ABC):
    method before_llm_request (line 46) | async def before_llm_request(self, request: "LlmRequest") -> "LlmReque...
    method after_llm_response (line 57) | async def after_llm_response(

FILE: src/vanna/core/observability/base.py
  class ObservabilityProvider (line 14) | class ObservabilityProvider(ABC):
    method record_metric (line 48) | async def record_metric(
    method create_span (line 65) | async def create_span(
    method end_span (line 82) | async def end_span(self, span: Span) -> None:

FILE: src/vanna/core/observability/models.py
  class Span (line 12) | class Span(BaseModel):
    method end (line 24) | def end(self) -> None:
    method duration_ms (line 29) | def duration_ms(self) -> Optional[float]:
    method set_attribute (line 35) | def set_attribute(self, key: str, value: Any) -> None:
  class Metric (line 40) | class Metric(BaseModel):

FILE: src/vanna/core/recovery/base.py
  class ErrorRecoveryStrategy (line 18) | class ErrorRecoveryStrategy(ABC):
    method handle_tool_error (line 50) | async def handle_tool_error(
    method handle_llm_error (line 68) | async def handle_llm_error(

FILE: src/vanna/core/recovery/models.py
  class RecoveryActionType (line 11) | class RecoveryActionType(str, Enum):
  class RecoveryAction (line 20) | class RecoveryAction(BaseModel):

FILE: src/vanna/core/registry.py
  class _LocalToolWrapper (line 20) | class _LocalToolWrapper(Tool[T]):
    method __init__ (line 23) | def __init__(self, wrapped_tool: Tool[T], access_groups: List[str]):
    method name (line 28) | def name(self) -> str:
    method description (line 32) | def description(self) -> str:
    method access_groups (line 36) | def access_groups(self) -> List[str]:
    method get_args_schema (line 39) | def get_args_schema(self) -> Type[T]:
    method execute (line 42) | async def execute(self, context: ToolContext, args: T) -> ToolResult:
  class ToolRegistry (line 46) | class ToolRegistry:
    method __init__ (line 49) | def __init__(
    method register_local_tool (line 63) | def register_local_tool(self, tool: Tool[Any], access_groups: List[str...
    method get_tool (line 82) | async def get_tool(self, name: str) -> Optional[Tool[Any]]:
    method list_tools (line 86) | async def list_tools(self) -> List[str]:
    method get_schemas (line 90) | async def get_schemas(self, user: Optional[User] = None) -> List[ToolS...
    method _validate_tool_permissions (line 98) | async def _validate_tool_permissions(self, tool: Tool[Any], user: User...
    method transform_args (line 113) | async def transform_args(
    method execute (line 144) | async def execute(

FILE: src/vanna/core/rich_component.py
  class ComponentType (line 19) | class ComponentType(str, Enum):
  class ComponentLifecycle (line 63) | class ComponentLifecycle(str, Enum):
  class RichComponent (line 72) | class RichComponent(BaseModel):
    method update (line 84) | def update(self: T, **kwargs: Any) -> T:
    method hide (line 92) | def hide(self: T) -> T:
    method show (line 96) | def show(self: T) -> T:
    method serialize_for_frontend (line 100) | def serialize_for_frontend(self) -> Dict[str, Any]:

FILE: src/vanna/core/simple_component.py
  class SimpleComponentType (line 8) | class SimpleComponentType(str, Enum):
  class SimpleComponent (line 14) | class SimpleComponent(BaseModel):
    method serialize_for_frontend (line 25) | def serialize_for_frontend(self) -> Dict[str, Any]:

FILE: src/vanna/core/storage/base.py
  class ConversationStore (line 14) | class ConversationStore(ABC):
    method create_conversation (line 18) | async def create_conversation(
    method get_conversation (line 25) | async def get_conversation(
    method update_conversation (line 32) | async def update_conversation(self, conversation: Conversation) -> None:
    method delete_conversation (line 37) | async def delete_conversation(self, conversation_id: str, user: User) ...
    method list_conversations (line 42) | async def list_conversations(

FILE: src/vanna/core/storage/models.py
  class Message (line 16) | class Message(BaseModel):
  class Conversation (line 29) | class Conversation(BaseModel):
    method add_message (line 43) | def add_message(self, message: Message) -> None:

FILE: src/vanna/core/system_prompt/base.py
  class SystemPromptBuilder (line 15) | class SystemPromptBuilder(ABC):
    method build_system_prompt (line 23) | async def build_system_prompt(

FILE: src/vanna/core/system_prompt/default.py
  class DefaultSystemPromptBuilder (line 18) | class DefaultSystemPromptBuilder(SystemPromptBuilder):
    method __init__ (line 26) | def __init__(self, base_prompt: Optional[str] = None):
    method build_system_prompt (line 34) | async def build_system_prompt(

FILE: src/vanna/core/tool/base.py
  class Tool (line 16) | class Tool(ABC, Generic[T]):
    method name (line 21) | def name(self) -> str:
    method description (line 27) | def description(self) -> str:
    method access_groups (line 32) | def access_groups(self) -> List[str]:
    method get_args_schema (line 37) | def get_args_schema(self) -> Type[T]:
    method execute (line 42) | async def execute(self, context: ToolContext, args: T) -> ToolResult:
    method get_schema (line 54) | def get_schema(self) -> ToolSchema:

FILE: src/vanna/core/tool/models.py
  class ToolCall (line 20) | class ToolCall(BaseModel):
  class ToolContext (line 28) | class ToolContext(BaseModel):
    class Config (line 43) | class Config:
  class ToolResult (line 47) | class ToolResult(BaseModel):
  class ToolSchema (line 64) | class ToolSchema(BaseModel):
  class ToolRejection (line 75) | class ToolRejection(BaseModel):

FILE: src/vanna/core/user/base.py
  class UserService (line 13) | class UserService(ABC):
    method get_user (line 17) | async def get_user(self, user_id: str) -> Optional[User]:
    method authenticate (line 22) | async def authenticate(self, credentials: Dict[str, Any]) -> Optional[...
    method has_permission (line 27) | async def has_permission(self, user: User, permission: str) -> bool:

FILE: src/vanna/core/user/models.py
  class User (line 12) | class User(BaseModel):

FILE: src/vanna/core/user/request_context.py
  class RequestContext (line 13) | class RequestContext(BaseModel):
    method get_cookie (line 43) | def get_cookie(self, name: str, default: Optional[str] = None) -> Opti...
    method get_header (line 55) | def get_header(self, name: str, default: Optional[str] = None) -> Opti...

FILE: src/vanna/core/user/resolver.py
  class UserResolver (line 14) | class UserResolver(ABC):
    method resolve_user (line 30) | async def resolve_user(self, request_context: RequestContext) -> User:

FILE: src/vanna/core/validation.py
  function validate_pydantic_models_in_package (line 14) | def validate_pydantic_models_in_package(package_name: str) -> Dict[str, ...
  function check_models_health (line 113) | def check_models_health() -> bool:

FILE: src/vanna/core/workflow/base.py
  class WorkflowResult (line 32) | class WorkflowResult:
  class WorkflowHandler (line 74) | class WorkflowHandler(ABC):
    method try_handle (line 134) | async def try_handle(
    method get_starter_ui (line 197) | async def get_starter_ui(

FILE: src/vanna/core/workflow/default.py
  class DefaultWorkflowHandler (line 32) | class DefaultWorkflowHandler(WorkflowHandler):
    method __init__ (line 42) | def __init__(self, welcome_message: Optional[str] = None):
    method try_handle (line 51) | async def try_handle(
    method get_starter_ui (line 164) | async def get_starter_ui(
    method _generate_starter_card (line 194) | def _generate_starter_card(
    method _generate_admin_starter_card (line 206) | def _generate_admin_starter_card(self, analysis: Dict[str, Any]) -> Ui...
    method _generate_user_starter_card (line 265) | def _generate_user_starter_card(self, analysis: Dict[str, Any]) -> UiC...
    method _analyze_setup (line 285) | def _analyze_setup(self, tool_names: List[str]) -> Dict[str, Any]:
    method _generate_setup_status_cards (line 332) | def _generate_setup_status_cards(
    method _generate_setup_guidance (line 399) | def _generate_setup_guidance(
    method _generate_status_check (line 455) | async def _generate_status_check(
    method _get_recent_memories (line 512) | async def _get_recent_memories(
    method _delete_memory (line 683) | async def _delete_memory(

FILE: src/vanna/examples/__main__.py
  function main (line 9) | def main() -> None:

FILE: src/vanna/examples/anthropic_quickstart.py
  function ensure_env (line 17) | def ensure_env() -> None:
  function main (line 35) | async def main() -> None:

FILE: src/vanna/examples/artifact_example.py
  class ArtifactDemoAgent (line 18) | class ArtifactDemoAgent(Agent):
    method __init__ (line 21) | def __init__(self, llm_service: Optional[LlmService] = None) -> None:
    method send_message (line 34) | async def send_message(
    method create_html_artifact (line 63) | async def create_html_artifact(self) -> AsyncGenerator[UiComponent, No...
    method create_d3_visualization (line 90) | async def create_d3_visualization(self) -> AsyncGenerator[UiComponent,...
    method create_dashboard_artifact (line 163) | async def create_dashboard_artifact(self) -> AsyncGenerator[UiComponen...
  function create_demo_agent (line 221) | def create_demo_agent() -> ArtifactDemoAgent:
  function main (line 230) | async def main() -> None:

FILE: src/vanna/examples/claude_sqlite_example.py
  function ensure_env (line 26) | def ensure_env() -> None:
  function main (line 44) | async def main() -> None:
  function create_demo_agent (line 166) | def create_demo_agent() -> "Agent":

FILE: src/vanna/examples/coding_agent_example.py
  class CodingLlmService (line 35) | class CodingLlmService(LlmService):
    method send_request (line 44) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 49) | async def stream_request(
    method validate_tools (line 68) | async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
    method _build_response (line 72) | def _build_response(self, request: LlmRequest) -> LlmResponse:
  function create_demo_agent (line 199) | def create_demo_agent() -> Agent:
  function main (line 232) | async def main() -> None:
  function _extract_filename (line 288) | def _extract_filename(message: str) -> Optional[str]:

FILE: src/vanna/examples/custom_system_prompt_example.py
  class CustomSystemPromptBuilder (line 17) | class CustomSystemPromptBuilder(SystemPromptBuilder):
    method build_system_prompt (line 20) | async def build_system_prompt(
  class SQLAssistantSystemPromptBuilder (line 61) | class SQLAssistantSystemPromptBuilder(SystemPromptBuilder):
    method __init__ (line 64) | def __init__(self, database_name: str = "database"):
    method build_system_prompt (line 72) | async def build_system_prompt(
  function demo (line 107) | async def demo() -> None:

FILE: src/vanna/examples/default_workflow_handler_example.py
  function demonstrate_setup_scenarios (line 26) | async def demonstrate_setup_scenarios():
  function main (line 202) | async def main():

FILE: src/vanna/examples/email_auth_example.py
  class DemoEmailUserService (line 72) | class DemoEmailUserService(UserService):
    method __init__ (line 75) | def __init__(self):
    method get_user (line 80) | async def get_user(self, user_id: str) -> Optional[User]:
    method authenticate (line 84) | async def authenticate(self, credentials: Dict[str, Any]) -> Optional[...
    method has_permission (line 111) | async def has_permission(self, user: User, permission: str) -> bool:
    method _is_valid_email (line 115) | def _is_valid_email(self, email: str) -> bool:
  class AuthArgs (line 121) | class AuthArgs(BaseModel):
  class AuthTool (line 127) | class AuthTool(Tool[AuthArgs]):
    method __init__ (line 130) | def __init__(self, user_service: DemoEmailUserService):
    method name (line 134) | def name(self) -> str:
    method description (line 138) | def description(self) -> str:
    method get_args_schema (line 141) | def get_args_schema(self) -> Type[AuthArgs]:
    method execute (line 144) | async def execute(self, context: ToolContext, args: AuthArgs) -> ToolR...
  function create_demo_agent (line 194) | def create_demo_agent() -> Agent:
  function create_auth_agent (line 203) | def create_auth_agent() -> Agent:
  function demo_auth_flow (line 243) | async def demo_auth_flow():
  function main (line 328) | async def main():
  function run_interactive (line 333) | def run_interactive():

FILE: src/vanna/examples/evaluation_example.py
  function create_sample_dataset (line 30) | def create_sample_dataset() -> EvaluationDataset:
  function create_test_agent (line 78) | def create_test_agent(name: str, response_content: str) -> Agent:
  function demo_single_agent_evaluation (line 87) | async def demo_single_agent_evaluation():
  function demo_agent_comparison (line 127) | async def demo_agent_comparison():
  function demo_dataset_operations (line 196) | async def demo_dataset_operations():
  function main (line 241) | async def main():

FILE: src/vanna/examples/extensibility_example.py
  class CachingMiddleware (line 37) | class CachingMiddleware(LlmMiddleware):
    method __init__ (line 40) | def __init__(self) -> None:
    method _compute_cache_key (line 45) | def _compute_cache_key(self, request: LlmRequest) -> str:
    method before_llm_request (line 50) | async def before_llm_request(self, request: LlmRequest) -> LlmRequest:
    method after_llm_response (line 58) | async def after_llm_response(
  class ExponentialBackoffStrategy (line 71) | class ExponentialBackoffStrategy(ErrorRecoveryStrategy):
    method __init__ (line 74) | def __init__(self, max_retries: int = 3) -> None:
    method handle_tool_error (line 77) | async def handle_tool_error(
    method handle_llm_error (line 98) | async def handle_llm_error(
  class UserPreferencesEnricher (line 121) | class UserPreferencesEnricher(ToolContextEnricher):
    method __init__ (line 124) | def __init__(self) -> None:
    method enrich_context (line 134) | async def enrich_context(self, context: ToolContext) -> ToolContext:
  class ContextWindowFilter (line 144) | class ContextWindowFilter(ConversationFilter):
    method __init__ (line 147) | def __init__(self, max_messages: int = 20) -> None:
    method filter_messages (line 150) | async def filter_messages(self, messages: List[Message]) -> List[Messa...
  class LoggingObservabilityProvider (line 168) | class LoggingObservabilityProvider(ObservabilityProvider):
    method __init__ (line 171) | def __init__(self) -> None:
    method record_metric (line 175) | async def record_metric(
    method create_span (line 188) | async def create_span(
    method end_span (line 196) | async def end_span(self, span: Span) -> None:
  function run_example (line 204) | async def run_example() -> None:

FILE: src/vanna/examples/minimal_example.py
  function create_demo_agent (line 30) | def create_demo_agent() -> Agent:

FILE: src/vanna/examples/mock_auth_example.py
  class UserEchoMiddleware (line 28) | class UserEchoMiddleware(LlmMiddleware):
    method after_llm_response (line 31) | async def after_llm_response(
  function create_demo_agent (line 48) | def create_demo_agent() -> Agent:
  function demo_authentication (line 81) | async def demo_authentication():
  function main (line 215) | async def main():
  function run_interactive (line 220) | def run_interactive():

FILE: src/vanna/examples/mock_custom_tool.py
  class CalculatorArgs (line 52) | class CalculatorArgs(BaseModel):
  class CalculatorTool (line 62) | class CalculatorTool(Tool[CalculatorArgs]):
    method name (line 66) | def name(self) -> str:
    method description (line 70) | def description(self) -> str:
    method get_args_schema (line 73) | def get_args_schema(self) -> Type[CalculatorArgs]:
    method execute (line 76) | async def execute(self, context: ToolContext, args: CalculatorArgs) ->...
  class MockCalculatorLlmService (line 158) | class MockCalculatorLlmService(LlmService):
    method __init__ (line 161) | def __init__(self, seed: Optional[int] = None):
    method send_request (line 164) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 169) | async def stream_request(
    method validate_tools (line 185) | async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
    method _build_response (line 189) | def _build_response(self, request: LlmRequest) -> LlmResponse:
    method _random_operands (line 219) | def _random_operands(self) -> Tuple[str, float, float]:
  function create_demo_agent (line 237) | def create_demo_agent() -> Agent:
  function main (line 259) | async def main() -> None:
  function run_interactive (line 304) | def run_interactive() -> None:

FILE: src/vanna/examples/mock_quickstart.py
  function create_demo_agent (line 25) | def create_demo_agent() -> Agent:
  function main (line 44) | async def main() -> None:
  function run_interactive (line 72) | def run_interactive() -> None:

FILE: src/vanna/examples/mock_quota_example.py
  function demonstrate_quota_system (line 28) | async def demonstrate_quota_system() -> None:
  function main (line 139) | async def main() -> None:

FILE: src/vanna/examples/mock_rich_components_demo.py
  class RichComponentsAgent (line 35) | class RichComponentsAgent(Agent):
    method send_message (line 38) | async def send_message(
  function create_rich_demo_agent (line 318) | def create_rich_demo_agent() -> RichComponentsAgent:
  function main (line 335) | async def main() -> None:
  function run_interactive (line 389) | def run_interactive() -> None:

FILE: src/vanna/examples/mock_sqlite_example.py
  class MockSqliteLlmService (line 52) | class MockSqliteLlmService(LlmService):
    method __init__ (line 55) | def __init__(self, seed: Optional[int] = None):
    method send_request (line 68) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 73) | async def stream_request(
    method validate_tools (line 89) | async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
    method _build_response (line 93) | def _build_response(self, request: LlmRequest) -> LlmResponse:
  function create_demo_agent (line 126) | def create_demo_agent() -> Agent:
  function main (line 160) | async def main() -> None:
  function run_interactive (line 215) | def run_interactive() -> None:

FILE: src/vanna/examples/openai_quickstart.py
  function ensure_env (line 17) | def ensure_env() -> None:
  function main (line 35) | async def main() -> None:

FILE: src/vanna/examples/primitive_components_demo.py
  class PrimitiveComponentsAgent (line 34) | class PrimitiveComponentsAgent(Agent):
    method send_message (line 37) | async def send_message(
  function create_primitive_demo_agent (line 220) | def create_primitive_demo_agent() -> PrimitiveComponentsAgent:
  function main (line 237) | async def main() -> None:
  function run_interactive (line 298) | def run_interactive() -> None:

FILE: src/vanna/examples/quota_lifecycle_example.py
  class QuotaExceededError (line 13) | class QuotaExceededError(AgentError):
  class QuotaCheckHook (line 19) | class QuotaCheckHook(LifecycleHook):
    method __init__ (line 22) | def __init__(self, default_quota: int = 10) -> None:
    method set_user_quota (line 32) | def set_user_quota(self, user_id: str, quota: int) -> None:
    method get_user_quota (line 36) | def get_user_quota(self, user_id: str) -> int:
    method get_user_usage (line 40) | def get_user_usage(self, user_id: str) -> int:
    method get_user_remaining (line 44) | def get_user_remaining(self, user_id: str) -> int:
    method reset_user_usage (line 48) | def reset_user_usage(self, user_id: str) -> None:
    method before_message (line 52) | async def before_message(self, user: User, message: str) -> Optional[s...
  class LoggingHook (line 75) | class LoggingHook(LifecycleHook):
    method before_message (line 78) | async def before_message(self, user: User, message: str) -> Optional[s...
    method after_message (line 83) | async def after_message(self, result: Any) -> None:
  function run_example (line 88) | async def run_example() -> None:

FILE: src/vanna/examples/visualization_example.py
  class VisualizationDemoLlmService (line 40) | class VisualizationDemoLlmService(LlmService):
    method __init__ (line 43) | def __init__(self) -> None:
    method send_request (line 47) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 52) | async def stream_request(
    method validate_tools (line 68) | async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
    method _build_response (line 72) | def _build_response(self, request: LlmRequest) -> LlmResponse:
  function create_demo_agent (line 138) | def create_demo_agent() -> Agent:
  function main (line 188) | async def main() -> None:

FILE: src/vanna/integrations/anthropic/llm.py
  class AnthropicLlmService (line 27) | class AnthropicLlmService(LlmService):
    method __init__ (line 38) | def __init__(
    method send_request (line 65) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 92) | async def stream_request(
    method validate_tools (line 123) | async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
    method _build_payload (line 132) | def _build_payload(self, request: LlmRequest) -> Dict[str, Any]:
    method _parse_message_content (line 226) | def _parse_message_content(self, msg: Any) -> Tuple[str, List[ToolCall]]:

FILE: src/vanna/integrations/azureopenai/llm.py
  function _is_reasoning_model (line 38) | def _is_reasoning_model(model: str) -> bool:
  class AzureOpenAILlmService (line 44) | class AzureOpenAILlmService(LlmService):
    method __init__ (line 62) | def __init__(
    method send_request (line 120) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 152) | async def stream_request(
    method validate_tools (line 233) | async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
    method _build_payload (line 243) | def _build_payload(self, request: LlmRequest) -> Dict[str, Any]:
    method _extract_tool_calls_from_message (line 305) | def _extract_tool_calls_from_message(self, message: Any) -> List[ToolC...

FILE: src/vanna/integrations/azuresearch/agent_memory.py
  class AzureAISearchAgentMemory (line 40) | class AzureAISearchAgentMemory(AgentMemory):
    method __init__ (line 43) | def __init__(
    method _get_index_client (line 65) | def _get_index_client(self):
    method _get_search_client (line 74) | def _get_search_client(self):
    method _ensure_index_exists (line 85) | def _ensure_index_exists(self):
    method _create_embedding (line 133) | def _create_embedding(self, text: str) -> List[float]:
    method save_tool_usage (line 140) | async def save_tool_usage(
    method search_similar_usage (line 173) | async def search_similar_usage(
    method get_recent_memories (line 227) | async def get_recent_memories(
    method delete_by_id (line 261) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method save_text_memory (line 275) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_text_memories (line 298) | async def search_text_memories(
    method get_recent_text_memories (line 336) | async def get_recent_text_memories(
    method delete_text_memory (line 367) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method clear_memories (line 381) | async def clear_memories(

FILE: src/vanna/integrations/bigquery/sql_runner.py
  class BigQueryRunner (line 10) | class BigQueryRunner(SqlRunner):
    method __init__ (line 13) | def __init__(self, project_id: str, cred_file_path: Optional[str] = No...
    method _get_client (line 38) | def _get_client(self):
    method run_sql (line 62) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...

FILE: src/vanna/integrations/chromadb/__init__.py
  function get_device (line 8) | def get_device() -> str:
  function create_sentence_transformer_embedding_function (line 49) | def create_sentence_transformer_embedding_function(

FILE: src/vanna/integrations/chromadb/agent_memory.py
  class NotFoundError (line 23) | class NotFoundError(Exception):
  class ChromaAgentMemory (line 42) | class ChromaAgentMemory(AgentMemory):
    method __init__ (line 102) | def __init__(
    method _get_client (line 120) | def _get_client(self):
    method _get_embedding_function (line 129) | def _get_embedding_function(self):
    method _get_collection (line 141) | def _get_collection(self):
    method _create_memory_id (line 160) | def _create_memory_id(self) -> str:
    method save_tool_usage (line 166) | async def save_tool_usage(
    method search_similar_usage (line 201) | async def search_similar_usage(
    method get_recent_memories (line 267) | async def get_recent_memories(
    method delete_by_id (line 315) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method save_text_memory (line 333) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_text_memories (line 356) | async def search_text_memories(
    method get_recent_text_memories (line 405) | async def get_recent_text_memories(
    method delete_text_memory (line 435) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method clear_memories (line 452) | async def clear_memories(

FILE: src/vanna/integrations/clickhouse/sql_runner.py
  class ClickHouseRunner (line 10) | class ClickHouseRunner(SqlRunner):
    method __init__ (line 13) | def __init__(
    method run_sql (line 49) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...

FILE: src/vanna/integrations/duckdb/sql_runner.py
  class DuckDBRunner (line 10) | class DuckDBRunner(SqlRunner):
    method __init__ (line 13) | def __init__(
    method _get_connection (line 39) | def _get_connection(self):
    method run_sql (line 47) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...

FILE: src/vanna/integrations/faiss/agent_memory.py
  class FAISSAgentMemory (line 34) | class FAISSAgentMemory(AgentMemory):
    method __init__ (line 37) | def __init__(
    method _load_index (line 58) | def _load_index(self):
    method _save_index (line 77) | def _save_index(self):
    method _create_embedding (line 86) | def _create_embedding(self, text: str) -> np.ndarray:
    method save_tool_usage (line 104) | async def save_tool_usage(
    method search_similar_usage (line 139) | async def search_similar_usage(
    method get_recent_memories (line 207) | async def get_recent_memories(
    method delete_by_id (line 242) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method save_text_memory (line 262) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_text_memories (line 288) | async def search_text_memories(
    method get_recent_text_memories (line 346) | async def get_recent_text_memories(
    method delete_text_memory (line 377) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method clear_memories (line 397) | async def clear_memories(

FILE: src/vanna/integrations/google/gemini.py
  class GeminiLlmService (line 27) | class GeminiLlmService(LlmService):
    method __init__ (line 39) | def __init__(
    method send_request (line 76) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 125) | async def stream_request(
    method validate_tools (line 175) | async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
    method _build_payload (line 186) | def _build_payload(self, request: LlmRequest) -> tuple[List[Any], Any]:
    method _parse_response (line 292) | def _parse_response(self, response: Any) -> tuple[str, List[ToolCall]]:
    method _parse_response_chunk (line 328) | def _parse_response_chunk(self, chunk: Any) -> tuple[str, List[ToolCal...
    method _clean_schema_for_gemini (line 332) | def _clean_schema_for_gemini(self, schema: Dict[str, Any]) -> Dict[str...

FILE: src/vanna/integrations/hive/sql_runner.py
  class HiveRunner (line 10) | class HiveRunner(SqlRunner):
    method __init__ (line 13) | def __init__(
    method run_sql (line 51) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...

FILE: src/vanna/integrations/local/agent_memory/in_memory.py
  class DemoAgentMemory (line 28) | class DemoAgentMemory(AgentMemory):
    method __init__ (line 37) | def __init__(self, *, max_items: int = 10_000):
    method _now_iso (line 51) | def _now_iso() -> str:
    method _normalize (line 56) | def _normalize(text: str) -> str:
    method _tokenize (line 61) | def _tokenize(text: str) -> set[str]:
    method _similarity (line 66) | def _similarity(cls, a: str, b: str) -> float:
    method save_tool_usage (line 89) | async def save_tool_usage(
    method save_text_memory (line 115) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_similar_usage (line 127) | async def search_similar_usage(
    method search_text_memories (line 166) | async def search_text_memories(
    method get_recent_memories (line 199) | async def get_recent_memories(
    method get_recent_text_memories (line 207) | async def get_recent_text_memories(
    method delete_text_memory (line 214) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method delete_by_id (line 223) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method clear_memories (line 232) | async def clear_memories(

FILE: src/vanna/integrations/local/audit.py
  class LoggingAuditLogger (line 17) | class LoggingAuditLogger(AuditLogger):
    method __init__ (line 31) | def __init__(self, log_level: int = logging.INFO):
    method log_event (line 39) | async def log_event(self, event: AuditEvent) -> None:

FILE: src/vanna/integrations/local/file_system.py
  class LocalFileSystem (line 18) | class LocalFileSystem(FileSystem):
    method __init__ (line 21) | def __init__(self, working_directory: str = "."):
    method _get_user_directory (line 29) | def _get_user_directory(self, context: ToolContext) -> Path:
    method _resolve_path (line 47) | def _resolve_path(self, path: str, context: ToolContext) -> Path:
    method list_files (line 70) | async def list_files(self, directory: str, context: ToolContext) -> Li...
    method read_file (line 87) | async def read_file(self, filename: str, context: ToolContext) -> str:
    method write_file (line 99) | async def write_file(
    method exists (line 115) | async def exists(self, path: str, context: ToolContext) -> bool:
    method is_directory (line 123) | async def is_directory(self, path: str, context: ToolContext) -> bool:
    method search_files (line 131) | async def search_files(
    method run_bash (line 207) | async def run_bash(

FILE: src/vanna/integrations/local/file_system_conversation_store.py
  class FileSystemConversationStore (line 19) | class FileSystemConversationStore(ConversationStore):
    method __init__ (line 29) | def __init__(self, base_dir: str = "conversations") -> None:
    method _get_conversation_dir (line 38) | def _get_conversation_dir(self, conversation_id: str) -> Path:
    method _get_metadata_path (line 42) | def _get_metadata_path(self, conversation_id: str) -> Path:
    method _get_messages_dir (line 46) | def _get_messages_dir(self, conversation_id: str) -> Path:
    method _save_metadata (line 50) | def _save_metadata(self, conversation: Conversation) -> None:
    method _load_messages (line 66) | def _load_messages(self, conversation_id: str) -> List[Message]:
    method _append_message (line 89) | def _append_message(
    method create_conversation (line 104) | async def create_conversation(
    method get_conversation (line 122) | async def get_conversation(
    method update_conversation (line 157) | async def update_conversation(self, conversation: Conversation) -> None:
    method delete_conversation (line 175) | async def delete_conversation(self, conversation_id: str, user: User) ...
    method list_conversations (line 208) | async def list_conversations(

FILE: src/vanna/integrations/local/storage.py
  class MemoryConversationStore (line 14) | class MemoryConversationStore(ConversationStore):
    method __init__ (line 17) | def __init__(self) -> None:
    method create_conversation (line 20) | async def create_conversation(
    method get_conversation (line 32) | async def get_conversation(
    method update_conversation (line 41) | async def update_conversation(self, conversation: Conversation) -> None:
    method delete_conversation (line 45) | async def delete_conversation(self, conversation_id: str, user: User) ...
    method list_conversations (line 53) | async def list_conversations(

FILE: src/vanna/integrations/marqo/agent_memory.py
  class MarqoAgentMemory (line 31) | class MarqoAgentMemory(AgentMemory):
    method __init__ (line 34) | def __init__(
    method _get_client (line 51) | def _get_client(self):
    method save_tool_usage (line 64) | async def save_tool_usage(
    method search_similar_usage (line 97) | async def search_similar_usage(
    method get_recent_memories (line 149) | async def get_recent_memories(
    method delete_by_id (line 184) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method save_text_memory (line 198) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_text_memories (line 222) | async def search_text_memories(
    method get_recent_text_memories (line 262) | async def get_recent_text_memories(
    method delete_text_memory (line 292) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method clear_memories (line 306) | async def clear_memories(

FILE: src/vanna/integrations/milvus/agent_memory.py
  class MilvusAgentMemory (line 38) | class MilvusAgentMemory(AgentMemory):
    method __init__ (line 41) | def __init__(
    method _get_collection (line 62) | def _get_collection(self):
    method _create_embedding (line 120) | def _create_embedding(self, text: str) -> List[float]:
    method save_tool_usage (line 127) | async def save_tool_usage(
    method search_similar_usage (line 161) | async def search_similar_usage(
    method get_recent_memories (line 234) | async def get_recent_memories(
    method delete_by_id (line 284) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method save_text_memory (line 299) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_text_memories (line 327) | async def search_text_memories(
    method get_recent_text_memories (line 382) | async def get_recent_text_memories(
    method delete_text_memory (line 417) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method clear_memories (line 432) | async def clear_memories(

FILE: src/vanna/integrations/mock/llm.py
  class MockLlmService (line 15) | class MockLlmService(LlmService):
    method __init__ (line 18) | def __init__(self, response_content: str = "Hello! This is a mock resp...
    method send_request (line 22) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 36) | async def stream_request(
    method validate_tools (line 54) | async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
    method set_response (line 59) | def set_response(self, content: str) -> None:
    method reset_call_count (line 63) | def reset_call_count(self) -> None:

FILE: src/vanna/integrations/mssql/sql_runner.py
  class MSSQLRunner (line 10) | class MSSQLRunner(SqlRunner):
    method __init__ (line 13) | def __init__(self, odbc_conn_str: str, **kwargs):
    method run_sql (line 50) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...

FILE: src/vanna/integrations/mysql/sql_runner.py
  class MySQLRunner (line 10) | class MySQLRunner(SqlRunner):
    method __init__ (line 13) | def __init__(
    method run_sql (line 48) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...

FILE: src/vanna/integrations/ollama/llm.py
  class OllamaLlmService (line 24) | class OllamaLlmService(LlmService):
    method __init__ (line 36) | def __init__(
    method send_request (line 65) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 98) | async def stream_request(
    method validate_tools (line 144) | async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
    method _build_payload (line 156) | def _build_payload(self, request: LlmRequest) -> Dict[str, Any]:
    method _extract_tool_calls_from_message (line 216) | def _extract_tool_calls_from_message(

FILE: src/vanna/integrations/openai/llm.py
  class OpenAILlmService (line 27) | class OpenAILlmService(LlmService):
    method __init__ (line 38) | def __init__(
    method send_request (line 68) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 100) | async def stream_request(
    method validate_tools (line 180) | async def validate_tools(self, tools: List[ToolSchema]) -> List[str]:
    method _build_payload (line 190) | def _build_payload(self, request: LlmRequest) -> Dict[str, Any]:
    method _extract_tool_calls_from_message (line 244) | def _extract_tool_calls_from_message(self, message: Any) -> List[ToolC...

FILE: src/vanna/integrations/openai/responses.py
  class OpenAIResponsesService (line 14) | class OpenAIResponsesService(LlmService):
    method __init__ (line 15) | def __init__(
    method send_request (line 29) | async def send_request(self, request: LlmRequest) -> LlmResponse:
    method stream_request (line 42) | async def stream_request(
    method validate_tools (line 60) | async def validate_tools(self, tools: List[Any]) -> List[str]:
    method _payload (line 65) | def _payload(self, request: LlmRequest) -> Dict[str, Any]:
    method _debug_print (line 76) | def _debug_print(self, label: str, obj: Any) -> None:
    method _extract (line 86) | def _extract(
    method _serialize_tool (line 125) | def _serialize_tool(self, tool: Any) -> Dict[str, Any]:

FILE: src/vanna/integrations/opensearch/agent_memory.py
  class OpenSearchAgentMemory (line 31) | class OpenSearchAgentMemory(AgentMemory):
    method __init__ (line 34) | def __init__(
    method _get_client (line 57) | def _get_client(self):
    method _create_embedding (line 99) | def _create_embedding(self, text: str) -> List[float]:
    method save_tool_usage (line 106) | async def save_tool_usage(
    method search_similar_usage (line 141) | async def search_similar_usage(
    method get_recent_memories (line 205) | async def get_recent_memories(
    method delete_by_id (line 242) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method save_text_memory (line 256) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_text_memories (line 282) | async def search_text_memories(
    method get_recent_text_memories (line 335) | async def get_recent_text_memories(
    method delete_text_memory (line 368) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method clear_memories (line 382) | async def clear_memories(

FILE: src/vanna/integrations/oracle/sql_runner.py
  class OracleRunner (line 10) | class OracleRunner(SqlRunner):
    method __init__ (line 13) | def __init__(self, user: str, password: str, dsn: str, **kwargs):
    method run_sql (line 36) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...

FILE: src/vanna/integrations/pinecone/agent_memory.py
  class PineconeAgentMemory (line 31) | class PineconeAgentMemory(AgentMemory):
    method __init__ (line 34) | def __init__(
    method _get_client (line 56) | def _get_client(self):
    method _get_index (line 62) | def _get_index(self):
    method _create_embedding (line 79) | def _create_embedding(self, text: str) -> List[float]:
    method save_tool_usage (line 87) | async def save_tool_usage(
    method search_similar_usage (line 119) | async def search_similar_usage(
    method get_recent_memories (line 174) | async def get_recent_memories(
    method delete_by_id (line 192) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method save_text_memory (line 206) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_text_memories (line 228) | async def search_text_memories(
    method get_recent_text_memories (line 272) | async def get_recent_text_memories(
    method delete_text_memory (line 287) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method clear_memories (line 301) | async def clear_memories(

FILE: src/vanna/integrations/plotly/chart_generator.py
  class PlotlyChartGenerator (line 11) | class PlotlyChartGenerator:
    method generate_chart (line 26) | def generate_chart(self, df: pd.DataFrame, title: str = "Chart") -> Di...
    method _apply_standard_layout (line 105) | def _apply_standard_layout(self, fig: go.Figure) -> go.Figure:
    method _create_histogram (line 126) | def _create_histogram(self, df: pd.DataFrame, column: str, title: str)...
    method _create_bar_chart (line 138) | def _create_bar_chart(
    method _create_scatter_plot (line 155) | def _create_scatter_plot(
    method _create_correlation_heatmap (line 170) | def _create_correlation_heatmap(
    method _create_time_series_chart (line 197) | def _create_time_series_chart(
    method _create_grouped_bar_chart (line 224) | def _create_grouped_bar_chart(
    method _create_generic_chart (line 257) | def _create_generic_chart(
    method _create_table (line 278) | def _create_table(self, df: pd.DataFrame, title: str) -> go.Figure:

FILE: src/vanna/integrations/postgres/sql_runner.py
  class PostgresRunner (line 10) | class PostgresRunner(SqlRunner):
    method __init__ (line 13) | def __init__(
    method run_sql (line 65) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...

FILE: src/vanna/integrations/premium/agent_memory/premium.py
  class CloudAgentMemory (line 23) | class CloudAgentMemory(AgentMemory):
    method __init__ (line 26) | def __init__(
    method _get_headers (line 37) | def _get_headers(self) -> Dict[str, str]:
    method save_tool_usage (line 46) | async def save_tool_usage(
    method search_similar_usage (line 73) | async def search_similar_usage(
    method get_recent_memories (line 110) | async def get_recent_memories(
    method delete_by_id (line 130) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method save_text_memory (line 142) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_text_memories (line 146) | async def search_text_memories(
    method get_recent_text_memories (line 157) | async def get_recent_text_memories(
    method delete_text_memory (line 163) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method clear_memories (line 167) | async def clear_memories(

FILE: src/vanna/integrations/presto/sql_runner.py
  class PrestoRunner (line 10) | class PrestoRunner(SqlRunner):
    method __init__ (line 13) | def __init__(
    method run_sql (line 64) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...

FILE: src/vanna/integrations/qdrant/agent_memory.py
  class QdrantAgentMemory (line 39) | class QdrantAgentMemory(AgentMemory):
    method __init__ (line 42) | def __init__(
    method _get_client (line 63) | def _get_client(self):
    method _create_embedding (line 82) | def _create_embedding(self, text: str) -> List[float]:
    method save_tool_usage (line 89) | async def save_tool_usage(
    method search_similar_usage (line 122) | async def search_similar_usage(
    method get_recent_memories (line 194) | async def get_recent_memories(
    method delete_by_id (line 240) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method save_text_memory (line 267) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_text_memories (line 291) | async def search_text_memories(
    method get_recent_text_memories (line 351) | async def get_recent_text_memories(
    method delete_text_memory (line 395) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method clear_memories (line 422) | async def clear_memories(

FILE: src/vanna/integrations/snowflake/sql_runner.py
  class SnowflakeRunner (line 11) | class SnowflakeRunner(SqlRunner):
    method __init__ (line 14) | def __init__(
    method run_sql (line 77) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...

FILE: src/vanna/integrations/sqlite/sql_runner.py
  class SqliteRunner (line 10) | class SqliteRunner(SqlRunner):
    method __init__ (line 13) | def __init__(self, database_path: str):
    method run_sql (line 21) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...

FILE: src/vanna/integrations/weaviate/agent_memory.py
  class WeaviateAgentMemory (line 36) | class WeaviateAgentMemory(AgentMemory):
    method __init__ (line 39) | def __init__(
    method _get_client (line 58) | def _get_client(self):
    method _create_embedding (line 88) | def _create_embedding(self, text: str) -> List[float]:
    method save_tool_usage (line 95) | async def save_tool_usage(
    method search_similar_usage (line 129) | async def search_similar_usage(
    method get_recent_memories (line 191) | async def get_recent_memories(
    method delete_by_id (line 234) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method save_text_memory (line 249) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_text_memories (line 277) | async def search_text_memories(
    method get_recent_text_memories (line 328) | async def get_recent_text_memories(
    method delete_text_memory (line 371) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method clear_memories (line 386) | async def clear_memories(

FILE: src/vanna/legacy/ZhipuAI/ZhipuAI_Chat.py
  class ZhipuAI_Chat (line 10) | class ZhipuAI_Chat(VannaBase):
    method __init__ (line 11) | def __init__(self, config=None):
    method system_message (line 23) | def system_message(message: str) -> dict:
    method user_message (line 27) | def user_message(message: str) -> dict:
    method assistant_message (line 31) | def assistant_message(message: str) -> dict:
    method str_to_approx_token_count (line 35) | def str_to_approx_token_count(string: str) -> int:
    method add_ddl_to_prompt (line 39) | def add_ddl_to_prompt(
    method add_documentation_to_prompt (line 56) | def add_documentation_to_prompt(
    method add_sql_to_prompt (line 73) | def add_sql_to_prompt(
    method get_sql_prompt (line 89) | def get_sql_prompt(
    method get_followup_questions_prompt (line 121) | def get_followup_questions_prompt(
    method generate_question (line 153) | def generate_question(self, sql: str, **kwargs) -> str:
    method _extract_python_code (line 166) | def _extract_python_code(self, markdown_string: str) -> str:
    method _sanitize_plotly_code (line 184) | def _sanitize_plotly_code(self, raw_plotly_code: str) -> str:
    method generate_plotly_code (line 190) | def generate_plotly_code(
    method submit_prompt (line 214) | def submit_prompt(

FILE: src/vanna/legacy/ZhipuAI/ZhipuAI_embeddings.py
  class ZhipuAI_Embeddings (line 7) | class ZhipuAI_Embeddings(VannaBase):
    method __init__ (line 15) | def __init__(self, config=None):
    method generate_embedding (line 22) | def generate_embedding(self, data: str, **kwargs) -> List[float]:
  class ZhipuAIEmbeddingFunction (line 31) | class ZhipuAIEmbeddingFunction(EmbeddingFunction[Documents]):
    method __init__ (line 48) | def __init__(self, config=None):
    method __call__ (line 60) | def __call__(self, input: Documents) -> Embeddings:

FILE: src/vanna/legacy/__init__.py
  function error_deprecation (line 47) | def error_deprecation():
  function __unauthenticated_rpc_call (line 60) | def __unauthenticated_rpc_call(method, params):
  function __dataclass_to_dict (line 72) | def __dataclass_to_dict(obj):
  function get_api_key (line 76) | def get_api_key(email: str, otp_code: Union[str, None] = None) -> str:
  function set_api_key (line 134) | def set_api_key(key: str) -> None:
  function get_models (line 138) | def get_models() -> List[str]:
  function create_model (line 142) | def create_model(model: str, db_type: str) -> bool:
  function add_user_to_model (line 146) | def add_user_to_model(model: str, email: str, is_admin: bool) -> bool:
  function update_model_visibility (line 150) | def update_model_visibility(public: bool) -> bool:
  function set_model (line 154) | def set_model(model: str):
  function add_sql (line 158) | def add_sql(
  function add_ddl (line 164) | def add_ddl(ddl: str) -> bool:
  function add_documentation (line 168) | def add_documentation(documentation: str) -> bool:
  class TrainingPlanItem (line 173) | class TrainingPlanItem:
    method __str__ (line 179) | def __str__(self):
  class TrainingPlan (line 192) | class TrainingPlan:
    method __init__ (line 207) | def __init__(self, plan: List[TrainingPlanItem]):
    method __str__ (line 210) | def __str__(self):
    method __repr__ (line 213) | def __repr__(self):
    method get_summary (line 216) | def get_summary(self) -> List[str]:
    method remove_item (line 233) | def remove_item(self, item: str):
  function get_training_plan_postgres (line 253) | def get_training_plan_postgres(
  function get_training_plan_generic (line 262) | def get_training_plan_generic(df) -> TrainingPlan:
  function get_training_plan_experimental (line 266) | def get_training_plan_experimental(
  function train (line 275) | def train(
  function flag_sql_for_review (line 287) | def flag_sql_for_review(
  function remove_sql (line 293) | def remove_sql(question: str) -> bool:
  function remove_training_data (line 297) | def remove_training_data(id: str) -> bool:
  function generate_sql (line 301) | def generate_sql(question: str) -> str:
  function get_related_training_data (line 305) | def get_related_training_data(question: str) -> TrainingData:
  function generate_meta (line 309) | def generate_meta(question: str) -> str:
  function generate_followup_questions (line 313) | def generate_followup_questions(question: str, df: pd.DataFrame) -> List...
  function generate_questions (line 317) | def generate_questions() -> List[str]:
  function ask (line 321) | def ask(
  function generate_plotly_code (line 338) | def generate_plotly_code(
  function get_plotly_figure (line 347) | def get_plotly_figure(
  function get_results (line 353) | def get_results(cs, default_database: str, sql: str) -> pd.DataFrame:
  function generate_explanation (line 357) | def generate_explanation(sql: str) -> str:
  function generate_question (line 361) | def generate_question(sql: str) -> str:
  function get_all_questions (line 365) | def get_all_questions() -> pd.DataFrame:
  function get_training_data (line 369) | def get_training_data() -> pd.DataFrame:
  function connect_to_sqlite (line 373) | def connect_to_sqlite(url: str):
  function connect_to_snowflake (line 377) | def connect_to_snowflake(
  function connect_to_postgres (line 388) | def connect_to_postgres(
  function connect_to_bigquery (line 398) | def connect_to_bigquery(cred_file_path: str = None, project_id: str = No...
  function connect_to_duckdb (line 402) | def connect_to_duckdb(url: str = "memory", init_sql: str = None):

FILE: src/vanna/legacy/adapter.py
  class LegacySqlRunner (line 32) | class LegacySqlRunner(SqlRunner):
    method __init__ (line 40) | def __init__(self, vn: VannaBase):
    method run_sql (line 48) | async def run_sql(self, args: RunSqlToolArgs, context: ToolContext) ->...
  class LegacyVannaAdapter (line 66) | class LegacyVannaAdapter(ToolRegistry, AgentMemory):
    method __init__ (line 97) | def __init__(
    method _register_tools (line 116) | def _register_tools(self) -> None:
    method save_tool_usage (line 142) | async def save_tool_usage(
    method search_similar_usage (line 169) | async def search_similar_usage(
    method save_text_memory (line 221) | async def save_text_memory(self, content: str, context: ToolContext) -...
    method search_text_memories (line 241) | async def search_text_memories(
    method get_recent_memories (line 300) | async def get_recent_memories(
    method get_recent_text_memories (line 335) | async def get_recent_text_memories(
    method delete_by_id (line 378) | async def delete_by_id(self, context: ToolContext, memory_id: str) -> ...
    method delete_text_memory (line 392) | async def delete_text_memory(self, context: ToolContext, memory_id: st...
    method clear_memories (line 406) | async def clear_memories(

FILE: src/vanna/legacy/advanced/__init__.py
  class VannaAdvanced (line 4) | class VannaAdvanced(ABC):
    method __init__ (line 5) | def __init__(self, config=None):
    method get_function (line 9) | def get_function(self, question: str, additional_data: dict = {}) -> d...
    method create_function (line 13) | def create_function(
    method update_function (line 19) | def update_function(self, old_function_name: str, updated_function: di...
    method delete_function (line 23) | def delete_function(self, function_name: str) -> bool:
    method get_all_functions (line 27) | def get_all_functions(self) -> list:

FILE: src/vanna/legacy/anthropic/anthropic_chat.py
  class Anthropic_Chat (line 8) | class Anthropic_Chat(VannaBase):
    method __init__ (line 9) | def __init__(self, client=None, config=None):
    method system_message (line 33) | def system_message(self, message: str) -> any:
    method user_message (line 36) | def user_message(self, message: str) -> any:
    method assistant_message (line 39) | def assistant_message(self, message: str) -> any:
    method submit_prompt (line 42) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/azuresearch/azuresearch_vector.py
  class AzureAISearch_VectorStore (line 28) | class AzureAISearch_VectorStore(VannaBase):
    method __init__ (line 48) | def __init__(self, config=None):
    method _create_index (line 93) | def _create_index(self) -> bool:
    method _get_indexes (line 143) | def _get_indexes(self) -> list:
    method add_ddl (line 146) | def add_ddl(self, ddl: str) -> str:
    method add_documentation (line 157) | def add_documentation(self, doc: str) -> str:
    method add_question_sql (line 168) | def add_question_sql(self, question: str, sql: str) -> str:
    method get_related_ddl (line 182) | def get_related_ddl(self, text: str) -> List[str]:
    method get_related_documentation (line 200) | def get_related_documentation(self, text: str) -> List[str]:
    method get_similar_question_sql (line 220) | def get_similar_question_sql(self, question: str) -> List[str]:
    method get_training_data (line 240) | def get_training_data(self) -> List[str]:
    method remove_training_data (line 264) | def remove_training_data(self, id: str) -> bool:
    method remove_index (line 268) | def remove_index(self):
    method generate_embedding (line 271) | def generate_embedding(self, data: str, **kwargs) -> List[float]:

FILE: src/vanna/legacy/base/base.py
  class VannaBase (line 72) | class VannaBase(ABC):
    method __init__ (line 73) | def __init__(self, config=None):
    method log (line 84) | def log(self, message: str, title: str = "Info"):
    method _response_language (line 87) | def _response_language(self) -> str:
    method generate_sql (line 93) | def generate_sql(self, question: str, allow_llm_to_see_data=False, **k...
    method extract_sql (line 170) | def extract_sql(self, llm_response: str) -> str:
    method is_sql_valid (line 238) | def is_sql_valid(self, sql: str) -> bool:
    method should_generate_chart (line 262) | def should_generate_chart(self, df: pd.DataFrame) -> bool:
    method generate_rewritten_question (line 284) | def generate_rewritten_question(
    method generate_followup_questions (line 320) | def generate_followup_questions(
    method generate_questions (line 356) | def generate_questions(self, **kwargs) -> List[str]:
    method generate_summary (line 369) | def generate_summary(self, question: str, df: pd.DataFrame, **kwargs) ...
    method generate_embedding (line 402) | def generate_embedding(self, data: str, **kwargs) -> List[float]:
    method get_similar_question_sql (line 407) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_related_ddl (line 420) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 433) | def get_related_documentation(self, question: str, **kwargs) -> list:
    method add_question_sql (line 446) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method add_ddl (line 460) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 473) | def add_documentation(self, documentation: str, **kwargs) -> str:
    method get_training_data (line 486) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 501) | def remove_training_data(self, id: str, **kwargs) -> bool:
    method system_message (line 521) | def system_message(self, message: str) -> any:
    method user_message (line 525) | def user_message(self, message: str) -> any:
    method assistant_message (line 529) | def assistant_message(self, message: str) -> any:
    method str_to_approx_token_count (line 532) | def str_to_approx_token_count(self, string: str) -> int:
    method add_ddl_to_prompt (line 535) | def add_ddl_to_prompt(
    method add_documentation_to_prompt (line 551) | def add_documentation_to_prompt(
    method add_sql_to_prompt (line 570) | def add_sql_to_prompt(
    method get_sql_prompt (line 586) | def get_sql_prompt(
    method get_followup_questions_prompt (line 660) | def get_followup_questions_prompt(
    method submit_prompt (line 692) | def submit_prompt(self, prompt, **kwargs) -> str:
    method generate_question (line 714) | def generate_question(self, sql: str, **kwargs) -> str:
    method _extract_python_code (line 727) | def _extract_python_code(self, markdown_string: str) -> str:
    method _sanitize_plotly_code (line 748) | def _sanitize_plotly_code(self, raw_plotly_code: str) -> str:
    method generate_plotly_code (line 754) | def generate_plotly_code(
    method connect_to_snowflake (line 780) | def connect_to_snowflake(
    method connect_to_sqlite (line 862) | def connect_to_sqlite(self, url: str, check_same_thread: bool = False,...
    method connect_to_postgres (line 896) | def connect_to_postgres(
    method connect_to_mysql (line 1026) | def connect_to_mysql(
    method connect_to_clickhouse (line 1113) | def connect_to_clickhouse(
    method connect_to_oracle (line 1191) | def connect_to_oracle(
    method connect_to_bigquery (line 1275) | def connect_to_bigquery(
    method connect_to_duckdb (line 1358) | def connect_to_duckdb(self, url: str, init_sql: str = None, **kwargs):
    method connect_to_mssql (line 1407) | def connect_to_mssql(self, odbc_conn_str: str, **kwargs):
    method connect_to_presto (line 1455) | def connect_to_presto(
    method connect_to_hive (line 1574) | def connect_to_hive(
    method run_sql (line 1673) | def run_sql(self, sql: str, **kwargs) -> pd.DataFrame:
    method ask (line 1692) | def ask(
    method train (line 1807) | def train(
    method _get_databases (line 1862) | def _get_databases(self) -> List[str]:
    method _get_information_schema_tables (line 1877) | def _get_information_schema_tables(self, database: str) -> pd.DataFrame:
    method get_training_plan_generic (line 1882) | def get_training_plan_generic(self, df) -> TrainingPlan:
    method get_training_plan_snowflake (line 1942) | def get_training_plan_snowflake(
    method get_plotly_figure (line 2072) | def get_plotly_figure(

FILE: src/vanna/legacy/bedrock/bedrock_converse.py
  class Bedrock_Converse (line 10) | class Bedrock_Converse(VannaBase):
    method __init__ (line 11) | def __init__(self, client=None, config=None):
    method system_message (line 41) | def system_message(self, message: str) -> dict:
    method user_message (line 44) | def user_message(self, message: str) -> dict:
    method assistant_message (line 47) | def assistant_message(self, message: str) -> dict:
    method submit_prompt (line 50) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/chromadb/chromadb_vector.py
  class ChromaDB_VectorStore (line 15) | class ChromaDB_VectorStore(VannaBase):
    method __init__ (line 16) | def __init__(self, config=None):
    method generate_embedding (line 61) | def generate_embedding(self, data: str, **kwargs) -> List[float]:
    method add_question_sql (line 67) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method add_ddl (line 84) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 93) | def add_documentation(self, documentation: str, **kwargs) -> str:
    method get_training_data (line 102) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 167) | def remove_training_data(self, id: str, **kwargs) -> bool:
    method remove_collection (line 180) | def remove_collection(self, collection_name: str) -> bool:
    method _extract_documents (line 212) | def _extract_documents(query_results) -> list:
    method get_similar_question_sql (line 237) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_related_ddl (line 245) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 253) | def get_related_documentation(self, question: str, **kwargs) -> list:

FILE: src/vanna/legacy/cohere/cohere_chat.py
  class Cohere_Chat (line 8) | class Cohere_Chat(VannaBase):
    method __init__ (line 9) | def __init__(self, client=None, config=None):
    method system_message (line 45) | def system_message(self, message: str) -> any:
    method user_message (line 51) | def user_message(self, message: str) -> any:
    method assistant_message (line 54) | def assistant_message(self, message: str) -> any:
    method submit_prompt (line 57) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/cohere/cohere_embeddings.py
  class Cohere_Embeddings (line 8) | class Cohere_Embeddings(VannaBase):
    method __init__ (line 9) | def __init__(self, client=None, config=None):
    method generate_embedding (line 41) | def generate_embedding(self, data: str, **kwargs) -> list[float]:

FILE: src/vanna/legacy/deepseek/deepseek_chat.py
  class DeepSeekChat (line 18) | class DeepSeekChat(VannaBase):
    method __init__ (line 19) | def __init__(self, config=None):
    method system_message (line 35) | def system_message(self, message: str) -> any:
    method user_message (line 38) | def user_message(self, message: str) -> any:
    method assistant_message (line 41) | def assistant_message(self, message: str) -> any:
    method generate_sql (line 44) | def generate_sql(self, question: str, **kwargs) -> str:
    method submit_prompt (line 53) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/exceptions/__init__.py
  class ImproperlyConfigured (line 1) | class ImproperlyConfigured(Exception):
  class DependencyError (line 7) | class DependencyError(Exception):
  class ConnectionError (line 13) | class ConnectionError(Exception):
  class OTPCodeError (line 19) | class OTPCodeError(Exception):
  class SQLRemoveError (line 25) | class SQLRemoveError(Exception):
  class ExecutionError (line 31) | class ExecutionError(Exception):
  class ValidationError (line 37) | class ValidationError(Exception):
  class APIError (line 43) | class APIError(Exception):

FILE: src/vanna/legacy/faiss/faiss.py
  class FAISS (line 14) | class FAISS(VannaBase):
    method __init__ (line 15) | def __init__(self, config=None):
    method _load_or_create_index (line 78) | def _load_or_create_index(self, filename):
    method _load_or_create_metadata (line 84) | def _load_or_create_metadata(self, filename):
    method _save_index (line 91) | def _save_index(self, index, filename):
    method _save_metadata (line 96) | def _save_metadata(self, metadata, filename):
    method generate_embedding (line 102) | def generate_embedding(self, data: str, **kwargs) -> List[float]:
    method _add_to_index (line 109) | def _add_to_index(self, index, metadata_list, text, extra_metadata=Non...
    method add_question_sql (line 116) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method add_ddl (line 127) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 135) | def add_documentation(self, documentation: str, **kwargs) -> str:
    method _get_similar (line 146) | def _get_similar(self, index, metadata_list, text, n_results) -> list:
    method get_similar_question_sql (line 153) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_related_ddl (line 158) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 166) | def get_related_documentation(self, question: str, **kwargs) -> list:
    method get_training_data (line 177) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 189) | def remove_training_data(self, id: str, **kwargs) -> bool:
    method remove_collection (line 215) | def remove_collection(self, collection_name: str) -> bool:

FILE: src/vanna/legacy/flask/__init__.py
  class Cache (line 21) | class Cache(ABC):
    method generate_id (line 27) | def generate_id(self, *args, **kwargs):
    method get (line 34) | def get(self, id, field):
    method get_all (line 41) | def get_all(self, field_list) -> list:
    method set (line 48) | def set(self, id, field, value):
    method delete (line 55) | def delete(self, id):
  class MemoryCache (line 62) | class MemoryCache(Cache):
    method __init__ (line 63) | def __init__(self):
    method generate_id (line 66) | def generate_id(self, *args, **kwargs):
    method set (line 69) | def set(self, id, field, value):
    method get (line 75) | def get(self, id, field):
    method get_all (line 84) | def get_all(self, field_list) -> list:
    method delete (line 90) | def delete(self, id):
  class VannaFlaskAPI (line 95) | class VannaFlaskAPI:
    method requires_cache (line 98) | def requires_cache(self, required_fields, optional_fields=[]):
    method requires_auth (line 130) | def requires_auth(self, f):
    method __init__ (line 145) | def __init__(
    method run (line 1176) | def run(self, *args, **kwargs):
  class VannaFlaskApp (line 1208) | class VannaFlaskApp(VannaFlaskAPI):
    method __init__ (line 1209) | def __init__(

FILE: src/vanna/legacy/flask/auth.py
  class AuthInterface (line 6) | class AuthInterface(ABC):
    method get_user (line 8) | def get_user(self, flask_request) -> any:
    method is_logged_in (line 12) | def is_logged_in(self, user: any) -> bool:
    method override_config_for_user (line 16) | def override_config_for_user(self, user: any, config: dict) -> dict:
    method login_form (line 20) | def login_form(self) -> str:
    method login_handler (line 24) | def login_handler(self, flask_request) -> str:
    method callback_handler (line 28) | def callback_handler(self, flask_request) -> str:
    method logout_handler (line 32) | def logout_handler(self, flask_request) -> str:
  class NoAuth (line 36) | class NoAuth(AuthInterface):
    method get_user (line 37) | def get_user(self, flask_request) -> any:
    method is_logged_in (line 40) | def is_logged_in(self, user: any) -> bool:
    method override_config_for_user (line 43) | def override_config_for_user(self, user: any, config: dict) -> dict:
    method login_form (line 46) | def login_form(self) -> str:
    method login_handler (line 49) | def login_handler(self, flask_request) -> str:
    method callback_handler (line 52) | def callback_handler(self, flask_request) -> str:
    method logout_handler (line 55) | def logout_handler(self, flask_request) -> str:

FILE: src/vanna/legacy/google/bigquery_vector.py
  class BigQuery_VectorStore (line 13) | class BigQuery_VectorStore(VannaBase):
    method __init__ (line 14) | def __init__(self, config: dict, **kwargs):
    method store_training_data (line 103) | def store_training_data(
    method fetch_similar_training_data (line 129) | def fetch_similar_training_data(
    method get_embeddings (line 157) | def get_embeddings(self, data: str, task: str) -> List[float]:
    method generate_question_embedding (line 179) | def generate_question_embedding(self, data: str, **kwargs) -> List[flo...
    method generate_storage_embedding (line 187) | def generate_storage_embedding(self, data: str, **kwargs) -> List[float]:
    method generate_embedding (line 206) | def generate_embedding(self, data: str, **kwargs) -> List[float]:
    method get_similar_question_sql (line 209) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_related_ddl (line 219) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 227) | def get_related_documentation(self, question: str, **kwargs) -> list:
    method add_question_sql (line 237) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method add_ddl (line 249) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 256) | def add_documentation(self, documentation: str, **kwargs) -> str:
    method get_training_data (line 266) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 273) | def remove_training_data(self, id: str, **kwargs) -> bool:

FILE: src/vanna/legacy/google/gemini_chat.py
  class GoogleGeminiChat (line 6) | class GoogleGeminiChat(VannaBase):
    method __init__ (line 7) | def __init__(self, config=None):
    method system_message (line 62) | def system_message(self, message: str) -> any:
    method user_message (line 65) | def user_message(self, message: str) -> any:
    method assistant_message (line 68) | def assistant_message(self, message: str) -> any:
    method submit_prompt (line 71) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/hf/hf.py
  class Hf (line 7) | class Hf(VannaBase):
    method __init__ (line 8) | def __init__(self, config=None):
    method system_message (line 21) | def system_message(self, message: str) -> any:
    method user_message (line 24) | def user_message(self, message: str) -> any:
    method assistant_message (line 27) | def assistant_message(self, message: str) -> any:
    method extract_sql_query (line 30) | def extract_sql_query(self, text):
    method generate_sql (line 52) | def generate_sql(self, question: str, **kwargs) -> str:
    method submit_prompt (line 63) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/local.py
  class LocalContext_OpenAI (line 5) | class LocalContext_OpenAI(ChromaDB_VectorStore, OpenAI_Chat):
    method __init__ (line 6) | def __init__(self, config=None):

FILE: src/vanna/legacy/marqo/marqo.py
  class Marqo_VectorStore (line 9) | class Marqo_VectorStore(VannaBase):
    method __init__ (line 10) | def __init__(self, config=None):
    method generate_embedding (line 33) | def generate_embedding(self, data: str, **kwargs) -> list[float]:
    method add_question_sql (line 37) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method add_ddl (line 52) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 65) | def add_documentation(self, documentation: str, **kwargs) -> str:
    method get_training_data (line 78) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 115) | def remove_training_data(self, id: str, **kwargs) -> bool:
    method _extract_documents (line 130) | def _extract_documents(data) -> list:
    method get_similar_question_sql (line 155) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_related_ddl (line 160) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 165) | def get_related_documentation(self, question: str, **kwargs) -> list:

FILE: src/vanna/legacy/milvus/milvus_vector.py
  class Milvus_VectorStore (line 24) | class Milvus_VectorStore(VannaBase):
    method __init__ (line 37) | def __init__(self, config=None):
    method _create_collections (line 55) | def _create_collections(self):
    method generate_embedding (line 60) | def generate_embedding(self, data: str, **kwargs) -> List[float]:
    method _create_sql_collection (line 63) | def _create_sql_collection(self, name: str):
    method _create_ddl_collection (line 101) | def _create_ddl_collection(self, name: str):
    method _create_doc_collection (line 136) | def _create_doc_collection(self, name: str):
    method add_question_sql (line 171) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method add_ddl (line 182) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 193) | def add_documentation(self, documentation: str, **kwargs) -> str:
    method get_training_data (line 204) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method get_similar_question_sql (line 251) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_related_ddl (line 275) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 296) | def get_related_documentation(self, question: str, **kwargs) -> list:
    method remove_training_data (line 317) | def remove_training_data(self, id: str, **kwargs) -> bool:

FILE: src/vanna/legacy/mistral/mistral.py
  class Mistral (line 9) | class Mistral(VannaBase):
    method __init__ (line 10) | def __init__(self, config=None):
    method system_message (line 27) | def system_message(self, message: str) -> any:
    method user_message (line 30) | def user_message(self, message: str) -> any:
    method assistant_message (line 33) | def assistant_message(self, message: str) -> any:
    method generate_sql (line 36) | def generate_sql(self, question: str, **kwargs) -> str:
    method submit_prompt (line 45) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/mock/embedding.py
  class MockEmbedding (line 6) | class MockEmbedding(VannaBase):
    method __init__ (line 7) | def __init__(self, config=None):
    method generate_embedding (line 10) | def generate_embedding(self, data: str, **kwargs) -> List[float]:

FILE: src/vanna/legacy/mock/llm.py
  class MockLLM (line 4) | class MockLLM(VannaBase):
    method __init__ (line 5) | def __init__(self, config=None):
    method system_message (line 8) | def system_message(self, message: str) -> any:
    method user_message (line 11) | def user_message(self, message: str) -> any:
    method assistant_message (line 14) | def assistant_message(self, message: str) -> any:
    method submit_prompt (line 17) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/mock/vectordb.py
  class MockVectorDB (line 6) | class MockVectorDB(VannaBase):
    method __init__ (line 7) | def __init__(self, config=None):
    method _get_id (line 10) | def _get_id(self, value: str, **kwargs) -> str:
    method add_ddl (line 14) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 17) | def add_documentation(self, doc: str, **kwargs) -> str:
    method add_question_sql (line 20) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method get_related_ddl (line 23) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 26) | def get_related_documentation(self, question: str, **kwargs) -> list:
    method get_similar_question_sql (line 29) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_training_data (line 32) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 66) | def remove_training_data(id: str, **kwargs) -> bool:

FILE: src/vanna/legacy/ollama/ollama.py
  class Ollama (line 10) | class Ollama(VannaBase):
    method __init__ (line 11) | def __init__(self, config=None):
    method __pull_model_if_ne (line 40) | def __pull_model_if_ne(ollama_client, model):
    method system_message (line 48) | def system_message(self, message: str) -> any:
    method user_message (line 51) | def user_message(self, message: str) -> any:
    method assistant_message (line 54) | def assistant_message(self, message: str) -> any:
    method extract_sql (line 57) | def extract_sql(self, llm_response):
    method submit_prompt (line 92) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/openai/openai_chat.py
  class OpenAI_Chat (line 8) | class OpenAI_Chat(VannaBase):
    method __init__ (line 9) | def __init__(self, client=None, config=None):
    method system_message (line 44) | def system_message(self, message: str) -> any:
    method user_message (line 47) | def user_message(self, message: str) -> any:
    method assistant_message (line 50) | def assistant_message(self, message: str) -> any:
    method submit_prompt (line 53) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/openai/openai_embeddings.py
  class OpenAI_Embeddings (line 6) | class OpenAI_Embeddings(VannaBase):
    method __init__ (line 7) | def __init__(self, client=None, config=None):
    method generate_embedding (line 34) | def generate_embedding(self, data: str, **kwargs) -> list[float]:

FILE: src/vanna/legacy/opensearch/opensearch_vector.py
  class OpenSearch_VectorStore (line 11) | class OpenSearch_VectorStore(VannaBase):
    method __init__ (line 12) | def __init__(self, config=None):
    method create_index (line 218) | def create_index(self):
    method create_index_if_not_exists (line 227) | def create_index_if_not_exists(self, index_name: str, index_settings: ...
    method add_ddl (line 240) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 249) | def add_documentation(self, doc: str, **kwargs) -> str:
    method add_question_sql (line 258) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method get_related_ddl (line 267) | def get_related_ddl(self, question: str, **kwargs) -> List[str]:
    method get_related_documentation (line 274) | def get_related_documentation(self, question: str, **kwargs) -> List[s...
    method get_similar_question_sql (line 280) | def get_similar_question_sql(self, question: str, **kwargs) -> List[str]:
    method get_training_data (line 291) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 340) | def remove_training_data(self, id: str, **kwargs) -> bool:
    method generate_embedding (line 357) | def generate_embedding(self, data: str, **kwargs) -> list[float]:

FILE: src/vanna/legacy/opensearch/opensearch_vector_semantic.py
  class OpenSearch_Semantic_VectorStore (line 10) | class OpenSearch_Semantic_VectorStore(VannaBase):
    method __init__ (line 11) | def __init__(self, config=None):
    method add_ddl (line 77) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 82) | def add_documentation(self, documentation: str, **kwargs) -> str:
    method add_question_sql (line 87) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method get_related_ddl (line 100) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 106) | def get_related_documentation(self, question: str, **kwargs) -> list:
    method get_similar_question_sql (line 112) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_training_data (line 118) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 182) | def remove_training_data(self, id: str, **kwargs) -> bool:
    method generate_embedding (line 199) | def generate_embedding(self, data: str, **kwargs) -> list[float]:

FILE: src/vanna/legacy/oracle/oracle_vector.py
  class Oracle_VectorStore (line 14) | class Oracle_VectorStore(VannaBase):
    method __init__ (line 15) | def __init__(self, config=None):
    method generate_embedding (line 43) | def generate_embedding(self, data: str, **kwargs) -> List[float]:
    method add_question_sql (line 49) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method add_ddl (line 97) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 141) | def add_documentation(self, documentation: str, **kwargs) -> str:
    method get_training_data (line 185) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 299) | def remove_training_data(self, id: str, **kwargs) -> bool:
    method update_training_data (line 316) | def update_training_data(
    method _extract_documents (line 369) | def _extract_documents(query_results) -> list:
    method get_similar_question_sql (line 389) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_related_ddl (line 408) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method search_tables_metadata (line 430) | def search_tables_metadata(
    method get_related_documentation (line 442) | def get_related_documentation(self, question: str, **kwargs) -> list:
    method create_tables_if_not_exists (line 465) | def create_tables_if_not_exists(self) -> None:
    method create_collections_if_not_exists (line 495) | def create_collections_if_not_exists(
    method get_collection (line 531) | def get_collection(self, name) -> Optional[dict]:
    method get_by_name (line 534) | def get_by_name(self, name: str) -> Optional[dict]:
    method delete_collection (line 556) | def delete_collection(self, name) -> None:

FILE: src/vanna/legacy/pgvector/pgvector.py
  class PG_VectorStore (line 16) | class PG_VectorStore(VannaBase):
    method __init__ (line 17) | def __init__(self, config=None):
    method add_question_sql (line 54) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method add_ddl (line 72) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 81) | def add_documentation(self, documentation: str, **kwargs) -> str:
    method get_collection (line 90) | def get_collection(self, collection_name):
    method get_similar_question_sql (line 101) | def get_similar_question_sql(self, question: str) -> list:
    method get_related_ddl (line 107) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 113) | def get_related_documentation(self, question: str, **kwargs) -> list:
    method train (line 119) | def train(
    method get_training_data (line 155) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 210) | def remove_training_data(self, id: str, **kwargs) -> bool:
    method remove_collection (line 238) | def remove_collection(self, collection_name: str) -> bool:
    method generate_embedding (line 281) | def generate_embedding(self, *args, **kwargs):

FILE: src/vanna/legacy/pinecone/pinecone_vector.py
  class PineconeDB_VectorStore (line 12) | class PineconeDB_VectorStore(VannaBase):
    method __init__ (line 36) | def __init__(self, config=None):
    method _set_index_host (line 82) | def _set_index_host(self, host: str) -> None:
    method _setup_index (line 85) | def _setup_index(self) -> None:
    method _get_indexes (line 109) | def _get_indexes(self) -> list:
    method _check_if_embedding_exists (line 112) | def _check_if_embedding_exists(self, id: str, namespace: str) -> bool:
    method add_ddl (line 118) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 129) | def add_documentation(self, doc: str, **kwargs) -> str:
    method add_question_sql (line 145) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method get_related_ddl (line 171) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 181) | def get_related_documentation(self, question: str, **kwargs) -> list:
    method get_similar_question_sql (line 195) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_training_data (line 215) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 259) | def remove_training_data(self, id: str, **kwargs) -> bool:
    method generate_embedding (line 272) | def generate_embedding(self, data: str, **kwargs) -> List[float]:

FILE: src/vanna/legacy/qdrant/qdrant.py
  class Qdrant_VectorStore (line 13) | class Qdrant_VectorStore(VannaBase):
    method __init__ (line 41) | def __init__(
    method add_question_sql (line 85) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method add_ddl (line 105) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 121) | def add_documentation(self, documentation: str, **kwargs) -> str:
    method get_training_data (line 139) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 202) | def remove_training_data(self, id: str, **kwargs) -> bool:
    method remove_collection (line 210) | def remove_collection(self, collection_name: str) -> bool:
    method embeddings_dimension (line 228) | def embeddings_dimension(self):
    method get_similar_question_sql (line 231) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_related_ddl (line 241) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 251) | def get_related_documentation(self, question: str, **kwargs) -> list:
    method generate_embedding (line 261) | def generate_embedding(self, data: str, **kwargs) -> List[float]:
    method _get_all_points (line 269) | def _get_all_points(self, collection_name: str):
    method _setup_collections (line 291) | def _setup_collections(self):
    method _format_point_id (line 321) | def _format_point_id(self, id: str, collection_name: str) -> str:
    method _parse_point_id (line 324) | def _parse_point_id(self, id: str) -> Tuple[str, str]:

FILE: src/vanna/legacy/qianfan/Qianfan_Chat.py
  class Qianfan_Chat (line 6) | class Qianfan_Chat(VannaBase):
    method __init__ (line 7) | def __init__(self, client=None, config=None):
    method system_message (line 36) | def system_message(self, message: str) -> any:
    method user_message (line 39) | def user_message(self, message: str) -> any:
    method assistant_message (line 42) | def assistant_message(self, message: str) -> any:
    method get_sql_prompt (line 45) | def get_sql_prompt(
    method submit_prompt (line 121) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/qianfan/Qianfan_embeddings.py
  class Qianfan_Embeddings (line 6) | class Qianfan_Embeddings(VannaBase):
    method __init__ (line 7) | def __init__(self, client=None, config=None):
    method generate_embedding (line 24) | def generate_embedding(self, data: str, **kwargs) -> list[float]:

FILE: src/vanna/legacy/qianwen/QianwenAI_chat.py
  class QianWenAI_Chat (line 8) | class QianWenAI_Chat(VannaBase):
    method __init__ (line 9) | def __init__(self, client=None, config=None):
    method system_message (line 52) | def system_message(self, message: str) -> any:
    method user_message (line 55) | def user_message(self, message: str) -> any:
    method assistant_message (line 58) | def assistant_message(self, message: str) -> any:
    method submit_prompt (line 61) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/qianwen/QianwenAI_embeddings.py
  class QianWenAI_Embeddings (line 6) | class QianWenAI_Embeddings(VannaBase):
    method __init__ (line 7) | def __init__(self, client=None, config=None):
    method generate_embedding (line 34) | def generate_embedding(self, data: str, **kwargs) -> list[float]:

FILE: src/vanna/legacy/remote.py
  class VannaDefault (line 40) | class VannaDefault(VannaDB_VectorStore):
    method __init__ (line 41) | def __init__(self, model: str, api_key: str, config=None):
    method system_message (line 56) | def system_message(self, message: str) -> any:
    method user_message (line 59) | def user_message(self, message: str) -> any:
    method assistant_message (line 62) | def assistant_message(self, message: str) -> any:
    method submit_prompt (line 65) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/types/__init__.py
  class Status (line 8) | class Status:
  class StatusWithId (line 14) | class StatusWithId:
  class QuestionList (line 21) | class QuestionList:
  class FullQuestionDocument (line 26) | class FullQuestionDocument:
  class QuestionSQLPair (line 35) | class QuestionSQLPair:
  class Organization (line 42) | class Organization:
  class OrganizationList (line 49) | class OrganizationList:
  class QuestionStringList (line 54) | class QuestionStringList:
  class Visibility (line 59) | class Visibility:
  class UserEmail (line 64) | class UserEmail:
  class NewOrganization (line 69) | class NewOrganization:
  class NewOrganizationMember (line 75) | class NewOrganizationMember:
  class UserOTP (line 82) | class UserOTP:
  class ApiKey (line 88) | class ApiKey:
  class QuestionId (line 93) | class QuestionId:
  class Question (line 98) | class Question:
  class QuestionCategory (line 103) | class QuestionCategory:
  class AccuracyStats (line 118) | class AccuracyStats:
  class Followup (line 124) | class Followup:
  class QuestionEmbedding (line 129) | class QuestionEmbedding:
  class Connection (line 135) | class Connection:
  class SQLAnswer (line 141) | class SQLAnswer:
  class Explanation (line 149) | class Explanation:
  class DataResult (line 154) | class DataResult:
  class PlotlyResult (line 163) | class PlotlyResult:
  class WarehouseDefinition (line 168) | class WarehouseDefinition:
  class TableDefinition (line 174) | class TableDefinition:
  class ColumnDefinition (line 182) | class ColumnDefinition:
  class Diagram (line 192) | class Diagram:
  class StringData (line 198) | class StringData:
  class DataFrameJSON (line 203) | class DataFrameJSON:
  class TrainingData (line 208) | class TrainingData:
  class TrainingPlanItem (line 215) | class TrainingPlanItem:
    method __str__ (line 221) | def __str__(self):
  class TrainingPlan (line 234) | class TrainingPlan:
    method __init__ (line 249) | def __init__(self, plan: List[TrainingPlanItem]):
    method __str__ (line 252) | def __str__(self):
    method __repr__ (line 255) | def __repr__(self):
    method get_summary (line 258) | def get_summary(self) -> List[str]:
    method remove_item (line 275) | def remove_item(self, item: str):

FILE: src/vanna/legacy/utils.py
  function validate_config_path (line 10) | def validate_config_path(path):
  function sanitize_model_name (line 23) | def sanitize_model_name(model_name):
  function deterministic_uuid (line 51) | def deterministic_uuid(content: Union[str, bytes]) -> str:

FILE: src/vanna/legacy/vannadb/vannadb_vector.py
  class VannaDB_VectorStore (line 24) | class VannaDB_VectorStore(VannaBase, VannaAdvanced):
    method __init__ (line 25) | def __init__(self, vanna_model: str, vanna_api_key: str, config=None):
    method _rpc_call (line 44) | def _rpc_call(self, method, params):
    method _dataclass_to_dict (line 66) | def _dataclass_to_dict(self, obj):
    method get_all_functions (line 69) | def get_all_functions(self) -> list:
    method get_function (line 108) | def get_function(self, question: str, additional_data: dict = {}) -> d...
    method create_function (line 160) | def create_function(
    method update_function (line 202) | def update_function(self, old_function_name: str, updated_function: di...
    method delete_function (line 284) | def delete_function(self, function_name: str) -> bool:
    method create_model (line 309) | def create_model(self, model: str, **kwargs) -> bool:
    method get_models (line 335) | def get_models(self) -> list:
    method generate_embedding (line 356) | def generate_embedding(self, data: str, **kwargs) -> list[float]:
    method add_question_sql (line 360) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method add_ddl (line 377) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 389) | def add_documentation(self, documentation: str, **kwargs) -> str:
    method get_training_data (line 401) | def get_training_data(self, **kwargs) -> pd.DataFrame:
    method remove_training_data (line 416) | def remove_training_data(self, id: str, **kwargs) -> bool:
    method get_related_training_data_cached (line 431) | def get_related_training_data_cached(self, question: str) -> TrainingD...
    method get_similar_question_sql (line 446) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_related_ddl (line 454) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 462) | def get_related_documentation(self, question: str, **kwargs) -> list:

FILE: src/vanna/legacy/vllm/vllm.py
  class Vllm (line 8) | class Vllm(VannaBase):
    method __init__ (line 9) | def __init__(self, config=None):
    method system_message (line 31) | def system_message(self, message: str) -> any:
    method user_message (line 34) | def user_message(self, message: str) -> any:
    method assistant_message (line 37) | def assistant_message(self, message: str) -> any:
    method extract_sql_query (line 40) | def extract_sql_query(self, text):
    method generate_sql (line 62) | def generate_sql(self, question: str, **kwargs) -> str:
    method submit_prompt (line 73) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/legacy/weaviate/weaviate_vector.py
  class WeaviateDatabase (line 8) | class WeaviateDatabase(VannaBase):
    method __init__ (line 9) | def __init__(self, config=None):
    method _create_collections_if_not_exist (line 49) | def _create_collections_if_not_exist(self):
    method _initialize_weaviate_client (line 75) | def _initialize_weaviate_client(self):
    method generate_embedding (line 91) | def generate_embedding(self, data: str, **kwargs):
    method _insert_data (line 96) | def _insert_data(self, cluster_key: str, data_object: dict, vector: li...
    method add_ddl (line 104) | def add_ddl(self, ddl: str, **kwargs) -> str:
    method add_documentation (line 111) | def add_documentation(self, doc: str, **kwargs) -> str:
    method add_question_sql (line 118) | def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
    method _query_collection (line 128) | def _query_collection(
    method get_related_ddl (line 144) | def get_related_ddl(self, question: str, **kwargs) -> list:
    method get_related_documentation (line 149) | def get_related_documentation(self, question: str, **kwargs) -> list:
    method get_similar_question_sql (line 154) | def get_similar_question_sql(self, question: str, **kwargs) -> list:
    method get_training_data (line 164) | def get_training_data(self, **kwargs) -> list:
    method remove_training_data (line 175) | def remove_training_data(self, id: str, **kwargs) -> bool:

FILE: src/vanna/legacy/xinference/xinference.py
  class Xinference (line 9) | class Xinference(VannaBase):
    method __init__ (line 10) | def __init__(self, config=None):
    method system_message (line 20) | def system_message(self, message: str) -> any:
    method user_message (line 23) | def user_message(self, message: str) -> any:
    method assistant_message (line 26) | def assistant_message(self, message: str) -> any:
    method submit_prompt (line 29) | def submit_prompt(self, prompt, **kwargs) -> str:

FILE: src/vanna/servers/base/chat_handler.py
  class ChatHandler (line 12) | class ChatHandler:
    method __init__ (line 15) | def __init__(
    method handle_stream (line 26) | async def handle_stream(
    method handle_poll (line 48) | async def handle_poll(self, request: ChatRequest) -> ChatResponse:
    method _generate_conversation_id (line 63) | def _generate_conversation_id(self) -> str:

FILE: src/vanna/servers/base/models.py
  class ChatRequest (line 16) | class ChatRequest(BaseModel):
  class ChatStreamChunk (line 33) | class ChatStreamChunk(BaseModel):
    method from_component (line 47) | def from_component(
    method from_component_update (line 79) | def from_component_update(
  class ChatResponse (line 92) | class ChatResponse(BaseModel):
    method from_chunks (line 101) | def from_chunks(cls, chunks: List[ChatStreamChunk]) -> "ChatResponse":

FILE: src/vanna/servers/base/templates.py
  function get_vanna_component_script (line 8) | def get_vanna_component_script(
  function get_index_html (line 31) | def get_index_html(

FILE: src/vanna/servers/cli/server_runner.py
  class ExampleAgentLoader (line 14) | class ExampleAgentLoader:
    method list_available_examples (line 18) | def list_available_examples() -> Dict[str, str]:
    method load_example_agent (line 34) | def load_example_agent(example_name: str) -> Agent:
  function main (line 104) | def main(

FILE: src/vanna/servers/fastapi/app.py
  class VannaFastAPIServer (line 16) | class VannaFastAPIServer:
    method __init__ (line 19) | def __init__(self, agent: Agent, config: Optional[Dict[str, Any]] = No...
    method create_app (line 30) | def create_app(self) -> FastAPI:
    method run (line 82) | def run(self, **kwargs: Any) -> None:

FILE: src/vanna/servers/fastapi/routes.py
  function register_chat_routes (line 17) | def register_chat_routes(

FILE: src/vanna/servers/flask/app.py
  class VannaFlaskServer (line 16) | class VannaFlaskServer:
    method __init__ (line 19) | def __init__(self, agent: Agent, config: Optional[Dict[str, Any]] = No...
    method create_app (line 30) | def create_app(self) -> Flask:
    method run (line 60) | def run(self, **kwargs: Any) -> None:

FILE: src/vanna/servers/flask/routes.py
  function register_chat_routes (line 17) | def register_chat_routes(

FILE: src/vanna/tools/agent_memory.py
  class SaveQuestionToolArgsParams (line 25) | class SaveQuestionToolArgsParams(BaseModel):
  class SearchSavedCorrectToolUsesParams (line 37) | class SearchSavedCorrectToolUsesParams(BaseModel):
  class SaveTextMemoryParams (line 54) | class SaveTextMemoryParams(BaseModel):
  class SaveQuestionToolArgsTool (line 60) | class SaveQuestionToolArgsTool(Tool[SaveQuestionToolArgsParams]):
    method name (line 64) | def name(self) -> str:
    method description (line 68) | def description(self) -> str:
    method get_args_schema (line 73) | def get_args_schema(self) -> Type[SaveQuestionToolArgsParams]:
    method execute (line 76) | async def execute(
  class SearchSavedCorrectToolUsesTool (line 120) | class SearchSavedCorrectToolUsesTool(Tool[SearchSavedCorrectToolUsesPara...
    method name (line 124) | def name(self) -> str:
    method description (line 128) | def description(self) -> str:
    method get_args_schema (line 131) | def get_args_schema(self) -> Type[SearchSavedCorrectToolUsesParams]:
    method execute (line 134) | async def execute(
  class SaveTextMemoryTool (line 269) | class SaveTextMemoryTool(Tool[SaveTextMemoryParams]):
    method name (line 273) | def name(self) -> str:
    method description (line 277) | def description(self) -> str:
    method get_args_schema (line 280) | def get_args_schema(self) -> Type[SaveTextMemoryParams]:
    method execute (line 283) | async def execute(

FILE: src/vanna/tools/file_system.py
  class FileSearchMatch (line 33) | class FileSearchMatch:
  class CommandResult (line 41) | class CommandResult:
  function _make_snippet (line 49) | def _make_snippet(text: str, query: str, context_window: int = 60) -> Op...
  class FileSystem (line 69) | class FileSystem(ABC):
    method list_files (line 73) | async def list_files(self, directory: str, context: ToolContext) -> Li...
    method read_file (line 78) | async def read_file(self, filename: str, context: ToolContext) -> str:
    method write_file (line 83) | async def write_file(
    method exists (line 90) | async def exists(self, path: str, context: ToolContext) -> bool:
    method is_directory (line 95) | async def is_directory(self, path: str, context: ToolContext) -> bool:
    method search_files (line 100) | async def search_files(
    method run_bash (line 112) | async def run_bash(
  class LocalFileSystem (line 123) | class LocalFileSystem(FileSystem):
    method __init__ (line 126) | def __init__(self, working_directory: str = "."):
    method _get_user_directory (line 134) | def _get_user_directory(self, context: ToolContext) -> Path:
    method _resolve_path (line 152) | def _resolve_path(self, path: str, context: ToolContext) -> Path:
    method list_files (line 175) | async def list_files(self, directory: str, context: ToolContext) -> Li...
    method read_file (line 192) | async def read_file(self, filename: str, context: ToolContext) -> str:
    method write_file (line 204) | async def write_file(
    method exists (line 220) | async def exists(self, path: str, context: ToolContext) -> bool:
    method is_directory (line 228) | async def is_directory(self, path: str, context: ToolContext) -> bool:
    method search_files (line 236) | async def search_files(
    method run_bash (line 301) | async def run_bash(
  class SearchFilesArgs (line 339) | class SearchFilesArgs(BaseModel):
  class SearchFilesTool (line 355) | class SearchFilesTool(Tool[SearchFilesArgs]):
    method __init__ (line 358) | def __init__(self, file_system: Optional[FileSystem] = None):
    method name (line 362) | def name(self) -> str:
    method description (line 366) | def description(self) -> str:
    method get_args_schema (line 369) | def get_args_schema(self) -> Type[SearchFilesArgs]:
    method execute (line 372) | async def execute(self, context: ToolContext, args: SearchFilesArgs) -...
  class ListFilesArgs (line 446) | class ListFilesArgs(BaseModel):
  class ListFilesTool (line 454) | class ListFilesTool(Tool[ListFilesArgs]):
    method __init__ (line 457) | def __init__(self, file_system: Optional[FileSystem] = None):
    method name (line 462) | def name(self) -> str:
    method description (line 466) | def description(self) -> str:
    method get_args_schema (line 469) | def get_args_schema(self) -> Type[ListFilesArgs]:
    method execute (line 472) | async def execute(self, context: ToolContext, args: ListFilesArgs) -> ...
  class ReadFileArgs (line 512) | class ReadFileArgs(BaseModel):
  class ReadFileTool (line 518) | class ReadFileTool(Tool[ReadFileArgs]):
    method __init__ (line 521) | def __init__(self, file_system: Optional[FileSystem] = None):
    method name (line 526) | def name(self) -> str:
    method description (line 530) | def description(self) -> str:
    method get_args_schema (line 533) | def get_args_schema(self) -> Type[ReadFileArgs]:
    method execute (line 536) | async def execute(self, context: ToolContext, args: ReadFileArgs) -> T...
  class WriteFileArgs (line 572) | class WriteFileArgs(BaseModel):
  class WriteFileTool (line 582) | class WriteFileTool(Tool[WriteFileArgs]):
    method __init__ (line 585) | def __init__(self, file_system: Optional[FileSystem] = None):
    method name (line 590) | def name(self) -> str:
    method description (line 594) | def description(self) -> str:
    method get_args_schema (line 597) | def get_args_schema(self) -> Type[WriteFileArgs]:
    method execute (line 600) | async def execute(self, context: ToolContext, args: WriteFileArgs) -> ...
  class LineEdit (line 639) | class LineEdit(BaseModel):
    method validate_line_range (line 657) | def validate_line_range(self) -> "LineEdit":
  class EditFileArgs (line 666) | class EditFileArgs(BaseModel):
  class EditFileTool (line 676) | class EditFileTool(Tool[EditFileArgs]):
    method __init__ (line 679) | def __init__(self, file_system: Optional[FileSystem] = None):
    method name (line 683) | def name(self) -> str:
    method description (line 687) | def description(self) -> str:
    method get_args_schema (line 690) | def get_args_schema(self) -> Type[EditFileArgs]:
    method execute (line 693) | async def execute(self, context: ToolContext, args: EditFileArgs) -> T...
    method _range_error (line 848) | def _range_error(
  function create_file_system_tools (line 868) | def create_file_system_tools(

FILE: src/vanna/tools/python.py
  class RunPythonFileArgs (line 25) | class RunPythonFileArgs(BaseModel):
  class RunPythonFileTool (line 42) | class RunPythonFileTool(Tool[RunPythonFileArgs]):
    method __init__ (line 45) | def __init__(self, file_system: Optional[FileSystem] = None):
    method name (line 49) | def name(self) -> str:
    method description (line 53) | def description(self) -> str:
    method get_args_schema (line 56) | def get_args_schema(self) -> Type[RunPythonFileArgs]:
    method execute (line 59) | async def execute(
  class PipInstallArgs (line 86) | class PipInstallArgs(BaseModel):
  class PipInstallTool (line 107) | class PipInstallTool(Tool[PipInstallArgs]):
    method __init__ (line 110) | def __init__(self, file_system: Optional[FileSystem] = None):
    method name (line 114) | def name(self) -> str:
    method description (line 118) | def description(self) -> str:
    method get_args_schema (line 121) | def get_args_schema(self) -> Type[PipInstallArgs]:
    method execute (line 124) | async def execute(self, context: ToolContext, args: PipInstallArgs) ->...
  function create_python_tools (line 151) | def create_python_tools(file_system: Optional[FileSystem] = None) -> Lis...
  function _quote_command (line 161) | def _quote_command(parts: Sequence[str]) -> str:
  function _truncate (line 165) | def _truncate(text: str, limit: int = MAX_OUTPUT_LENGTH) -> str:
  function _result_from_command (line 171) | def _result_from_command(
  function _error_result (line 209) | def _error_result(message: str) -> ToolResult:

FILE: src/vanna/tools/run_sql.py
  class RunSqlTool (line 18) | class RunSqlTool(Tool[RunSqlToolArgs]):
    method __init__ (line 21) | def __init__(
    method name (line 42) | def name(self) -> str:
    method description (line 46) | def description(self) -> str:
    method get_args_schema (line 53) | def get_args_schema(self) -> Type[RunSqlToolArgs]:
    method execute (line 56) | async def execute(self, context: ToolContext, args: RunSqlToolArgs) ->...

FILE: src/vanna/tools/visualize_data.py
  class VisualizeDataArgs (line 23) | class VisualizeDataArgs(BaseModel):
  class VisualizeDataTool (line 32) | class VisualizeDataTool(Tool[VisualizeDataArgs]):
    method __init__ (line 35) | def __init__(
    method name (line 50) | def name(self) -> str:
    method description (line 54) | def description(self) -> str:
    method get_args_schema (line 57) | def get_args_schema(self) -> Type[VisualizeDataArgs]:
    method execute (line 60) | async def execute(

FILE: src/vanna/web_components/__init__.py
  function get_component_files (line 13) | def get_component_files() -> Dict[str, Path]:
  function get_component_html (line 22) | def get_component_html() -> str:

FILE: tests/conftest.py
  function pytest_configure (line 14) | def pytest_configure(config):
  function pytest_collection_modifyitems (line 29) | def pytest_collection_modifyitems(config, items):
  function chinook_db (line 70) | def chinook_db(tmp_path_factory):

FILE: tests/test_agent_memory.py
  function test_user (line 19) | def test_user():
  function create_test_context (line 29) | def create_test_context(test_user, agent_memory):
  function chromadb_memory (line 41) | def chromadb_memory():
  function qdrant_memory (line 59) | def qdrant_memory():
  function faiss_memory (line 75) | def faiss_memory():
  class TestLocalAgentMemory (line 94) | class TestLocalAgentMemory:
    method test_save_and_search (line 98) | async def test_save_and_search(self, memory_fixture, test_user, request):
    method test_multiple_memories (line 126) | async def test_multiple_memories(self, memory_fixture, test_user, requ...
    method test_tool_filter (line 162) | async def test_tool_filter(self, memory_fixture, test_user, request):
    method test_clear_memories (line 194) | async def test_clear_memories(self, memory_fixture, test_user, request):
    method test_get_recent_memories (line 210) | async def test_get_recent_memories(self, memory_fixture, test_user, re...
    method test_delete_by_id (line 240) | async def test_delete_by_id(self, memory_fixture, test_user, request):
    method test_save_and_search_text_memories (line 276) | async def test_save_and_search_text_memories(
    method test_multiple_text_memories (line 312) | async def test_multiple_text_memories(self, memory_fixture, test_user,...
    method test_get_recent_text_memories (line 340) | async def test_get_recent_text_memories(self, memory_fixture, test_use...
    method test_delete_text_memory (line 363) | async def test_delete_text_memory(self, memory_fixture, test_user, req...
    method test_mixed_tool_and_text_memories (line 393) | async def test_mixed_tool_and_text_memories(

FILE: tests/test_agent_memory_sanity.py
  class TestAgentMemoryInterface (line 18) | class TestAgentMemoryInterface:
    method test_agent_memory_import (line 21) | def test_agent_memory_import(self):
    method test_agent_memory_is_abstract (line 27) | def test_agent_memory_is_abstract(self):
    method test_agent_memory_has_required_methods (line 33) | def test_agent_memory_has_required_methods(self):
    method test_all_methods_are_async (line 56) | def test_all_methods_are_async(self):
  class TestToolMemoryModel (line 77) | class TestToolMemoryModel:
    method test_tool_memory_import (line 80) | def test_tool_memory_import(self):
    method test_tool_memory_is_pydantic_model (line 86) | def test_tool_memory_is_pydantic_model(self):
    method test_tool_memory_has_required_fields (line 93) | def test_tool_memory_has_required_fields(self):
    method test_tool_memory_instantiation (line 108) | def test_tool_memory_instantiation(self):
  class TestToolMemorySearchResultModel (line 126) | class TestToolMemorySearchResultModel:
    method test_memory_search_result_import (line 129) | def test_memory_search_result_import(self):
    method test_memory_search_result_instantiation (line 135) | def test_memory_search_result_instantiation(self):
  class TestTextMemoryModel (line 148) | class TestTextMemoryModel:
    method test_text_memory_import (line 151) | def test_text_memory_import(self):
    method test_text_memory_is_pydantic_model (line 157) | def test_text_memory_is_pydantic_model(self):
    method test_text_memory_has_required_fields (line 164) | def test_text_memory_has_required_fields(self):
    method test_text_memory_instantiation (line 179) | def test_text_memory_instantiation(self):
  class TestTextMemorySearchResultModel (line 191) | class TestTextMemorySearchResultModel:
    method test_text_memory_search_result_import (line 194) | def test_text_memory_search_result_import(self):
    method test_text_memory_search_result_instantiation (line 200) | def test_text_memory_search_result_instantiation(self):
  class TestChromaDBAgentMemory (line 213) | class TestChromaDBAgentMemory:
    method test_chromadb_import (line 216) | def test_chromadb_import(self):
    method test_chromadb_implements_agent_memory (line 225) | def test_chromadb_implements_agent_memory(self):
    method test_chromadb_has_all_methods (line 235) | def test_chromadb_has_all_methods(self):
    method test_chromadb_instantiation (line 261) | def test_chromadb_instantiation(self):
  class TestQdrantAgentMemory (line 279) | class TestQdrantAgentMemory:
    method test_qdrant_import (line 282) | def test_qdrant_import(self):
    method test_qdrant_implements_agent_memory (line 291) | def test_qdrant_implements_agent_memory(self):
    method test_qdrant_has_all_methods (line 301) | def test_qdrant_has_all_methods(self):
    method test_qdrant_instantiation (line 323) | def test_qdrant_instantiation(self):
  class TestPineconeAgentMemory (line 336) | class TestPineconeAgentMemory:
    method test_pinecone_import (line 339) | def test_pinecone_import(self):
    method test_pinecone_implements_agent_memory (line 348) | def test_pinecone_implements_agent_memory(self):
    method test_pinecone_has_all_methods (line 358) | def test_pinecone_has_all_methods(self):
  class TestMilvusAgentMemory (line 381) | class TestMilvusAgentMemory:
    method test_milvus_import (line 384) | def test_milvus_import(self):
    method test_milvus_implements_agent_memory (line 393) | def test_milvus_implements_agent_memory(self):
    method test_milvus_has_all_methods (line 403) | def test_milvus_has_all_methods(self):
  class TestWeaviateAgentMemory (line 426) | class TestWeaviateAgentMemory:
    method test_weaviate_import (line 429) | def test_weaviate_import(self):
    method test_weaviate_implements_agent_memory (line 438) | def test_weaviate_implements_agent_memory(self):
    method test_weaviate_has_all_methods (line 448) | def test_weaviate_has_all_methods(self):
  class TestFAISSAgentMemory (line 471) | class TestFAISSAgentMemory:
    method test_faiss_import (line 474) | def test_faiss_import(self):
    method test_faiss_implements_agent_memory (line 483) | def test_faiss_implements_agent_memory(self):
    method test_faiss_has_all_methods (line 493) | def test_faiss_has_all_methods(self):
    method test_faiss_instantiation (line 515) | def test_faiss_instantiation(self):
  class TestOpenSearchAgentMemory (line 530) | class TestOpenSearchAgentMemory:
    method test_opensearch_import (line 533) | def test_opensearch_import(self):
    method test_opensearch_implements_agent_memory (line 542) | def test_opensearch_implements_agent_memory(self):
    method test_opensearch_has_all_methods (line 552) | def test_opensearch_has_all_methods(self):
  class TestAzureAISearchAgentMemory (line 575) | class TestAzureAISearchAgentMemory:
    method test_azuresearch_import (line 578) | def test_azuresearch_import(self):
    method test_azuresearch_implements_agent_memory (line 587) | def test_azuresearch_implements_agent_memory(self):
    method test_azuresearch_has_all_methods (line 597) | def test_azuresearch_has_all_methods(self):
  class TestMarqoAgentMemory (line 620) | class TestMarqoAgentMemory:
    method test_marqo_import (line 623) | def test_marqo_import(self):
    method test_marqo_implements_agent_memory (line 632) | def test_marqo_implements_agent_memory(self):
    method test_marqo_has_all_methods (line 642) | def test_marqo_has_all_methods(self):
  class TestDemoAgentMemory (line 665) | class TestDemoAgentMemory:
    method test_demo_import (line 668) | def test_demo_import(self):
    method test_demo_implements_agent_memory (line 674) | def test_demo_implements_agent_memory(self):
    method test_demo_has_all_methods (line 681) | def test_demo_has_all_methods(self):
    method test_demo_instantiation (line 700) | def test_demo_instantiation(self):

FILE: tests/test_agents.py
  class SimpleUserResolver (line 14) | class SimpleUserResolver(UserResolver):
    method resolve_user (line 17) | async def resolve_user(self, request_context: RequestContext) -> User:
  function create_agent (line 23) | def create_agent(llm_service, sql_runner):
  function test_agent_top_artist (line 55) | async def test_agent_top_artist(agent, expected_artist="Iron Maiden"):
  function test_anthropic_top_artist (line 110) | async def test_anthropic_top_artist(chinook_db):
  function test_openai_top_artist (line 123) | async def test_openai_top_artist(chinook_db):
  function test_azure_openai_top_artist (line 136) | async def test_azure_openai_top_artist(chinook_db):
  function test_ollama_top_artist (line 172) | async def test_ollama_top_artist(chinook_db):
  function test_gemini_top_artist (line 187) | async def test_gemini_top_artist(chinook_db):

FILE: tests/test_azureopenai_llm.py
  class TestReasoningModelDetection (line 13) | class TestReasoningModelDetection:
    method test_is_reasoning_model_o1 (line 16) | def test_is_reasoning_model_o1(self):
    method test_is_reasoning_model_o3 (line 22) | def test_is_reasoning_model_o3(self):
    method test_is_reasoning_model_gpt5 (line 26) | def test_is_reasoning_model_gpt5(self):
    method test_is_not_reasoning_model (line 34) | def test_is_not_reasoning_model(self):
    method test_case_insensitive_detection (line 41) | def test_case_insensitive_detection(self):
  class TestAzureOpenAILlmServiceInitialization (line 48) | class TestAzureOpenAILlmServiceInitialization:
    method test_init_with_all_params (line 52) | def test_init_with_all_params(self, mock_azure_openai):
    method test_init_with_reasoning_model (line 72) | def test_init_with_reasoning_model(self, mock_azure_openai):
    method test_init_from_environment (line 93) | def test_init_from_environment(self, mock_azure_openai):
    method test_init_missing_model_raises (line 106) | def test_init_missing_model_raises(self, mock_azure_openai):
    method test_init_missing_endpoint_raises (line 115) | def test_init_missing_endpoint_raises(self, mock_azure_openai):
    method test_init_missing_auth_raises (line 124) | def test_init_missing_auth_raises(self, mock_azure_openai):
    method test_init_with_azure_ad_token_provider (line 133) | def test_init_with_azure_ad_token_provider(self, mock_azure_openai):
    method test_init_default_api_version (line 148) | def test_init_default_api_version(self, mock_azure_openai):
  class TestAzureOpenAILlmServicePayloadBuilding (line 161) | class TestAzureOpenAILlmServicePayloadBuilding:
    method test_build_payload_includes_temperature_for_standard_model (line 165) | def test_build_payload_includes_temperature_for_standard_model(
    method test_build_payload_excludes_temperature_for_reasoning_model (line 191) | def test_build_payload_excludes_temperature_for_reasoning_model(
    method test_build_payload_with_system_prompt (line 216) | def test_build_payload_with_system_prompt(self, mock_azure_openai):
    method test_build_payload_with_tools (line 240) | def test_build_payload_with_tools(self, mock_azure_openai):
  class TestImportError (line 276) | class TestImportError:
    method test_import_error_message (line 279) | def test_import_error_message(self):

FILE: tests/test_chromadb_persistence_fix.py
  function test_user (line 19) | def test_user():
  function create_test_context (line 29) | def create_test_context(test_user, agent_memory):
  function test_chromadb_collection_retrieval_without_embedding_function (line 41) | async def test_chromadb_collection_retrieval_without_embedding_function(...
  function test_chromadb_collection_creation_with_embedding_function (line 137) | async def test_chromadb_collection_creation_with_embedding_function():

FILE: tests/test_database_sanity.py
  class TestSqlRunnerInterface (line 19) | class TestSqlRunnerInterface:
    method test_sql_runner_import (line 22) | def test_sql_runner_import(self):
    method test_sql_runner_is_abstract (line 28) | def test_sql_runner_is_abstract(self):
    method test_sql_runner_has_run_sql_method (line 35) | def test_sql_runner_has_run_sql_method(self):
    method test_run_sql_method_signature (line 42) | def test_run_sql_method_signature(self):
    method test_run_sql_is_async (line 55) | def test_run_sql_is_async(self):
  class TestRunSqlToolArgsModel (line 64) | class TestRunSqlToolArgsModel:
    method test_run_sql_tool_args_import (line 67) | def test_run_sql_tool_args_import(self):
    method test_run_sql_tool_args_has_sql_field (line 73) | def test_run_sql_tool_args_has_sql_field(self):
    method test_run_sql_tool_args_is_pydantic_model (line 82) | def test_run_sql_tool_args_is_pydantic_model(self):
  class TestPostgresRunner (line 90) | class TestPostgresRunner:
    method test_postgres_runner_import (line 93) | def test_postgres_runner_import(self):
    method test_postgres_runner_implements_sql_runner (line 99) | def test_postgres_runner_implements_sql_runner(self):
    method test_postgres_runner_has_run_sql_method (line 106) | def test_postgres_runner_has_run_sql_method(self):
    method test_postgres_runner_instantiation_with_connection_string (line 114) | def test_postgres_runner_instantiation_with_connection_string(self):
    method test_postgres_runner_instantiation_with_params (line 124) | def test_postgres_runner_instantiation_with_params(self):
    method test_postgres_runner_requires_valid_params (line 141) | def test_postgres_runner_requires_valid_params(self):
    method test_postgres_runner_checks_psycopg2_import (line 148) | def test_postgres_runner_checks_psycopg2_import(self):
  class TestSqliteRunner (line 161) | class TestSqliteRunner:
    method test_sqlite_runner_import (line 164) | def test_sqlite_runner_import(self):
    method test_sqlite_runner_implements_sql_runner (line 170) | def test_sqlite_runner_implements_sql_runner(self):
    method test_sqlite_runner_has_run_sql_method (line 177) | def test_sqlite_runner_has_run_sql_method(self):
    method test_sqlite_runner_instantiation (line 185) | def test_sqlite_runner_instantiation(self):
    method test_sqlite_uses_builtin_sqlite3 (line 193) | def test_sqlite_uses_builtin_sqlite3(self):
  class TestLegacySqlRunner (line 202) | class TestLegacySqlRunner:
    method test_legacy_sql_runner_import (line 205) | def test_legacy_sql_runner_import(self):
    method test_legacy_sql_runner_implements_sql_runner (line 211) | def test_legacy_sql_runner_implements_sql_runner(self):
    method test_legacy_sql_runner_has_run_sql_method (line 218) | def test_legacy_sql_runner_has_run_sql_method(self):
    method test_legacy_sql_runner_instantiation (line 226) | def test_legacy_sql_runner_instantiation(self):
  class TestDatabaseIntegrationModules (line 239) | class TestDatabaseIntegrationModules:
    method test_postgres_module_import (line 242) | def test_postgres_module_import(self):
    method test_sqlite_module_import (line 251) | def test_sqlite_module_import(self):
    method test_postgres_module_exports_runner (line 260) | def test_postgres_module_exports_runner(self):
    method test_sqlite_module_exports_runner (line 266) | def test_sqlite_module_exports_runner(self):
  class TestLegacyVannaBaseConnections (line 273) | class TestLegacyVannaBaseConnections:
    method test_vanna_base_import (line 276) | def test_vanna_base_import(self):
    method test_vanna_base_has_connection_methods (line 282) | def test_vanna_base_has_connection_methods(self):
    method test_vanna_base_has_run_sql_method (line 303) | def test_vanna_base_has_run_sql_method(self):
  class TestLegacyVannaAdapter (line 310) | class TestLegacyVannaAdapter:
    method test_legacy_vanna_adapter_import (line 313) | def test_legacy_vanna_adapter_import(self):
    method test_legacy_vanna_adapter_is_tool_registry (line 319) | def test_legacy_vanna_adapter_is_tool_registry(self):
  class TestSnowflakeRunner (line 327) | class TestSnowflakeRunner:
    method test_snowflake_runner_import (line 330) | def test_snowflake_runner_import(self):
    method test_snowflake_runner_implements_sql_runner (line 336) | def test_snowflake_runner_implements_sql_runner(self):
    method test_snowflake_runner_has_run_sql_method (line 343) | def test_snowflake_runner_has_run_sql_method(self):
    method test_snowflake_runner_instantiation (line 350) | def test_snowflake_runner_instantiation(self):
    method test_snowflake_runner_key_pair_auth_with_path (line 363) | def test_snowflake_runner_key_pair_auth_with_path(self, tmp_path):
    method test_snowflake_runner_key_pair_auth_with_content (line 387) | def test_snowflake_runner_key_pair_auth_with_content(self):
    method test_snowflake_runner_key_pair_auth_without_passphrase (line 407) | def test_snowflake_runner_key_pair_auth_without_passphrase(self, tmp_p...
    method test_snowflake_runner_missing_auth_raises_error (line 426) | def test_snowflake_runner_missing_auth_raises_error(self):
    method test_snowflake_runner_invalid_key_path_raises_error (line 439) | def test_snowflake_runner_invalid_key_path_raises_error(self):
    method test_snowflake_runner_password_auth_backwards_compatible (line 452) | def test_snowflake_runner_password_auth_backwards_compatible(self):
  class TestMySQLRunner (line 470) | class TestMySQLRunner:
    method test_mysql_runner_import (line 473) | def test_mysql_runner_import(self):
    method test_mysql_runner_implements_sql_runner (line 479) | def test_mysql_runner_implements_sql_runner(self):
    method test_mysql_runner_has_run_sql_method (line 486) | def test_mysql_runner_has_run_sql_method(self):
    method test_mysql_runner_instantiation (line 493) | def test_mysql_runner_instantiation(self):
  class TestClickHouseRunner (line 504) | class TestClickHouseRunner:
    method test_clickhouse_runner_import (line 507) | def test_clickhouse_runner_import(self):
    method test_clickhouse_runner_implements_sql_runner (line 513) | def test_clickhouse_runner_implements_sql_runner(self):
    method test_clickhouse_runner_has_run_sql_method (line 520) | def test_clickhouse_runner_has_run_sql_method(self):
    method test_clickhouse_runner_instantiation (line 527) | def test_clickhouse_runner_instantiation(self):
  class TestOracleRunner (line 538) | class TestOracleRunner:
    method test_oracle_runner_import (line 541) | def test_oracle_runner_import(self):
    method test_oracle_runner_implements_sql_runner (line 547) | def test_oracle_runner_implements_sql_runner(self):
    method test_oracle_runner_has_run_sql_method (line 554) | def test_oracle_runner_has_run_sql_method(self):
    method test_oracle_runner_instantiation (line 561) | def test_oracle_runner_instantiation(self):
  class TestBigQueryRunner (line 572) | class TestBigQueryRunner:
    method test_bigquery_runner_import (line 575) | def test_bigquery_runner_import(self):
    method test_bigquery_runner_implements_sql_runner (line 581) | def test_bigquery_runner_implements_sql_runner(self):
    method test_bigquery_runner_has_run_sql_method (line 588) | def test_bigquery_runner_has_run_sql_method(self):
    method test_bigquery_runner_instantiation (line 595) | def test_bigquery_runner_instantiation(self):
  class TestDuckDBRunner (line 604) | class TestDuckDBRunner:
    method test_duckdb_runner_import (line 607) | def test_duckdb_runner_import(self):
    method test_duckdb_runner_implements_sql_runner (line 613) | def test_duckdb_runner_implements_sql_runner(self):
    method test_duckdb_runner_has_run_sql_method (line 620) | def test_duckdb_runner_has_run_sql_method(self):
    method test_duckdb_runner_instantiation_memory (line 627) | def test_duckdb_runner_instantiation_memory(self):
    method test_duckdb_runner_instantiation_file (line 635) | def test_duckdb_runner_instantiation_file(self):
  class TestMSSQLRunner (line 644) | class TestMSSQLRunner:
    method test_mssql_runner_import (line 647) | def test_mssql_runner_import(self):
    method test_mssql_runner_implements_sql_runner (line 653) | def test_mssql_runner_implements_sql_runner(self):
    method test_mssql_runner_has_run_sql_method (line 660) | def test_mssql_runner_has_run_sql_method(self):
    method test_mssql_runner_instantiation (line 667) | def test_mssql_runner_instantiation(self):
  class TestPrestoRunner (line 677) | class TestPrestoRunner:
    method test_presto_runner_import (line 680) | def test_presto_runner_import(self):
    method test_presto_runner_implements_sql_runner (line 686) | def test_presto_runner_implements_sql_runner(self):
    method test_presto_runner_has_run_sql_method (line 693) | def test_presto_runner_has_run_sql_method(self):
    method test_presto_runner_instantiation (line 700) | def test_presto_runner_instantiation(self):
  class TestHiveRunner (line 709) | class TestHiveRunner:
    method test_hive_runner_import (line 712) | def test_hive_runner_import(self):
    method test_hive_runner_implements_sql_runner (line 718) | def test_hive_runner_implements_sql_runner(self):
    method test_hive_runner_has_run_sql_method (line 725) | def test_hive_runner_has_run_sql_method(self):
    method test_hive_runner_instantiation (line 732) | def test_hive_runner_instantiation(self):

FILE: tests/test_gemini_integration.py
  function test_user (line 18) | def test_user():
  function test_gemini_import (line 30) | async def test_gemini_import():
  function test_gemini_initialization_without_key (line 40) | async def test_gemini_initialization_without_key():
  function test_gemini_initialization (line 61) | async def test_gemini_initialization():
  function test_gemini_basic_request (line 81) | async def test_gemini_basic_request(test_user):
  function test_gemini_streaming_request (line 115) | async def test_gemini_streaming_request(test_user):
  function test_gemini_validate_tools (line 149) | async def test_gemini_validate_tools():

FILE: tests/test_legacy_adapter.py
  class SimpleUserResolver (line 15) | class SimpleUserResolver(UserResolver):
    method resolve_user (line 18) | async def resolve_user(self, request_context: RequestContext) -> User:
  function test_legacy_adapter_with_anthropic (line 29) | async def test_legacy_adapter_with_anthropic():
  function test_legacy_adapter_memory_operations (line 100) | async def test_legacy_adapter_memory_operations():

FILE: tests/test_llm_context_enhancer.py
  class MockAgentMemory (line 25) | class MockAgentMemory(AgentMemory):
    method __init__ (line 28) | def __init__(self):
    method save_tool_usage (line 31) | async def save_tool_usage(
    method save_text_memory (line 36) | async def save_text_memory(self, content, context):
    method search_similar_usage (line 43) | async def search_similar_usage(
    method search_text_memories (line 54) | async def search_text_memories(
    method get_recent_memories (line 67) | async def get_recent_memories(self, context, limit=10):
    method get_recent_text_memories (line 70) | async def get_recent_text_memories(self, context, limit=10):
    method delete_by_id (line 73) | async def delete_by_id(self, context, memory_id):
    method delete_text_memory (line 76) | async def delete_text_memory(self, context, memory_id):
    method clear_memories (line 79) | async def clear_memories(self, context, tool_name=None, before_date=No...
  class MockLlmService (line 83) | class MockLlmService(LlmService):
    method __init__ (line 86) | def __init__(self):
    method send_request (line 90) | async def send_request(self, request):
    method stream_request (line 103) | async def stream_request(self, request):
    method validate_tools (line 112) | async def validate_tools(self, tools):
  class SimpleUserResolver (line 117) | class SimpleUserResolver(UserResolver):
    method resolve_user (line 120) | async def resolve_user(self, request_context: RequestContext) -> User:
  class TrackingEnhancer (line 126) | class TrackingEnhancer(LlmContextEnhancer):
    method __init__ (line 129) | def __init__(self):
    method enhance_system_prompt (line 133) | async def enhance_system_prompt(
    method enhance_user_messages (line 146) | async def enhance_user_messages(
  function test_custom_enhancer_system_prompt_is_called (line 166) | async def test_custom_enhancer_system_prompt_is_called():
  function test_custom_enhancer_user_messages_is_called (line 214) | async def test_custom_enhancer_user_messages_is_called():
  function test_default_enhancer_with_agent_memory (line 258) | async def test_default_enhancer_with_agent_memory():
  function test_default_enhancer_without_agent_memory (line 322) | async def test_default_enhancer_without_agent_memory():
  function test_no_enhancer_means_no_enhancement (line 363) | async def test_no_enhancer_means_no_enhancement():

FILE: tests/test_memory_tools.py
  function demo_agent_memory (line 19) | def demo_agent_memory():
  function admin_user (line 25) | def admin_user():
  function regular_user (line 31) | def regular_user():
  function search_tool (line 37) | def search_tool():
  class TestMemoryToolDetailedResults (line 42) | class TestMemoryToolDetailedResults:
    method test_admin_sees_detailed_results (line 46) | async def test_admin_sees_detailed_results(
    method test_non_admin_sees_simple_status (line 100) | async def test_non_admin_sees_simple_status(
    method test_detailed_results_include_all_memory_fields (line 145) | async def test_detailed_results_include_all_memory_fields(
    method test_no_results_works_for_both_admin_and_user (line 193) | async def test_no_results_works_for_both_admin_and_user(
    method test_llm_result_same_for_admin_and_user (line 245) | async def test_llm_result_same_for_admin_and_user(

FILE: tests/test_ollama_direct.py
  function test_user (line 14) | def test_user():
  function test_ollama_import (line 26) | async def test_ollama_import():
  function test_ollama_initialization (line 39) | async def test_ollama_initialization():
  function test_ollama_basic_request (line 63) | async def test_ollama_basic_request(test_user):
  function test_ollama_pydantic_response (line 104) | async def test_ollama_pydantic_response(test_user):
  function test_ollama_streaming (line 147) | async def test_ollama_streaming(test_user):
  function test_ollama_tool_calling_attempt (line 194) | async def test_ollama_tool_calling_attempt(test_user):
  function test_ollama_payload_building (line 262) | async def test_ollama_payload_building(test_user):

FILE: tests/test_tool_permissions.py
  class SimpleToolArgs (line 25) | class SimpleToolArgs(BaseModel):
  class MockTool (line 31) | class MockTool(Tool[SimpleToolArgs]):
    method __init__ (line 34) | def __init__(self, tool_name: str = "mock_tool"):
    method name (line 38) | def name(self) -> str:
    method description (line 42) | def description(self) -> str:
    method get_args_schema (line 45) | def get_args_schema(self) -> Type[SimpleToolArgs]:
    method execute (line 48) | async def execute(self, context: ToolContext, args: SimpleToolArgs) ->...
  function agent_memory (line 55) | def agent_memory():
  function admin_user (line 61) | def admin_user():
  function regular_user (line 72) | def regular_user():
  function analyst_user (line 83) | def analyst_user():
  function guest_user (line 94) | def guest_user():
  function test_tool_access_empty_groups_allows_all (line 102) | async def test_tool_access_empty_groups_allows_all(regular_user, agent_m...
  function test_tool_access_granted_matching_group (line 135) | async def test_tool_access_granted_matching_group(admin_user, agent_memo...
  function test_tool_access_denied_no_matching_group (line 167) | async def test_tool_access_denied_no_matching_group(regular_user, agent_...
  function test_tool_access_multiple_allowed_groups (line 202) | async def test_tool_access_multiple_allowed_groups(
  function test_tool_access_guest_user_denied (line 256) | async def test_tool_access_guest_user_denied(guest_user, agent_memory):
  function test_get_schemas_filters_by_user (line 286) | async def test_get_schemas_filters_by_user(admin_user, regular_user):
  function test_tool_not_found (line 319) | async def test_tool_not_found(agent_memory):
  function test_duplicate_tool_registration (line 347) | async def test_duplicate_tool_registration():
  function test_tool_access_group_intersection (line 366) | async def test_tool_access_group_intersection(admin_user, agent_memory):
  function test_list_tools (line 398) | async def test_list_tools():
  function test_transform_args_default_no_transformation (line 425) | async def test_transform_args_default_no_transformation(regular_user, ag...
  class CustomTransformRegistry (line 458) | class CustomTransformRegistry(ToolRegistry):
    method transform_args (line 461) | async def transform_args(
  function test_transform_args_custom_modification (line 479) | async def test_transform_args_custom_modification(regular_user, agent_me...
  class RejectionRegistry (line 511) | class RejectionRegistry(ToolRegistry):
    method transform_args (line 514) | async def transform_args(
  function test_transform_args_rejection (line 531) | async def test_transform_args_rejection(regular_user, agent_memory):
  function test_transform_args_allows_approved_content (line 565) | async def test_transform_args_allows_approved_content(regular_user, agen...
  class RowLevelSecurityRegistry (line 597) | class RowLevelSecurityRegistry(ToolRegistry):
    method transform_args (line 600) | async def transform_args(
  function test_transform_args_row_level_security (line 627) | async def test_transform_args_row_level_security(
  function test_transform_args_called_during_execution (line 686) | async def test_transform_args_called_during_execution(regular_user, agen...
  function test_transform_args_receives_correct_parameters (line 730) | async def test_transform_args_receives_correct_parameters(regular_user, ...
  function test_transform_args_called_during_agent_send_message (line 786) | async def test_transform_args_called_during_agent_send_message():

FILE: tests/test_workflow.py
  class SimpleUserResolver (line 19) | class SimpleUserResolver(UserResolver):
    method resolve_user (line 22) | async def resolve_user(self, request_context: RequestContext) -> User:
  class MockAgent (line 28) | class MockAgent:
    method __init__ (line 31) | def __init__(self, agent_memory=None, tool_registry=None):
  class MockToolRegistry (line 36) | class MockToolRegistry:
    method get_schemas (line 39) | async def get_schemas(self, user):
  class MockConversation (line 44) | class MockConversation:
    method __init__ (line 47) | def __init__(self, conversation_id=None):
  function test_user (line 52) | def test_user():
  function admin_test_user (line 58) | def admin_test_user():
  function test_conversation (line 64) | def test_conversation():
  function workflow_handler (line 70) | def workflow_handler():
  function agent_with_memory (line 76) | def agent_with_memory():
  function agent_without_memory (line 83) | def agent_without_memory():
  class TestWorkflowCommands (line 88) | class TestWorkflowCommands:
    method test_help_command (line 92) | async def test_help_command(
    method test_status_command (line 114) | async def test_status_command(
    method test_memories_command (line 130) | async def test_memories_command(
    method test_unknown_command (line 146) | async def test_unknown_command(
  class TestMemoriesView (line 157) | class TestMemoriesView:
    method test_memories_no_agent_memory (line 161) | async def test_memories_no_agent_memory(
    method test_memories_empty (line 176) | async def test_memories_empty(
    method test_memories_with_tool_memories (line 191) | async def test_memories_with_tool_memories(
    method test_memories_with_text_memories (line 244) | async def test_memories_with_text_memories(
    method test_memories_with_both_types (line 286) | async def test_memories_with_both_types(
    method test_memories_have_delete_buttons (line 336) | async def test_memories_have_delete_buttons(
  class TestMemoryDeletion (line 376) | class TestMemoryDeletion:
    method test_delete_no_agent_memory (line 380) | async def test_delete_no_agent_memory(
    method test_delete_no_id_provided (line 393) | async def test_delete_no_id_provided(
    method test_delete_nonexistent_memory (line 407) | async def test_delete_nonexistent_memory(
    method test_delete_tool_memory_success (line 420) | async def test_delete_tool_memory_success(
    method test_delete_text_memory_success (line 464) | async def test_delete_text_memory_success(
    method test_delete_command_parsing (line 501) | async def test_delete_command_parsing(
  class TestWorkflowComponentStructure (line 543) | class TestWorkflowComponentStructure:
    method test_help_has_rich_component (line 547) | async def test_help_has_rich_component(
    method test_memories_cards_have_proper_structure (line 561) | async def test_memories_cards_have_proper_structure(
  class TestStarterUI (line 602) | class TestStarterUI:
    method test_starter_ui_single_component (line 606) | async def test_starter_ui_single_component(
    method test_starter_ui_user_view (line 631) | async def test_starter_ui_user_view(
    method test_starter_ui_admin_view (line 664) | async def test_starter_ui_admin_view(
    method test_starter_ui_admin_without_memory (line 715) | async def test_starter_ui_admin_without_memory(
  class TestAdminOnlyCommands (line 755) | class TestAdminOnlyCommands:
    method test_non_admin_cannot_access_status (line 759) | async def test_non_admin_cannot_access_status(
    method test_non_admin_cannot_access_memories (line 777) | async def test_non_admin_cannot_access_memories(
    method test_non_admin_cannot_delete_memories (line 795) | async def test_non_admin_cannot_delete_memories(
    method test_admin_can_access_memories (line 813) | async def test_admin_can_access_memories(
    method test_help_shows_admin_commands_for_admin (line 832) | async def test_help_shows_admin_commands_for_admin(
    method test_help_hides_admin_commands_for_non_admin (line 853) | async def test_help_hides_admin_commands_for_non_admin(
Condensed preview — 355 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,551K chars).
[
  {
    "path": ".gitattributes",
    "chars": 34,
    "preview": "*.ipynb linguist-detectable=false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 746,
    "preview": "---\r\nname: Bug report\r\nabout: Create a report to help us improve\r\ntitle: ''\r\nlabels: [\"bug\"]\r\nassignees: ''\r\n\r\n---\r\n\r\n**"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 629,
    "preview": "---\r\nname: Feature request\r\nabout: Suggest an idea for this project\r\ntitle: ''\r\nlabels: [\"enhancements\"]\r\nassignees: ''\r"
  },
  {
    "path": ".github/workflows/python-publish.yaml",
    "chars": 1083,
    "preview": "# This workflow will upload a Python Package using Twine when a release is created\n# For more information see: https://d"
  },
  {
    "path": ".github/workflows/tests.yml",
    "chars": 965,
    "preview": "name: Basic Integration Tests\n\non:\n  push:\n    branches:\n      - main\n\npermissions:\n  contents: read\n\njobs:\n  build:\n   "
  },
  {
    "path": ".gitignore",
    "chars": 402,
    "preview": "build\n**.egg-info\nvenn\n.DS_Store\ntests/__pycache__\n__pycache__/\n.idea\n.coverage\ndocs/*.html\n.ipynb_checkpoints/\n.tox/\nno"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 493,
    "preview": "exclude: 'docs|node_modules|migrations|.git|.tox|assets.py'\ndefault_stages: [ commit ]\nfail_fast: true\n\nrepos:\n  - repo:"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 11040,
    "preview": "# Contributing to Vanna\n\nThank you for your interest in contributing to Vanna! This guide will help you get started with"
  },
  {
    "path": "LICENSE",
    "chars": 1065,
    "preview": "MIT License\n\nCopyright (c) 2024 Vanna.AI\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
  },
  {
    "path": "MIGRATION_GUIDE.md",
    "chars": 10106,
    "preview": "# Migration Guide: Vanna 0.x to Vanna 2.0+\n\nThis guide will help you migrate from Vanna 0.x (legacy) to Vanna 2.0+, the "
  },
  {
    "path": "README.md",
    "chars": 9427,
    "preview": "# Vanna 2.0: Turn Questions into Data Insights\n\n**Natural language → SQL → Answers.** Now with enterprise security and u"
  },
  {
    "path": "README_LEGACY.md",
    "chars": 10221,
    "preview": "\n\n| GitHub | PyPI | Documentation | Gurubase |\n| ------ | ---- | ------------- | -------- |\n| [![GitHub](https://img.shi"
  },
  {
    "path": "examples/chromadb_gpu_example.py",
    "chars": 4128,
    "preview": "\"\"\"\nExample: Using ChromaDB AgentMemory with GPU acceleration\n\nThis example demonstrates how to use ChromaAgentMemory wi"
  },
  {
    "path": "examples/transform_args_example.py",
    "chars": 5250,
    "preview": "\"\"\"\nExample demonstrating how to use ToolRegistry.transform_args for user-specific\nargument transformation, such as appl"
  },
  {
    "path": "frontends/webcomponent/.storybook/main.ts",
    "chars": 685,
    "preview": "import type { StorybookConfig } from '@storybook/web-components-vite';\n\nconst config: StorybookConfig = {\n  stories: ['."
  },
  {
    "path": "frontends/webcomponent/.storybook/preview-head.html",
    "chars": 328,
    "preview": "<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" cr"
  },
  {
    "path": "frontends/webcomponent/.storybook/preview.ts",
    "chars": 289,
    "preview": "import type { Preview } from '@storybook/web-components';\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n  "
  },
  {
    "path": "frontends/webcomponent/TEST_README.md",
    "chars": 11564,
    "preview": "# Vanna Webcomponent Comprehensive Test Suite\n\nThis test suite validates all component types and update patterns in the "
  },
  {
    "path": "frontends/webcomponent/package.json",
    "chars": 1495,
    "preview": "{\n  \"name\": \"@vanna/webcomponent\",\n  \"version\": \"2.0.0\",\n  \"description\": \"Lit-based web components for Vanna User Agent"
  },
  {
    "path": "frontends/webcomponent/requirements-test.txt",
    "chars": 255,
    "preview": "# Test backend requirements for vanna-webcomponent comprehensive testing\n\nfastapi>=0.115.0\nuvicorn[standard]>=0.32.0\npyd"
  },
  {
    "path": "frontends/webcomponent/scripts/sync-version.js",
    "chars": 1716,
    "preview": "/**\n * Sync version from pyproject.toml to package.json\n *\n * This ensures the webcomponent version always matches the P"
  },
  {
    "path": "frontends/webcomponent/src/components/button.stories.ts",
    "chars": 15095,
    "preview": "import type { Meta, StoryObj } from '@storybook/web-components';\nimport { ComponentManager, ComponentUpdate } from './ri"
  },
  {
    "path": "frontends/webcomponent/src/components/dataframe-component.stories.ts",
    "chars": 19876,
    "preview": "import type { Meta, StoryObj } from '@storybook/web-components';\nimport { ComponentManager, ComponentUpdate } from './ri"
  },
  {
    "path": "frontends/webcomponent/src/components/plotly-chart.stories.ts",
    "chars": 6516,
    "preview": "import type { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport './plotly-chart';\n\nc"
  },
  {
    "path": "frontends/webcomponent/src/components/plotly-chart.ts",
    "chars": 5218,
    "preview": "import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { vanna"
  },
  {
    "path": "frontends/webcomponent/src/components/rich-card.stories.ts",
    "chars": 4914,
    "preview": "import type { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport './rich-card';\n\ncons"
  },
  {
    "path": "frontends/webcomponent/src/components/rich-card.ts",
    "chars": 8803,
    "preview": "import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { vanna"
  },
  {
    "path": "frontends/webcomponent/src/components/rich-component-system.stories.ts",
    "chars": 11365,
    "preview": "import type { Meta, StoryObj } from '@storybook/web-components';\nimport { ComponentManager, ComponentUpdate } from './ri"
  },
  {
    "path": "frontends/webcomponent/src/components/rich-component-system.ts",
    "chars": 70768,
    "preview": "/**\n * Rich Component System for Vanna Agents\n *\n * Provides a generic component registry and rendering system that can "
  },
  {
    "path": "frontends/webcomponent/src/components/rich-progress-bar.stories.ts",
    "chars": 6442,
    "preview": "import type { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport './rich-progress-bar"
  },
  {
    "path": "frontends/webcomponent/src/components/rich-progress-bar.ts",
    "chars": 5442,
    "preview": "import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { vanna"
  },
  {
    "path": "frontends/webcomponent/src/components/rich-task-list.stories.ts",
    "chars": 6889,
    "preview": "import type { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport './rich-task-list';\n"
  },
  {
    "path": "frontends/webcomponent/src/components/rich-task-list.ts",
    "chars": 7327,
    "preview": "import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { vanna"
  },
  {
    "path": "frontends/webcomponent/src/components/vanna-chat.stories.ts",
    "chars": 43324,
    "preview": "import type { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport './vanna-chat';\nimpo"
  },
  {
    "path": "frontends/webcomponent/src/components/vanna-chat.ts",
    "chars": 44436,
    "preview": "import { LitElement, html, css } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport "
  },
  {
    "path": "frontends/webcomponent/src/components/vanna-message.stories.ts",
    "chars": 2725,
    "preview": "import type { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport './vanna-message';\n\n"
  },
  {
    "path": "frontends/webcomponent/src/components/vanna-message.ts",
    "chars": 6467,
    "preview": "import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { vanna"
  },
  {
    "path": "frontends/webcomponent/src/components/vanna-progress-tracker.stories.ts",
    "chars": 9037,
    "preview": "import type { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport './vanna-progress-tr"
  },
  {
    "path": "frontends/webcomponent/src/components/vanna-progress-tracker.ts",
    "chars": 7309,
    "preview": "import { LitElement, html, css } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport "
  },
  {
    "path": "frontends/webcomponent/src/components/vanna-status-bar.stories.ts",
    "chars": 4420,
    "preview": "import type { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport './vanna-status-bar'"
  },
  {
    "path": "frontends/webcomponent/src/components/vanna-status-bar.ts",
    "chars": 13100,
    "preview": "import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { vanna"
  },
  {
    "path": "frontends/webcomponent/src/index.ts",
    "chars": 1109,
    "preview": "// Log build information when the module loads\nconsole.log(\n  '%c🎨 Vanna Web Components',\n  'color: #4CAF50; font-weight"
  },
  {
    "path": "frontends/webcomponent/src/services/api-client.ts",
    "chars": 8394,
    "preview": "/**\n * API client for communicating with Vanna Agents backend\n */\n\nexport interface ChatMessage {\n  id: string;\n  conten"
  },
  {
    "path": "frontends/webcomponent/src/styles/rich-component-styles.ts",
    "chars": 41059,
    "preview": "import { css } from 'lit';\n\nexport const richComponentStyles = css`\n  .rich-component {\n    margin-bottom: var(--vanna-s"
  },
  {
    "path": "frontends/webcomponent/src/styles/vanna-design-tokens.ts",
    "chars": 6049,
    "preview": "import { css } from 'lit';\n\n// Vanna 2.0 design tokens - Data-First Agents branding\nexport const vannaDesignTokens = css"
  },
  {
    "path": "frontends/webcomponent/src/vite-env.d.ts",
    "chars": 118,
    "preview": "/// <reference types=\"vite/client\" />\n\ndeclare const __BUILD_TIME__: string;\ndeclare const __BUILD_VERSION__: string;\n"
  },
  {
    "path": "frontends/webcomponent/test-comprehensive.html",
    "chars": 19107,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width"
  },
  {
    "path": "frontends/webcomponent/test_backend.py",
    "chars": 29134,
    "preview": "#!/usr/bin/env python3\n\"\"\"\nComprehensive test backend for vanna-webcomponent validation.\n\nThis backend exercises all com"
  },
  {
    "path": "frontends/webcomponent/tsconfig.json",
    "chars": 520,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n "
  },
  {
    "path": "frontends/webcomponent/vite.config.ts",
    "chars": 554,
    "preview": "import { defineConfig } from 'vite';\n\nexport default defineConfig({\n  define: {\n    __BUILD_TIME__: JSON.stringify(new D"
  },
  {
    "path": "notebooks/quickstart.ipynb",
    "chars": 4824,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Install the Package\\n\",\n    \"Here"
  },
  {
    "path": "papers/ai-sql-accuracy-2023-08-17.md",
    "chars": 18761,
    "preview": "# AI SQL Accuracy: Testing different LLMs + context strategies to maximize SQL generation accuracy\n_2023-08-17_\n\n## TLDR"
  },
  {
    "path": "pyproject.toml",
    "chars": 7145,
    "preview": "[build-system]\nrequires = [\"flit_core >=3.2,<4\"]\nbuild-backend = \"flit_core.buildapi\"\n\n[project]\nname = \"vanna\"\nversion "
  },
  {
    "path": "setup.cfg",
    "chars": 277,
    "preview": "[flake8]\nignore = BLK100,W503,E203,E722,F821,F841\nmax-line-length = 100\nexclude = .tox,.git,docs,venv,jupyter_notebook_c"
  },
  {
    "path": "src/evals/benchmarks/llm_comparison.py",
    "chars": 4794,
    "preview": "\"\"\"\nLLM Comparison Benchmark\n\nThis script compares different LLMs on SQL generation tasks.\nRun from repository root:\n   "
  },
  {
    "path": "src/evals/datasets/sql_generation/basic.yaml",
    "chars": 4079,
    "preview": "dataset:\n  name: \"SQL Generation - Basic\"\n  description: \"Basic SQL generation tasks for evaluating agent SQL capabiliti"
  },
  {
    "path": "src/vanna/__init__.py",
    "chars": 3683,
    "preview": "\"\"\"\nVanna Agents - A modular framework for building LLM agents.\n\nThis package provides a flexible framework for creating"
  },
  {
    "path": "src/vanna/agents/__init__.py",
    "chars": 116,
    "preview": "\"\"\"\nAgent implementations.\n\nThis package contains agent implementations and utilities.\n\"\"\"\n\n__all__: list[str] = []\n"
  },
  {
    "path": "src/vanna/capabilities/__init__.py",
    "chars": 392,
    "preview": "\"\"\"\nCapabilities module.\n\nThis package contains abstractions for tool capabilities - reusable utilities\nthat tools can c"
  },
  {
    "path": "src/vanna/capabilities/agent_memory/__init__.py",
    "chars": 350,
    "preview": "\"\"\"\nAgent memory capability package.\n\"\"\"\n\nfrom .base import AgentMemory\nfrom .models import (\n    MemoryStats,\n    TextM"
  },
  {
    "path": "src/vanna/capabilities/agent_memory/base.py",
    "chars": 2988,
    "preview": "\"\"\"\nAgent memory capability interface for tool usage learning.\n\nThis module contains the abstract base class for agent m"
  },
  {
    "path": "src/vanna/capabilities/agent_memory/models.py",
    "chars": 1125,
    "preview": "\"\"\"\nMemory storage models and types.\n\"\"\"\n\nfrom typing import Any, Dict, List, Optional\n\nfrom pydantic import BaseModel\n\n"
  },
  {
    "path": "src/vanna/capabilities/file_system/__init__.py",
    "chars": 267,
    "preview": "\"\"\"\nFile system capability.\n\nThis module provides abstractions for file system operations used by tools.\n\"\"\"\n\nfrom .base"
  },
  {
    "path": "src/vanna/capabilities/file_system/base.py",
    "chars": 1859,
    "preview": "\"\"\"\nFile system capability interface.\n\nThis module contains the abstract base class for file system operations.\n\"\"\"\n\nfro"
  },
  {
    "path": "src/vanna/capabilities/file_system/models.py",
    "chars": 464,
    "preview": "\"\"\"\nFile system capability models.\n\nThis module contains data models for file system operations.\n\"\"\"\n\nfrom dataclasses i"
  },
  {
    "path": "src/vanna/capabilities/sql_runner/__init__.py",
    "chars": 217,
    "preview": "\"\"\"\nSQL runner capability.\n\nThis module provides abstractions for SQL execution used by tools.\n\"\"\"\n\nfrom .base import Sq"
  },
  {
    "path": "src/vanna/capabilities/sql_runner/base.py",
    "chars": 826,
    "preview": "\"\"\"\nSQL runner capability interface.\n\nThis module contains the abstract base class for SQL execution.\n\"\"\"\n\nfrom abc impo"
  },
  {
    "path": "src/vanna/capabilities/sql_runner/models.py",
    "chars": 261,
    "preview": "\"\"\"\nSQL runner capability models.\n\nThis module contains data models for SQL execution.\n\"\"\"\n\nfrom pydantic import BaseMod"
  },
  {
    "path": "src/vanna/components/__init__.py",
    "chars": 2057,
    "preview": "\"\"\"UI Component system for Vanna Agents.\"\"\"\n\n# Base component\nfrom .base import UiComponent\n\n# Simple components\nfrom .s"
  },
  {
    "path": "src/vanna/components/base.py",
    "chars": 341,
    "preview": "\"\"\"\nUI components base - re-exports UiComponent from core.\n\nUiComponent lives in core/ because it's a fundamental return"
  },
  {
    "path": "src/vanna/components/rich/__init__.py",
    "chars": 1735,
    "preview": "\"\"\"Rich UI components for the Vanna Agents framework.\"\"\"\n\n# Base classes and enums - import from core\nfrom ...core.rich_"
  },
  {
    "path": "src/vanna/components/rich/containers/__init__.py",
    "chars": 108,
    "preview": "\"\"\"Container components for layout.\"\"\"\n\nfrom .card import CardComponent\n\n__all__ = [\n    \"CardComponent\",\n]\n"
  },
  {
    "path": "src/vanna/components/rich/containers/card.py",
    "chars": 717,
    "preview": "\"\"\"Card component for displaying structured information.\"\"\"\n\nfrom typing import Any, Dict, List, Optional\nfrom pydantic "
  },
  {
    "path": "src/vanna/components/rich/data/__init__.py",
    "chars": 171,
    "preview": "\"\"\"Data display components.\"\"\"\n\nfrom .dataframe import DataFrameComponent\nfrom .chart import ChartComponent\n\n__all__ = ["
  },
  {
    "path": "src/vanna/components/rich/data/chart.py",
    "chars": 655,
    "preview": "\"\"\"Chart component for data visualization.\"\"\"\n\nfrom typing import Any, Dict, Optional, Union\nfrom pydantic import Field\n"
  },
  {
    "path": "src/vanna/components/rich/data/dataframe.py",
    "chars": 3166,
    "preview": "\"\"\"DataFrame component for displaying tabular data.\"\"\"\n\nfrom typing import Any, Dict, List, Optional\nfrom pydantic impor"
  },
  {
    "path": "src/vanna/components/rich/feedback/__init__.py",
    "chars": 630,
    "preview": "\"\"\"User feedback components.\"\"\"\n\nfrom .notification import NotificationComponent\nfrom .status_card import StatusCardComp"
  },
  {
    "path": "src/vanna/components/rich/feedback/badge.py",
    "chars": 514,
    "preview": "\"\"\"Badge component for displaying status or labels.\"\"\"\n\nfrom typing import Optional\nfrom ....core.rich_component import "
  },
  {
    "path": "src/vanna/components/rich/feedback/icon_text.py",
    "chars": 467,
    "preview": "\"\"\"Icon with text component.\"\"\"\n\nfrom ....core.rich_component import RichComponent, ComponentType\n\n\nclass IconTextCompon"
  },
  {
    "path": "src/vanna/components/rich/feedback/log_viewer.py",
    "chars": 1332,
    "preview": "\"\"\"Log viewer component.\"\"\"\n\nimport uuid\nfrom datetime import datetime\nfrom typing import Any, Dict, List, Optional\nfrom"
  },
  {
    "path": "src/vanna/components/rich/feedback/notification.py",
    "chars": 670,
    "preview": "\"\"\"Notification component for alerts and messages.\"\"\"\n\nfrom typing import Any, Dict, List, Optional\nfrom pydantic import"
  },
  {
    "path": "src/vanna/components/rich/feedback/progress.py",
    "chars": 1312,
    "preview": "\"\"\"Progress components for displaying progress indicators.\"\"\"\n\nfrom typing import Any, Dict, Optional\nfrom ....core.rich"
  },
  {
    "path": "src/vanna/components/rich/feedback/status_card.py",
    "chars": 1058,
    "preview": "\"\"\"Status card component for displaying process status.\"\"\"\n\nfrom typing import Any, Dict, List, Optional\nfrom pydantic i"
  },
  {
    "path": "src/vanna/components/rich/feedback/status_indicator.py",
    "chars": 425,
    "preview": "\"\"\"Status indicator component.\"\"\"\n\nfrom typing import Optional\nfrom ....core.rich_component import RichComponent, Compon"
  },
  {
    "path": "src/vanna/components/rich/interactive/__init__.py",
    "chars": 495,
    "preview": "\"\"\"Interactive components.\"\"\"\n\nfrom .task_list import TaskListComponent, Task\nfrom .ui_state import (\n    StatusBarUpdat"
  },
  {
    "path": "src/vanna/components/rich/interactive/button.py",
    "chars": 2939,
    "preview": "\"\"\"Button component for interactive actions.\"\"\"\n\nfrom typing import Any, Dict, List, Literal, Optional\nfrom ....core.ric"
  },
  {
    "path": "src/vanna/components/rich/interactive/task_list.py",
    "chars": 2046,
    "preview": "\"\"\"Task list component for interactive task tracking.\"\"\"\n\nimport uuid\nfrom datetime import datetime\nfrom typing import A"
  },
  {
    "path": "src/vanna/components/rich/interactive/ui_state.py",
    "chars": 3214,
    "preview": "\"\"\"UI state update components for controlling interface elements.\"\"\"\n\nfrom enum import Enum\nfrom typing import Any, Opti"
  },
  {
    "path": "src/vanna/components/rich/specialized/__init__.py",
    "chars": 111,
    "preview": "\"\"\"Specialized components.\"\"\"\n\nfrom .artifact import ArtifactComponent\n\n__all__ = [\n    \"ArtifactComponent\",\n]\n"
  },
  {
    "path": "src/vanna/components/rich/specialized/artifact.py",
    "chars": 752,
    "preview": "\"\"\"Artifact component for interactive content.\"\"\"\n\nimport uuid\nfrom typing import Optional\nfrom pydantic import Field\nfr"
  },
  {
    "path": "src/vanna/components/rich/text.py",
    "chars": 485,
    "preview": "\"\"\"Rich text component.\"\"\"\n\nfrom typing import Optional\nfrom ...core.rich_component import RichComponent, ComponentType\n"
  },
  {
    "path": "src/vanna/components/simple/__init__.py",
    "chars": 405,
    "preview": "\"\"\"Simple UI components for basic rendering.\"\"\"\n\n# Import from core\nfrom ...core.simple_component import SimpleComponent"
  },
  {
    "path": "src/vanna/components/simple/image.py",
    "chars": 487,
    "preview": "\"\"\"Simple image component.\"\"\"\n\nfrom typing import Optional\nfrom pydantic import Field\nfrom ...core.simple_component impo"
  },
  {
    "path": "src/vanna/components/simple/link.py",
    "chars": 473,
    "preview": "\"\"\"Simple link component.\"\"\"\n\nfrom typing import Optional\nfrom pydantic import Field\nfrom ...core.simple_component impor"
  },
  {
    "path": "src/vanna/components/simple/text.py",
    "chars": 341,
    "preview": "\"\"\"Simple text component.\"\"\"\n\nfrom pydantic import Field\nfrom ...core.simple_component import SimpleComponent, SimpleCom"
  },
  {
    "path": "src/vanna/core/__init__.py",
    "chars": 4776,
    "preview": "\"\"\"\nCore components of the Vanna Agents framework.\n\nThis package contains the fundamental abstractions and implementatio"
  },
  {
    "path": "src/vanna/core/_compat.py",
    "chars": 414,
    "preview": "\"\"\"\nCompatibility shims for different Python versions.\n\nThis module provides compatibility utilities for features that v"
  },
  {
    "path": "src/vanna/core/agent/__init__.py",
    "chars": 187,
    "preview": "\"\"\"\nAgent module.\n\nThis module contains the core Agent implementation and configuration.\n\"\"\"\n\nfrom .agent import Agent\nf"
  },
  {
    "path": "src/vanna/core/agent/agent.py",
    "chars": 61677,
    "preview": "\"\"\"\nAgent implementation for the Vanna Agents framework.\n\nThis module provides the main Agent class that orchestrates th"
  },
  {
    "path": "src/vanna/core/agent/config.py",
    "chars": 4415,
    "preview": "\"\"\"\nAgent configuration.\n\nThis module contains configuration models that control agent behavior.\n\"\"\"\n\nfrom typing import"
  },
  {
    "path": "src/vanna/core/audit/__init__.py",
    "chars": 623,
    "preview": "\"\"\"\nAudit logging for the Vanna Agents framework.\n\nThis module provides interfaces and models for audit logging, enablin"
  },
  {
    "path": "src/vanna/core/audit/base.py",
    "chars": 9726,
    "preview": "\"\"\"\nBase audit logger interface.\n\nAudit loggers enable tracking user actions, tool invocations, and access control\ndecis"
  },
  {
    "path": "src/vanna/core/audit/models.py",
    "chars": 3614,
    "preview": "\"\"\"\nAudit event models.\n\nThis module contains data models for audit logging events.\n\"\"\"\n\nimport uuid\nfrom datetime impor"
  },
  {
    "path": "src/vanna/core/component_manager.py",
    "chars": 11311,
    "preview": "\"\"\"\nComponent state management and update protocol for rich components.\n\"\"\"\n\nimport uuid\nfrom datetime import datetime\nf"
  },
  {
    "path": "src/vanna/core/components.py",
    "chars": 1868,
    "preview": "\"\"\"\nUI component base class.\n\nThis module defines the UiComponent class which is the return type for tool executions.\nIt"
  },
  {
    "path": "src/vanna/core/enhancer/__init__.py",
    "chars": 392,
    "preview": "\"\"\"\nLLM context enhancement system for adding context to prompts and messages.\n\nThis module provides interfaces for enri"
  },
  {
    "path": "src/vanna/core/enhancer/base.py",
    "chars": 3094,
    "preview": "\"\"\"\nLLM context enhancer interface.\n\nLLM context enhancers allow you to add additional context to the system prompt\nand "
  },
  {
    "path": "src/vanna/core/enhancer/default.py",
    "chars": 3986,
    "preview": "\"\"\"\nDefault LLM context enhancer implementation using AgentMemory.\n\nThis implementation enriches the system prompt with "
  },
  {
    "path": "src/vanna/core/enricher/__init__.py",
    "chars": 254,
    "preview": "\"\"\"\nContext enrichment system for adding data to tool execution context.\n\nThis module provides interfaces for enriching "
  },
  {
    "path": "src/vanna/core/enricher/base.py",
    "chars": 1759,
    "preview": "\"\"\"\nBase context enricher interface.\n\nContext enrichers allow you to add additional data to the ToolContext\nbefore tools"
  },
  {
    "path": "src/vanna/core/errors.py",
    "chars": 751,
    "preview": "\"\"\"\nException classes for the Vanna Agents framework.\n\nThis module defines all custom exceptions used throughout the fra"
  },
  {
    "path": "src/vanna/core/evaluation/__init__.py",
    "chars": 2053,
    "preview": "\"\"\"\nEvaluation framework for Vanna Agents.\n\nThis module provides a complete evaluation system for testing and comparing\n"
  },
  {
    "path": "src/vanna/core/evaluation/base.py",
    "chars": 6041,
    "preview": "\"\"\"\nCore evaluation abstractions for the Vanna Agents framework.\n\nThis module provides the base classes and models for e"
  },
  {
    "path": "src/vanna/core/evaluation/dataset.py",
    "chars": 8074,
    "preview": "\"\"\"\nDataset loaders for evaluation test cases.\n\nThis module provides utilities for loading test case datasets from\nYAML "
  },
  {
    "path": "src/vanna/core/evaluation/evaluators.py",
    "chars": 12574,
    "preview": "\"\"\"\nBuilt-in evaluators for common evaluation tasks.\n\nThis module provides ready-to-use evaluators for:\n- Trajectory eva"
  },
  {
    "path": "src/vanna/core/evaluation/report.py",
    "chars": 10625,
    "preview": "\"\"\"\nEvaluation reporting with HTML, CSV, and console output.\n\nThis module provides classes for generating evaluation rep"
  },
  {
    "path": "src/vanna/core/evaluation/runner.py",
    "chars": 10108,
    "preview": "\"\"\"\nEvaluation runner with parallel execution support.\n\nThis module provides the EvaluationRunner class that executes te"
  },
  {
    "path": "src/vanna/core/filter/__init__.py",
    "chars": 259,
    "preview": "\"\"\"\nConversation filtering system for managing conversation history.\n\nThis module provides interfaces for filtering and "
  },
  {
    "path": "src/vanna/core/filter/base.py",
    "chars": 2035,
    "preview": "\"\"\"\nBase conversation filter interface.\n\nConversation filters allow you to transform conversation history before\nit's se"
  },
  {
    "path": "src/vanna/core/lifecycle/__init__.py",
    "chars": 233,
    "preview": "\"\"\"\nLifecycle hook system for agent execution.\n\nThis module provides hooks for intercepting and modifying agent behavior"
  },
  {
    "path": "src/vanna/core/lifecycle/base.py",
    "chars": 2292,
    "preview": "\"\"\"\nBase lifecycle hook interface.\n\nLifecycle hooks allow you to intercept and customize agent behavior\nat key points in"
  },
  {
    "path": "src/vanna/core/llm/__init__.py",
    "chars": 324,
    "preview": "\"\"\"\nLLM domain.\n\nThis module provides the core abstractions for LLM services in the Vanna Agents framework.\n\"\"\"\n\nfrom .b"
  },
  {
    "path": "src/vanna/core/llm/base.py",
    "chars": 1067,
    "preview": "\"\"\"\nLLM domain interface.\n\nThis module contains the abstract base class for LLM services.\n\"\"\"\n\nfrom abc import ABC, abst"
  },
  {
    "path": "src/vanna/core/llm/models.py",
    "chars": 1962,
    "preview": "\"\"\"\nLLM domain models.\n\nThis module contains data models for LLM communication.\n\"\"\"\n\nfrom typing import Any, Dict, List,"
  },
  {
    "path": "src/vanna/core/middleware/__init__.py",
    "chars": 233,
    "preview": "\"\"\"\nMiddleware system for LLM request/response interception.\n\nThis module provides middleware interfaces for interceptin"
  },
  {
    "path": "src/vanna/core/middleware/base.py",
    "chars": 1985,
    "preview": "\"\"\"\nBase LLM middleware interface.\n\nMiddleware allows you to intercept and transform LLM requests and responses\nfor cach"
  },
  {
    "path": "src/vanna/core/observability/__init__.py",
    "chars": 284,
    "preview": "\"\"\"\nObservability system for telemetry and monitoring.\n\nThis module provides interfaces for collecting metrics, traces, "
  },
  {
    "path": "src/vanna/core/observability/base.py",
    "chars": 2557,
    "preview": "\"\"\"\nBase observability provider interface.\n\nObservability providers allow you to collect telemetry data about\nagent exec"
  },
  {
    "path": "src/vanna/core/observability/models.py",
    "chars": 1638,
    "preview": "\"\"\"\nObservability models for spans and metrics.\n\"\"\"\n\nimport time\nfrom typing import Any, Dict, Optional\nfrom uuid import"
  },
  {
    "path": "src/vanna/core/recovery/__init__.py",
    "chars": 335,
    "preview": "\"\"\"\nError recovery system for handling failures gracefully.\n\nThis module provides interfaces for custom error handling, "
  },
  {
    "path": "src/vanna/core/recovery/base.py",
    "chars": 2736,
    "preview": "\"\"\"\nBase error recovery strategy interface.\n\nRecovery strategies allow you to customize how the agent handles errors\ndur"
  },
  {
    "path": "src/vanna/core/recovery/models.py",
    "chars": 811,
    "preview": "\"\"\"\nRecovery action models for error handling.\n\"\"\"\n\nfrom enum import Enum\nfrom typing import Any, Optional\n\nfrom pydanti"
  },
  {
    "path": "src/vanna/core/registry.py",
    "chars": 9469,
    "preview": "\"\"\"\nTool registry for the Vanna Agents framework.\n\nThis module provides the ToolRegistry class for managing and executin"
  },
  {
    "path": "src/vanna/core/rich_component.py",
    "chars": 4868,
    "preview": "\"\"\"\nBase classes for rich UI components.\n\nThis module provides the base RichComponent class and supporting enums\nfor the"
  },
  {
    "path": "src/vanna/core/simple_component.py",
    "chars": 820,
    "preview": "\"\"\"Base classes for simple UI components.\"\"\"\n\nfrom typing import Any, Dict, Optional\nfrom pydantic import BaseModel, Fie"
  },
  {
    "path": "src/vanna/core/storage/__init__.py",
    "chars": 278,
    "preview": "\"\"\"\nStorage domain.\n\nThis module provides the core abstractions for conversation storage in the Vanna Agents framework.\n"
  },
  {
    "path": "src/vanna/core/storage/base.py",
    "chars": 1269,
    "preview": "\"\"\"\nStorage domain interface.\n\nThis module contains the abstract base class for conversation storage.\n\"\"\"\n\nfrom abc impo"
  },
  {
    "path": "src/vanna/core/storage/models.py",
    "chars": 1556,
    "preview": "\"\"\"\nStorage domain models.\n\nThis module contains data models for conversation storage.\n\"\"\"\n\nfrom datetime import datetim"
  },
  {
    "path": "src/vanna/core/system_prompt/__init__.py",
    "chars": 296,
    "preview": "\"\"\"\nSystem prompt domain.\n\nThis module provides the core abstractions for building system prompts in the Vanna Agents fr"
  },
  {
    "path": "src/vanna/core/system_prompt/base.py",
    "chars": 986,
    "preview": "\"\"\"\nSystem prompt builder interface.\n\nThis module contains the abstract base class for system prompt builders.\n\"\"\"\n\nfrom"
  },
  {
    "path": "src/vanna/core/system_prompt/default.py",
    "chars": 6886,
    "preview": "\"\"\"\nDefault system prompt builder implementation with memory workflow support.\n\nThis module provides a default implement"
  },
  {
    "path": "src/vanna/core/tool/__init__.py",
    "chars": 342,
    "preview": "\"\"\"\nTool domain.\n\nThis module provides the core abstractions for tools in the Vanna Agents framework.\n\"\"\"\n\nfrom .base im"
  },
  {
    "path": "src/vanna/core/tool/base.py",
    "chars": 1871,
    "preview": "\"\"\"\nTool domain interface.\n\nThis module contains the abstract base class for tools.\n\"\"\"\n\nfrom abc import ABC, abstractme"
  },
  {
    "path": "src/vanna/core/tool/models.py",
    "chars": 2790,
    "preview": "\"\"\"\nTool domain models.\n\nThis module contains data models for tool execution.\n\"\"\"\n\nfrom typing import TYPE_CHECKING, Any"
  },
  {
    "path": "src/vanna/core/user/__init__.py",
    "chars": 339,
    "preview": "\"\"\"\nUser domain.\n\nThis module provides the core abstractions for user management in the Vanna Agents framework.\n\"\"\"\n\nfro"
  },
  {
    "path": "src/vanna/core/user/base.py",
    "chars": 753,
    "preview": "\"\"\"\nUser domain interface.\n\nThis module contains the abstract base class for user services.\n\"\"\"\n\nfrom abc import ABC, ab"
  },
  {
    "path": "src/vanna/core/user/models.py",
    "chars": 742,
    "preview": "\"\"\"\nUser domain models.\n\nThis module contains data models for user management.\n\"\"\"\n\nfrom typing import Any, Dict, List, "
  },
  {
    "path": "src/vanna/core/user/request_context.py",
    "chars": 2156,
    "preview": "\"\"\"\nRequest context for user resolution.\n\nThis module provides the RequestContext model for passing web request\ninformat"
  },
  {
    "path": "src/vanna/core/user/resolver.py",
    "chars": 1293,
    "preview": "\"\"\"\nUser resolver interface for web request authentication.\n\nThis module provides the abstract base class for resolving "
  },
  {
    "path": "src/vanna/core/validation.py",
    "chars": 5467,
    "preview": "\"\"\"\nDevelopment utilities for validating Pydantic models.\n\nThis module provides utilities that can be used during develo"
  },
  {
    "path": "src/vanna/core/workflow/__init__.py",
    "chars": 475,
    "preview": "\"\"\"\nWorkflow handler system for deterministic workflow execution.\n\nThis module provides the WorkflowHandler interface fo"
  },
  {
    "path": "src/vanna/core/workflow/base.py",
    "chars": 10056,
    "preview": "\"\"\"\nBase workflow handler interface.\n\nWorkflow triggers allow you to execute deterministic workflows in response to\nuser"
  },
  {
    "path": "src/vanna/core/workflow/default.py",
    "chars": 31757,
    "preview": "\"\"\"\nDefault workflow handler implementation with setup health checking.\n\nThis module provides a default implementation o"
  },
  {
    "path": "src/vanna/examples/__init__.py",
    "chars": 53,
    "preview": "\"\"\"Examples for using the Vanna Agents framework.\"\"\"\n"
  },
  {
    "path": "src/vanna/examples/__main__.py",
    "chars": 1396,
    "preview": "\"\"\"\nInteractive example runner for Vanna Agents.\n\"\"\"\n\nimport sys\nimport importlib\n\n\ndef main() -> None:\n    \"\"\"Run an ex"
  },
  {
    "path": "src/vanna/examples/anthropic_quickstart.py",
    "chars": 2314,
    "preview": "\"\"\"\nAnthropic example using AnthropicLlmService.\n\nLoads environment from .env (via python-dotenv), uses model 'claude-so"
  },
  {
    "path": "src/vanna/examples/artifact_example.py",
    "chars": 12180,
    "preview": "#!/usr/bin/env python3\n\"\"\"\nExample demonstrating the artifact system in Vanna Agents.\n\nThis script shows how agents can "
  },
  {
    "path": "src/vanna/examples/claude_sqlite_example.py",
    "chars": 7951,
    "preview": "\"\"\"\nClaude example using the SQL query tool with the Chinook database.\n\nThis example demonstrates using the RunSqlTool w"
  },
  {
    "path": "src/vanna/examples/coding_agent_example.py",
    "chars": 11003,
    "preview": "\"\"\"\nExample coding agent using the vanna-agents framework.\n\nThis example demonstrates building an agent that can edit co"
  },
  {
    "path": "src/vanna/examples/custom_system_prompt_example.py",
    "chars": 5541,
    "preview": "\"\"\"\nExample demonstrating custom system prompt builder with dependency injection.\n\nThis example shows how to create a cu"
  },
  {
    "path": "src/vanna/examples/default_workflow_handler_example.py",
    "chars": 7172,
    "preview": "\"\"\"\nExample demonstrating the DefaultWorkflowHandler with setup health checking.\n\nThis example shows how the DefaultWork"
  },
  {
    "path": "src/vanna/examples/email_auth_example.py",
    "chars": 11497,
    "preview": "\"\"\"\nEmail authentication example for the Vanna Agents framework.\n\nThis example demonstrates how to create an agent with "
  },
  {
    "path": "src/vanna/examples/evaluation_example.py",
    "chars": 8508,
    "preview": "\"\"\"\nEvaluation System Example\n\nThis example demonstrates how to use the evaluation framework to test\nand compare agents."
  },
  {
    "path": "src/vanna/examples/extensibility_example.py",
    "chars": 9310,
    "preview": "\"\"\"\nComprehensive example demonstrating all extensibility interfaces.\n\nThis example shows how to use:\n- LlmMiddleware fo"
  },
  {
    "path": "src/vanna/examples/minimal_example.py",
    "chars": 1939,
    "preview": "\"\"\"Minimal Claude + SQLite example ready for FastAPI.\"\"\"\n\nfrom __future__ import annotations\n\nimport os\nfrom pathlib imp"
  },
  {
    "path": "src/vanna/examples/mock_auth_example.py",
    "chars": 7514,
    "preview": "\"\"\"\nMock authentication example to verify user resolution is working.\n\nThis example demonstrates the new UserResolver ar"
  },
  {
    "path": "src/vanna/examples/mock_custom_tool.py",
    "chars": 10596,
    "preview": "\"\"\"\nMock example showing how to create and use custom tools.\n\nThis example demonstrates creating a simple calculator too"
  },
  {
    "path": "src/vanna/examples/mock_quickstart.py",
    "chars": 2004,
    "preview": "\"\"\"\nMock quickstart example for the Vanna Agents framework.\n\nThis example shows how to create a basic agent with a mock "
  },
  {
    "path": "src/vanna/examples/mock_quota_example.py",
    "chars": 4658,
    "preview": "\"\"\"\nMock quota-based agent example using Mock LLM service.\n\nThis example demonstrates how to create a custom agent runne"
  },
  {
    "path": "src/vanna/examples/mock_rich_components_demo.py",
    "chars": 12629,
    "preview": "\"\"\"\nMock rich components demonstration example.\n\nThis example shows how to create an agent that emits rich, stateful com"
  },
  {
    "path": "src/vanna/examples/mock_sqlite_example.py",
    "chars": 7360,
    "preview": "\"\"\"\nMock example showing how to use the SQL query tool with the Chinook database.\n\nThis example demonstrates using the R"
  },
  {
    "path": "src/vanna/examples/openai_quickstart.py",
    "chars": 2493,
    "preview": "\"\"\"\nOpenAI example using OpenAILlmService.\n\nLoads environment from .env (via python-dotenv), uses model 'gpt-5' by defau"
  },
  {
    "path": "src/vanna/examples/primitive_components_demo.py",
    "chars": 9706,
    "preview": "\"\"\"\nDemonstration of the new primitive component system.\n\nThis example shows how tools compose UI from primitive, domain"
  },
  {
    "path": "src/vanna/examples/quota_lifecycle_example.py",
    "chars": 4470,
    "preview": "\"\"\"\nExample demonstrating lifecycle hooks for user quota management.\n\nThis example shows how to use lifecycle hooks to a"
  },
  {
    "path": "src/vanna/examples/visualization_example.py",
    "chars": 8376,
    "preview": "\"\"\"\nExample demonstrating SQL query execution with automatic visualization.\n\nThis example shows the integration of RunSq"
  },
  {
    "path": "src/vanna/integrations/__init__.py",
    "chars": 383,
    "preview": "\"\"\"\nIntegrations module.\n\nThis package contains concrete implementations of core abstractions and capabilities.\n\"\"\"\n\nfro"
  },
  {
    "path": "src/vanna/integrations/anthropic/__init__.py",
    "chars": 164,
    "preview": "\"\"\"\nAnthropic integration.\n\nThis module provides Anthropic LLM service implementation.\n\"\"\"\n\nfrom .llm import AnthropicLl"
  },
  {
    "path": "src/vanna/integrations/anthropic/llm.py",
    "chars": 10189,
    "preview": "\"\"\"\nAnthropic LLM service implementation.\n\nImplements the LlmService interface using Anthropic's Messages API\n(anthropic"
  },
  {
    "path": "src/vanna/integrations/azureopenai/__init__.py",
    "chars": 175,
    "preview": "\"\"\"\nAzure OpenAI integration.\n\nThis module provides Azure OpenAI LLM service implementations.\n\"\"\"\n\nfrom .llm import Azur"
  },
  {
    "path": "src/vanna/integrations/azureopenai/llm.py",
    "chars": 12428,
    "preview": "\"\"\"\nAzure OpenAI LLM service implementation.\n\nProvides an `LlmService` backed by Azure OpenAI Chat Completions (openai>="
  },
  {
    "path": "src/vanna/integrations/azuresearch/__init__.py",
    "chars": 146,
    "preview": "\"\"\"\nAzure AI Search integration for Vanna Agents.\n\"\"\"\n\nfrom .agent_memory import AzureAISearchAgentMemory\n\n__all__ = [\"A"
  },
  {
    "path": "src/vanna/integrations/azuresearch/agent_memory.py",
    "chars": 13823,
    "preview": "\"\"\"\nAzure AI Search implementation of AgentMemory.\n\nThis implementation uses Azure Cognitive Search for vector storage o"
  },
  {
    "path": "src/vanna/integrations/bigquery/__init__.py",
    "chars": 108,
    "preview": "\"\"\"BigQuery integration for Vanna.\"\"\"\n\nfrom .sql_runner import BigQueryRunner\n\n__all__ = [\"BigQueryRunner\"]\n"
  },
  {
    "path": "src/vanna/integrations/bigquery/sql_runner.py",
    "chars": 2691,
    "preview": "\"\"\"BigQuery implementation of SqlRunner interface.\"\"\"\n\nfrom typing import Optional\nimport pandas as pd\n\nfrom vanna.capab"
  },
  {
    "path": "src/vanna/integrations/chromadb/__init__.py",
    "chars": 3642,
    "preview": "\"\"\"\nChromaDB integration for Vanna Agents.\n\"\"\"\n\nfrom .agent_memory import ChromaAgentMemory\n\n\ndef get_device() -> str:\n "
  },
  {
    "path": "src/vanna/integrations/chromadb/agent_memory.py",
    "chars": 18347,
    "preview": "\"\"\"\nLocal vector database implementation of AgentMemory.\n\nThis implementation uses ChromaDB for local vector storage of "
  },
  {
    "path": "src/vanna/integrations/clickhouse/__init__.py",
    "chars": 114,
    "preview": "\"\"\"ClickHouse integration for Vanna.\"\"\"\n\nfrom .sql_runner import ClickHouseRunner\n\n__all__ = [\"ClickHouseRunner\"]\n"
  },
  {
    "path": "src/vanna/integrations/clickhouse/sql_runner.py",
    "chars": 2350,
    "preview": "\"\"\"ClickHouse implementation of SqlRunner interface.\"\"\"\n\nfrom typing import Optional\nimport pandas as pd\n\nfrom vanna.cap"
  },
  {
    "path": "src/vanna/integrations/duckdb/__init__.py",
    "chars": 102,
    "preview": "\"\"\"DuckDB integration for Vanna.\"\"\"\n\nfrom .sql_runner import DuckDBRunner\n\n__all__ = [\"DuckDBRunner\"]\n"
  },
  {
    "path": "src/vanna/integrations/duckdb/sql_runner.py",
    "chars": 2088,
    "preview": "\"\"\"DuckDB implementation of SqlRunner interface.\"\"\"\n\nfrom typing import Optional\nimport pandas as pd\n\nfrom vanna.capabil"
  },
  {
    "path": "src/vanna/integrations/faiss/__init__.py",
    "chars": 120,
    "preview": "\"\"\"\nFAISS integration for Vanna Agents.\n\"\"\"\n\nfrom .agent_memory import FAISSAgentMemory\n\n__all__ = [\"FAISSAgentMemory\"]\n"
  },
  {
    "path": "src/vanna/integrations/faiss/agent_memory.py",
    "chars": 14370,
    "preview": "\"\"\"\nFAISS vector database implementation of AgentMemory.\n\nThis implementation uses FAISS for local vector storage of too"
  },
  {
    "path": "src/vanna/integrations/google/__init__.py",
    "chars": 159,
    "preview": "\"\"\"\nGoogle AI integrations.\n\nThis module provides Google AI service implementations.\n\"\"\"\n\nfrom .gemini import GeminiLlmS"
  },
  {
    "path": "src/vanna/integrations/google/gemini.py",
    "chars": 13091,
    "preview": "\"\"\"\nGoogle Gemini LLM service implementation.\n\nImplements the LlmService interface using Google's Gen AI SDK\n(google-gen"
  },
  {
    "path": "src/vanna/integrations/hive/__init__.py",
    "chars": 96,
    "preview": "\"\"\"Hive integration for Vanna.\"\"\"\n\nfrom .sql_runner import HiveRunner\n\n__all__ = [\"HiveRunner\"]\n"
  },
  {
    "path": "src/vanna/integrations/hive/sql_runner.py",
    "chars": 2584,
    "preview": "\"\"\"Hive implementation of SqlRunner interface.\"\"\"\n\nfrom typing import Optional\nimport pandas as pd\n\nfrom vanna.capabilit"
  },
  {
    "path": "src/vanna/integrations/local/__init__.py",
    "chars": 408,
    "preview": "\"\"\"\nLocal integration.\n\nThis module provides built-in local implementations.\n\"\"\"\n\nfrom .audit import LoggingAuditLogger\n"
  },
  {
    "path": "src/vanna/integrations/local/agent_memory/__init__.py",
    "chars": 115,
    "preview": "\"\"\"\nLocal agent memory implementations.\n\"\"\"\n\nfrom .in_memory import DemoAgentMemory\n\n__all__ = [\"DemoAgentMemory\"]\n"
  },
  {
    "path": "src/vanna/integrations/local/agent_memory/in_memory.py",
    "chars": 10061,
    "preview": "\"\"\"\nDemo in-memory implementation of AgentMemory.\n\nThis implementation provides a zero-dependency, minimal storage solut"
  },
  {
    "path": "src/vanna/integrations/local/audit.py",
    "chars": 1838,
    "preview": "\"\"\"\nLocal audit logger implementation using Python logging.\n\nThis module provides a simple audit logger that writes even"
  }
]

// ... and 155 more files (download for full content)

About this extraction

This page contains the full source code of the vanna-ai/vanna GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 355 files (2.3 MB), approximately 619.3k tokens, and a symbol index with 2076 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!