Metadata-Version: 2.4
Name: sqlmind
Version: 0.1.1
Summary: LangGraph-native NL→SQL agent library with pluggable guardrails and semantic layer
Author: sqlmind contributors
License-Expression: MIT
Project-URL: Homepage, https://github.com/aviiiii01/sqlmind
Project-URL: Repository, https://github.com/aviiiii01/sqlmind
Project-URL: Bug Tracker, https://github.com/aviiiii01/sqlmind/issues
Project-URL: Changelog, https://github.com/aviiiii01/sqlmind/blob/main/CHANGELOG.md
Project-URL: Documentation, https://github.com/aviiiii01/sqlmind#readme
Keywords: langgraph,sql,nlp,agent,llm,text-to-sql,natural-language,database,nl2sql,langchain
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Database
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: sqlalchemy>=2.0
Requires-Dist: sqlglot>=25.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: pydantic>=2.0
Requires-Dist: typing-extensions>=4.9
Provides-Extra: langgraph
Requires-Dist: langgraph>=0.2; extra == "langgraph"
Requires-Dist: langchain-core>=0.3; extra == "langgraph"
Provides-Extra: openai
Requires-Dist: openai>=1.0; extra == "openai"
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.30; extra == "anthropic"
Provides-Extra: postgres
Requires-Dist: psycopg2-binary>=2.9; extra == "postgres"
Provides-Extra: mysql
Requires-Dist: pymysql>=1.1; extra == "mysql"
Provides-Extra: index
Requires-Dist: faiss-cpu>=1.8; extra == "index"
Requires-Dist: sentence-transformers>=3.0; extra == "index"
Requires-Dist: numpy>=1.26; extra == "index"
Provides-Extra: all
Requires-Dist: sqlmind[anthropic,index,langgraph,mysql,openai,postgres]; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Requires-Dist: sqlmind[anthropic,langgraph,mysql,openai,postgres]; extra == "dev"
Dynamic: license-file

# sqlmind

> **LangGraph-native NL→SQL agent library** — drop your database query pipeline directly into an existing agent graph as a composable node.

