Metadata-Version: 2.4
Name: langchain-rezunate
Version: 0.1.0
Summary: LangChain integration for rezunate-llm-sdk
Project-URL: Homepage, https://github.com/rezunate/langchain-rezunate
Project-URL: Repository, https://github.com/rezunate/langchain-rezunate
Project-URL: Issues, https://github.com/rezunate/langchain-rezunate/issues
Author-email: Rezunate <engineering@rezunate.ai>
License: MIT
License-File: LICENSE
Keywords: anthropic,google,guardrails,langchain,llm,openai,rezunate
Requires-Python: >=3.10
Requires-Dist: langchain-core<2.0.0,>=1.0.0
Requires-Dist: rezunate-llm-sdk>=0.1.2
Provides-Extra: test
Requires-Dist: langchain-tests<2.0.0,>=1.0.0; extra == 'test'
Requires-Dist: pytest>=8.0; extra == 'test'
Description-Content-Type: text/markdown

# langchain-rezunate

[![PyPI version](https://img.shields.io/pypi/v/langchain-rezunate.svg)](https://pypi.org/project/langchain-rezunate/)
[![Python versions](https://img.shields.io/pypi/pyversions/langchain-rezunate.svg)](https://pypi.org/project/langchain-rezunate/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

LangChain integration for [`rezunate-llm-sdk`](https://pypi.org/project/rezunate-llm-sdk/).

Use any provider supported by Rezunate (OpenAI, Anthropic, Google) through the
standard LangChain interfaces — chat models, tool calling, prompt templates,
runnables, and guardrails — backed by a single unified gateway.

## Features

- **`ChatRezunate`** — a `BaseChatModel` supporting `invoke`/`ainvoke`, streaming-free
  generation, and tool calling via `bind_tools()`.
- **`RezunateGuardrailsMiddleware`** — wrap any chat-model runnable to scan input and
  output messages against Rezunate guardrails.
- **`RezunatePromptTemplate`** — fetch a prompt from the Rezunate LLM-Router by slug and
  render it with mustache (`{{var}}`) variables.
- **`chat_complete_runnable`** — a lightweight `RunnableLambda` wrapper around the SDK's
  `chat_complete`, for composing into LCEL chains.
- **`RezunateConfig`** — shared configuration with environment-variable key resolution.
- **`RezunateAPIError`** — a typed exception for provider/SDK errors.

## Installation

```bash
pip install langchain-rezunate
```

### From source (development)

```bash
pip install -e ".[test]"
```

> **Requires Python 3.10+.**

## Quickstart

```python
from langchain_rezunate import ChatRezunate

llm = ChatRezunate(
    provider="anthropic",          # or "openai", "google"
    model="claude-sonnet-4-20250514",
    api_key="your-provider-api-key",
    max_tokens=100,
)

response = llm.invoke("Hello!")
print(response.content)
```

Async is supported out of the box:

```python
response = await llm.ainvoke("Hello!")
```

## Configuration & API keys

You can pass `api_key=` directly, or let it resolve from the environment. The provider
key is resolved in this order:

1. `api_key` / `provider_api_key` passed directly
2. `REZUNATE_API_KEY` (override for any provider)
3. `{PROVIDER}_API_KEY` — `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GROK_API_KEY`, `LLAMA_API_KEY`, `DEEPSEEK_API_KEY`, `QWEN_API_KEY` or `GOOGLE_API_KEY`

The control-plane (LLM-Router) key, used by `RezunatePromptTemplate` and server-side
guardrails, resolves from `control_plane_api_key` or the `REZUNATE_LLM_API_KEY` env var.

```python
from langchain_rezunate import ChatRezunate, RezunateConfig

config = RezunateConfig(provider="openai", provider_api_key="sk-...")
llm = ChatRezunate(provider="openai", model="gpt-4o-mini", config=config)
```

## Tool calling

Bind Pydantic models, functions, or LangChain tools and the model will return
structured `tool_calls`:

```python
from pydantic import BaseModel, Field
from langchain_rezunate import ChatRezunate

class GetWeather(BaseModel):
    """Look up the current weather for a city."""
    city: str = Field(description="City name, e.g. 'Tokyo'")

llm = ChatRezunate(provider="openai", model="gpt-4o-mini", api_key="sk-...")
llm_with_tools = llm.bind_tools([GetWeather])

response = llm_with_tools.invoke("What's the weather in Tokyo?")
print(response.tool_calls)
# [{'name': 'GetWeather', 'args': {'city': 'Tokyo'}, 'id': '...', 'type': 'tool_call'}]
```

`tool_choice` accepts `"auto"`, `"required"`, `"none"`, `"any"`, or a specific tool name.

## Remote prompt templates

Fetch and render a prompt managed in the Rezunate LLM-Router:

```python
from langchain_rezunate import RezunatePromptTemplate

tmpl = RezunatePromptTemplate(slug_id="welcome", input_variables=["name"])
print(tmpl.format(name="Sam"))

# Or let input_variables be discovered from the remote prompt:
tmpl = RezunatePromptTemplate.from_slug("welcome")
```

## Guardrails

Wrap a chat model to scan both input and output against your guardrails config:

```python
from langchain_rezunate import ChatRezunate, RezunateGuardrailsMiddleware
from rezunate_llm_sdk import load_guardrails

model = ChatRezunate(provider="openai", model="gpt-4o-mini", api_key="sk-...")
guarded = RezunateGuardrailsMiddleware(
    model,
    guardrails_config=load_guardrails("guardrails.yaml"),
    # or: guardrails_path="guardrails.yaml"
)

guarded.invoke("Hello!")
```

Guardrails can also be applied directly on the model via the `guardrails_config` argument
of `ChatRezunate`, which forwards to the SDK's `chat_complete`.

## Composing with LCEL

`chat_complete_runnable` returns a `RunnableLambda` you can pipe into LCEL chains:

```python
from langchain_core.prompts import ChatPromptTemplate
from langchain_rezunate import chat_complete_runnable

prompt = ChatPromptTemplate.from_template("Translate to French: {text}")
chain = prompt | chat_complete_runnable(
    provider="openai", model="gpt-4o-mini", api_key="sk-..."
)

print(chain.invoke({"text": "Good morning"}).content)
```

## Development

Run the test suite:

```bash
pip install -e ".[test]"
pytest
```

## License

[MIT](LICENSE) © Deeptechs.ai
