Metadata-Version: 2.4
Name: aiecs-kg
Version: 0.9.0
Summary: Enterprise knowledge graph (L2) — optional PyPI package split from AIECS
Author-email: AIECS Team <iretbl@gmail.com>
License: Apache-2.0
Project-URL: Homepage, https://github.com/Howmany-Zeta/AI-Execute-Services-KnowledgeGraph
Project-URL: Documentation, https://github.com/Howmany-Zeta/AI-Execute-Services-KnowledgeGraph#readme
Project-URL: Bug Tracker, https://github.com/Howmany-Zeta/AI-Execute-Services-KnowledgeGraph/issues
Keywords: knowledge-graph,graph-store,aiecs,rag,entity-linking
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: <3.13,>=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: LICENSE_HEADER.txt
Requires-Dist: pydantic<3.0.0,>=2.11.5
Requires-Dist: pydantic-settings<3.0.0,>=2.9.1
Requires-Dist: python-dotenv<2.0.0,>=1.1.0
Requires-Dist: numpy<3.0.0,>=2.4.1
Requires-Dist: networkx<4.0.0,>=3.0
Requires-Dist: cachetools<6.0.0,>=5.0.0
Requires-Dist: typing-extensions<5.0.0,>=4.13.2
Requires-Dist: pyyaml<7.0.0,>=6.0.2
Requires-Dist: tqdm<5.0.0,>=4.66.0
Provides-Extra: postgres
Requires-Dist: asyncpg<1.0.0,>=0.30.0; extra == "postgres"
Provides-Extra: sqlite
Requires-Dist: aiosqlite<1.0.0,>=0.20.0; extra == "sqlite"
Provides-Extra: neo4j
Requires-Dist: neo4j<6.0.0,>=5.25.0; extra == "neo4j"
Provides-Extra: graph
Requires-Dist: asyncpg<1.0.0,>=0.30.0; extra == "graph"
Requires-Dist: neo4j<6.0.0,>=5.25.0; extra == "graph"
Provides-Extra: reasoning
Requires-Dist: lark-parser<0.13.0,>=0.12.0; extra == "reasoning"
Requires-Dist: colorama<1.0.0,>=0.4.6; extra == "reasoning"
Requires-Dist: python-Levenshtein<1.0.0,>=0.25.0; extra == "reasoning"
Provides-Extra: builder
Requires-Dist: pandas<3.0.0,>=2.2.0; extra == "builder"
Requires-Dist: openpyxl<4.0.0,>=3.1.0; extra == "builder"
Requires-Dist: pyreadstat<2.0.0,>=1.2.0; extra == "builder"
Requires-Dist: psutil<8.0.0,>=6.0.0; extra == "builder"
Provides-Extra: fusion
Requires-Dist: redis<7.0.0,>=6.2.0; extra == "fusion"
Provides-Extra: spg
Requires-Dist: urllib3<3.0.0,>=2.0.0; extra == "spg"
Requires-Dist: six>=1.16.0; extra == "spg"
Requires-Dist: python-dateutil>=2.8.0; extra == "spg"
Requires-Dist: certifi>=2024.0.0; extra == "spg"
Provides-Extra: dev
Requires-Dist: pytest<9.0.0,>=8.4.2; extra == "dev"
Requires-Dist: pytest-asyncio<2.0.0,>=1.2.0; extra == "dev"
Requires-Dist: pytest-cov<8.0.0,>=7.0.0; extra == "dev"
Requires-Dist: pytest-timeout<3.0.0,>=2.4.0; extra == "dev"
Requires-Dist: mypy<2.0.0,>=1.18.2; extra == "dev"
Requires-Dist: flake8<8.0.0,>=7.3.0; extra == "dev"
Requires-Dist: black<26.0.0,>=25.1.0; extra == "dev"
Requires-Dist: pre-commit<5.0.0,>=4.5.1; extra == "dev"
Requires-Dist: deptry<0.24.0,>=0.23.0; extra == "dev"
Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
Requires-Dist: types-cachetools>=5.0.0; extra == "dev"
Requires-Dist: types-six>=1.16.0; extra == "dev"
Requires-Dist: types-python-dateutil>=2.8.0; extra == "dev"
Requires-Dist: asyncpg<1.0.0,>=0.30.0; extra == "dev"
Requires-Dist: aiosqlite<1.0.0,>=0.20.0; extra == "dev"
Requires-Dist: lark-parser<0.13.0,>=0.12.0; extra == "dev"
Requires-Dist: colorama<1.0.0,>=0.4.6; extra == "dev"
Requires-Dist: python-Levenshtein<1.0.0,>=0.25.0; extra == "dev"
Requires-Dist: redis<7.0.0,>=6.2.0; extra == "dev"
Requires-Dist: neo4j<6.0.0,>=5.25.0; extra == "dev"
Requires-Dist: pandas<3.0.0,>=2.2.0; extra == "dev"
Requires-Dist: openpyxl<4.0.0,>=3.1.0; extra == "dev"
Requires-Dist: pyreadstat<2.0.0,>=1.2.0; extra == "dev"
Requires-Dist: psutil<8.0.0,>=6.0.0; extra == "dev"
Provides-Extra: all
Requires-Dist: asyncpg<1.0.0,>=0.30.0; extra == "all"
Requires-Dist: aiosqlite<1.0.0,>=0.20.0; extra == "all"
Requires-Dist: neo4j<6.0.0,>=5.25.0; extra == "all"
Requires-Dist: lark-parser<0.13.0,>=0.12.0; extra == "all"
Requires-Dist: colorama<1.0.0,>=0.4.6; extra == "all"
Requires-Dist: python-Levenshtein<1.0.0,>=0.25.0; extra == "all"
Requires-Dist: pandas<3.0.0,>=2.2.0; extra == "all"
Requires-Dist: openpyxl<4.0.0,>=3.1.0; extra == "all"
Requires-Dist: pyreadstat<2.0.0,>=1.2.0; extra == "all"
Requires-Dist: psutil<8.0.0,>=6.0.0; extra == "all"
Requires-Dist: redis<7.0.0,>=6.2.0; extra == "all"
Requires-Dist: urllib3<3.0.0,>=2.0.0; extra == "all"
Requires-Dist: six>=1.16.0; extra == "all"
Requires-Dist: python-dateutil>=2.8.0; extra == "all"
Requires-Dist: certifi>=2024.0.0; extra == "all"
Provides-Extra: release
Requires-Dist: build<2.0.0,>=1.2.0; extra == "release"
Requires-Dist: twine<7.0.0,>=5.1.0; extra == "release"
Requires-Dist: packaging<26.0.0,>=24.0; extra == "release"
Dynamic: license-file

