Metadata-Version: 2.4
Name: langchain-pi
Version: 0.2.1
Summary: LangChain BaseChatModel adapter for Pi (@earendil-works/pi-ai) via a Node sidecar — use Pi with any provider, model and auth from LangChain/LangGraph in Python. Includes a native opencode/Zen chat model (no pi).
Project-URL: Homepage, https://github.com/cgaravitoq/langchain-pi
Project-URL: Repository, https://github.com/cgaravitoq/langchain-pi
Author: cgaravitoq
License: MIT
License-File: LICENSE
Keywords: chat-model,langchain,langgraph,llm,pi,pi-ai
Requires-Python: >=3.9
Requires-Dist: langchain-core<2,>=0.3.15
Provides-Extra: opencode
Requires-Dist: langchain-openai>=0.2; extra == 'opencode'
Provides-Extra: test
Requires-Dist: langchain-tests>=0.3.5; extra == 'test'
Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
Requires-Dist: pytest-socket>=0.7; extra == 'test'
Requires-Dist: pytest>=7.4; extra == 'test'
Description-Content-Type: text/markdown

# langchain-pi

A LangChain [`BaseChatModel`](https://python.langchain.com/) adapter for **Pi**
([`@earendil-works/pi-ai`](https://www.npmjs.com/package/@earendil-works/pi-ai)),
the Python twin of [`langchain-pi-ts`](https://github.com/cgaravitoq/langchain-pi-ts).
Use Pi — and any provider, model and credential it resolves — from LangChain and
LangGraph in Python, with native tool calling and streaming.

Pi is a TypeScript/Node stack with no Python SDK, so `langchain-pi` drives a tiny
**Node sidecar** that wraps pi-ai's `streamSimple` + `ModelRegistry`/`AuthStorage`.
Node keeps owning provider dispatch, OAuth refresh and the provider stealth
headers; Python only frames the request and reconstructs the streamed events.
**Python never touches a token.**

## Requirements

- **Python** ≥ 3.9
- **Node** ≥ 22.19.0 on `PATH`, with `@earendil-works/pi-ai` and
  `@earendil-works/pi-coding-agent` resolvable (install them where the sidecar can
  reach them, or point `node_modules_dir` at a `node_modules` directory that has
  them). Note: `NODE_PATH` does not work for ESM, so `node_modules_dir` resolves
  each package via its `package.json` entry.
- A provider authenticated in `~/.pi` (e.g. `openai-codex`), exactly as for the
  Pi CLI / the TS package.

## Install

```sh
pip install langchain-pi          # or: uv add langchain-pi
npm install @earendil-works/pi-ai @earendil-works/pi-coding-agent
```

## Usage

```python
from langchain_pi import ChatPi

model = ChatPi(
    provider="openai-codex",
    model="gpt-5.3-codex-spark",
    reasoning="minimal",
    system="You are a helpful assistant.",
)

print(model.invoke("Hello!").content)
```

### Tool calling

Accepts any LangChain tool; schemas are converted to the JSON Schema pi-ai expects.

```python
from langchain_core.tools import tool

@tool
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"It is sunny in {city}, 24C."

agent_model = model.bind_tools([get_weather])
```

### Streaming

```python
for chunk in model.stream("Write a haiku."):
    print(chunk.content, end="")
```

### LangGraph

```python
from langgraph.prebuilt import create_react_agent

agent = create_react_agent(model, [get_weather])
agent.invoke({"messages": [("user", "What's the weather in Paris?")]})
```

### Pointing at your Node install

If pi-ai isn't resolvable from the sidecar's location, pass the `node_modules`
directory that contains it:

```python
ChatPi(provider="opencode", model="deepseek-v4-flash-free",
       node_modules_dir="/path/to/your/project/node_modules")
```

## Native opencode/Zen (no Pi)

For [OpenCode Zen](https://opencode.ai/docs/zen/) you don't need Pi — it's an
OpenAI-compatible endpoint. `langchain_pi.opencode` ships a `ChatOpencode` (a thin
`ChatOpenAI` subclass) that points at it and reads the key opencode auto-provisions
into `~/.local/share/opencode/auth.json`. Install the optional extra:

```sh
pip install "langchain-pi[opencode]"
```

Free models work **two ways** — with or without an API key:

- **No key** → the anonymous IP-rate-limited trial (works out of the box).
- **With a key** (auto-read from `auth.json`, or `OPENCODE_API_KEY` / `api_key`) → higher limits.

Paid models require a key.

```python
from langchain_pi.opencode import ChatOpencode

# Free — no key needed (anonymous), or auto-uses a key if present for higher limits:
free = ChatOpencode("deepseek-v4-flash-free")

# Paid — requires a key (auto-read or explicit api_key):
paid = ChatOpencode("glm-5")
go = ChatOpencode("glm-5", tier="go")
```

Free models: `deepseek-v4-flash-free`, `big-pickle`, `mimo-v2.5-free`, `nemotron-3-super-free`.

## Notes

- Node is a runtime prerequisite — the heavy provider/auth logic lives in pi-ai.
- Tool-call deltas and usage/cost metadata are reconstructed 1:1 with the TS twin.
- Cancellation (e.g. LangGraph) aborts the in-flight provider request via the sidecar.

## License

MIT
