Metadata-Version: 2.4
Name: langchain-age
Version: 0.1.2
Summary: LangChain integration for Apache AGE (graph) + pgvector (vector) on PostgreSQL
Project-URL: Homepage, https://github.com/BAEM1N/langchain-age
Project-URL: Repository, https://github.com/BAEM1N/langchain-age
Project-URL: Issues, https://github.com/BAEM1N/langchain-age/issues
License: MIT License
        
        Copyright (c) 2024 BAEM1N
        
        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.
License-File: LICENSE
Keywords: apache-age,graph-database,graphrag,langchain,pgvector,postgresql,rag
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Requires-Dist: antlr4-python3-runtime>=4.11.0
Requires-Dist: langchain-community>=0.4.0
Requires-Dist: langchain-core<2.0.0,>=1.0.0
Requires-Dist: langchain<2.0.0,>=1.0.0
Requires-Dist: psycopg[binary]>=3.1.0
Provides-Extra: all
Requires-Dist: numpy>=1.24; extra == 'all'
Requires-Dist: pgvector>=0.3.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: langchain-openai>=0.2.0; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: numpy>=1.24; extra == 'dev'
Requires-Dist: pgvector>=0.3.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Provides-Extra: vector
Requires-Dist: numpy>=1.24; extra == 'vector'
Requires-Dist: pgvector>=0.3.0; extra == 'vector'
Description-Content-Type: text/markdown

# langchain-age

