# RagSaaS Python SDK

Zero-config RAG for LangChain agents. One decorator, instant knowledge base.

## Installation

```bash
pip install ragsaas
```

## Quick Start

```python
import os
os.environ["RAGSAAS_API_KEY"] = "sk_xxx"  # Your project API key

from ragsaas import with_rag
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI

# Wrap your agent - tenant is your customer's ID
@with_rag(tenant_id="customer-123")
def create_agent():
    return create_react_agent(ChatOpenAI(), [])

agent = create_agent()
result = agent.invoke({"messages": [("user", "What does the docs say about pricing?")]})
# Agent automatically has access to customer-123's knowledge base
```

## Dynamic Tenant (Multi-tenant Apps)

For web apps where tenant comes from request context:

```python
from ragsaas import with_rag
from flask import g

# Tenant resolved at runtime
@with_rag(tenant_id=lambda: g.current_user.tenant_id)
def get_agent():
    return create_react_agent(llm, tools)

@app.route("/chat")
def chat():
    agent = get_agent()
    return agent.invoke({"messages": [("user", request.json["query"])]})
```

## How It Works

The `@with_rag` decorator:
1. Intercepts agent invocations
2. Extracts the user's query
3. Searches the tenant's knowledge base
4. Injects relevant context as a system message
5. Passes to the original agent

Your agent gets knowledge base context automatically - no tools, no pipelines, no config.

## Manual Usage

If you need more control:

```python
from ragsaas import RAGAgent

rag = RAGAgent(tenant_id="customer-123")

# Retrieve context manually
context = rag.retrieve("What is the refund policy?")
print(context.content)
print(context.sources)

# Or wrap an existing agent
agent = rag.wrap(my_agent)
```

## Configuration

| Env Variable | Required | Description |
|--------------|----------|-------------|
| `RAGSAAS_API_KEY` | Yes | Your project API key |
| `RAGSAAS_BASE_URL` | No | API URL (default: https://api.ragsaas.com) |

Decorator options:

```python
@with_rag(
    tenant_id="customer-123",      # Required: customer identifier
    collection="support-docs",      # Optional: filter by collection
    top_k=10,                       # Optional: number of results (default: 5)
    use_hybrid=True,                # Optional: hybrid search (default: False)
    threshold=0.7,                  # Optional: minimum score threshold
)
```

## With Different Frameworks

### LangGraph

```python
from langgraph.prebuilt import create_react_agent
from ragsaas import with_rag

@with_rag(tenant_id="customer-123")
def create_support_agent():
    return create_react_agent(
        ChatOpenAI(model="gpt-4o"),
        tools=[search_tool, calculator_tool],
    )
```

### LangChain Chains

```python
from langchain.chains import RetrievalQA
from ragsaas import RagSaaSRetriever

# For chains, use the retriever directly
retriever = RagSaaSRetriever(tenant_id="customer-123")
qa = RetrievalQA.from_chain_type(llm=llm, retriever=retriever)
```

### Raw Client

```python
from ragsaas import RagSaaSClient

client = RagSaaSClient(
    api_key="sk_xxx",
    tenant_id="customer-123",
)

# Search
docs = client.search("machine learning", top_k=5)

# Hybrid search
docs = client.hybrid_search("ML basics", semantic_weight=0.7)

# Generate answer
answer = client.answer("What is ML?")
print(answer.answer)
print(answer.sources)
```