[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org)
[![License: MIT](https://img.shields.io/badge/License-MIT-green)](LICENSE)

---

## Why sqlmind?

Most NL→SQL tools are standalone apps or ChatGPT wrappers. **sqlmind is a library** — designed to be dropped into your *existing* LangGraph agent as a composable node. No hosting, no vendor lock-in, no new service to manage.

| Feature | sqlmind | Most alternatives |
|---------|-----------|-------------------|
| LangGraph-native nodes | ✅ First-class | ❌ Standalone only |
| Pluggable guardrails | ✅ Full interface | ❌ Fixed policies |
| Semantic glossary | ✅ YAML/dict/custom | ❌ None |
| Canonical metric defs | ✅ Injected into LLM | ❌ LLM guesses |
| Self-correction loop | ✅ Up to N retries | ❌ One-shot |
| Read-only by default | ✅ Session-level | ⚠️ Convention only |
| Any LLM | ✅ Protocol + adapters | ❌ OpenAI only |

---

## Installation

```bash
# Core + PostgreSQL + LangGraph/LangChain
pip install sqlmind[langgraph,postgres]

# Add OpenAI or Anthropic direct adapters
pip install sqlmind[openai]
pip install sqlmind[anthropic]

# Everything
pip install sqlmind[all]
```

---

## Quick Start

### Shape A — Single drop-in node

```python
from sqlmind import SQLAgent, SQLAgentConfig
from sqlmind.core import PostgresConnection
from sqlmind.guardrails import ReadOnlyGuardrail, RowLimitGuardrail, BlockedColumnsGuardrail
from sqlmind.semantic import Glossary, MetricRegistry
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, END

# 1. Connect (read-only enforced at DB session level)
conn = PostgresConnection(url="postgresql://user:pass@host/mydb")

# 2. Semantic layer — eliminates LLM guessing about your business terms
glossary = Glossary.from_yaml("glossary.yaml")
metrics = MetricRegistry()
metrics.define("mrr", "Monthly Recurring Revenue", formula="SUM(amount) WHERE cycle='monthly'", unit="USD")

# 3. Guardrails — fail closed, explainable violations
guardrails = [
    ReadOnlyGuardrail(),                              # Block INSERT/UPDATE/DELETE/DROP
    RowLimitGuardrail(max_rows=500),                  # Inject LIMIT clause
    BlockedColumnsGuardrail(columns=["ssn", "password_hash"]),  # PII protection
]

# 4. Build agent — any LLM works
agent = SQLAgent(
    connection=conn,
    llm=ChatOpenAI(model="gpt-4o"),    # or OpenAIAdapter, AnthropicAdapter, or any custom LLM
    guardrails=guardrails,
    glossary=glossary,
    metrics=metrics,
)

# 5. Drop into your LangGraph graph — ONE LINE
graph = StateGraph(dict)
graph.add_node("db", agent.as_node())
graph.set_entry_point("db")
graph.add_edge("db", END)
app = graph.compile()

result = app.invoke({"user_query": "How many active users signed up last month?"})
# → {"success": True, "sql_result": [...], "row_count": 1, "sql_executed": "SELECT ...", ...}
```

### Shape B — Exploded sub-graph (power users)

Individual nodes for full control flow — route to human-in-the-loop on low confidence, add custom steps between pipeline stages.

```python
from sqlmind.integrations import clarify_node, generate_node, validate_node, execute_node

graph = StateGraph(MyState)
graph.add_node("clarify",  clarify_node(agent))
graph.add_node("generate", generate_node(agent))
graph.add_node("validate", validate_node(agent))
graph.add_node("execute",  execute_node(agent))

# Your own routing
def route_after_clarify(state):
    return "human_in_loop" if state.get("needs_clarification") else "generate"

graph.add_conditional_edges("clarify", route_after_clarify, {...})
```

### Use outside LangGraph

```python
result = agent.query("Show me top 10 customers by revenue this quarter")
print(result["sql"])         # The executed SQL
print(result["rows"])        # Query result as list of dicts
print(result["explanation"]) # Human-readable explanation
```

---

## Custom LLM Integration

Any LLM works. Three ways:

```python
# Option 1: Any LangChain model (ChatOpenAI, ChatAnthropic, ChatOllama, etc.)
from langchain_openai import ChatOpenAI
agent = SQLAgent(connection=conn, llm=ChatOpenAI(model="gpt-4o"))

# Option 2: Direct OpenAI (no LangChain dep)
from sqlmind.llm import OpenAIAdapter
agent = SQLAgent(connection=conn, llm=OpenAIAdapter(api_key="sk-...", model="gpt-4o"))

# Option 3: Direct Anthropic
from sqlmind.llm import AnthropicAdapter
agent = SQLAgent(connection=conn, llm=AnthropicAdapter(model="claude-3-5-sonnet-20241022"))

# Option 4: Fully custom — implement 2 methods
class MyCustomLLM:
    def complete(self, messages, **kwargs):
        ...  # return LLMResponse(content="...")
    def complete_structured(self, messages, schema, **kwargs):
        ...  # return dict

agent = SQLAgent(connection=conn, llm=MyCustomLLM())
```

---

## Custom Guardrails

```python
from sqlmind.guardrails import Guardrail, GuardrailResult
import datetime

class NoDeleteOnWeekendsGuardrail(Guardrail):
    def check(self, query, context):
        is_weekend = datetime.date.today().weekday() >= 5
        has_delete = "DELETE" in query.sql.upper()
        if is_weekend and has_delete:
            return GuardrailResult(
                passed=False,
                guardrail_name=self.name,
                reason="DELETE queries are blocked on weekends per data policy.",
            )
        return GuardrailResult(passed=True, guardrail_name=self.name)

agent = SQLAgent(
    connection=conn,
    llm=llm,
    guardrails=[ReadOnlyGuardrail(), NoDeleteOnWeekendsGuardrail()],
)
```

---

## Glossary YAML Format

```yaml
# glossary.yaml
amt_cents:
  description: "Revenue in USD cents. Always divide by 100 before display."
  example: "SELECT SUM(amt_cents) / 100.0 AS revenue_usd FROM orders"
  tags: [finance, revenue]

status:
  description: "User status: 1=active, 2=trial, 3=churned, 4=suspended"
  tags: [user, lifecycle]

# Shorthand
mrr: "Monthly Recurring Revenue. See metric definitions for formula."
```

---

## Configuration

```python
from sqlmind import SQLAgentConfig

config = SQLAgentConfig(
    max_retries=3,                # Self-correction attempts on execution error
    confidence_threshold=0.65,    # Below this → trigger clarification step
    max_rows=1000,                # Hard row cap
    query_timeout_seconds=30,     # Wall-clock execution timeout
    memory_window=10,             # Multi-turn context turns kept
    input_state_key="user_query", # LangGraph state key for the question
    output_state_key="sql_result",# LangGraph state key for the result
    verbose=False,                # Debug logging
    llm_temperature=0.0,          # Deterministic generation
)
```

---

## LangGraph State Contract

The sqlmind node reads and writes these keys on the shared LangGraph state:

| Key | Direction | Type | Description |
|-----|-----------|------|-------------|
| `user_query` | Read | `str` | The NL question |
| `sql_result` | Write | `list[dict]` | Query result rows |
| `sql_executed` | Write | `str` | Final SQL (after any guardrail rewrites) |
| `row_count` | Write | `int` | Number of rows returned |
| `success` | Write | `bool` | Whether execution succeeded |
| `error` | Write | `str\|None` | Error message if failed |
| `clarification_question` | Write | `str\|None` | Set if question was ambiguous |
| `sql_confidence` | Write | `float` | Model confidence 0.0–1.0 |
| `execution_attempts` | Write | `int` | Number of self-correction attempts |

---

## Architecture

```
sqlmind/
├── core/           # DB connection + schema introspection + embedding index
├── semantic/       # Glossary (YAML/dict) + MetricRegistry
├── agent/          # clarify → generate → validate → execute → memory
├── guardrails/     # Abstract interface + 5 built-ins + custom registry
├── integrations/   # langgraph_node.py (as_node + exploded nodes)
└── llm/            # LLMProvider protocol + LangChain/OpenAI/Anthropic adapters
```

---

## Running Tests

```bash
pip install sqlmind[dev]
pytest tests/ -v
```

---

## License

MIT
