PHPackages                             condoedge/ai - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. condoedge/ai

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

condoedge/ai
============

AI-powered text-to-query system with RAG, Neo4j, and Qdrant

v0.0.4(3mo ago)09[2 issues](https://github.com/condoedge/AI/issues)MITPHPPHP ^8.1

Since Nov 21Pushed 2mo agoCompare

[ Source](https://github.com/condoedge/AI)[ Packagist](https://packagist.org/packages/condoedge/ai)[ RSS](/packages/condoedge-ai/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (9)Versions (9)Used By (0)

AI Package - Text-to-Cypher with RAG
====================================

[](#ai-package---text-to-cypher-with-rag)

> A Laravel package providing intelligent text-to-Cypher query generation with RAG (Retrieval-Augmented Generation), dual-storage coordination (Neo4j + Qdrant), and auto-discovery from Eloquent models.

[![PHP Version](https://camo.githubusercontent.com/cc9cdea9aa96b40a822425e981b0a030e3371202973c7d57b74e8e99834f81dc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e312d626c7565)](https://php.net)[![Laravel](https://camo.githubusercontent.com/f2b9fa6d4f7cf0147089fb2f8ee7f4963039f2cf411330a0dd34ea6f4f4c12df/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d253545392e302d726564)](https://laravel.com)[![License: MIT](https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667)](LICENSE)

Table of Contents
-----------------

[](#table-of-contents)

- [Overview](#overview)
- [Architecture](#architecture)
- [Key Features](#key-features)
- [Security Architecture](#security-architecture)
- [Quick Start](#quick-start)
- [Artisan Commands](#artisan-commands)
- [Project Structure](#project-structure)
- [Testing](#testing)
- [Documentation](#documentation)
- [Development](#development)
- [Technical Decisions](#technical-decisions)

Overview
--------

[](#overview)

### What This Package Does

[](#what-this-package-does)

The AI package transforms natural language questions into executable Neo4j Cypher queries using RAG-powered LLMs. It automatically discovers entity configurations from your existing Eloquent models, eliminating manual setup while maintaining dual-storage synchronization between Neo4j (graph relationships) and Qdrant (vector embeddings).

**Core Value Proposition:**

- Simple setup: Run `ai:discover` once to generate configuration
- Automatic discovery from Eloquent models - no duplication
- Dual-storage coordination with consistency guarantees
- Production-ready security (injection protection, retry logic, circuit breakers)
- RAG-powered intelligent query generation

**Key Technologies:**

- **Neo4j**: Graph database for relationship storage and pattern matching
- **Qdrant**: Vector database for semantic similarity search
- **Laravel**: PHP framework integration with Eloquent ORM
- **OpenAI/Anthropic**: LLM providers for query generation and embeddings

### Example

[](#example)

```
// 1. Make your model Nodeable (zero config needed)
class Customer extends Model implements Nodeable
{
    use HasNodeableConfig;

    protected $fillable = ['name', 'email', 'status'];

    public function scopeActive($query) {
        return $query->where('status', 'active');
    }
}

// 2. Data auto-syncs on create/update/delete
$customer = Customer::create(['name' => 'John Doe', 'email' => 'john@example.com']);
// Automatically stored in Neo4j + Qdrant

// 3. Ask questions in natural language
$response = AI::chat("How many active customers do we have?");
// Generated Cypher: MATCH (n:Customer) WHERE n.status = 'active' RETURN count(n)
// Response: "You have 1,250 active customers in the system."
```

Architecture
------------

[](#architecture)

### High-Level Overview

[](#high-level-overview)

```
┌─────────────────────────────────────────────────────────────────────┐
│                         User Question                                │
│                "Show active customers in USA"                        │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                     ChatOrchestrator                                 │
│  ┌─────────────────────────────────────────────────────────┐        │
│  │ 1. Context Retrieval (RAG)                              │        │
│  │    - Vector search for similar past queries             │        │
│  │    - Fetch graph schema from Neo4j                      │        │
│  │    - Retrieve example entities                          │        │
│  └─────────────────────────────────────────────────────────┘        │
│  ┌─────────────────────────────────────────────────────────┐        │
│  │ 2. Query Generation                                     │        │
│  │    - Build LLM prompt with context                      │        │
│  │    - Generate Cypher query                              │        │
│  │    - Validate (injection check, complexity, safety)     │        │
│  └─────────────────────────────────────────────────────────┘        │
│  ┌─────────────────────────────────────────────────────────┐        │
│  │ 3. Query Execution                                      │        │
│  │    - Execute against Neo4j with timeout                 │        │
│  │    - Format results                                     │        │
│  └─────────────────────────────────────────────────────────┘        │
│  ┌─────────────────────────────────────────────────────────┐        │
│  │ 4. Response Generation                                  │        │
│  │    - Transform to natural language                      │        │
│  │    - Extract insights (trends, outliers, patterns)      │        │
│  │    - Suggest visualizations                             │        │
│  └─────────────────────────────────────────────────────────┘        │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│        Natural Language Answer + Insights + Suggestions             │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│                      Data Ingestion Flow                             │
└─────────────────────────────────────────────────────────────────────┘

Eloquent Model Event (create/update/delete)
           │
           ▼
   HasNodeableConfig Trait
   (Auto-sync listener)
           │
           ▼
   EntityAutoDiscovery
   - Reflect on model
   - Extract properties from $fillable, $casts
   - Discover relationships (belongsTo)
   - Detect text fields for embedding
   - Convert scopes to Cypher patterns
           │
           ▼
   DataIngestionService
   ┌──────────────────────────────────┐
   │ Compensating Transaction Pattern │
   └──────────────────────────────────┘
           │
           ├─────────────────────┬──────────────────────┐
           ▼                     ▼                      ▼
    Generate Embedding    Neo4j Store           Qdrant Store
    (OpenAI/Anthropic)   (Graph + Relations)   (Vector + Metadata)
           │                     │                      │
           └─────────────────────┴──────────────────────┘
                                 │
                     ┌───────────┴──────────┐
                     │  Success?            │
                     │  - Both stores OK    │
                     │  - Rollback on fail  │
                     └──────────────────────┘

```

### Core Components

[](#core-components)

#### 1. Auto-Discovery System

[](#1-auto-discovery-system)

- **EntityAutoDiscovery**: Introspects Eloquent models using PHP Reflection
- **CypherScopeAdapter**: Converts Eloquent scopes to Cypher patterns
- **SchemaInspector**: Extracts database schema hints
- **ConfigCache**: Caches expensive discovery operations

#### 2. Dual-Storage Coordination

[](#2-dual-storage-coordination)

- **DataIngestionService**: Orchestrates writes to both stores with compensating transactions
- **Neo4j (GraphStore)**: Node storage, relationships, pattern matching
- **Qdrant (VectorStore)**: Vector embeddings, semantic search, metadata filtering
- **Auto-Sync**: Automatic synchronization via Laravel model events

#### 3. RAG System

[](#3-rag-system)

- **ContextRetriever**: Fetches similar queries + schema + examples
- **PatternLibrary**: Pre-defined query patterns for common questions
- **QueryGenerator**: LLM-powered Cypher generation with validation
- **QueryExecutor**: Safe query execution with timeouts and limits
- **ResponseGenerator**: Natural language explanations with insights

#### 4. Security Layer

[](#4-security-layer)

- **CypherSanitizer**: Injection prevention for labels, types, property keys
- **RetryPolicy**: Exponential backoff with jitter
- **CircuitBreaker**: Fail-fast pattern for cascading failure prevention
- **SensitiveDataSanitizer**: API key and credential redaction in logs

Key Features
------------

[](#key-features)

### Auto-Discovery from Eloquent Models

[](#auto-discovery-from-eloquent-models)

Eliminates duplication by extracting entity configuration directly from your models:

- **Properties**: Auto-detected from `$fillable`, `$casts`, `$dates`
- **Relationships**: Auto-discovered from `belongsTo()` methods
- **Scopes**: Auto-converted from `scopeX()` methods to Cypher patterns
- **Embed Fields**: Text fields automatically identified for vector embeddings
- **Aliases**: Generated from table names for semantic matching

**Configuration priority**: `nodeableConfig()` method &gt; `config/entities.php`

**Note:** You must run `php artisan ai:discover` to generate configuration. There is no runtime auto-discovery.

### Dual-Storage Coordination

[](#dual-storage-coordination)

Synchronized writes to Neo4j (graph) and Qdrant (vector) with consistency guarantees:

- **Compensating Transactions**: Automatic rollback on partial failure
- **No Orphaned Data**: Either both stores succeed or both roll back
- **Independent Resilience**: One store failing doesn't break the other
- **Batch Operations**: Efficient bulk ingestion

### RAG-Powered Query Generation

[](#rag-powered-query-generation)

Intelligent Cypher generation using retrieval-augmented generation:

- **Context-Aware**: Similar past queries inform new query generation
- **Schema-Aware**: Graph structure guides query construction
- **Example-Based**: Sample data provides reference patterns
- **Pattern Matching**: Pre-defined templates for common queries
- **Validation**: Syntax, safety, and complexity checks

### Auto-Sync Capabilities

[](#auto-sync-capabilities)

Zero-boilerplate synchronization via Laravel events:

- **Event-Driven**: Automatic sync on create, update, delete
- **Async Support**: Optional queue processing
- **Configurable**: Per-model, per-operation granularity
- **Error Handling**: Silent failure with logging or exception throwing

### Extensible Prompt Builders

[](#extensible-prompt-builders)

Both the Query Generator and Response Generator use extensible section-based architectures that allow you to customize how prompts are built.

#### SemanticPromptBuilder (Query Generation)

[](#semanticpromptbuilder-query-generation)

The `SemanticPromptBuilder` constructs prompts for Cypher query generation using a pipeline of sections:

SectionPriorityPurpose`project_context`10Project name, description, domain, business rules`generic_context`15Current date/time`schema`20Graph schema (labels, relationships, properties)`relationships`30Entity relationships with exact directions`example_entities`40Sample data showing actual types/formats`similar_queries`50RAG: similar past queries for few-shot learning`detected_entities`60Entities detected in user's question`detected_scopes`65Business concepts detected in question`pattern_library`70Available query patterns`query_rules`75Query generation rules`question`80User's question`task_instructions`90Final task instructions**Extension Methods:**

```
use Condoedge\Ai\Services\SemanticPromptBuilder;

// Global extension (applies to all new instances)
SemanticPromptBuilder::extendBuild(function($builder) {
    $builder->setProjectContext([
        'name' => 'My CRM',
        'description' => 'Customer relationship management system',
        'domain' => 'Sales',
        'business_rules' => [
            'All dates are stored as ISO strings',
            'Active customers have status = "active"',
        ],
    ]);
});

// Instance-level extensions
$builder = app(SemanticPromptBuilder::class);

// Add custom section
$builder->addSection(new CustomContextSection());

// Remove a section
$builder->removeSection('similar_queries');

// Replace a section
$builder->replaceSection('project_context', new MyProjectContextSection());

// Extend with callbacks (before/after sections)
$builder->extendAfter('schema', function($question, $context, $options) {
    return "\n=== CUSTOM INFO ===\n\nAdditional context here\n\n";
});

// Convenience methods
$builder->addBusinessRule('Orders cannot be deleted once shipped');
$builder->addQueryRule('PERFORMANCE', 'Always use indexed properties');
$builder->setMaxSimilarQueries(5);
```

**Creating Custom Sections:**

```
use Condoedge\Ai\Contracts\PromptSectionInterface;
use Condoedge\Ai\Services\PromptSections\BasePromptSection;

class DomainTermsSection extends BasePromptSection
{
    protected string $name = 'domain_terms';
    protected int $priority = 25; // After schema, before relationships

    public function format(string $question, array $context, array $options = []): string
    {
        return $this->header('DOMAIN TERMINOLOGY') .
               "- 'Client' and 'Customer' are synonyms\n" .
               "- 'Active' means status = 'active' or 'enabled'\n\n";
    }

    public function shouldInclude(string $question, array $context, array $options = []): bool
    {
        // Only include if question mentions domain terms
        return str_contains(strtolower($question), 'client') ||
               str_contains(strtolower($question), 'active');
    }
}
```

#### ResponseGenerator (Response Generation)

[](#responsegenerator-response-generation)

The `ResponseGenerator` uses the same extensible pattern for building prompts that explain query results:

SectionPriorityPurpose`system`10System prompt (LLM role)`project_context`20Project context for explanations`question`30Original user question`query`40Executed Cypher query`data`50Query results`statistics`60Execution statistics`guidelines`70Response guidelines (style, format)`task`80Final task instruction**Extension Methods:**

```
use Condoedge\Ai\Services\ResponseGenerator;

// Global extension
ResponseGenerator::extendBuild(function($generator) {
    $generator->setSystemPrompt(
        "You are a friendly data analyst who explains results clearly.\n\n"
    );
    $generator->addGuideline('Always mention the total count first');
});

// Instance-level extensions
$generator = app(ResponseGenerator::class);

// Add/remove/replace sections
$generator->addSection(new CustomAnalysisSection());
$generator->removeSection('statistics');

// Convenience methods
$generator->setProjectContext(['name' => 'My App', 'domain' => 'E-commerce']);
$generator->setMaxDataItems(20);

// Extend with callbacks
$generator->extendAfter('data', function($context, $options) {
    $count = count($context['data']);
    return "\nNote: Showing {$count} results.\n\n";
});
```

Security Architecture
---------------------

[](#security-architecture)

The package implements **defense-in-depth security** with multiple layers of protection. All security features are enabled by default with no configuration required.

### 1. Injection Protection

[](#1-injection-protection)

**Cypher Injection Prevention** (`CypherSanitizer`):

- Validates all labels, relationship types, and property keys against strict patterns
- Regex: `[a-zA-Z_][a-zA-Z0-9_]*` (alphanumeric + underscore, must start with letter)
- Blocks reserved Cypher keywords (MATCH, DELETE, DROP, CREATE, etc.)
- Maximum length validation (255 characters)
- Backtick escaping as additional defense layer

**SQL Injection Prevention** (`SchemaInspector`):

- Table/index name validation in SQLite PRAGMA queries
- Prevents malicious identifiers in auto-discovery schema introspection
- Parameter binding for MySQL/PostgreSQL

**Example Protection:**

```
// Automatic injection protection
CypherSanitizer::validateLabel("User}); DELETE (n) //");
// Throws: CypherInjectionException

CypherSanitizer::validateLabel("User_Profile");
// Returns: "User_Profile" ✓
```

### 2. Data Consistency Guarantees

[](#2-data-consistency-guarantees)

**Compensating Transactions** (`DataIngestionService`):

- Two-phase commit pattern for dual-store operations
- Automatic rollback on vector store failure
- Automatic restoration on deletion failure
- Critical error logging when compensation fails

**Transaction Flow:**

```
1. Write to Neo4j → Success
2. Write to Qdrant → Failure
3. Rollback Neo4j → Success
4. Throw DataConsistencyException

```

### 3. Resilience &amp; Fault Tolerance

[](#3-resilience--fault-tolerance)

**Circuit Breaker Pattern** (`CircuitBreaker`):

- States: CLOSED → OPEN → HALF\_OPEN → CLOSED
- Prevents cascading failures
- Configurable failure threshold (default: 5 failures)
- Configurable recovery timeout (default: 30 seconds)
- Fail-fast when circuit open

**Retry Policy** (`RetryPolicy`):

- Exponential backoff with jitter
- Prevents thundering herd problem
- Configurable max attempts (default: 3-5 depending on operation)
- Separate policies for API calls, database operations, network requests

**Example:**

```
// Automatic retry and circuit breaking
$neo4j = new Neo4jStore(); // Includes retry + circuit breaker
$result = $neo4j->createNode('User', $properties);
// Retries on transient failures, fails fast if circuit open
```

### 4. Sensitive Data Protection

[](#4-sensitive-data-protection)

**Log Sanitization** (`SensitiveDataSanitizer`):

- Automatic redaction of API keys, passwords, tokens, secrets
- Pattern detection for multiple formats:
    - OpenAI keys: `sk-...`
    - Anthropic keys: `sk-ant-...`
    - AWS credentials
    - Bearer tokens
    - Database passwords
- Stack trace sanitization
- Absolute path removal

**Protected Patterns:**

```
// Automatic sanitization
Log::error('API failed', SensitiveDataSanitizer::forLogging([
    'api_key' => 'sk-abc123...', // Logged as: ***REDACTED***
    'error' => $exception->getMessage(),
]));
```

### 5. Recursion &amp; Resource Protection

[](#5-recursion--resource-protection)

**Auto-Discovery Guards**:

- Maximum stack depth: 5 levels
- Circular reference detection
- Automatic cycle breaking
- Deep merge protection: 10 level limit

**Resource Limits**:

- Query timeout: 30 seconds (configurable)
- Result limit: 100 rows (configurable)
- Max query complexity scoring
- Identifier length limits

### Security Testing

[](#security-testing)

The package includes comprehensive security test coverage:

- **Injection Testing**: Adversarial inputs, malicious patterns, edge cases
- **Data Consistency Testing**: Partial failure scenarios, rollback verification
- **Resilience Testing**: Retry logic, circuit breaker state transitions, timeout handling
- **Sanitization Testing**: API key patterns, stack traces, nested objects

All security tests are passing. See `tests/Unit/StressTests/` for details.

Quick Start
-----------

[](#quick-start)

### Prerequisites

[](#prerequisites)

- PHP 8.1+
- Laravel 9.x+
- Neo4j 4.4+
- Qdrant 1.0+
- OpenAI or Anthropic API key

### Installation

[](#installation)

```
# Install package
composer require condoedge/ai

# Publish config (optional)
php artisan vendor:publish --tag=ai-config
```

### Configuration

[](#configuration)

Add to `.env`:

```
# Neo4j
NEO4J_HOST=http://localhost:7474
NEO4J_USER=neo4j
NEO4J_PASSWORD=your-password

# Qdrant
QDRANT_HOST=http://localhost:6333

# LLM Provider (OpenAI or Anthropic)
OPENAI_API_KEY=sk-your-key
AI_LLM_PROVIDER=openai
AI_EMBEDDING_PROVIDER=openai
```

### Basic Usage

[](#basic-usage)

```
// 1. Make models Nodeable
use Condoedge\Ai\Domain\Contracts\Nodeable;
use Condoedge\Ai\Domain\Traits\HasNodeableConfig;

class Customer extends Model implements Nodeable
{
    use HasNodeableConfig;

    protected $fillable = ['name', 'email', 'status'];
}

// 2. Discover and generate config
php artisan ai:discover

// This generates config/entities.php with discovered configuration:
// - Neo4j label, properties, relationships
// - Qdrant collection, embed fields
// - Aliases for natural language queries
// Review and customize config/entities.php as needed

// 3. Bulk ingest existing data (one-time setup)
php artisan ai:ingest

// This ingests all existing entities into Neo4j + Qdrant
// - Processes in batches for efficiency
// - Shows progress bar
// - Reports success/failure counts

// 4. New data auto-syncs (after initial ingest)

    public function orders() {
        return $this->hasMany(Order::class);
    }

    public function scopeActive($query) {
        return $query->where('status', 'active');
    }
}

// 2. Data auto-syncs
$customer = Customer::create([
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'status' => 'active'
]);
// Automatically stored in Neo4j + Qdrant

// 3. Ask questions
use Condoedge\Ai\Facades\AI;

$response = AI::chat("How many active customers do we have?");
// Generates Cypher, executes, returns natural language answer
```

### Manual Configuration Override

[](#manual-configuration-override)

```
use Condoedge\Ai\Domain\ValueObjects\NodeableConfig;

class Customer extends Model implements Nodeable
{
    use HasNodeableConfig;

    public function nodeableConfig(): NodeableConfig
    {
        return NodeableConfig::discover($this)
            ->embedFields(['name', 'bio'])        // Override embed fields
            ->addAlias('client')                  // Add custom alias
            ->addRelationship('HAS_ORDER', 'Order', 'customer_id')
            ->disableVectorStore();               // Graph-only entity
    }
}
```

Project Structure
-----------------

[](#project-structure)

```
ai/
├── config/
│   ├── ai.php              # Main package configuration
│   └── ai-patterns.php     # Query pattern definitions
├── docs/
│   ├── ARCHITECTURE.md     # Detailed technical architecture
│   └── GETTING-STARTED.md  # User guide and tutorials
├── examples/
│   └── *.php               # Working examples and demos
├── src/
│   ├── Contracts/          # Service interfaces
│   │   ├── DataIngestionServiceInterface.php
│   │   ├── GraphStoreInterface.php
│   │   ├── VectorStoreInterface.php
│   │   ├── LlmProviderInterface.php
│   │   └── ...
│   ├── Domain/             # Domain models and value objects
│   │   ├── Contracts/
│   │   │   └── Nodeable.php           # Entity interface
│   │   ├── Traits/
│   │   │   └── HasNodeableConfig.php  # Auto-sync + discovery
│   │   └── ValueObjects/
│   │       ├── GraphConfig.php
│   │       ├── VectorConfig.php
│   │       └── NodeableConfig.php
│   ├── Services/           # Core services
│   │   ├── Discovery/
│   │   │   ├── EntityAutoDiscovery.php
│   │   │   ├── CypherScopeAdapter.php
│   │   │   ├── SchemaInspector.php
│   │   │   └── ...
│   │   ├── PromptSections/  # Extensible prompt sections
│   │   │   ├── BasePromptSection.php
│   │   │   ├── ProjectContextSection.php
│   │   │   ├── SchemaSection.php
│   │   │   ├── RelationshipsSection.php
│   │   │   ├── ExampleEntitiesSection.php
│   │   │   ├── SimilarQueriesSection.php
│   │   │   ├── QueryRulesSection.php
│   │   │   └── ...
│   │   ├── ResponseSections/ # Extensible response sections
│   │   │   ├── BaseResponseSection.php
│   │   │   ├── SystemPromptSection.php
│   │   │   ├── GuidelinesSection.php
│   │   │   └── ...
│   │   ├── Resilience/
│   │   │   ├── RetryPolicy.php
│   │   │   └── CircuitBreaker.php
│   │   ├── Security/
│   │   │   └── SensitiveDataSanitizer.php
│   │   ├── DataIngestionService.php
│   │   ├── ContextRetriever.php
│   │   ├── SemanticPromptBuilder.php
│   │   ├── QueryGenerator.php
│   │   ├── QueryExecutor.php
│   │   └── ResponseGenerator.php
│   ├── GraphStore/         # Neo4j implementation
│   │   ├── Neo4jStore.php
│   │   └── CypherSanitizer.php
│   ├── VectorStore/        # Qdrant implementation
│   │   └── QdrantStore.php
│   ├── LlmProviders/       # LLM integrations
│   │   ├── OpenAiLlmProvider.php
│   │   └── AnthropicLlmProvider.php
│   ├── EmbeddingProviders/
│   │   ├── OpenAiEmbeddingProvider.php
│   │   └── AnthropicEmbeddingProvider.php
│   ├── Jobs/               # Queue jobs
│   │   ├── IngestEntityJob.php
│   │   ├── SyncEntityJob.php
│   │   └── RemoveEntityJob.php
│   ├── Exceptions/         # Custom exceptions
│   │   ├── CypherInjectionException.php
│   │   ├── DataConsistencyException.php
│   │   ├── CircuitBreakerOpenException.php
│   │   └── ...
│   └── Facades/
│       └── AI.php          # Main facade
├── tests/
│   ├── Unit/               # Unit tests
│   │   ├── Domain/
│   │   ├── Services/
│   │   └── StressTests/    # Security & resilience tests
│   ├── Integration/        # Integration tests
│   │   ├── EntityAutoDiscoveryTest.php
│   │   ├── DualStorageCoordinationTest.php
│   │   └── ...
│   └── Fixtures/           # Test models
└── composer.json

```

### Key Files &amp; Purposes

[](#key-files--purposes)

**Core Services:**

- `DataIngestionService.php`: Dual-store coordination with compensating transactions
- `EntityAutoDiscovery.php`: Model introspection and config extraction
- `CypherScopeAdapter.php`: Eloquent scope to Cypher conversion
- `ContextRetriever.php`: RAG context fetching (similar queries + schema)
- `SemanticPromptBuilder.php`: Extensible prompt builder with section pipeline
- `QueryGenerator.php`: LLM-powered Cypher generation with validation
- `QueryExecutor.php`: Safe query execution with timeouts
- `ResponseGenerator.php`: Natural language response generation with extensible sections

**Extensible Sections:**

- `PromptSectionInterface.php`: Contract for query prompt sections
- `ResponseSectionInterface.php`: Contract for response prompt sections
- `BasePromptSection.php`: Base class for query prompt sections
- `BaseResponseSection.php`: Base class for response prompt sections

**Security:**

- `CypherSanitizer.php`: Injection prevention for Cypher identifiers
- `SensitiveDataSanitizer.php`: API key/credential redaction in logs
- `RetryPolicy.php`: Exponential backoff retry logic
- `CircuitBreaker.php`: Circuit breaker pattern for resilience

**Configuration:**

- `HasNodeableConfig.php`: Trait providing auto-sync and discovery
- `NodeableConfig.php`: Fluent builder for entity configuration
- `GraphConfig.php`, `VectorConfig.php`: Store-specific configurations

Testing
-------

[](#testing)

### Running Tests

[](#running-tests)

```
# All tests
composer test

# Unit tests only
composer test-unit

# Integration tests only
composer test-integration

# With coverage report
composer test-coverage
```

### Test Organization

[](#test-organization)

```
tests/
├── Unit/
│   ├── Domain/              # Domain model tests
│   ├── Services/
│   │   ├── Discovery/       # Auto-discovery tests
│   │   ├── Resilience/      # Retry + circuit breaker tests
│   │   └── Security/        # Sanitization tests
│   └── StressTests/
│       ├── AdversarialSecurityTest.php      # Injection tests
│       ├── DualStorageFailureTest.php       # Consistency tests
│       └── ...
├── Integration/
│   ├── EntityAutoDiscoveryTest.php          # End-to-end discovery
│   ├── DualStorageCoordinationTest.php      # Store coordination
│   └── RealBusinessScenarioTest.php         # Business logic tests
└── Fixtures/
    └── Test*.php            # Test models

```

### Test Coverage

[](#test-coverage)

- Unit tests: 150+ tests
- Integration tests: 20+ tests
- Security tests: 54 tests (all passing)
    - 30 Cypher injection scenarios
    - 5 data consistency scenarios
    - 19 resilience scenarios (retry + circuit breaker)

Documentation
-------------

[](#documentation)

- **Foundations Track** (`resources/docs/1.0/foundations/`): Requirements, installation, infrastructure, configuration, and troubleshooting (rendered at `/ai-docs/foundations`).
- **Usage &amp; Extension Track** (`resources/docs/1.0/usage/`): Quick start, AI facade APIs, ingestion/context guides, Laravel integration, testing, and extension playbooks.
- **Internals &amp; Architecture Track** (`resources/docs/1.0/internals/`): Architecture diagrams, component deep dives, data flows, storage reference, resilience/security details.
- **Examples**: Working code samples in `examples/` directory.
- **Tests**: Test suite demonstrates usage patterns.

Artisan Commands
----------------

[](#artisan-commands)

### `php artisan ai:discover`

[](#php-artisan-aidiscover)

Auto-discover Nodeable entities and generate `config/entities.php`.

```
# Discover all Nodeable models
php artisan ai:discover

# Discover specific model
php artisan ai:discover --model="App\Models\Customer"

# Overwrite existing config
php artisan ai:discover --force

# Preview without writing
php artisan ai:discover --dry-run
```

**What it does:**

- Scans `app/Models` for classes implementing `Nodeable`
- Resolves model inheritance (merges child models into parents)
- Analyzes models to discover:
    - Neo4j label, properties, relationships
    - Qdrant collection, embed fields
    - Aliases for natural language queries
    - Eloquent scopes converted to Cypher patterns
- Generates/merges `config/entities.php`

**Important:** This command is **required**. There is no runtime auto-discovery.

**When to run:**

- Initial setup (required before using AI features)
- After adding new Nodeable models
- After changing model structure (new columns, relationships, scopes)
- During CI/CD deployment

### `php artisan ai:ingest`

[](#php-artisan-aiingest)

Bulk ingest existing Nodeable entities into Neo4j and Qdrant.

```
# Ingest all entities
php artisan ai:ingest

# Ingest specific model
php artisan ai:ingest --model="App\Models\Customer"

# Clear stores before ingesting
php artisan ai:ingest --fresh

# Custom batch size (default: 100)
php artisan ai:ingest --chunk=500

# Preview without ingesting
php artisan ai:ingest --dry-run
```

**What it does:**

- Finds all Nodeable models
- Processes existing database records in batches
- Ingests into Neo4j (graph) + Qdrant (vectors)
- Shows progress bar and success/failure counts

**When to run:**

- Initial setup (when you have existing data)
- After migrating to the AI package
- To rebuild graph/vector stores from scratch (`--fresh`)

**Note:** After initial ingestion, new/updated entities auto-sync via model events.

Development
-----------

[](#development)

### Contributing

[](#contributing)

1. Fork the repository
2. Create a feature branch: `git checkout -b feature/amazing-feature`
3. Make your changes
4. Run tests: `composer test`
5. Commit: `git commit -m "Add amazing feature"`
6. Push: `git push origin feature/amazing-feature`
7. Open a pull request

### Code Standards

[](#code-standards)

- **PSR-12**: PHP coding standard
- **PHP 8.1+**: Type hints, readonly properties, intersection types
- **Interface-based**: Depend on interfaces, not implementations
- **Test Coverage**: All new features must have tests
- **Documentation**: Update docs for API changes

### Running Development Environment

[](#running-development-environment)

```
# Install dependencies
composer install

# Run tests
composer test

# Generate coverage report
composer test-coverage
```

Technical Decisions
-------------------

[](#technical-decisions)

### Why Neo4j + Qdrant?

[](#why-neo4j--qdrant)

**Neo4j (Graph Database):**

- Native graph storage optimized for relationship traversal
- Cypher query language provides expressive pattern matching
- Efficient multi-hop queries for complex relationships
- ACID transactions for data consistency

**Qdrant (Vector Database):**

- High-performance vector similarity search
- Metadata filtering alongside vector search
- Scales to millions of vectors
- Easy deployment (Docker, cloud)

**Why Dual-Storage?**

- Neo4j excels at relationship queries ("who is connected to whom")
- Qdrant excels at semantic search ("find similar entities")
- Together: Powerful hybrid queries combining structure and semantics

### Why Compensating Transactions vs 2PC?

[](#why-compensating-transactions-vs-2pc)

**Two-Phase Commit (2PC)** requires:

- Coordinator service
- Prepare phase locks
- Complex failure recovery
- Increased latency

**Compensating Transactions** provide:

- Simpler implementation (rollback on failure)
- No distributed coordinator needed
- Lower latency (no prepare phase)
- Adequate consistency for this use case

**Trade-off**: Brief window of inconsistency on failure (acceptable for AI indexing, not financial transactions)

### Why Interface-Based Design?

[](#why-interface-based-design)

**Benefits:**

- **Testability**: Easy to mock dependencies in unit tests
- **Flexibility**: Swap implementations (e.g., switch from OpenAI to Anthropic)
- **Loose Coupling**: Components depend on contracts, not concrete classes
- **Laravel Integration**: Works naturally with service container binding

**Example:**

```
// Bind interface to implementation
$this->app->singleton(GraphStoreInterface::class, Neo4jStore::class);

// Swap to different implementation
$this->app->singleton(GraphStoreInterface::class, ArangoDbStore::class);
```

### Why Auto-Discovery vs Manual Config?

[](#why-auto-discovery-vs-manual-config)

**Manual Configuration Issues:**

- Duplication between model definition and config file
- Config drift when models change
- Maintenance burden
- Error-prone

**Auto-Discovery Benefits:**

- Single source of truth (Eloquent model analyzed at discover time)
- Zero duplication
- Version-controlled configuration (`config/entities.php`)
- Laravel philosophy: Convention over configuration
- Re-run `ai:discover` after model changes to update

**Escape Hatch**: Override via `nodeableConfig()` method when needed

License
-------

[](#license)

MIT License - see [LICENSE](LICENSE) file for details

Support
-------

[](#support)

- **Issues**: GitHub Issues for bug reports and feature requests
- **Documentation**: See `resources/docs/1.0/` (rendered via LaRecipe at `/ai-docs`)
- **Examples**: Working code samples in `examples/` directory

---

**Built with Laravel** | **Powered by RAG** | **Secured by Design**

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance83

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity39

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~20 days

Total

4

Last Release

119d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b723bc3b74495836b78647de6a763c5bd5f7a30a1647bc0da8b344fecd29631b?d=identicon)[Anonimatrix](/maintainers/Anonimatrix)

---

Top Contributors

[![Ez-Bruno](https://avatars.githubusercontent.com/u/56374691?v=4)](https://github.com/Ez-Bruno "Ez-Bruno (280 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/condoedge-ai/health.svg)

```
[![Health](https://phpackages.com/badges/condoedge-ai/health.svg)](https://phpackages.com/packages/condoedge-ai)
```

###  Alternatives

[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

728272.9k20](/packages/civicrm-civicrm-core)[theodo-group/llphant

LLPhant is a library to help you build Generative AI applications.

1.5k311.5k5](/packages/theodo-group-llphant)[helgesverre/extractor

AI-Powered Data Extraction for your Laravel application.

22128.0k](/packages/helgesverre-extractor)[boomcms/boom-core

Core classes for BoomCMS

193.0k6](/packages/boomcms-boom-core)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