# aiecs-kg

Enterprise knowledge graph (L2) for [AIECS](https://github.com/Howmany-Zeta/AI-Execute-Services), split from the monorepo as an optional PyPI package.

## Status

**0.9.0 (Beta)** — first non-prerelease PyPI cut (`Development Status :: 4 - Beta`; tag `v0.9.0`). Includes SPG OpenAPI/write-token work, live gates/F1a, and packaging integrity fixes. Core graph store, reasoning (heuristic + Logic DSL), builder paths, and OpenSPG (`[spg]`) integration are usable; PostgreSQL / Neo4j dual-store and LLM features require optional extras and caller configuration.

Not GA: treat as Beta until maintainers attest PostgreSQL, Neo4j/`pg_neo4j`, and SPG live paths outside default CI. Security reporting: [SECURITY.md](SECURITY.md).

See [docs/development_plan/archive/KNOWLEDGE_GRAPH_OPTIONAL_PACKAGING.md](docs/development_plan/archive/KNOWLEDGE_GRAPH_OPTIONAL_PACKAGING.md) for the full split checklist.

### CI verification scope

GitHub Actions (`pip install -e ".[dev]"`, no external services) validates:

| Area | CI | Requires local / maintainer setup |
|------|-----|-----------------------------------|
| In-memory graph store | Yes | — |
| SQLite backend | Yes | — |
| Reasoning (Logic DSL, orchestrator) | Yes | — |
| Structured builder import | Yes | — |
| LLM injection (mock clients) | Yes | Real LLM keys: manual / nightly |
| PostgreSQL (`[postgres]`) | No (skip) | `KG_POSTGRES_URL` + `.env.test` |
| Neo4j / `pg_neo4j` / GDS (`[graph]`) | No (skip) | `KG_NEO4J_URI` + system Neo4j 5.26+ |
| AIECS integrations | No (skip) | `pip install -r requirements/optional-aiecs.txt` (or `pip install aiecs`) |
| SPG / OpenSPG (`[spg]`) | Unit + mock only | `pip install aiecs-kg[spg]` + compose; see [docs/spg/README.md](docs/spg/README.md) |

Release gate (tag `v*`): unit tests + `deptry` + `build` + `twine check` + artifact `smoke` (LICENSE + package data) + `verify-install` (Logic DSL from wheel). Does **not** run Postgres/Neo4j/SPG live integration (see [scripts/README.md](scripts/README.md)).

## Install

```bash
# Core (in-memory graph store)
pip install -e .

# With backends
pip install -e ".[postgres,sqlite,reasoning]"

# Neo4j graph compute + PostgreSQL dual-store (Phase NG)
pip install -e ".[graph]"          # neo4j + postgres extras
# or: pip install -e ".[neo4j,postgres]"

# Development
pip install -e ".[dev,sqlite]"

# OpenSPG / aiecs-spg HTTP client + Profile B bridge
pip install -e ".[dev,spg]"
```

### Optional extras (`pyproject.toml`)

| Extra | Installs | LLM / AIECS |
|-------|----------|-------------|
| *(core)* | Graph store, reasoning heuristics | No LLM — pass `llm_client=` / `embedding_client=` yourself |
| `postgres` / `sqlite` / `neo4j` / `graph` | Storage backends (`graph` = neo4j + postgres) | No LLM |
| `reasoning` | Lark Logic DSL parser | No LLM |
| `builder` | Structured data import (pandas, etc.) | No LLM; `GraphBuilder` accepts injected `embedding_client=` |
| `fusion` | Redis-backed fusion helpers | No LLM |
| `spg` | urllib3/six/dateutil for OpenSPG HTTP SDK | `client/spg/*`, `KG_STORAGE_MODE=spg`; see [docs/spg/README.md](docs/spg/README.md) |
| `all` | Union of runtime extras above (not `dev` / `release`) | No LLM |
| `dev` / `release` | Test/lint tools; build/twine | Maintainers |

Heavy optional stacks stay out of PyPI extras (keeps lock/resolve light). Install from the repo:

```bash
pip install -r requirements/optional-aiecs.txt   # aiecs integrations helpers
pip install -r requirements/optional-nlp.txt     # spaCy NER
pip install -r requirements/optional-rerank.txt  # CrossEncoder rerank
```

For LLM usage patterns see [LLM integration](#llm-integration) and [LLM_CLIENT_INJECTION_PLAN.md §7](docs/development_plan/archive/LLM_CLIENT_INJECTION_PLAN.md).

Deprecated factory methods (`GraphBuilder.from_config`, `LLMEntityExtractor.from_config`) remain for compatibility but do not resolve AIECS clients in core — use explicit injection or `aiecs_kg.integrations.aiecs`.

### Storage modes (`KG_STORAGE_MODE`)

| Mode | PostgreSQL | Neo4j | Use case |
|------|------------|-------|----------|
| `pg_only` (default) | authority + vector | — | Zero Neo4j regression; Python graph fallback |
| `pg_neo4j` | authority + pgvector RAG | traverse + GDS projection | **Recommended production** embed path |
| `neo4j_only` | — | single store | POC / graph-only dev |

Design: [AIECS_KG_NEO4J_PG_DUAL_STORE_DESIGN.md](docs/development_plan/archive/AIECS_KG_NEO4J_PG_DUAL_STORE_DESIGN.md) · ADR: [ADR-004](docs/development_plan/adr/ADR-004-neo4j-pg-dual-store.md)

### pg_neo4j quick example

```bash
export KG_STORAGE_MODE=pg_neo4j
export KG_STORAGE_BACKEND=postgresql
export KG_POSTGRES_URL=postgresql://user:pass@localhost:5432/aiecs_knowledge_graph
export KG_NEO4J_URI=bolt://localhost:7687
export KG_NEO4J_USER=neo4j
export KG_NEO4J_PASSWORD=your-password
export KG_NEO4J_DATABASE=aiecs_graph
```

```python
from aiecs_kg import create_graph_store, create_graph_algorithm_service

store = create_graph_store()          # CompositeGraphStore when pg_neo4j
await store.initialize()
algo = create_graph_algorithm_service(graph_store=store)
scores = await algo.pagerank(seed_entity_ids=["entity-a"], top_k=10)
```

See [.env.example](.env.example) for all `KG_*` variables.

## Quick start

```python
from aiecs_kg import create_graph_store, Entity

store = create_graph_store()  # KG_STORAGE_BACKEND=inmemory (default)
await store.initialize()

entity = Entity(id="e1", entity_type="Person", properties={"name": "Alice"})
await store.add_entity(entity)
```

### Reasoning (Phase R0–R2)

Prefer `ReasoningOrchestrator` over `ReasoningEngine` for NL, Logic DSL, and hybrid pipelines:

```python
import asyncio
from aiecs_kg import create_reasoning_orchestrator, ReasoningOrchestrator
from aiecs_kg.application.reasoning import ReasoningPipelineConfig

async def main():
    orchestrator = create_reasoning_orchestrator()  # or ReasoningOrchestrator(store, ...)
    result = await orchestrator.query(
        "Find all people older than 30",
        mode="hybrid",  # nl | logic_dsl | hybrid
        context={"start_entity_id": "alice"},
    )
    print(result.answer, result.evidence_count)

asyncio.run(main())
```

Install Logic DSL support: `pip install -e ".[reasoning]"`. Optional rerank: `pip install -r requirements/optional-rerank.txt`.

## LLM integration

`pip install aiecs-kg` does **not** install or import AIECS. LLM-powered features (entity/relation extraction, NL→DSL, QueryPlan, embeddings) require a caller-provided client via constructor or factory parameters (`llm_client=`, `embedding_client=`).

```python
from aiecs_kg import create_reasoning_orchestrator
from aiecs_kg.ports.llm_client import LLMMessage  # use this, not aiecs.llm.LLMMessage

# Heuristic / retrieval-only — no LLM required
orchestrator = create_reasoning_orchestrator()

# With an injected client (AIECS resolve_llm_client, OpenAI SDK wrapper, etc.)
orchestrator = create_reasoning_orchestrator(llm_client=my_client)
```

All `generate_text` messages in core code use `aiecs_kg.ports.llm_client.LLMMessage`. Clients must implement at least `generate_text` and/or `get_embeddings` (see `LLMClientProtocol`). For a minimal OpenAI SDK example without AIECS, see [LLM_CLIENT_INJECTION_PLAN.md §7.4](docs/development_plan/archive/LLM_CLIENT_INJECTION_PLAN.md#74-自定义-client任意-sdk--无需-aiecs).

Optional AIECS convenience helpers (when both packages are installed) live under `aiecs_kg.integrations.aiecs` — not exported from core `__init__.py`.

## Configuration

All settings use `KG_*` environment variables. See [.env.example](.env.example).

```bash
export KG_STORAGE_BACKEND=inmemory   # inmemory | sqlite | postgresql
export KG_ENABLED=true               # consumed by AIECS core (not this package)
```

### OpenSPG / SPG mode (`KG_STORAGE_MODE=spg`)

Install: `pip install aiecs-kg[spg]`. Set `KG_STORAGE_MODE=spg` plus:

| Variable | Required | Description |
|----------|----------|-------------|
| `KG_SPG_HOST` | Yes | Server URL (e.g. `http://127.0.0.1:8887`) |
| `KG_SPG_PROJECT_ID` | Yes | OpenSPG project id |
| `KG_SPG_WRITE_TOKEN` | Yes | Write-graph token (request body only — never log) |
| `KG_SPG_NAMESPACE` | Recommended | Schema/type namespace |
| `KG_SPG_WRITE_TOKEN_NEXT` | Optional | Dual-token rotation |
| `KG_REASONING_MODE` | Optional | Default orchestrator mode |
| `KG_SPG_WRITE_GRAPH_THRESHOLD` | Optional | Bulk vs `write_graph` threshold (default 500) |
| `KG_SPG_BRIDGE_ENABLED` | Optional | Profile B deployment flag |

**Profile A** — `GraphBuilder` / `ReasoningOrchestrator` → `client/spg` HTTP (no `kag` wheel).

**Profile B** — Pemja → `integrations/spg_bridge.SpgServerBridge` → same L3 paths. F1a (UI DAG → Neo4jSinkWriter) is documented only; F1b (bridge → HTTP) is the Repo B contract. See [docs/spg/README.md](docs/spg/README.md).

## Project layout

```
src/aiecs_kg/
├── domain/          # Entity, Relation, schema models
├── application/     # search, reasoning, builder, fusion, …
├── client/spg/      # OpenSPG HTTP SDK (L2, optional [spg])
├── integrations/    # spg_bridge (Profile B), aiecs helpers
├── storage/         # GraphStore backends (in-memory, SQLite, Postgres)
├── config.py        # KGSettings / get_kg_settings()
└── factory.py       # create_graph_store()
```

## Tests

```bash
# 1) 依赖（见 .env.test 注释）
pip install -e ".[dev]"
pip install -r requirements/optional-rerank.txt
pip install -r requirements/optional-nlp.txt
python -m spacy download en_core_web_sm
# aiecs：prefer requirements/optional-aiecs.txt; if resolve conflicts, editable install
pip install -r requirements/optional-aiecs.txt
# or: pip install -e /path/to/python-middleware-dev

# 2) 环境
set -a && source .env.test && set +a   # KG_USE_AIECS_STUB=false + XAI_API_KEY 等

pytest tests/unit -q
pytest tests/integration/spg/ -q          # SPG mock + skipped live without KG_SPG_HOST
pytest tests/integration/neo4j_graph/ -q   # 需系统 Neo4j 5.26.x + GDS（ADR-004）
```

## Pre-commit

Same hook set as [AI-Execute-Services](https://github.com/Howmany-Zeta/AI-Execute-Services): license header, black, flake8, mypy, and **deptry** (no AIECS-specific schema hooks).

Runtime extras are declared in `pyproject.toml`; heavy optional stacks use `requirements/optional-*.txt`. CI installs `pip install -e ".[dev]"` (+ optional-dev-heavy as needed). See `.cursor/rules/dependency-maintenance.mdc`.

```bash
pip install -e ".[dev]"
pre-commit install
pre-commit run --all-files
```

## License

Apache-2.0 — see [LICENSE](LICENSE).