**LangChain integration for [Apache AGE](https://age.apache.org/) (graph) + [pgvector](https://github.com/pgvector/pgvector) (vector) on PostgreSQL.**

Drop-in replacement for `langchain-neo4j` — same API, runs on PostgreSQL instead of Neo4j.

```python
from langchain_age import AGEGraph, AGEVector, AGEGraphCypherQAChain
```

> **v0.1.1 — Initial stable release.** The public API (`AGEGraph`, `AGEVector`, `AGEGraphCypherQAChain`) is considered stable. Breaking changes in 0.1.x will be avoided where possible.

### Tested with

- Python 3.10–3.14
- PostgreSQL 18 + Apache AGE 1.7.0 + pgvector 0.8.2

### Known limitations

- AGE does not support parameterised Cypher (`$param`) — `langchain-age` provides `mogrify`-based safe value escaping as a workaround
- Async methods use `run_in_executor` wrapping (not native `psycopg.AsyncConnection` yet)

## Installation

Three install modes depending on what you need:

```bash
# Graph only
pip install langchain-age

# Graph + Vector (everything)
pip install "langchain-age[all]"
```

> The Apache AGE Python driver is vendored — no separate installation required.
> Graph features work out of the box with `pip install langchain-age`.

## Quick Start

### 1. Start the database

```bash
cd docker
docker compose up -d
```

Single container: PostgreSQL 18 + Apache AGE 1.7.0 + pgvector.

### 2. Graph mode

```python
from langchain_age import AGEGraph

graph = AGEGraph(
    "host=localhost port=5433 dbname=langchain_age user=langchain password=langchain",
    graph_name="my_graph",
)

graph.query("CREATE (:Person {name: 'Alice', age: 30})")
results = graph.query("MATCH (n:Person) RETURN n.name AS name")
# [{'name': 'Alice'}]
```

### 3. Vector mode

```python
from langchain_age import AGEVector, DistanceStrategy

store = AGEVector(
    connection_string="host=localhost port=5433 dbname=langchain_age user=langchain password=langchain",
    embedding_function=my_embeddings,
    collection_name="docs",
    distance_strategy=DistanceStrategy.COSINE,
)

store.add_texts(["Apache AGE adds Cypher to PostgreSQL."])
results = store.similarity_search("graph database", k=5)
```

### 4. Graph + Vector (GraphRAG)

```python
# Vectorise existing graph nodes
store = AGEVector.from_existing_graph(
    embedding=my_embeddings,
    connection_string="...",
    graph_name="my_graph",
    node_label="Document",
    text_node_properties=["title", "content"],
)
```

### 5. Cypher QA Chain

```python
from langchain_age import AGEGraph, AGEGraphCypherQAChain
from langchain_openai import ChatOpenAI

chain = AGEGraphCypherQAChain.from_llm(
    ChatOpenAI(model="gpt-4o-mini"),
    graph=AGEGraph("...", "movies"),
    allow_dangerous_requests=True,
)
answer = chain.run("Which movies did Tom Hanks act in?")
```

### 6. Long-term Memory & Checkpointing

Uses the same PostgreSQL instance via [langgraph-checkpoint-postgres](https://langchain-ai.github.io/langgraph/reference/checkpoints/#langgraph.checkpoint.postgres.PostgresSaver):

```python
from langgraph.store.postgres import PostgresStore

with PostgresStore.from_conn_string("host=localhost port=5433 ...") as store:
    store.setup()
    store.put(("users", "123"), "prefs", {"theme": "dark"})
```

AGE graph tables, pgvector tables, and LangGraph store tables coexist in the same database.

## Features

| Component | Class | Description |
|-----------|-------|-------------|
| **Graph** | `AGEGraph` | GraphStore backed by Apache AGE. Cypher execution, schema introspection, GraphDocument upserts. |
| **Vector** | `AGEVector` | VectorStore backed by pgvector. Cosine/L2/IP distance, HNSW & IVFFlat indexes, hybrid search (vector + full-text via RRF), MMR. |
| **Chain** | `AGEGraphCypherQAChain` | LLM generates Cypher, executes against AGE, returns natural-language answer. |

### Security

- SQL identifier validation at construction (`validate_sql_identifier`)
- Cypher identifier backtick-quoting for all 25 AGE reserved words (`escape_cypher_identifier`)
- OpenCypher-standard string escaping with `''` doubling (`escape_cypher_string`)
- `allow_dangerous_requests` gate on the QA chain
- Double-quoted SQL table/index names throughout

### langchain-neo4j API Compatibility

| Feature | langchain-neo4j | langchain-age |
|---------|----------------|---------------|
| `from_existing_graph()` | `Neo4jVector.from_existing_graph()` | `AGEVector.from_existing_graph()` |
| `from_existing_index()` | `Neo4jVector.from_existing_index()` | `AGEVector.from_existing_index()` |
| `similarity_search_with_relevance_scores()` | Yes | Yes |
| `as_retriever()` | Yes | Yes |
| Hybrid search | Lucene full-text | PostgreSQL tsvector + RRF |
| `include_types` / `exclude_types` | Yes | Yes |
| `add_graph_documents()` | Yes | Yes |
| Context manager | Yes | Yes |
| Batch insert | `UNWIND ... IN TRANSACTIONS OF 1000 ROWS` | `executemany` with `batch_size=1000` |

## AGE vs Neo4j

| | Neo4j | Apache AGE |
|---|---|---|
| Cypher execution | Bolt protocol | SQL-wrapped: `SELECT * FROM cypher(...)` |
| Connection | `neo4j://` | PostgreSQL DSN |
| Vector search | Native index | pgvector extension |
| APOC | Available | Not available |
| Data types | Native graph | `agtype` (JSON superset) |
| Parameterised Cypher | Yes (`$param`) | mogrify-based (`%s` placeholders) |

`langchain-age` handles SQL wrapping automatically — you write plain Cypher.

## Documentation

| Language | Getting Started | Tutorial | API Reference |
|----------|----------------|----------|---------------|
| English  | [getting-started.md](docs/en/getting-started.md) | [tutorial.md](docs/en/tutorial.md) | [api-reference.md](docs/en/api-reference.md) |
| Korean   | [getting-started.md](docs/ko/getting-started.md) | [tutorial.md](docs/ko/tutorial.md) | [api-reference.md](docs/ko/api-reference.md) |

## Notebooks

| Notebook | Description |
|----------|-------------|
| [01_graph.ipynb](notebooks/01_graph.ipynb) | AGEGraph: Cypher CRUD, schema, GraphDocument |
| [02_vector.ipynb](notebooks/02_vector.ipynb) | AGEVector: similarity, hybrid, MMR, filters, HNSW |
| [03_graph_vector.ipynb](notebooks/03_graph_vector.ipynb) | GraphRAG: from_existing_graph, QA chain |

01 requires no API key. 02–03 use OpenAI via `getpass`.

## Running Tests

```bash
# Unit tests (no DB required) — 65 tests
pytest tests/unit/

# Integration tests (requires Docker container) — 53 tests
export LANGCHAIN_AGE_TEST_DSN="host=localhost port=5433 dbname=langchain_age user=langchain password=langchain"
pytest tests/integration/
```

## Project Structure

```
langchain-age/
├── docker/                          # PG18 + AGE + pgvector container
│   ├── Dockerfile
│   ├── docker-compose.yml
│   └── init/01_init_extensions.sql
├── langchain_age/
│   ├── __init__.py                  # Lazy imports (3-mode support)
│   ├── graphs/
│   │   └── age_graph.py             # AGEGraph (GraphStore)
│   ├── vectorstores/
│   │   └── age_vector.py            # AGEVector (VectorStore)
│   ├── chains/
│   │   └── graph_cypher_qa_chain.py # AGEGraphCypherQAChain
│   └── utils/
│       ├── agtype.py                # Vertex/Edge/Path → dict conversion
│       └── cypher.py                # SQL wrapping, escaping, validation
├── tests/
│   ├── conftest.py                  # Auto-skip integration when DSN unset
│   ├── unit/                        # 65 tests, no DB
│   └── integration/                 # 53 tests, live DB
├── pyproject.toml
├── LICENSE                          # MIT
├── CHANGELOG.md                     # Version history
└── .github/workflows/ci.yml        # Lint + unit (3.10–3.13) + integration
```

## Python Support

Tested on Python 3.10, 3.11, 3.12, 3.13, 3.14.

## License

MIT
