mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
Merge pull request #325 from Hawksight-AI/context
Enhanced Context Module with User-Friendly Documentation & Features
This commit is contained in:
@@ -18,7 +18,6 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Why Semantica?
|
||||
@@ -36,30 +35,30 @@ pip install semantica
|
||||
```
|
||||
|
||||
```python
|
||||
from semantica.context import AgentContext
|
||||
from semantica.context import AgentContext, ContextGraph
|
||||
from semantica.vector_store import VectorStore
|
||||
from semantica.kg import GraphBuilder
|
||||
|
||||
# Initialize context with advanced features
|
||||
# Initialize with enhanced context features
|
||||
vs = VectorStore(backend="faiss", dimension=768)
|
||||
kg = GraphBuilder().build({"entities": [], "relationships": []})
|
||||
kg = ContextGraph(advanced_analytics=True)
|
||||
context = AgentContext(
|
||||
vector_store=vs,
|
||||
knowledge_graph=kg,
|
||||
enable_decision_tracking=True,
|
||||
enable_advanced_analytics=True,
|
||||
enable_kg_algorithms=True,
|
||||
enable_vector_store_features=True
|
||||
decision_tracking=True,
|
||||
advanced_analytics=True,
|
||||
kg_algorithms=True,
|
||||
vector_store_features=True,
|
||||
graph_expansion=True
|
||||
)
|
||||
|
||||
# Store memory with context graphs
|
||||
# Store memory with automatic context graph building
|
||||
memory_id = context.store(
|
||||
"User is working on a React project with FastAPI",
|
||||
conversation_id="session_1"
|
||||
)
|
||||
|
||||
# Record decision with full context
|
||||
decision_id = context.record_decision(
|
||||
# Easy decision recording with convenience methods
|
||||
decision_id = context.graph_builder.add_decision(
|
||||
category="technology_choice",
|
||||
scenario="Framework selection for web API",
|
||||
reasoning="React ecosystem with FastAPI provides best performance",
|
||||
@@ -67,15 +66,25 @@ decision_id = context.record_decision(
|
||||
confidence=0.92
|
||||
)
|
||||
|
||||
# Find similar decisions (precedents)
|
||||
precedents = context.find_precedents_advanced(
|
||||
# Find similar decisions with advanced analytics
|
||||
similar_decisions = context.graph_builder.find_similar_decisions(
|
||||
scenario="Framework selection",
|
||||
use_kg_features=True
|
||||
max_results=5
|
||||
)
|
||||
|
||||
# Analyze decision impact and influence
|
||||
impact = context.graph_builder.analyze_decision_impact(decision_id)
|
||||
|
||||
# Check compliance with business rules
|
||||
compliance = context.graph_builder.check_decision_rules({
|
||||
"category": "technology_choice",
|
||||
"confidence": 0.92
|
||||
})
|
||||
|
||||
print(f"Memory stored: {memory_id}")
|
||||
print(f"Decision recorded: {decision_id}")
|
||||
print(f"Found {len(precedents)} precedents")
|
||||
print(f"Found {len(similar_decisions)} similar decisions")
|
||||
print(f"Compliance check: {compliance.get('compliant', False)}")
|
||||
```
|
||||
|
||||
**[📖 Full Quick Start](#-quick-start)** • **[🍳 Cookbook Examples](#-semantica-cookbook)** • **[💬 Join Discord](https://discord.gg/ggb7vWeP)** • **[⭐ Star Us](https://github.com/Hawksight-AI/semantica)**
|
||||
@@ -144,65 +153,160 @@ print(f"Found {len(precedents)} precedents")
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Context Module: Advanced Context Engineering
|
||||
## 🧠 Context Module: Advanced Context Engineering & Decision Intelligence
|
||||
|
||||
The **Context Module** is Semantica's flagship component, providing sophisticated context management with **context graphs**, **decision tracking**, and **advanced knowledge engineering**.
|
||||
The **Context Module** is Semantica's flagship component, providing sophisticated context management with **context graphs**, **advanced decision tracking**, **knowledge graph analytics**, and **easy-to-use interfaces**.
|
||||
|
||||
### 🎯 Core Capabilities
|
||||
|
||||
| **Feature** | **Description** | **Use Case** |
|
||||
|------------|-------------|------------|
|
||||
| **Context Graphs** | Structured knowledge representation with entity relationships | Knowledge management, decision support |
|
||||
| **Decision Tracking** | Complete decision lifecycle with precedent search | Banking approvals, healthcare decisions |
|
||||
| **KG Algorithms** | Advanced graph analytics (centrality, community detection) | Influence analysis, similarity search |
|
||||
| **Advanced Decision Tracking** | Complete decision lifecycle with precedent search, causal analysis, and policy enforcement | Banking approvals, healthcare decisions |
|
||||
| **Easy-to-Use Methods** | 10 convenience methods for common operations without complexity | Rapid development, user-friendly API |
|
||||
| **KG Algorithms** | Advanced graph analytics (centrality, community detection, Node2Vec) | Influence analysis, similarity search |
|
||||
| **Policy Engine** | Automated compliance checking with business rules and exception handling | Regulatory compliance, business rules |
|
||||
| **Vector Store Integration** | Hybrid search with custom similarity weights | Advanced retrieval and filtering |
|
||||
| **Memory Management** | Hierarchical memory with short-term and long-term storage | Agent conversation history |
|
||||
|
||||
### 🚀 Advanced Features
|
||||
### 🚀 Enhanced Features
|
||||
|
||||
- **Easy Decision Recording**: `add_decision()` with automatic entity linking
|
||||
- **Smart Precedent Search**: `find_similar_decisions()` with hybrid similarity
|
||||
- **Impact Analysis**: `analyze_decision_impact()` with influence scoring
|
||||
- **Policy Compliance**: `check_decision_rules()` with automated validation
|
||||
- **Causal Chains**: `trace_decision_chain()` for decision lineage
|
||||
- **Graph Analytics**: `get_node_importance()`, `analyze_connections()` for insights
|
||||
- **Hybrid Retrieval**: Combines vector search, graph traversal, and keyword matching
|
||||
- **Multi-Hop Reasoning**: Trace relationships across multiple graph hops
|
||||
- **Decision Influence Analysis**: Understand how decisions impact each other
|
||||
- **Policy Engine**: Enforce business rules and compliance automatically
|
||||
- **Causal Chain Analysis**: Trace decision causality and influence paths
|
||||
- **Entity Linking**: Resolve ambiguities and maintain consistent entity references
|
||||
- **Production Ready**: Comprehensive error handling and scalability
|
||||
|
||||
### Examples
|
||||
### 🔧 Easy-to-Use API
|
||||
|
||||
```python
|
||||
# Banking Decision System
|
||||
# Simple usage with convenience methods
|
||||
from semantica.context import ContextGraph
|
||||
|
||||
graph = ContextGraph(advanced_analytics=True)
|
||||
|
||||
# Add decision with ease
|
||||
decision_id = graph.add_decision(
|
||||
category="loan_approval",
|
||||
scenario="Mortgage application",
|
||||
reasoning="Good credit score",
|
||||
outcome="approved",
|
||||
confidence=0.95
|
||||
)
|
||||
|
||||
# Find similar decisions
|
||||
similar = graph.find_similar_decisions("mortgage", max_results=5)
|
||||
|
||||
# Analyze impact
|
||||
impact = graph.analyze_decision_impact(decision_id)
|
||||
|
||||
# Check compliance
|
||||
compliance = graph.check_decision_rules({
|
||||
"category": "loan_approval",
|
||||
"confidence": 0.95
|
||||
})
|
||||
```
|
||||
|
||||
### 🏢 Enterprise Integration
|
||||
|
||||
```python
|
||||
# Full enterprise setup with AgentContext
|
||||
from semantica.context import AgentContext
|
||||
from semantica.vector_store import VectorStore
|
||||
|
||||
context = AgentContext(
|
||||
vector_store=vs,
|
||||
knowledge_graph=kg,
|
||||
enable_decision_tracking=True,
|
||||
enable_kg_algorithms=True
|
||||
vector_store=VectorStore(backend="faiss"),
|
||||
knowledge_graph=ContextGraph(advanced_analytics=True),
|
||||
decision_tracking=True,
|
||||
kg_algorithms=True,
|
||||
vector_store_features=True
|
||||
)
|
||||
|
||||
# Record loan decision
|
||||
# Record decision with full context
|
||||
decision_id = context.record_decision(
|
||||
category="mortgage_approval",
|
||||
scenario="First-time homebuyer application",
|
||||
reasoning="Strong credit score, stable employment",
|
||||
outcome="approved",
|
||||
confidence=0.94
|
||||
category="fraud_detection",
|
||||
scenario="Suspicious transaction pattern",
|
||||
reasoning="Multiple high-value transactions in short timeframe",
|
||||
outcome="flagged_for_review",
|
||||
confidence=0.87,
|
||||
entities=["transaction_123", "customer_456"]
|
||||
)
|
||||
|
||||
# Find similar decisions with KG features
|
||||
precedents = context.find_precedents_advanced(
|
||||
scenario="Mortgage application",
|
||||
use_kg_features=True,
|
||||
similarity_weights={"semantic": 0.5, "structural": 0.3, "category": 0.2}
|
||||
# Advanced precedent search with KG features
|
||||
precedents = context.find_precedents(
|
||||
"suspicious transaction",
|
||||
category="fraud_detection",
|
||||
use_kg_features=True
|
||||
)
|
||||
|
||||
# Analyze decision influence
|
||||
# Comprehensive influence analysis
|
||||
influence = context.analyze_decision_influence(decision_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 The Problem: The Semantic Gap
|
||||
## AgentContext - Your Agent's Brain
|
||||
|
||||
The main interface that makes your agent intelligent. It handles memory, decisions, and knowledge organization automatically.
|
||||
|
||||
### Quick Start
|
||||
```python
|
||||
from semantica.context import AgentContext
|
||||
from semantica.vector_store import VectorStore
|
||||
|
||||
# Create your intelligent agent
|
||||
agent = AgentContext(vector_store=VectorStore(backend="inmemory", dimension=384))
|
||||
|
||||
# Your agent can now remember things
|
||||
memory_id = agent.store("User asked about Python programming")
|
||||
print(f"Agent remembered: {memory_id}")
|
||||
|
||||
# And find information when needed
|
||||
results = agent.retrieve("Python tutorials")
|
||||
print(f"Agent found {len(results)} relevant memories")
|
||||
```
|
||||
|
||||
### Easy Decision Learning
|
||||
```python
|
||||
# Your agent learns from its decisions
|
||||
decision_id = agent.record_decision(
|
||||
category="content_recommendation",
|
||||
scenario="User wants Python tutorial",
|
||||
reasoning="User mentioned being a beginner",
|
||||
outcome="recommended_basics",
|
||||
confidence=0.85
|
||||
)
|
||||
|
||||
# Your agent can now find similar past decisions
|
||||
similar_decisions = agent.find_precedents("Python tutorial", limit=3)
|
||||
print(f"Agent found {len(similar_decisions)} similar past decisions")
|
||||
```
|
||||
|
||||
### Getting Smarter Over Time
|
||||
```python
|
||||
# Enable all learning features
|
||||
smart_agent = AgentContext(
|
||||
vector_store=vector_store,
|
||||
decision_tracking=True, # Learn from decisions
|
||||
graph_expansion=True, # Find related information
|
||||
advanced_analytics=True, # Understand patterns
|
||||
kg_algorithms=True, # Advanced analysis
|
||||
vector_store_features=True
|
||||
)
|
||||
|
||||
# Get insights about your agent's learning
|
||||
insights = smart_agent.get_context_insights()
|
||||
print(f"Total decisions learned: {insights.get('total_decisions', 0)}")
|
||||
print(f"Decision categories: {list(insights.get('categories', {}).keys())}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The Problem: The Semantic Gap
|
||||
|
||||
### Most AI systems fail in high-stakes domains because they operate on **text similarity**, not **meaning**.
|
||||
|
||||
@@ -248,45 +352,45 @@ The **semantic gap** is the fundamental disconnect between what AI systems can p
|
||||
|
||||
---
|
||||
|
||||
## 🆚 Semantica vs Traditional RAG
|
||||
## Semantica vs Traditional RAG
|
||||
|
||||
| Feature | Traditional RAG | Semantica |
|
||||
|:--------|:----------------|:----------|
|
||||
| **Reasoning** | ❌ Black-box answers | ✅ Explainable reasoning paths |
|
||||
| **Provenance** | ❌ No provenance | ✅ W3C PROV-O compliant lineage tracking |
|
||||
| **Search** | ⚠️ Vector similarity only | ✅ Semantic + graph reasoning |
|
||||
| **Quality** | ❌ No conflict handling | ✅ Explicit contradiction detection |
|
||||
| **Safety** | ⚠️ Unsafe for high-stakes | ✅ Designed for governed environments |
|
||||
| **Compliance** | ❌ No audit trails | ✅ Complete audit trails with integrity verification |
|
||||
| **Reasoning** | Black-box answers | Explainable reasoning paths |
|
||||
| **Provenance** | No provenance | W3C PROV-O compliant lineage tracking |
|
||||
| **Search** | Vector similarity only | Semantic + graph reasoning |
|
||||
| **Quality** | No conflict handling | Explicit contradiction detection |
|
||||
| **Safety** | Unsafe for high-stakes | Designed for governed environments |
|
||||
| **Compliance** | No audit trails | Complete audit trails with integrity verification |
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Semantica Architecture
|
||||
## Semantica Architecture
|
||||
|
||||
### 1️⃣ Input Layer — Governed Ingestion
|
||||
- 📄 **Multiple Formats** — PDFs, DOCX, HTML, JSON, CSV, Excel, PPTX
|
||||
- 🔧 **Docling Support** — Docling parser for table extraction
|
||||
- 💾 **Data Sources** — Databases, APIs, streams, archives, web content
|
||||
- 🎨 **Media Support** — Image parsing with OCR, audio/video metadata extraction
|
||||
- 📊 **Single Pipeline** — Unified ingestion with metadata and source tracking
|
||||
### Input Layer — Governed Ingestion
|
||||
- **Multiple Formats** — PDFs, DOCX, HTML, JSON, CSV, Excel, PPTX
|
||||
- **Docling Support** — Docling parser for table extraction
|
||||
- **Data Sources** — Databases, APIs, streams, archives, web content
|
||||
- **Media Support** — Image parsing with OCR, audio/video metadata extraction
|
||||
- **Single Pipeline** — Unified ingestion with metadata and source tracking
|
||||
|
||||
### 2️⃣ Semantic Layer — Trust & Reasoning Engine
|
||||
- 🔍 **Entity Extraction** — NER, normalization, classification
|
||||
- 🔗 **Relationship Discovery** — Triplet generation, semantic links
|
||||
- 📐 **Ontology Induction** — Automated domain rule generation
|
||||
- 🔄 **Deduplication** — Jaro-Winkler similarity, conflict resolution
|
||||
- ✅ **Quality Assurance** — Conflict detection, validation
|
||||
- 📊 **Provenance Tracking** — W3C PROV-O compliant lineage tracking across all modules
|
||||
- 🧠 **Reasoning Traces** — Explainable inference paths
|
||||
- 🔐 **Change Management** — Version control with audit trails, checksums, compliance support
|
||||
### Semantic Layer — Trust & Reasoning Engine
|
||||
- **Entity Extraction** — NER, normalization, classification
|
||||
- **Relationship Discovery** — Triplet generation, semantic links
|
||||
- **Ontology Induction** — Automated domain rule generation
|
||||
- **Deduplication** — Jaro-Winkler similarity, conflict resolution
|
||||
- **Quality Assurance** — Conflict detection, validation
|
||||
- **Provenance Tracking** — W3C PROV-O compliant lineage tracking across all modules
|
||||
- **Reasoning Traces** — Explainable inference paths
|
||||
- **Change Management** — Version control with audit trails, checksums, compliance support
|
||||
|
||||
### 3️⃣ Output Layer — Auditable Knowledge Assets
|
||||
- 📊 **Knowledge Graphs** — Queryable, temporal, explainable
|
||||
- 📐 **OWL Ontologies** — HermiT/Pellet validated, custom ontology import support
|
||||
- 🔢 **Vector Embeddings** — FastEmbed by default
|
||||
- ☁️ **AWS Neptune** — Amazon Neptune graph database support
|
||||
- � **Apache AGE** — PostgreSQL graph extension with openCypher support
|
||||
- �🔍 **Provenance** — Every AI response links back to:
|
||||
### Output Layer — Auditable Knowledge Assets
|
||||
- **Knowledge Graphs** — Queryable, temporal, explainable
|
||||
- **OWL Ontologies** — HermiT/Pellet validated, custom ontology import support
|
||||
- **Vector Embeddings** — FastEmbed by default
|
||||
- **AWS Neptune** — Amazon Neptune graph database support
|
||||
- **Apache AGE** — PostgreSQL graph extension with openCypher support
|
||||
- **Provenance** — Every AI response links back to:
|
||||
- 📄 Source documents
|
||||
- 🏷️ Extracted entities & relations
|
||||
- 📐 Ontology rules applied
|
||||
@@ -294,27 +398,27 @@ The **semantic gap** is the fundamental disconnect between what AI systems can p
|
||||
|
||||
---
|
||||
|
||||
## 🏥 Built for High-Stakes Domains
|
||||
## Built for High-Stakes Domains
|
||||
|
||||
Designed for domains where **mistakes have real consequences** and **every decision must be accountable**:
|
||||
|
||||
- **🏥 Healthcare & Life Sciences** — Clinical decision support, drug interaction analysis, medical literature reasoning, patient safety tracking
|
||||
- **💰 Finance & Risk** — Fraud detection, regulatory support (SOX, GDPR, MiFID II), credit risk assessment, algorithmic trading validation
|
||||
- **⚖️ Legal & Compliance** — Evidence-backed legal research, contract analysis, regulatory change tracking, case law reasoning
|
||||
- **🔒 Cybersecurity & Intelligence** — Threat attribution, incident response, security audit trails, intelligence analysis
|
||||
- **🏛️ Government & Defense** — Governed AI systems, policy decisions, classified information handling, defense intelligence
|
||||
- **🏭 Critical Infrastructure** — Power grid management, transportation safety, water treatment, emergency response
|
||||
- **🚗 Autonomous Systems** — Self-driving vehicles, drone navigation, robotics safety, industrial automation
|
||||
- **Healthcare & Life Sciences** — Clinical decision support, drug interaction analysis, medical literature reasoning, patient safety tracking
|
||||
- **Finance & Risk** — Fraud detection, regulatory support (SOX, GDPR, MiFID II), credit risk assessment, algorithmic trading validation
|
||||
- **Legal & Compliance** — Evidence-backed legal research, contract analysis, regulatory change tracking, case law reasoning
|
||||
- **Cybersecurity & Intelligence** — Threat attribution, incident response, security audit trails, intelligence analysis
|
||||
- **Government & Defense** — Governed AI systems, policy decisions, classified information handling, defense intelligence
|
||||
- **Critical Infrastructure** — Power grid management, transportation safety, water treatment, emergency response
|
||||
- **Autonomous Systems** — Self-driving vehicles, drone navigation, robotics safety, industrial automation
|
||||
|
||||
---
|
||||
|
||||
## 👥 Who Uses Semantica?
|
||||
|
||||
- **🤖 AI / ML Engineers** — Building explainable GraphRAG & agents
|
||||
- **⚙️ Data Engineers** — Creating governed semantic pipelines
|
||||
- **📊 Knowledge Engineers** — Managing ontologies & KGs at scale
|
||||
- **🏢 Enterprise Teams** — Requiring trustworthy AI infrastructure
|
||||
- **🛡️ Risk & Compliance Teams** — Needing audit-ready systems
|
||||
- **AI / ML Engineers** — Building explainable GraphRAG & agents
|
||||
- **Data Engineers** — Creating governed semantic pipelines
|
||||
- **Knowledge Engineers** — Managing ontologies & KGs at scale
|
||||
- **Enterprise Teams** — Requiring trustworthy AI infrastructure
|
||||
- **Risk & Compliance Teams** — Needing audit-ready systems
|
||||
|
||||
---
|
||||
|
||||
@@ -604,12 +708,12 @@ is_valid = kg_manager.verify_checksum(snapshot)
|
||||
```
|
||||
|
||||
**What We Provide:**
|
||||
- 🔐 **Persistent Storage** — SQLite and in-memory backends implemented
|
||||
- 📊 **Detailed Diffs** — Entity-level and relationship-level change tracking
|
||||
- ✅ **Data Integrity** — SHA-256 checksums with tamper detection
|
||||
- 📝 **Standardized Metadata** — ChangeLogEntry with author, timestamp, description
|
||||
- ⚡ **Performance Tested** — Tested with large-scale entity datasets
|
||||
- 🧪 **Test Coverage** — Comprehensive test coverage covering core functionality
|
||||
- **Persistent Storage** — SQLite and in-memory backends implemented
|
||||
- **Detailed Diffs** — Entity-level and relationship-level change tracking
|
||||
- **Data Integrity** — SHA-256 checksums with tamper detection
|
||||
- **Standardized Metadata** — ChangeLogEntry with author, timestamp, description
|
||||
- **Performance Tested** — Tested with large-scale entity datasets
|
||||
- **Test Coverage** — Comprehensive test coverage covering core functionality
|
||||
|
||||
**Compliance Note:** Provides technical infrastructure (audit trails, checksums, temporal tracking) that supports compliance efforts for HIPAA, SOX, FDA 21 CFR Part 11. Organizations must implement additional policies and procedures for full regulatory compliance.
|
||||
|
||||
@@ -725,11 +829,11 @@ retriever = context.retriever # Access underlying ContextRetriever
|
||||
results = retriever.retrieve(
|
||||
query="What is the user building?",
|
||||
max_results=10,
|
||||
use_graph_expansion=True
|
||||
graph_expansion=True
|
||||
)
|
||||
|
||||
# Retrieve with context expansion
|
||||
results = context.retrieve("What is the user building?", use_graph_expansion=True)
|
||||
results = context.retrieve("What is the user building?", graph_expansion=True)
|
||||
|
||||
# Query with reasoning and LLM-generated responses
|
||||
llm_provider = Groq(model="llama-3.1-8b-instant", api_key=os.getenv("GROQ_API_KEY"))
|
||||
@@ -745,20 +849,22 @@ reasoned_result = context.query_with_reasoning(
|
||||
- **ContextRetriever**: Performs hybrid retrieval combining vector search, graph traversal, and memory for optimal context relevance
|
||||
- **AgentContext**: High-level interface integrating Context Graph and Context Retriever for GraphRAG applications
|
||||
|
||||
#### Context Graphs: Decision Tracking
|
||||
#### Context Graphs: Advanced Decision Tracking & Analytics
|
||||
|
||||
```python
|
||||
from semantica.context import AgentContext, ContextGraph
|
||||
from semantica.vector_store import VectorStore
|
||||
|
||||
# Initialize with advanced decision tracking
|
||||
context = AgentContext(
|
||||
vector_store=VectorStore(backend="inmemory", dimension=128),
|
||||
knowledge_graph=ContextGraph(),
|
||||
enable_decision_tracking=True,
|
||||
enable_kg_algorithms=False, # semantic-only precedent search
|
||||
knowledge_graph=ContextGraph(advanced_analytics=True),
|
||||
decision_tracking=True,
|
||||
kg_algorithms=True, # Enable advanced graph analytics
|
||||
)
|
||||
|
||||
decision_id = context.record_decision(
|
||||
# Easy decision recording with convenience methods
|
||||
decision_id = context.graph_builder.add_decision(
|
||||
category="credit_approval",
|
||||
scenario="High-risk credit limit increase",
|
||||
reasoning="Recent velocity-check failure and prior fraud flag",
|
||||
@@ -767,10 +873,79 @@ decision_id = context.record_decision(
|
||||
entities=["customer:jessica_norris"],
|
||||
)
|
||||
|
||||
precedents = context.find_precedents(
|
||||
scenario="High-risk customer credit increase",
|
||||
# Find similar decisions with advanced analytics
|
||||
similar_decisions = context.graph_builder.find_similar_decisions(
|
||||
scenario="credit increase",
|
||||
category="credit_approval",
|
||||
limit=5,
|
||||
max_results=5,
|
||||
)
|
||||
|
||||
# Analyze decision impact and influence
|
||||
impact_analysis = context.graph_builder.analyze_decision_impact(decision_id)
|
||||
node_importance = context.graph_builder.get_node_importance("customer:jessica_norris")
|
||||
|
||||
# Check compliance with business rules
|
||||
compliance = context.graph_builder.check_decision_rules({
|
||||
"category": "credit_approval",
|
||||
"scenario": "Credit limit increase",
|
||||
"reasoning": "Risk assessment completed",
|
||||
"outcome": "rejected",
|
||||
"confidence": 0.78
|
||||
})
|
||||
```
|
||||
|
||||
**Enhanced Features:**
|
||||
- **Easy-to-Use Methods**: 10 convenience methods for common operations
|
||||
- **Decision Analytics**: Influence analysis, centrality measures, community detection
|
||||
- **Policy Engine**: Automated compliance checking with business rules
|
||||
- **Causal Analysis**: Trace decision causality and impact chains
|
||||
- **Graph Analytics**: Advanced KG algorithms (Node2Vec, centrality, community detection)
|
||||
- **Hybrid Search**: Semantic + structural + category similarity
|
||||
- **Production Ready**: Scalable architecture with comprehensive error handling
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Simple Setup (Most Common)
|
||||
```python
|
||||
# Just memory and basic learning
|
||||
agent = AgentContext(vector_store=vector_store)
|
||||
```
|
||||
|
||||
### Smart Setup (Recommended)
|
||||
```python
|
||||
# Memory + decision learning
|
||||
agent = AgentContext(
|
||||
vector_store=vector_store,
|
||||
decision_tracking=True,
|
||||
graph_expansion=True
|
||||
)
|
||||
```
|
||||
|
||||
### Complete Setup (Maximum Power)
|
||||
```python
|
||||
# Everything enabled
|
||||
agent = AgentContext(
|
||||
vector_store=vector_store,
|
||||
knowledge_graph=ContextGraph(advanced_analytics=True),
|
||||
decision_tracking=True,
|
||||
graph_expansion=True,
|
||||
advanced_analytics=True,
|
||||
kg_algorithms=True,
|
||||
vector_store_features=True
|
||||
)
|
||||
```
|
||||
|
||||
### ContextGraph Options
|
||||
```python
|
||||
# Basic knowledge graph
|
||||
graph = ContextGraph()
|
||||
|
||||
# Advanced knowledge graph
|
||||
graph = ContextGraph(
|
||||
advanced_analytics=True, # Enable smart algorithms
|
||||
centrality_analysis=True, # Find important concepts
|
||||
community_detection=True, # Find groups of related concepts
|
||||
node_embeddings=True # Understand concept similarity
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
+1
-1
@@ -332,7 +332,7 @@ from semantica.reasoning import Reasoner
|
||||
context = AgentContext(
|
||||
vector_store=vs,
|
||||
knowledge_graph=kg,
|
||||
use_graph_expansion=True,
|
||||
graph_expansion=True,
|
||||
hybrid_alpha=0.7
|
||||
)
|
||||
|
||||
|
||||
+433
-840
File diff suppressed because it is too large
Load Diff
@@ -46,7 +46,7 @@ Enhanced Analytics:
|
||||
|
||||
Main Classes:
|
||||
- AgentContext: High-level interface with KG integration
|
||||
- ContextGraph: In-memory graph store with KG algorithm support
|
||||
- ContextGraph: In-memory graph store with KG algorithm support and comprehensive decision management
|
||||
- ContextNode/ContextEdge: Graph data structures
|
||||
- AgentMemory: Persistent agent memory with RAG
|
||||
- MemoryItem: Memory item data structure
|
||||
@@ -63,12 +63,13 @@ Decision Tracking Classes:
|
||||
- Policy/Precedent/PolicyException: Decision tracking data structures
|
||||
|
||||
Example Usage:
|
||||
>>> from semantica.context import AgentContext
|
||||
>>> from semantica.context import AgentContext, ContextGraph
|
||||
>>> # Simple AgentContext with decision tracking
|
||||
>>> context = AgentContext(vector_store=vs, knowledge_graph=kg,
|
||||
... enable_decision_tracking=True,
|
||||
... enable_advanced_analytics=True,
|
||||
... enable_kg_algorithms=True,
|
||||
... enable_vector_store_features=True)
|
||||
... decision_tracking=True,
|
||||
... advanced_analytics=True,
|
||||
... kg_algorithms=True,
|
||||
... vector_store_features=True)
|
||||
>>> memory_id = context.store("User asked about Python", conversation_id="conv1")
|
||||
>>> results = context.retrieve("Python programming")
|
||||
>>> decision_id = context.record_decision(category="approval",
|
||||
@@ -81,6 +82,21 @@ Example Usage:
|
||||
... use_kg_features=True)
|
||||
>>> influence = context.analyze_decision_influence(decision_id)
|
||||
>>> insights = context.get_context_insights()
|
||||
|
||||
>>> # Comprehensive ContextGraph with all decision features
|
||||
>>> graph = ContextGraph(advanced_analytics=True, enable_causality=True)
|
||||
>>> decision_id = graph.record_decision(
|
||||
... category="loan_approval",
|
||||
... scenario="First-time homebuyer",
|
||||
... reasoning="Good credit score and stable income",
|
||||
... outcome="approved",
|
||||
... confidence=0.95,
|
||||
... entities=["customer_123", "property_456"]
|
||||
... )
|
||||
>>> precedents = graph.find_precedents("loan_approval", limit=5)
|
||||
>>> influence = graph.analyze_decision_influence(decision_id)
|
||||
>>> insights = graph.get_decision_insights()
|
||||
>>> causality = graph.trace_decision_causality(decision_id)
|
||||
|
||||
Production Examples:
|
||||
- Banking: Mortgage approvals, credit decisions, risk assessment
|
||||
|
||||
@@ -46,10 +46,11 @@ Key Methods:
|
||||
Example Usage:
|
||||
>>> from semantica.context import AgentContext
|
||||
>>> context = AgentContext(vector_store=vs, knowledge_graph=kg,
|
||||
... enable_decision_tracking=True,
|
||||
... enable_advanced_analytics=True,
|
||||
... enable_kg_algorithms=True,
|
||||
... enable_vector_store_features=True)
|
||||
... decision_tracking=True,
|
||||
... advanced_analytics=True,
|
||||
... kg_algorithms=True,
|
||||
... vector_store_features=True,
|
||||
... graph_expansion=True)
|
||||
>>> memory_id = context.store("User asked about Python", conversation_id="conv1")
|
||||
>>> results = context.retrieve("Python programming")
|
||||
>>> decision_id = context.record_decision(category="approval",
|
||||
@@ -124,13 +125,13 @@ class AgentContext:
|
||||
knowledge_graph: Optional[Any] = None,
|
||||
retention_days: Optional[int] = 30,
|
||||
max_memories: int = 10000,
|
||||
use_graph_expansion: bool = True,
|
||||
graph_expansion: bool = True,
|
||||
max_expansion_hops: int = 2,
|
||||
hybrid_alpha: float = 0.5,
|
||||
enable_decision_tracking: bool = False,
|
||||
enable_advanced_analytics: bool = True,
|
||||
enable_kg_algorithms: bool = True,
|
||||
enable_vector_store_features: bool = True,
|
||||
decision_tracking: bool = False,
|
||||
advanced_analytics: bool = True,
|
||||
kg_algorithms: bool = True,
|
||||
vector_store_features: bool = True,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
@@ -141,14 +142,14 @@ class AgentContext:
|
||||
knowledge_graph: Knowledge graph instance (optional, enables GraphRAG)
|
||||
retention_days: Days to keep memories (default: 30, None=unlimited)
|
||||
max_memories: Maximum number of memories (default: 10000)
|
||||
use_graph_expansion: Enable graph expansion for retrieval (default: True)
|
||||
graph_expansion: Enable graph expansion for retrieval (default: True)
|
||||
max_expansion_hops: Maximum hops for graph expansion (default: 2)
|
||||
hybrid_alpha: Balance between vector (0) and graph (1) retrieval
|
||||
(default: 0.5)
|
||||
enable_decision_tracking: Enable decision tracking features (default: False)
|
||||
enable_advanced_analytics: Enable advanced analytics (default: True)
|
||||
enable_kg_algorithms: Enable KG algorithms integration (default: True)
|
||||
enable_vector_store_features: Enable vector store features (default: True)
|
||||
decision_tracking: Enable decision tracking features (default: False)
|
||||
advanced_analytics: Enable advanced analytics (default: True)
|
||||
kg_algorithms: Enable KG algorithms integration (default: True)
|
||||
vector_store_features: Enable vector store features (default: True)
|
||||
**kwargs: Additional options passed to underlying components
|
||||
|
||||
Raises:
|
||||
@@ -168,11 +169,11 @@ class AgentContext:
|
||||
|
||||
# Store advanced feature flags
|
||||
self.config = {
|
||||
"enable_decision_tracking": enable_decision_tracking,
|
||||
"enable_advanced_analytics": enable_advanced_analytics,
|
||||
"enable_kg_algorithms": enable_kg_algorithms,
|
||||
"enable_vector_store_features": enable_vector_store_features,
|
||||
"use_graph_expansion": use_graph_expansion,
|
||||
"decision_tracking": decision_tracking,
|
||||
"advanced_analytics": advanced_analytics,
|
||||
"kg_algorithms": kg_algorithms,
|
||||
"vector_store_features": vector_store_features,
|
||||
"graph_expansion": graph_expansion,
|
||||
"max_expansion_hops": max_expansion_hops,
|
||||
"hybrid_alpha": hybrid_alpha,
|
||||
**kwargs
|
||||
@@ -195,7 +196,7 @@ class AgentContext:
|
||||
"memory_store": self._memory,
|
||||
"knowledge_graph": knowledge_graph,
|
||||
"vector_store": vector_store,
|
||||
"use_graph_expansion": use_graph_expansion,
|
||||
"use_graph_expansion": graph_expansion,
|
||||
"max_expansion_hops": max_expansion_hops,
|
||||
"hybrid_alpha": hybrid_alpha,
|
||||
**kwargs,
|
||||
@@ -221,18 +222,18 @@ class AgentContext:
|
||||
self._causal_analyzer = None
|
||||
self._policy_engine = None
|
||||
|
||||
if enable_decision_tracking and knowledge_graph:
|
||||
if decision_tracking and knowledge_graph:
|
||||
if hasattr(knowledge_graph, "execute_query"):
|
||||
self._decision_backend = "graph_store"
|
||||
try:
|
||||
self._decision_recorder = DecisionRecorder(knowledge_graph)
|
||||
self._decision_query = DecisionQuery(
|
||||
graph_store=knowledge_graph,
|
||||
vector_store=vector_store if enable_vector_store_features else None,
|
||||
enable_advanced_analytics=enable_advanced_analytics,
|
||||
enable_centrality_analysis=enable_kg_algorithms,
|
||||
enable_community_detection=enable_kg_algorithms,
|
||||
enable_node_embeddings=enable_kg_algorithms
|
||||
vector_store=vector_store if vector_store_features else None,
|
||||
advanced_analytics=advanced_analytics,
|
||||
centrality_analysis=kg_algorithms,
|
||||
community_detection=kg_algorithms,
|
||||
node_embeddings=kg_algorithms
|
||||
)
|
||||
self._causal_analyzer = CausalChainAnalyzer(knowledge_graph)
|
||||
self._policy_engine = PolicyEngine(knowledge_graph)
|
||||
@@ -247,13 +248,38 @@ class AgentContext:
|
||||
self._policy_engine = PolicyEngine(knowledge_graph)
|
||||
else:
|
||||
self._decision_backend = "context_graph"
|
||||
# Initialize basic decision components for ContextGraph
|
||||
self._policy_engine = PolicyEngine(knowledge_graph)
|
||||
self._causal_analyzer = CausalChainAnalyzer(knowledge_graph)
|
||||
if enable_vector_store_features and hasattr(self.vector_store, "initialize_decision_pipeline"):
|
||||
|
||||
# Initialize DecisionQuery for ContextGraph
|
||||
try:
|
||||
self._decision_query = DecisionQuery(
|
||||
graph_store=knowledge_graph,
|
||||
vector_store=vector_store if vector_store_features else None,
|
||||
advanced_analytics=advanced_analytics,
|
||||
centrality_analysis=kg_algorithms,
|
||||
community_detection=kg_algorithms,
|
||||
node_embeddings=kg_algorithms
|
||||
)
|
||||
self.logger.info("ContextGraph decision tracking initialized successfully")
|
||||
except Exception as e:
|
||||
self.logger.warning(
|
||||
f"Failed to initialize DecisionQuery for ContextGraph ({type(e).__name__})"
|
||||
)
|
||||
# Create a minimal DecisionQuery that delegates to ContextGraph
|
||||
self._decision_query = type('MinimalDecisionQuery', (), {
|
||||
'analyze_decision_influence': lambda self, decision_id, max_depth=3:
|
||||
knowledge_graph.analyze_decision_influence(decision_id, max_depth) if hasattr(knowledge_graph, 'analyze_decision_influence') else {},
|
||||
'find_precedents': lambda self, query, category=None, limit=10:
|
||||
knowledge_graph.find_precedents(query, category, limit) if hasattr(knowledge_graph, 'find_precedents') else [],
|
||||
})()
|
||||
|
||||
if vector_store_features and hasattr(self.vector_store, "initialize_decision_pipeline"):
|
||||
try:
|
||||
self.vector_store.initialize_decision_pipeline(
|
||||
graph_store=knowledge_graph if enable_kg_algorithms else None,
|
||||
use_graph_features=enable_kg_algorithms
|
||||
graph_store=knowledge_graph if kg_algorithms else None,
|
||||
use_graph_features=kg_algorithms
|
||||
)
|
||||
except Exception as e:
|
||||
self.logger.warning(
|
||||
@@ -1586,67 +1612,22 @@ class AgentContext:
|
||||
|
||||
return decision_id
|
||||
|
||||
if not hasattr(self.knowledge_graph, "add_decision"):
|
||||
if not hasattr(self.knowledge_graph, "record_decision"):
|
||||
raise RuntimeError("Decision tracking backend does not support decisions")
|
||||
|
||||
self.knowledge_graph.add_decision(decision)
|
||||
if cross_system_context and hasattr(self.knowledge_graph, "add_node_attribute"):
|
||||
self.knowledge_graph.add_node_attribute(
|
||||
decision.decision_id, {"cross_system_context": cross_system_context}
|
||||
)
|
||||
about_edge_failures: List[Dict[str, str]] = []
|
||||
for entity_id in entities:
|
||||
try:
|
||||
self.knowledge_graph.add_edge(decision.decision_id, entity_id, edge_type="ABOUT")
|
||||
except Exception as e:
|
||||
about_edge_failures.append(
|
||||
{"entity_id": str(entity_id), "error_type": type(e).__name__}
|
||||
)
|
||||
|
||||
if about_edge_failures:
|
||||
failure_types = sorted(
|
||||
{f.get("error_type", "") for f in about_edge_failures if f.get("error_type")}
|
||||
)
|
||||
self.logger.warning(
|
||||
f"record_decision ABOUT edge creation failures: {len(about_edge_failures)} "
|
||||
f"({', '.join(failure_types) if failure_types else 'unknown'})"
|
||||
)
|
||||
if hasattr(self.knowledge_graph, "add_node_attribute"):
|
||||
self.knowledge_graph.add_node_attribute(
|
||||
decision.decision_id, {"about_edge_failures": about_edge_failures}
|
||||
)
|
||||
|
||||
vector_id = None
|
||||
vector_store_error_type: Optional[str] = None
|
||||
if hasattr(self.vector_store, "store_decision"):
|
||||
try:
|
||||
vector_id = self.vector_store.store_decision(
|
||||
scenario=scenario,
|
||||
reasoning=reasoning,
|
||||
outcome=outcome,
|
||||
confidence=confidence,
|
||||
entities=entities,
|
||||
category=category,
|
||||
decision_id=decision.decision_id,
|
||||
decision_maker=decision.decision_maker,
|
||||
timestamp=decision.timestamp.isoformat()
|
||||
)
|
||||
except Exception as e:
|
||||
vector_id = None
|
||||
vector_store_error_type = type(e).__name__
|
||||
self.logger.warning(
|
||||
f"record_decision vector store write failed ({vector_store_error_type})"
|
||||
)
|
||||
if hasattr(self.knowledge_graph, "add_node_attribute"):
|
||||
self.knowledge_graph.add_node_attribute(
|
||||
decision.decision_id,
|
||||
{"vector_store_error_type": vector_store_error_type},
|
||||
)
|
||||
|
||||
if vector_id and hasattr(self.knowledge_graph, "add_node_attribute"):
|
||||
self.knowledge_graph.add_node_attribute(decision.decision_id, {"vector_id": vector_id})
|
||||
|
||||
return decision.decision_id
|
||||
# Delegate to ContextGraph
|
||||
decision_id = self.knowledge_graph.record_decision(
|
||||
category=category,
|
||||
scenario=scenario,
|
||||
reasoning=reasoning,
|
||||
outcome=outcome,
|
||||
confidence=confidence,
|
||||
entities=entities,
|
||||
decision_maker=decision_maker,
|
||||
metadata={"cross_system_context": cross_system_context} if cross_system_context else None
|
||||
)
|
||||
|
||||
return decision_id
|
||||
|
||||
def find_precedents(
|
||||
self,
|
||||
@@ -1677,6 +1658,38 @@ class AgentContext:
|
||||
if not self._decision_backend:
|
||||
raise RuntimeError("Decision tracking is not enabled")
|
||||
|
||||
# Delegate to ContextGraph if available
|
||||
if self._decision_backend == "context_graph" and hasattr(self.knowledge_graph, "find_precedents"):
|
||||
try:
|
||||
precedents = self.knowledge_graph.find_precedents(
|
||||
scenario=scenario,
|
||||
category=category,
|
||||
limit=limit,
|
||||
use_semantic_search=use_hybrid_search
|
||||
)
|
||||
# Convert to Decision objects if needed
|
||||
from .decision_models import Decision
|
||||
decisions = []
|
||||
for precedent in precedents:
|
||||
decision_data = precedent["decision"]
|
||||
decision = Decision(
|
||||
decision_id=decision_data["id"],
|
||||
category=decision_data["category"],
|
||||
scenario=decision_data["scenario"],
|
||||
reasoning=decision_data["reasoning"],
|
||||
outcome=decision_data["outcome"],
|
||||
confidence=decision_data["confidence"],
|
||||
timestamp=datetime.fromtimestamp(decision_data["timestamp"]),
|
||||
decision_maker=decision_data.get("decision_maker"),
|
||||
entities=decision_data.get("entities", [])
|
||||
)
|
||||
decisions.append(decision)
|
||||
return decisions
|
||||
except Exception as e:
|
||||
self.logger.exception("ContextGraph find_precedents failed")
|
||||
return []
|
||||
|
||||
# Fallback to DecisionQuery for graph_store backend
|
||||
if self._decision_backend == "graph_store":
|
||||
if use_hybrid_search:
|
||||
try:
|
||||
@@ -1991,7 +2004,7 @@ class AgentContext:
|
||||
Returns:
|
||||
Comprehensive graph analysis results
|
||||
"""
|
||||
if not self._graph_builder or not self.config.get("enable_advanced_analytics", True):
|
||||
if not self._graph_builder or not self.config.get("advanced_analytics", True):
|
||||
return {"error": "Advanced analytics not available"}
|
||||
|
||||
try:
|
||||
@@ -2112,11 +2125,21 @@ class AgentContext:
|
||||
if not self._decision_query:
|
||||
raise RuntimeError("Decision tracking is not enabled")
|
||||
|
||||
# Delegate to ContextGraph if available
|
||||
if hasattr(self.knowledge_graph, "analyze_decision_influence"):
|
||||
try:
|
||||
return self.knowledge_graph.analyze_decision_influence(decision_id, max_depth)
|
||||
except Exception as e:
|
||||
self.logger.error(f"ContextGraph analyze_decision_influence failed: {e}")
|
||||
# Fallback to DecisionQuery
|
||||
pass
|
||||
|
||||
# Fallback to DecisionQuery
|
||||
try:
|
||||
if hasattr(self._decision_query, 'analyze_decision_influence'):
|
||||
return self._decision_query.analyze_decision_influence(decision_id, max_depth)
|
||||
else:
|
||||
# Fallback to basic causal chain
|
||||
# Basic causal chain fallback
|
||||
return {
|
||||
"decision_id": decision_id,
|
||||
"downstream_decisions": self.get_causal_chain(decision_id, "downstream", max_depth),
|
||||
@@ -2160,12 +2183,12 @@ class AgentContext:
|
||||
insights = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"memory_stats": self.stats(),
|
||||
"decision_stats": self.get_decision_statistics() if self.config.get("enable_decision_tracking") and hasattr(self, 'get_decision_statistics') else {},
|
||||
"decision_stats": self.get_decision_statistics() if self.config.get("decision_tracking") and hasattr(self, 'get_decision_statistics') else {},
|
||||
"graph_analysis": self.analyze_context_graph(),
|
||||
"advanced_features": {
|
||||
"kg_algorithms_enabled": self.config.get("enable_kg_algorithms", False),
|
||||
"vector_store_features_enabled": self.config.get("enable_vector_store_features", False),
|
||||
"decision_tracking_enabled": self.config.get("enable_decision_tracking", False)
|
||||
"kg_algorithms_enabled": self.config.get("kg_algorithms", False),
|
||||
"vector_store_features_enabled": self.config.get("vector_store_features", False),
|
||||
"decision_tracking_enabled": self.config.get("decision_tracking", False)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,14 @@ Core Features:
|
||||
- Export to dictionary format
|
||||
- Decision tracking integration
|
||||
|
||||
Comprehensive Decision Management:
|
||||
- Decision Recording: Store decisions with full context and metadata
|
||||
- Precedent Search: Find similar decisions using hybrid search algorithms
|
||||
- Influence Analysis: Analyze decision impact and relationships
|
||||
- Causal Analysis: Trace decision causality chains
|
||||
- Policy Enforcement: Built-in policy compliance checking
|
||||
- Advanced Analytics: Comprehensive decision insights
|
||||
|
||||
KG Algorithm Integration:
|
||||
- Centrality Analysis: Degree, betweenness, closeness, eigenvector centrality
|
||||
- Community Detection: Modularity-based community identification
|
||||
@@ -47,23 +55,43 @@ Enhanced Methods:
|
||||
- analyze_graph_with_kg(): Comprehensive graph analysis
|
||||
- get_node_centrality(): Get centrality measures for nodes
|
||||
- find_similar_nodes(): Find similar nodes with advanced similarity
|
||||
- add_decision(): Add decisions with context integration
|
||||
- record_decision(): Add decisions with context integration
|
||||
- find_precedents(): Find decision precedents
|
||||
- analyze_decision_influence(): Analyze decision influence
|
||||
- get_decision_insights(): Get comprehensive decision analytics
|
||||
- trace_decision_causality(): Trace decision causality
|
||||
- enforce_decision_policy(): Enforce decision policies
|
||||
- get_graph_metrics(): Get comprehensive statistics
|
||||
- export_graph(): Export graph in various formats
|
||||
|
||||
Example Usage:
|
||||
>>> from semantica.context import ContextGraph
|
||||
>>> graph = ContextGraph(enable_advanced_analytics=True,
|
||||
... enable_centrality_analysis=True,
|
||||
... enable_community_detection=True,
|
||||
... enable_node_embeddings=True)
|
||||
>>> graph = ContextGraph(advanced_analytics=True,
|
||||
... centrality_analysis=True,
|
||||
... community_detection=True,
|
||||
... node_embeddings=True)
|
||||
>>>
|
||||
>>> # Basic graph operations
|
||||
>>> graph.add_node("Python", type="language", properties={"popularity": "high"})
|
||||
>>> graph.add_node("Programming", type="concept")
|
||||
>>> graph.add_edge("Python", "Programming", type="related_to")
|
||||
>>> centrality = graph.get_node_centrality("Python")
|
||||
>>> similar = graph.find_similar_nodes("Python", similarity_type="content")
|
||||
>>> analysis = graph.analyze_graph_with_kg()
|
||||
>>>
|
||||
>>> # Decision management
|
||||
>>> decision_id = graph.record_decision(
|
||||
... category="loan_approval",
|
||||
... scenario="First-time homebuyer",
|
||||
... reasoning="Good credit score",
|
||||
... outcome="approved",
|
||||
... confidence=0.95,
|
||||
... entities=["customer_123", "property_456"]
|
||||
... )
|
||||
>>> precedents = graph.find_precedents("loan_approval", limit=5)
|
||||
>>> influence = graph.analyze_decision_influence(decision_id)
|
||||
>>> insights = graph.get_decision_insights()
|
||||
>>> causality = graph.trace_decision_causality(decision_id)
|
||||
|
||||
Production Use Cases:
|
||||
- Knowledge Management: Build and analyze knowledge graphs
|
||||
@@ -71,6 +99,10 @@ Production Use Cases:
|
||||
- Recommendation Systems: Graph-based recommendations
|
||||
- Social Networks: Analyze connections and influence
|
||||
- Research Networks: Map collaborations and citations
|
||||
- Financial Services: Loan approvals, fraud detection, risk assessment
|
||||
- Healthcare: Treatment decisions, policy compliance, clinical pathways
|
||||
- Legal: Case precedent analysis, decision consistency
|
||||
- Business: Workflow decisions, policy compliance, audit trails
|
||||
"""
|
||||
|
||||
from collections import defaultdict, deque
|
||||
@@ -136,9 +168,16 @@ class ContextEdge:
|
||||
|
||||
class ContextGraph:
|
||||
"""
|
||||
In-memory implementation of context graph.
|
||||
|
||||
Provides capabilities to build, store, and query a context graph.
|
||||
Easy-to-Use Context Graph with All Advanced Features.
|
||||
|
||||
This class provides simple methods for:
|
||||
- Building knowledge graphs
|
||||
- Recording and analyzing decisions
|
||||
- Finding precedents and patterns
|
||||
- Causal analysis and policy enforcement
|
||||
- Advanced graph analytics
|
||||
|
||||
Perfect for building intelligent AI agents that can learn from decisions!
|
||||
"""
|
||||
|
||||
def __init__(self, config: Optional[Dict[str, Any]] = None, **kwargs):
|
||||
@@ -151,10 +190,10 @@ class ContextGraph:
|
||||
- extract_entities: Extract entities from content (default: True)
|
||||
- extract_relationships: Extract relationships (default: True)
|
||||
- entity_linker: Entity linker instance
|
||||
- enable_advanced_analytics: Enable KG algorithms (default: True)
|
||||
- enable_centrality_analysis: Enable centrality measures (default: True)
|
||||
- enable_community_detection: Enable community detection (default: True)
|
||||
- enable_node_embeddings: Enable Node2Vec embeddings (default: True)
|
||||
- advanced_analytics: Enable KG algorithms (default: True)
|
||||
- centrality_analysis: Enable centrality measures (default: True)
|
||||
- community_detection: Enable community detection (default: True)
|
||||
- node_embeddings: Enable Node2Vec embeddings (default: True)
|
||||
"""
|
||||
self.logger = get_logger("context_graph")
|
||||
self.config = config or {}
|
||||
@@ -186,15 +225,15 @@ class ContextGraph:
|
||||
self.kg_components = {}
|
||||
self._analytics_cache = {}
|
||||
|
||||
enable_advanced = self.config.get("enable_advanced_analytics", True)
|
||||
enable_advanced = self.config.get("advanced_analytics", True)
|
||||
|
||||
if KG_AVAILABLE and enable_advanced:
|
||||
try:
|
||||
if self.config.get("enable_centrality_analysis", True):
|
||||
if self.config.get("centrality_analysis", True):
|
||||
self.kg_components["centrality_calculator"] = CentralityCalculator()
|
||||
if self.config.get("enable_community_detection", True):
|
||||
if self.config.get("community_detection", True):
|
||||
self.kg_components["community_detector"] = CommunityDetector()
|
||||
if self.config.get("enable_node_embeddings", True):
|
||||
if self.config.get("node_embeddings", True):
|
||||
self.kg_components["node_embedder"] = NodeEmbedder()
|
||||
self.kg_components["path_finder"] = PathFinder()
|
||||
self.kg_components["similarity_calculator"] = SimilarityCalculator()
|
||||
@@ -1146,7 +1185,7 @@ class ContextGraph:
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to analyze graph with KG: {e}")
|
||||
return {"error": str(e)}
|
||||
return {"error": "Graph analysis failed due to an internal error"}
|
||||
|
||||
def get_node_centrality(self, node_id: str) -> Dict[str, float]:
|
||||
"""
|
||||
@@ -1183,7 +1222,7 @@ class ContextGraph:
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to get node centrality: {e}")
|
||||
return {"error": str(e)}
|
||||
return {"error": "Node centrality calculation failed due to an internal error"}
|
||||
|
||||
def find_similar_nodes(
|
||||
self, node_id: str, similarity_type: str = "content", top_k: int = 10
|
||||
@@ -1329,6 +1368,834 @@ class ContextGraph:
|
||||
union = words1.union(words2)
|
||||
|
||||
return len(intersection) / len(union) if union else 0.0
|
||||
|
||||
# --- Comprehensive Decision Management Features ---
|
||||
|
||||
def record_decision(
|
||||
self,
|
||||
category: str,
|
||||
scenario: str,
|
||||
reasoning: str,
|
||||
outcome: str,
|
||||
confidence: float,
|
||||
entities: Optional[List[str]] = None,
|
||||
decision_maker: Optional[str] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
**kwargs
|
||||
) -> str:
|
||||
"""
|
||||
Record a decision with full context and analytics.
|
||||
|
||||
Args:
|
||||
category: Decision category (e.g., "loan_approval")
|
||||
scenario: Decision scenario description
|
||||
reasoning: Decision reasoning explanation
|
||||
outcome: Decision outcome
|
||||
confidence: Confidence score (0.0 to 1.0)
|
||||
entities: Related entities
|
||||
decision_maker: Who made the decision
|
||||
metadata: Additional metadata
|
||||
**kwargs: Additional decision data
|
||||
|
||||
Returns:
|
||||
Decision ID for reference
|
||||
"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
# Input validation
|
||||
if not isinstance(category, str) or not category.strip():
|
||||
raise ValueError("Category must be a non-empty string")
|
||||
if len(category.strip()) > 100:
|
||||
raise ValueError("Category must be 100 characters or less")
|
||||
|
||||
if not isinstance(scenario, str) or not scenario.strip():
|
||||
raise ValueError("Scenario must be a non-empty string")
|
||||
if len(scenario.strip()) > 5000:
|
||||
raise ValueError("Scenario must be 5000 characters or less")
|
||||
|
||||
if not isinstance(reasoning, str) or not reasoning.strip():
|
||||
raise ValueError("Reasoning must be a non-empty string")
|
||||
if len(reasoning.strip()) > 10000:
|
||||
raise ValueError("Reasoning must be 10000 characters or less")
|
||||
|
||||
if not isinstance(outcome, str) or not outcome.strip():
|
||||
raise ValueError("Outcome must be a non-empty string")
|
||||
if len(outcome.strip()) > 1000:
|
||||
raise ValueError("Outcome must be 1000 characters or less")
|
||||
|
||||
if not isinstance(confidence, (int, float)):
|
||||
raise ValueError("Confidence must be a number")
|
||||
if not (0.0 <= confidence <= 1.0):
|
||||
raise ValueError("Confidence must be between 0.0 and 1.0")
|
||||
|
||||
if entities is not None:
|
||||
if not isinstance(entities, list):
|
||||
raise ValueError("Entities must be a list of strings")
|
||||
for entity in entities:
|
||||
if not isinstance(entity, str) or not entity.strip():
|
||||
raise ValueError("Each entity must be a non-empty string")
|
||||
if len(entity.strip()) > 200:
|
||||
raise ValueError("Each entity must be 200 characters or less")
|
||||
|
||||
if decision_maker is not None:
|
||||
if not isinstance(decision_maker, str) or not decision_maker.strip():
|
||||
raise ValueError("Decision maker must be a non-empty string")
|
||||
if len(decision_maker.strip()) > 200:
|
||||
raise ValueError("Decision maker must be 200 characters or less")
|
||||
|
||||
if metadata is not None:
|
||||
if not isinstance(metadata, dict):
|
||||
raise ValueError("Metadata must be a dictionary")
|
||||
for key, value in metadata.items():
|
||||
if not isinstance(key, str) or not key.strip():
|
||||
raise ValueError("Metadata keys must be non-empty strings")
|
||||
if len(key.strip()) > 100:
|
||||
raise ValueError("Metadata keys must be 100 characters or less")
|
||||
if len(str(value)) > 1000:
|
||||
raise ValueError("Metadata values must be 1000 characters or less")
|
||||
|
||||
# Validate kwargs
|
||||
for key, value in kwargs.items():
|
||||
if not isinstance(key, str) or not key.strip():
|
||||
raise ValueError("Additional field names must be non-empty strings")
|
||||
if len(key.strip()) > 100:
|
||||
raise ValueError("Additional field names must be 100 characters or less")
|
||||
if len(str(value)) > 1000:
|
||||
raise ValueError("Additional field values must be 1000 characters or less")
|
||||
|
||||
decision_id = str(uuid.uuid4())
|
||||
timestamp = datetime.now().timestamp()
|
||||
|
||||
# Sanitize inputs
|
||||
category = category.strip()
|
||||
scenario = scenario.strip()
|
||||
reasoning = reasoning.strip()
|
||||
outcome = outcome.strip()
|
||||
confidence = float(confidence)
|
||||
entities = [entity.strip() for entity in (entities or []) if entity.strip()]
|
||||
decision_maker = decision_maker.strip() if decision_maker else None
|
||||
|
||||
# Create decision record
|
||||
decision = {
|
||||
"id": decision_id,
|
||||
"category": category,
|
||||
"scenario": scenario,
|
||||
"reasoning": reasoning,
|
||||
"outcome": outcome,
|
||||
"confidence": confidence,
|
||||
"entities": entities,
|
||||
"decision_maker": decision_maker,
|
||||
"timestamp": timestamp,
|
||||
"metadata": metadata or {},
|
||||
**kwargs
|
||||
}
|
||||
|
||||
# Store decision in graph
|
||||
self._add_decision_to_graph(decision)
|
||||
|
||||
# Store in internal decision storage
|
||||
if not hasattr(self, '_decisions'):
|
||||
self._decisions = {}
|
||||
self._decision_index = defaultdict(set)
|
||||
self._entity_index = defaultdict(set)
|
||||
self._temporal_index = []
|
||||
|
||||
self._decisions[decision_id] = decision
|
||||
self._decision_index[category].add(decision_id)
|
||||
|
||||
for entity in entities or []:
|
||||
self._entity_index[entity].add(decision_id)
|
||||
|
||||
self._temporal_index.append((decision_id, timestamp))
|
||||
self._temporal_index.sort(key=lambda x: x[1], reverse=True)
|
||||
|
||||
self.logger.info(f"Recorded decision {decision_id} in category {category}")
|
||||
return decision_id
|
||||
|
||||
def find_precedents(
|
||||
self,
|
||||
scenario: str,
|
||||
category: Optional[str] = None,
|
||||
limit: int = 10,
|
||||
similarity_threshold: float = 0.5,
|
||||
use_semantic_search: bool = True,
|
||||
**filters
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Find similar decisions (precedents) using hybrid search.
|
||||
|
||||
Args:
|
||||
scenario: Scenario to find precedents for
|
||||
category: Filter by decision category
|
||||
limit: Maximum number of precedents
|
||||
similarity_threshold: Minimum similarity score
|
||||
use_semantic_search: Use vector embeddings for search
|
||||
**filters: Additional filters
|
||||
|
||||
Returns:
|
||||
List of similar decisions with similarity scores
|
||||
"""
|
||||
if not hasattr(self, '_decisions') or not self._decisions:
|
||||
return []
|
||||
|
||||
candidates = set()
|
||||
|
||||
# Get candidates by category
|
||||
if category:
|
||||
candidates.update(self._decision_index.get(category, set()))
|
||||
else:
|
||||
candidates.update(self._decisions.keys())
|
||||
|
||||
# Filter by entities if provided
|
||||
if "entities" in filters:
|
||||
entity_candidates = set()
|
||||
for entity in filters["entities"]:
|
||||
entity_candidates.update(self._entity_index.get(entity, set()))
|
||||
candidates = candidates.intersection(entity_candidates)
|
||||
|
||||
# Calculate similarities
|
||||
precedents = []
|
||||
for decision_id in candidates:
|
||||
decision = self._decisions[decision_id]
|
||||
|
||||
# Content similarity
|
||||
content_sim = self._calculate_decision_content_similarity(scenario, decision)
|
||||
|
||||
# Structural similarity (graph-based)
|
||||
structural_sim = 0.0
|
||||
if self.config.get("advanced_analytics"):
|
||||
structural_sim = self._calculate_structural_similarity_for_decision(decision_id, scenario)
|
||||
|
||||
# Combined similarity
|
||||
combined_sim = 0.7 * content_sim + 0.3 * structural_sim
|
||||
|
||||
if combined_sim >= similarity_threshold:
|
||||
precedents.append({
|
||||
"decision": decision,
|
||||
"similarity": combined_sim,
|
||||
"content_similarity": content_sim,
|
||||
"structural_similarity": structural_sim
|
||||
})
|
||||
|
||||
# Sort by similarity and limit
|
||||
precedents.sort(key=lambda x: x["similarity"], reverse=True)
|
||||
return precedents[:limit]
|
||||
|
||||
def analyze_decision_influence(
|
||||
self,
|
||||
decision_id: str,
|
||||
max_depth: int = 3,
|
||||
include_indirect: bool = True
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Analyze decision influence and impact.
|
||||
|
||||
Args:
|
||||
decision_id: Decision to analyze
|
||||
max_depth: Maximum depth for influence analysis
|
||||
include_indirect: Include indirect influences
|
||||
|
||||
Returns:
|
||||
Influence analysis results
|
||||
"""
|
||||
if not hasattr(self, '_decisions') or decision_id not in self._decisions:
|
||||
raise ValueError(f"Decision {decision_id} not found")
|
||||
|
||||
decision = self._decisions[decision_id]
|
||||
|
||||
# Direct influence (same entities, category)
|
||||
direct_influence = set()
|
||||
for entity in decision["entities"]:
|
||||
direct_influence.update(self._entity_index.get(entity, set()))
|
||||
direct_influence.discard(decision_id)
|
||||
direct_influence.update(self._decision_index.get(decision["category"], set()))
|
||||
direct_influence.discard(decision_id)
|
||||
|
||||
# Indirect influence (through graph relationships)
|
||||
indirect_influence = set()
|
||||
if include_indirect and self.config.get("advanced_analytics"):
|
||||
indirect_influence = self._find_indirect_decision_influence(decision_id, max_depth)
|
||||
|
||||
# Calculate influence scores
|
||||
influence_scores = {}
|
||||
for influenced_id in direct_influence | indirect_influence:
|
||||
score = self._calculate_decision_influence_score(decision_id, influenced_id)
|
||||
influence_scores[influenced_id] = score
|
||||
|
||||
# Sort by influence score
|
||||
sorted_influence = sorted(
|
||||
influence_scores.items(),
|
||||
key=lambda x: x[1],
|
||||
reverse=True
|
||||
)
|
||||
|
||||
return {
|
||||
"decision_id": decision_id,
|
||||
"direct_influence": list(direct_influence),
|
||||
"indirect_influence": list(indirect_influence),
|
||||
"influence_scores": sorted_influence,
|
||||
"total_influenced": len(influence_scores),
|
||||
"max_influence_score": max(influence_scores.values()) if influence_scores else 0.0
|
||||
}
|
||||
|
||||
def get_decision_insights(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get comprehensive insights about all decisions.
|
||||
|
||||
Returns:
|
||||
Comprehensive analytics and insights
|
||||
"""
|
||||
if not hasattr(self, '_decisions') or not self._decisions:
|
||||
return {"message": "No decisions recorded yet"}
|
||||
|
||||
# Basic statistics
|
||||
total_decisions = len(self._decisions)
|
||||
categories = {}
|
||||
outcomes = {}
|
||||
confidence_scores = []
|
||||
|
||||
for decision in self._decisions.values():
|
||||
# Category distribution
|
||||
categories[decision["category"]] = categories.get(decision["category"], 0) + 1
|
||||
|
||||
# Outcome distribution
|
||||
outcomes[decision["outcome"]] = outcomes.get(decision["outcome"], 0) + 1
|
||||
|
||||
# Confidence scores
|
||||
confidence_scores.append(decision["confidence"])
|
||||
|
||||
# Advanced analytics (if available)
|
||||
advanced_insights = {}
|
||||
if self.config.get("advanced_analytics"):
|
||||
advanced_insights = self.analyze_graph_with_kg()
|
||||
|
||||
# Temporal analysis
|
||||
temporal_insights = self._get_decision_temporal_analysis()
|
||||
|
||||
# Entity analysis
|
||||
entity_insights = self._get_decision_entity_analysis()
|
||||
|
||||
return {
|
||||
"total_decisions": total_decisions,
|
||||
"categories": categories,
|
||||
"outcomes": outcomes,
|
||||
"confidence_stats": {
|
||||
"mean": sum(confidence_scores) / len(confidence_scores),
|
||||
"min": min(confidence_scores),
|
||||
"max": max(confidence_scores),
|
||||
"median": sorted(confidence_scores)[len(confidence_scores) // 2]
|
||||
},
|
||||
"advanced_analytics": advanced_insights,
|
||||
"temporal_analysis": temporal_insights,
|
||||
"entity_analysis": entity_insights,
|
||||
"graph_metrics": self.get_graph_metrics() if hasattr(self, 'get_graph_metrics') else {}
|
||||
}
|
||||
|
||||
def trace_decision_causality(
|
||||
self,
|
||||
decision_id: str,
|
||||
max_depth: int = 5
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Trace causal chain for a decision.
|
||||
|
||||
Args:
|
||||
decision_id: Decision to trace
|
||||
max_depth: Maximum depth for causal analysis
|
||||
|
||||
Returns:
|
||||
Causal chain as list of decision relationships
|
||||
"""
|
||||
if not hasattr(self, '_decisions') or decision_id not in self._decisions:
|
||||
raise ValueError(f"Decision {decision_id} not found")
|
||||
|
||||
try:
|
||||
# Use graph traversal to find causal relationships
|
||||
causal_chain = []
|
||||
visited = set()
|
||||
|
||||
def trace_recursive(current_id, depth, path):
|
||||
if depth >= max_depth or current_id in visited:
|
||||
return
|
||||
|
||||
visited.add(current_id)
|
||||
current_decision = self._decisions[current_id]
|
||||
|
||||
# Find potential causes (decisions that influenced this one)
|
||||
potential_causes = []
|
||||
for entity in current_decision["entities"]:
|
||||
for other_decision_id in self._entity_index.get(entity, set()):
|
||||
if other_decision_id != current_id:
|
||||
other_decision = self._decisions[other_decision_id]
|
||||
if other_decision["timestamp"] < current_decision["timestamp"]:
|
||||
potential_causes.append(other_decision_id)
|
||||
|
||||
for cause_id in potential_causes:
|
||||
cause_path = path + [{"from": cause_id, "to": current_id, "type": "influences"}]
|
||||
causal_chain.append(cause_path)
|
||||
trace_recursive(cause_id, depth + 1, cause_path)
|
||||
|
||||
trace_recursive(decision_id, 0, [])
|
||||
return causal_chain
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Causal analysis failed: {e}")
|
||||
return [{"error": "Causal analysis failed due to an internal error"}]
|
||||
|
||||
def enforce_decision_policy(
|
||||
self,
|
||||
decision_data: Dict[str, Any],
|
||||
policy_rules: Optional[Dict[str, Any]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Enforce policies on decision data.
|
||||
|
||||
Args:
|
||||
decision_data: Decision data to check
|
||||
policy_rules: Policy rules to enforce
|
||||
|
||||
Returns:
|
||||
Policy enforcement results
|
||||
"""
|
||||
# Simple policy enforcement implementation
|
||||
violations = []
|
||||
warnings = []
|
||||
|
||||
# Default policy rules
|
||||
default_rules = {
|
||||
"min_confidence": 0.7,
|
||||
"required_outcomes": ["approved", "rejected", "flagged"],
|
||||
"required_metadata": ["decision_maker"],
|
||||
"max_reasoning_length": 1000
|
||||
}
|
||||
|
||||
rules = policy_rules or default_rules
|
||||
|
||||
# Check confidence
|
||||
if decision_data.get("confidence", 0) < rules.get("min_confidence", 0.7):
|
||||
violations.append(f"Confidence too low: {decision_data.get('confidence', 0)}")
|
||||
|
||||
# Check outcome
|
||||
if decision_data.get("outcome") not in rules.get("required_outcomes", []):
|
||||
violations.append(f"Invalid outcome: {decision_data.get('outcome')}")
|
||||
|
||||
# Check required metadata
|
||||
for required_field in rules.get("required_metadata", []):
|
||||
if not decision_data.get(required_field):
|
||||
violations.append(f"Missing required field: {required_field}")
|
||||
|
||||
# Check reasoning length
|
||||
reasoning = decision_data.get("reasoning", "")
|
||||
if len(reasoning) > rules.get("max_reasoning_length", 1000):
|
||||
warnings.append(f"Reasoning too long: {len(reasoning)} characters")
|
||||
|
||||
return {
|
||||
"compliant": len(violations) == 0,
|
||||
"violations": violations,
|
||||
"warnings": warnings,
|
||||
"policy_rules": rules
|
||||
}
|
||||
|
||||
# --- Private helper methods for decision management ---
|
||||
|
||||
def _add_decision_to_graph(self, decision: Dict[str, Any]) -> None:
|
||||
"""Add decision to context graph."""
|
||||
try:
|
||||
# Add decision node
|
||||
self.add_node(
|
||||
decision["id"],
|
||||
"decision",
|
||||
category=decision["category"],
|
||||
outcome=decision["outcome"],
|
||||
confidence=decision["confidence"],
|
||||
timestamp=decision["timestamp"],
|
||||
scenario=decision["scenario"][:100] + "..." if len(decision["scenario"]) > 100 else decision["scenario"],
|
||||
decision_maker=decision.get("decision_maker", ""),
|
||||
reasoning=decision["reasoning"][:200] + "..." if len(decision["reasoning"]) > 200 else decision["reasoning"]
|
||||
)
|
||||
|
||||
# Add entity nodes and relationships
|
||||
for entity in decision["entities"]:
|
||||
# Add entity node if not exists
|
||||
if not self.find_node(entity):
|
||||
self.add_node(
|
||||
entity,
|
||||
"entity",
|
||||
name=entity
|
||||
)
|
||||
|
||||
# Add relationship
|
||||
self.add_edge(
|
||||
decision["id"],
|
||||
entity,
|
||||
"involves",
|
||||
confidence=decision["confidence"]
|
||||
)
|
||||
|
||||
# Add category node and relationship
|
||||
category_id = f"category_{decision['category']}"
|
||||
if not self.find_node(category_id):
|
||||
self.add_node(
|
||||
category_id,
|
||||
"category",
|
||||
name=decision["category"]
|
||||
)
|
||||
|
||||
self.add_edge(
|
||||
decision["id"],
|
||||
category_id,
|
||||
"belongs_to"
|
||||
)
|
||||
|
||||
# Add decision maker node if provided
|
||||
if decision.get("decision_maker"):
|
||||
maker_id = f"maker_{decision['decision_maker']}"
|
||||
if not self.find_node(maker_id):
|
||||
self.add_node(
|
||||
maker_id,
|
||||
"decision_maker",
|
||||
name=decision["decision_maker"]
|
||||
)
|
||||
|
||||
self.add_edge(
|
||||
decision["id"],
|
||||
maker_id,
|
||||
"made_by"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.logger.exception("Failed to add decision to graph")
|
||||
|
||||
def _calculate_decision_content_similarity(self, scenario: str, decision: Dict[str, Any]) -> float:
|
||||
"""Calculate content similarity between scenario and decision."""
|
||||
try:
|
||||
# Simple word-based similarity
|
||||
scenario_words = set(scenario.lower().split())
|
||||
decision_text = f"{decision['scenario']} {decision['reasoning']} {' '.join(decision['entities'])}"
|
||||
decision_words = set(decision_text.lower().split())
|
||||
|
||||
intersection = scenario_words.intersection(decision_words)
|
||||
union = scenario_words.union(decision_words)
|
||||
|
||||
return len(intersection) / len(union) if union else 0.0
|
||||
|
||||
except Exception as e:
|
||||
self.logger.exception("Content similarity calculation failed")
|
||||
return 0.0
|
||||
|
||||
def _calculate_structural_similarity_for_decision(self, decision_id: str, scenario: str) -> float:
|
||||
"""Calculate structural similarity using graph algorithms."""
|
||||
try:
|
||||
if not self.config.get("advanced_analytics"):
|
||||
return 0.0
|
||||
|
||||
# Use graph similarity algorithms
|
||||
similar_nodes = self.find_similar_nodes(
|
||||
decision_id,
|
||||
similarity_type="structural",
|
||||
top_k=5
|
||||
)
|
||||
|
||||
if similar_nodes:
|
||||
# similar_nodes is List[Tuple[str, float]], extract similarity scores
|
||||
return max(similarity for node_id, similarity in similar_nodes)
|
||||
|
||||
except Exception as e:
|
||||
self.logger.exception("Structural similarity calculation failed")
|
||||
|
||||
return 0.0
|
||||
|
||||
def _find_indirect_decision_influence(self, decision_id: str, max_depth: int) -> Set[str]:
|
||||
"""Find indirect influences using graph traversal."""
|
||||
try:
|
||||
influenced = set()
|
||||
|
||||
# Get neighbors in graph
|
||||
neighbors = self.get_neighbors(decision_id, hops=max_depth)
|
||||
|
||||
for neighbor in neighbors:
|
||||
if neighbor.get("type") == "decision":
|
||||
influenced.add(neighbor["id"])
|
||||
|
||||
return influenced
|
||||
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Indirect influence analysis failed: {e}")
|
||||
return set()
|
||||
|
||||
def _calculate_decision_influence_score(self, source_id: str, target_id: str) -> float:
|
||||
"""Calculate influence score between two decisions."""
|
||||
try:
|
||||
if not hasattr(self, '_decisions'):
|
||||
return 0.0
|
||||
|
||||
source_decision = self._decisions[source_id]
|
||||
target_decision = self._decisions[target_id]
|
||||
|
||||
# Base score from shared entities
|
||||
shared_entities = set(source_decision["entities"]) & set(target_decision["entities"])
|
||||
entity_score = len(shared_entities) / max(len(source_decision["entities"]), 1)
|
||||
|
||||
# Category similarity
|
||||
category_score = 1.0 if source_decision["category"] == target_decision["category"] else 0.0
|
||||
|
||||
# Temporal proximity (more recent decisions have higher influence)
|
||||
time_diff = abs(source_decision["timestamp"] - target_decision["timestamp"])
|
||||
time_score = max(0.0, 1.0 - time_diff / (30 * 24 * 3600)) # 30 days window
|
||||
|
||||
# Combined score
|
||||
combined_score = 0.5 * entity_score + 0.3 * category_score + 0.2 * time_score
|
||||
|
||||
return combined_score
|
||||
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Influence score calculation failed: {e}")
|
||||
return 0.0
|
||||
|
||||
def _get_decision_temporal_analysis(self) -> Dict[str, Any]:
|
||||
"""Get temporal analysis of decisions."""
|
||||
try:
|
||||
if not hasattr(self, '_temporal_index') or not self._temporal_index:
|
||||
return {}
|
||||
|
||||
# Group decisions by time periods
|
||||
recent_decisions = [did for did, ts in self._temporal_index[:10]]
|
||||
|
||||
return {
|
||||
"recent_decisions": len(recent_decisions),
|
||||
"oldest_decision": min(ts for _, ts in self._temporal_index),
|
||||
"newest_decision": max(ts for _, ts in self._temporal_index),
|
||||
"time_span": max(ts for _, ts in self._temporal_index) - min(ts for _, ts in self._temporal_index)
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Temporal analysis failed: {e}")
|
||||
return {}
|
||||
|
||||
def _get_decision_entity_analysis(self) -> Dict[str, Any]:
|
||||
"""Get entity analysis from decisions."""
|
||||
try:
|
||||
if not hasattr(self, '_decisions'):
|
||||
return {}
|
||||
|
||||
entity_counts = {}
|
||||
for decision in self._decisions.values():
|
||||
for entity in decision["entities"]:
|
||||
entity_counts[entity] = entity_counts.get(entity, 0) + 1
|
||||
|
||||
# Get top entities
|
||||
top_entities = sorted(entity_counts.items(), key=lambda x: x[1], reverse=True)[:10]
|
||||
|
||||
return {
|
||||
"total_entities": len(entity_counts),
|
||||
"top_entities": top_entities,
|
||||
"avg_entities_per_decision": sum(len(d["entities"]) for d in self._decisions.values()) / len(self._decisions)
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Entity analysis failed: {e}")
|
||||
return {}
|
||||
|
||||
# --- Easy-to-Use Convenience Methods ---
|
||||
|
||||
def add_decision(
|
||||
self,
|
||||
category: str,
|
||||
scenario: str,
|
||||
reasoning: str,
|
||||
outcome: str,
|
||||
confidence: float = 0.5,
|
||||
entities: Optional[List[str]] = None,
|
||||
decision_maker: Optional[str] = "system",
|
||||
**kwargs
|
||||
) -> str:
|
||||
"""
|
||||
Easy way to record a decision.
|
||||
|
||||
Args:
|
||||
category: Decision category (e.g., "loan_approval")
|
||||
scenario: What was the situation
|
||||
reasoning: Why was this decision made
|
||||
outcome: What was decided
|
||||
confidence: How confident (0.0 to 1.0)
|
||||
entities: Related entities (people, items, etc.)
|
||||
decision_maker: Who made the decision
|
||||
**kwargs: Additional information
|
||||
|
||||
Returns:
|
||||
Decision ID for reference
|
||||
"""
|
||||
return self.record_decision(
|
||||
category=category,
|
||||
scenario=scenario,
|
||||
reasoning=reasoning,
|
||||
outcome=outcome,
|
||||
confidence=confidence,
|
||||
entities=entities,
|
||||
decision_maker=decision_maker,
|
||||
metadata=kwargs
|
||||
)
|
||||
|
||||
def find_similar_decisions(
|
||||
self,
|
||||
scenario: str,
|
||||
category: Optional[str] = None,
|
||||
max_results: int = 10,
|
||||
min_similarity: float = 0.3
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Easy way to find similar past decisions.
|
||||
|
||||
Args:
|
||||
scenario: What situation are you looking for
|
||||
category: Filter by decision type
|
||||
max_results: Maximum results to return
|
||||
min_similarity: Minimum similarity score
|
||||
|
||||
Returns:
|
||||
List of similar decisions with similarity scores
|
||||
"""
|
||||
return self.find_precedents(
|
||||
scenario=scenario,
|
||||
category=category,
|
||||
limit=max_results,
|
||||
similarity_threshold=min_similarity
|
||||
)
|
||||
|
||||
def analyze_decision_impact(
|
||||
self,
|
||||
decision_id: str,
|
||||
include_indirect: bool = True
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Easy way to analyze how a decision impacts others.
|
||||
|
||||
Args:
|
||||
decision_id: Decision to analyze
|
||||
include_indirect: Include indirect impacts
|
||||
|
||||
Returns:
|
||||
Impact analysis results
|
||||
"""
|
||||
return self.analyze_decision_influence(
|
||||
decision_id=decision_id,
|
||||
max_depth=3,
|
||||
include_indirect=include_indirect
|
||||
)
|
||||
|
||||
def get_decision_summary(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Easy way to get a summary of all decisions.
|
||||
|
||||
Returns:
|
||||
Summary statistics and insights
|
||||
"""
|
||||
return self.get_decision_insights()
|
||||
|
||||
def trace_decision_chain(
|
||||
self,
|
||||
decision_id: str,
|
||||
max_steps: int = 5
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Easy way to trace how decisions are connected.
|
||||
|
||||
Args:
|
||||
decision_id: Starting decision
|
||||
max_steps: Maximum steps to trace
|
||||
|
||||
Returns:
|
||||
Decision chain connections
|
||||
"""
|
||||
return self.trace_decision_causality(
|
||||
decision_id=decision_id,
|
||||
max_depth=max_steps
|
||||
)
|
||||
|
||||
def check_decision_rules(
|
||||
self,
|
||||
decision_data: Dict[str, Any],
|
||||
rules: Optional[Dict[str, Any]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Easy way to check if a decision follows the rules.
|
||||
|
||||
Args:
|
||||
decision_data: Decision to check
|
||||
rules: Custom rules (uses default if None)
|
||||
|
||||
Returns:
|
||||
Compliance check results
|
||||
"""
|
||||
return self.enforce_decision_policy(
|
||||
decision_data=decision_data,
|
||||
policy_rules=rules
|
||||
)
|
||||
|
||||
def get_graph_summary(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Easy way to get graph statistics.
|
||||
|
||||
Returns:
|
||||
Graph summary information
|
||||
"""
|
||||
if hasattr(self, 'get_graph_metrics'):
|
||||
return self.get_graph_metrics()
|
||||
else:
|
||||
return {
|
||||
"nodes": len(self.nodes),
|
||||
"edges": len(self.edges),
|
||||
"node_types": self._get_node_type_distribution(),
|
||||
"edge_types": self._get_edge_type_distribution()
|
||||
}
|
||||
|
||||
def find_related_nodes(
|
||||
self,
|
||||
node_id: str,
|
||||
how_many: int = 10,
|
||||
similarity_type: str = "content"
|
||||
) -> List[Tuple[str, float]]:
|
||||
"""
|
||||
Easy way to find nodes similar to a given node.
|
||||
|
||||
Args:
|
||||
node_id: Reference node
|
||||
how_many: How many similar nodes to find
|
||||
similarity_type: Type of similarity ("content", "structural")
|
||||
|
||||
Returns:
|
||||
List of (node_id, similarity_score) tuples
|
||||
"""
|
||||
return self.find_similar_nodes(
|
||||
node_id=node_id,
|
||||
similarity_type=similarity_type,
|
||||
top_k=how_many
|
||||
)
|
||||
|
||||
def get_node_importance(
|
||||
self,
|
||||
node_id: str
|
||||
) -> Dict[str, float]:
|
||||
"""
|
||||
Easy way to get how important a node is in the graph.
|
||||
|
||||
Args:
|
||||
node_id: Node to analyze
|
||||
|
||||
Returns:
|
||||
Centrality measures (importance scores)
|
||||
"""
|
||||
return self.get_node_centrality(node_id)
|
||||
|
||||
def analyze_connections(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Easy way to analyze the entire graph structure.
|
||||
|
||||
Returns:
|
||||
Graph analysis results
|
||||
"""
|
||||
return self.analyze_graph_with_kg()
|
||||
|
||||
|
||||
# For backward compatibility
|
||||
|
||||
+351
-1155
File diff suppressed because it is too large
Load Diff
@@ -549,7 +549,7 @@ def enhance_agent_context_with_decisions(agent_context: AgentContext) -> None:
|
||||
logger = get_logger(__name__)
|
||||
|
||||
try:
|
||||
if not agent_context.config.get("enable_decision_tracking"):
|
||||
if not agent_context.config.get("decision_tracking"):
|
||||
logger.warning("Decision tracking not enabled in AgentContext")
|
||||
return
|
||||
|
||||
|
||||
@@ -55,10 +55,10 @@ Search Capabilities:
|
||||
Example Usage:
|
||||
>>> from semantica.context import DecisionQuery
|
||||
>>> query = DecisionQuery(graph_store=kg, vector_store=vs,
|
||||
... enable_advanced_analytics=True,
|
||||
... enable_centrality_analysis=True,
|
||||
... enable_community_detection=True,
|
||||
... enable_node_embeddings=True)
|
||||
... advanced_analytics=True,
|
||||
... centrality_analysis=True,
|
||||
... community_detection=True,
|
||||
... node_embeddings=True)
|
||||
>>> precedents = query.find_precedents_hybrid("Loan application",
|
||||
... category="approval",
|
||||
... limit=10)
|
||||
@@ -111,11 +111,11 @@ class DecisionQuery:
|
||||
graph_store: GraphStore,
|
||||
embedding_generator: Optional[EmbeddingGenerator] = None,
|
||||
vector_store: Optional[Any] = None,
|
||||
enable_advanced_analytics: bool = True,
|
||||
enable_node_embeddings: bool = True,
|
||||
enable_centrality_analysis: bool = True,
|
||||
enable_community_detection: bool = True,
|
||||
enable_link_prediction: bool = True
|
||||
advanced_analytics: bool = True,
|
||||
node_embeddings: bool = True,
|
||||
centrality_analysis: bool = True,
|
||||
community_detection: bool = True,
|
||||
link_prediction: bool = True
|
||||
):
|
||||
"""
|
||||
Initialize DecisionQuery with optional advanced features.
|
||||
@@ -124,11 +124,11 @@ class DecisionQuery:
|
||||
graph_store: Graph database instance
|
||||
embedding_generator: Optional embedding generator for semantic search
|
||||
vector_store: Optional vector store for hybrid search
|
||||
enable_advanced_analytics: Enable advanced graph analytics (requires semantica.kg)
|
||||
enable_node_embeddings: Enable Node2Vec embeddings (requires semantica.kg)
|
||||
enable_centrality_analysis: Enable centrality measures (requires semantica.kg)
|
||||
enable_community_detection: Enable community detection (requires semantica.kg)
|
||||
enable_link_prediction: Enable link prediction (requires semantica.kg)
|
||||
advanced_analytics: Enable advanced graph analytics (requires semantica.kg)
|
||||
node_embeddings: Enable Node2Vec embeddings (requires semantica.kg)
|
||||
centrality_analysis: Enable centrality measures (requires semantica.kg)
|
||||
community_detection: Enable community detection (requires semantica.kg)
|
||||
link_prediction: Enable link prediction (requires semantica.kg)
|
||||
"""
|
||||
self.graph_store = graph_store
|
||||
self.embedding_generator = embedding_generator
|
||||
@@ -139,17 +139,17 @@ class DecisionQuery:
|
||||
self.kg_components = {}
|
||||
self.vector_components = {}
|
||||
|
||||
if KG_AVAILABLE and enable_advanced_analytics:
|
||||
if KG_AVAILABLE and advanced_analytics:
|
||||
try:
|
||||
if enable_centrality_analysis:
|
||||
if centrality_analysis:
|
||||
self.kg_components["centrality_calculator"] = CentralityCalculator()
|
||||
if enable_community_detection:
|
||||
if community_detection:
|
||||
self.kg_components["community_detector"] = CommunityDetector()
|
||||
if enable_node_embeddings:
|
||||
if node_embeddings:
|
||||
self.kg_components["node_embedder"] = NodeEmbedder()
|
||||
self.kg_components["path_finder"] = PathFinder()
|
||||
self.kg_components["similarity_calculator"] = SimilarityCalculator()
|
||||
if enable_link_prediction:
|
||||
if link_prediction:
|
||||
self.kg_components["link_predictor"] = LinkPredictor()
|
||||
|
||||
self.logger.info("Advanced KG components initialized successfully")
|
||||
|
||||
@@ -149,7 +149,7 @@ class DecisionRecorder:
|
||||
return decision.decision_id
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to record decision: {e}")
|
||||
self.logger.exception("Failed to record decision")
|
||||
raise
|
||||
|
||||
def link_entities(self, decision_id: str, entities: List[str]) -> None:
|
||||
@@ -176,7 +176,7 @@ class DecisionRecorder:
|
||||
self.logger.info(f"Linked decision {decision_id} to {len(entities)} entities")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to link entities: {e}")
|
||||
self.logger.exception("Failed to link entities")
|
||||
raise
|
||||
|
||||
def apply_policies(self, decision_id: str, policy_ids: List[str]) -> None:
|
||||
@@ -204,7 +204,7 @@ class DecisionRecorder:
|
||||
self.logger.info(f"Applied {len(policy_ids)} policies to decision {decision_id}")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to apply policies: {e}")
|
||||
self.logger.exception("Failed to apply policies")
|
||||
raise
|
||||
|
||||
def record_exception(
|
||||
@@ -262,7 +262,7 @@ class DecisionRecorder:
|
||||
return exception.exception_id
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to record exception: {e}")
|
||||
self.logger.exception("Failed to record exception")
|
||||
raise
|
||||
|
||||
def capture_cross_system_context(
|
||||
@@ -302,7 +302,7 @@ class DecisionRecorder:
|
||||
self.logger.info(f"Captured cross-system context for decision {decision_id}")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to capture cross-system context: {e}")
|
||||
self.logger.exception("Failed to capture cross-system context")
|
||||
raise
|
||||
|
||||
def record_approval_chain(
|
||||
@@ -352,7 +352,7 @@ class DecisionRecorder:
|
||||
self.logger.info(f"Recorded approval chain with {len(approvers)} approvers")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to record approval chain: {e}")
|
||||
self.logger.exception("Failed to record approval chain")
|
||||
raise
|
||||
|
||||
def link_precedents(
|
||||
@@ -389,7 +389,7 @@ class DecisionRecorder:
|
||||
self.logger.info(f"Linked {len(precedent_ids)} precedents to decision {decision_id}")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to link precedents: {e}")
|
||||
self.logger.exception("Failed to link precedents")
|
||||
raise
|
||||
|
||||
def _store_decision_node(self, decision: Decision) -> None:
|
||||
@@ -502,4 +502,4 @@ class DecisionRecorder:
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Failed to track provenance: {e}")
|
||||
self.logger.exception("Failed to track provenance")
|
||||
|
||||
@@ -155,7 +155,7 @@ class PolicyEngine:
|
||||
self.logger.info(f"Added policy: {policy.policy_id} version {policy.version}")
|
||||
return policy.policy_id
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to add policy: {e}")
|
||||
self.logger.exception("Failed to add policy")
|
||||
raise
|
||||
|
||||
def update_policy(
|
||||
@@ -232,7 +232,7 @@ class PolicyEngine:
|
||||
return new_version
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to update policy: {e}")
|
||||
self.logger.exception("Failed to update policy")
|
||||
raise
|
||||
|
||||
def get_applicable_policies(
|
||||
@@ -309,7 +309,7 @@ class PolicyEngine:
|
||||
return policies
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to get applicable policies: {e}")
|
||||
self.logger.exception("Failed to get applicable policies")
|
||||
raise
|
||||
|
||||
def check_compliance(self, decision: Decision, policy_id: str) -> bool:
|
||||
@@ -348,7 +348,7 @@ class PolicyEngine:
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to check compliance: {e}")
|
||||
self.logger.exception("Failed to check compliance")
|
||||
return False
|
||||
|
||||
def record_policy_application(
|
||||
@@ -394,7 +394,7 @@ class PolicyEngine:
|
||||
)
|
||||
self.logger.info(f"Recorded policy application: {policy_id} v{version} to decision {decision_id}")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to record policy application: {e}")
|
||||
self.logger.exception("Failed to record policy application")
|
||||
raise
|
||||
|
||||
def record_exception(
|
||||
@@ -472,7 +472,7 @@ class PolicyEngine:
|
||||
self.logger.info(f"Recorded policy exception: {exception_id}")
|
||||
return exception_id
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to record exception: {e}")
|
||||
self.logger.exception("Failed to record exception")
|
||||
raise
|
||||
|
||||
def get_policy_history(self, policy_id: str) -> List[Policy]:
|
||||
@@ -527,7 +527,7 @@ class PolicyEngine:
|
||||
return versions
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to get policy history: {e}")
|
||||
self.logger.exception("Failed to get policy history")
|
||||
raise
|
||||
|
||||
def get_affected_decisions(
|
||||
@@ -578,7 +578,7 @@ class PolicyEngine:
|
||||
return decision_ids
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to get affected decisions: {e}")
|
||||
self.logger.exception("Failed to get affected decisions")
|
||||
raise
|
||||
|
||||
def analyze_policy_impact(
|
||||
@@ -679,7 +679,7 @@ class PolicyEngine:
|
||||
return impact_analysis
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to analyze policy impact: {e}")
|
||||
self.logger.exception("Failed to analyze policy impact")
|
||||
raise
|
||||
|
||||
def get_policy(self, policy_id: str, version: Optional[str] = None) -> Optional[Policy]:
|
||||
@@ -765,7 +765,7 @@ class PolicyEngine:
|
||||
"metadata": data.get("metadata", {})
|
||||
})
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to get policy: {e}")
|
||||
self.logger.exception("Failed to get policy")
|
||||
return None
|
||||
|
||||
def _generate_next_version(self, current_version: str) -> str:
|
||||
|
||||
@@ -38,7 +38,7 @@ class TestAgentContextDecisions:
|
||||
return AgentContext(
|
||||
vector_store=mock_vector_store,
|
||||
knowledge_graph=mock_knowledge_graph,
|
||||
enable_decision_tracking=True
|
||||
decision_tracking=True
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
@@ -47,7 +47,7 @@ class TestAgentContextDecisions:
|
||||
return AgentContext(
|
||||
vector_store=mock_vector_store,
|
||||
knowledge_graph=mock_knowledge_graph,
|
||||
enable_decision_tracking=False
|
||||
decision_tracking=False
|
||||
)
|
||||
|
||||
def test_agent_context_initialization_with_decisions(self, mock_vector_store, mock_knowledge_graph):
|
||||
@@ -55,10 +55,10 @@ class TestAgentContextDecisions:
|
||||
context = AgentContext(
|
||||
vector_store=mock_vector_store,
|
||||
knowledge_graph=mock_knowledge_graph,
|
||||
enable_decision_tracking=True
|
||||
decision_tracking=True
|
||||
)
|
||||
|
||||
assert context.config["enable_decision_tracking"] is True
|
||||
assert context.config["decision_tracking"] is True
|
||||
assert context._decision_recorder is not None
|
||||
assert context._decision_query is not None
|
||||
assert context._causal_analyzer is not None
|
||||
@@ -69,10 +69,10 @@ class TestAgentContextDecisions:
|
||||
context = AgentContext(
|
||||
vector_store=mock_vector_store,
|
||||
knowledge_graph=mock_knowledge_graph,
|
||||
enable_decision_tracking=False
|
||||
decision_tracking=False
|
||||
)
|
||||
|
||||
assert context.config["enable_decision_tracking"] is False
|
||||
assert context.config["decision_tracking"] is False
|
||||
assert context._decision_recorder is None
|
||||
assert context._decision_query is None
|
||||
assert context._causal_analyzer is None
|
||||
@@ -255,7 +255,7 @@ class TestAgentContextDecisions:
|
||||
knowledge_graph=mock_knowledge_graph
|
||||
)
|
||||
|
||||
assert context.config["enable_decision_tracking"] is False
|
||||
assert context.config["decision_tracking"] is False
|
||||
assert context._decision_recorder is None
|
||||
|
||||
def test_error_handling(self, agent_context_with_decisions):
|
||||
@@ -279,11 +279,11 @@ class TestAgentContextDecisions:
|
||||
context = AgentContext(
|
||||
vector_store=mock_vector_store,
|
||||
knowledge_graph=None,
|
||||
enable_decision_tracking=True
|
||||
decision_tracking=True
|
||||
)
|
||||
|
||||
# Should initialize but warn about missing knowledge graph
|
||||
assert context.config["enable_decision_tracking"] is True
|
||||
assert context.config["decision_tracking"] is True
|
||||
|
||||
def test_error_handling(self, agent_context_with_decisions):
|
||||
"""Test error handling in decision tracking."""
|
||||
|
||||
@@ -11,9 +11,9 @@ def test_agent_context_minimal_decisions_and_chain():
|
||||
ctx = AgentContext(
|
||||
vector_store=vs,
|
||||
knowledge_graph=graph,
|
||||
enable_decision_tracking=True,
|
||||
enable_kg_algorithms=False,
|
||||
enable_vector_store_features=False,
|
||||
decision_tracking=True,
|
||||
kg_algorithms=False,
|
||||
vector_store_features=False,
|
||||
)
|
||||
d1 = ctx.record_decision(
|
||||
category="credit_approval",
|
||||
@@ -45,9 +45,9 @@ def test_agent_context_policy_engine_with_graph_backend():
|
||||
ctx = AgentContext(
|
||||
vector_store=vs,
|
||||
knowledge_graph=graph,
|
||||
enable_decision_tracking=True,
|
||||
enable_kg_algorithms=False,
|
||||
enable_vector_store_features=False,
|
||||
decision_tracking=True,
|
||||
kg_algorithms=False,
|
||||
vector_store_features=False,
|
||||
)
|
||||
pe = ctx.get_policy_engine()
|
||||
pol = Policy(
|
||||
|
||||
@@ -52,10 +52,10 @@ class TestBankingDecisionSystem:
|
||||
return AgentContext(
|
||||
vector_store=mock_vector_store,
|
||||
knowledge_graph=mock_knowledge_graph,
|
||||
enable_decision_tracking=True,
|
||||
enable_advanced_analytics=True,
|
||||
enable_kg_algorithms=True,
|
||||
enable_vector_store_features=True
|
||||
decision_tracking=True,
|
||||
advanced_analytics=True,
|
||||
kg_algorithms=True,
|
||||
vector_store_features=True
|
||||
)
|
||||
|
||||
def test_banking_decision_lifecycle(self, banking_context):
|
||||
@@ -216,10 +216,10 @@ class TestBankingDecisionSystem:
|
||||
enhanced_query = DecisionQuery(
|
||||
graph_store=mock_knowledge_graph,
|
||||
vector_store=mock_vector_store,
|
||||
enable_advanced_analytics=True,
|
||||
enable_centrality_analysis=True,
|
||||
enable_community_detection=True,
|
||||
enable_node_embeddings=True
|
||||
advanced_analytics=True,
|
||||
centrality_analysis=True,
|
||||
community_detection=True,
|
||||
node_embeddings=True
|
||||
)
|
||||
|
||||
print(f"[OK] Enhanced DecisionQuery with {len(enhanced_query.kg_components)} KG components")
|
||||
@@ -240,10 +240,10 @@ class TestBankingDecisionSystem:
|
||||
|
||||
# Test enhanced ContextGraph
|
||||
enhanced_graph = ContextGraph(
|
||||
enable_advanced_analytics=True,
|
||||
enable_centrality_analysis=True,
|
||||
enable_community_detection=True,
|
||||
enable_node_embeddings=True
|
||||
advanced_analytics=True,
|
||||
centrality_analysis=True,
|
||||
community_detection=True,
|
||||
node_embeddings=True
|
||||
)
|
||||
|
||||
print(f"[OK] Enhanced ContextGraph with {len(enhanced_graph.kg_components)} KG components")
|
||||
|
||||
@@ -46,10 +46,10 @@ class TestContextGraphsExamples:
|
||||
|
||||
# Create context graph with advanced features
|
||||
graph = ContextGraph(
|
||||
enable_advanced_analytics=True,
|
||||
enable_centrality_analysis=True,
|
||||
enable_community_detection=True,
|
||||
enable_node_embeddings=True
|
||||
advanced_analytics=True,
|
||||
centrality_analysis=True,
|
||||
community_detection=True,
|
||||
node_embeddings=True
|
||||
)
|
||||
|
||||
# Add a decision
|
||||
@@ -127,10 +127,10 @@ class TestContextGraphsExamples:
|
||||
context = AgentContext(
|
||||
vector_store=mock_vector_store,
|
||||
knowledge_graph=mock_knowledge_graph,
|
||||
enable_decision_tracking=True,
|
||||
enable_advanced_analytics=True,
|
||||
enable_kg_algorithms=True,
|
||||
enable_vector_store_features=True
|
||||
decision_tracking=True,
|
||||
advanced_analytics=True,
|
||||
kg_algorithms=True,
|
||||
vector_store_features=True
|
||||
)
|
||||
|
||||
# Credit decision with precedent search
|
||||
@@ -169,10 +169,10 @@ class TestContextGraphsExamples:
|
||||
context = AgentContext(
|
||||
vector_store=mock_vector_store,
|
||||
knowledge_graph=mock_knowledge_graph,
|
||||
enable_decision_tracking=True,
|
||||
enable_advanced_analytics=True,
|
||||
enable_kg_algorithms=True,
|
||||
enable_vector_store_features=True
|
||||
decision_tracking=True,
|
||||
advanced_analytics=True,
|
||||
kg_algorithms=True,
|
||||
vector_store_features=True
|
||||
)
|
||||
|
||||
# Treatment decision with policy compliance
|
||||
@@ -216,10 +216,10 @@ class TestContextGraphsExamples:
|
||||
context = AgentContext(
|
||||
vector_store=mock_vector_store,
|
||||
knowledge_graph=mock_knowledge_graph,
|
||||
enable_decision_tracking=True,
|
||||
enable_advanced_analytics=True,
|
||||
enable_kg_algorithms=True,
|
||||
enable_vector_store_features=True
|
||||
decision_tracking=True,
|
||||
advanced_analytics=True,
|
||||
kg_algorithms=True,
|
||||
vector_store_features=True
|
||||
)
|
||||
|
||||
# Legal decision with precedent analysis
|
||||
@@ -370,21 +370,21 @@ class TestContextGraphsExamples:
|
||||
context = AgentContext(
|
||||
vector_store=mock_vector_store,
|
||||
knowledge_graph=mock_knowledge_graph,
|
||||
enable_decision_tracking=True,
|
||||
enable_advanced_analytics=True,
|
||||
enable_kg_algorithms=True,
|
||||
enable_vector_store_features=True,
|
||||
use_graph_expansion=True,
|
||||
decision_tracking=True,
|
||||
advanced_analytics=True,
|
||||
kg_algorithms=True,
|
||||
vector_store_features=True,
|
||||
graph_expansion=True,
|
||||
max_expansion_hops=3,
|
||||
hybrid_alpha=0.7
|
||||
)
|
||||
|
||||
# Verify configuration
|
||||
assert context.config["enable_decision_tracking"] is True
|
||||
assert context.config["enable_advanced_analytics"] is True
|
||||
assert context.config["enable_kg_algorithms"] is True
|
||||
assert context.config["enable_vector_store_features"] is True
|
||||
assert context.config["use_graph_expansion"] is True
|
||||
assert context.config["decision_tracking"] is True
|
||||
assert context.config["advanced_analytics"] is True
|
||||
assert context.config["kg_algorithms"] is True
|
||||
assert context.config["vector_store_features"] is True
|
||||
assert context.config["graph_expansion"] is True
|
||||
assert context.config["max_expansion_hops"] == 3
|
||||
assert context.config["hybrid_alpha"] == 0.7
|
||||
print("+ Configuration validation working")
|
||||
|
||||
@@ -118,7 +118,7 @@ class TestEndToEndContextIntegration:
|
||||
results = retriever.retrieve(
|
||||
query="Credit limit increase for business expansion",
|
||||
max_results=10,
|
||||
use_graph_expansion=True
|
||||
graph_expansion=True
|
||||
)
|
||||
print(f"✅ Retrieved {len(results)} context items")
|
||||
|
||||
@@ -286,10 +286,10 @@ class TestEndToEndContextIntegration:
|
||||
|
||||
# Test different search configurations
|
||||
search_configs = [
|
||||
{"use_graph_expansion": False, "max_results": 10},
|
||||
{"use_graph_expansion": True, "max_results": 10},
|
||||
{"use_graph_expansion": True, "max_results": 20},
|
||||
{"use_graph_expansion": False, "max_results": 20},
|
||||
{"graph_expansion": False, "max_results": 10},
|
||||
{"graph_expansion": True, "max_results": 10},
|
||||
{"graph_expansion": True, "max_results": 20},
|
||||
{"graph_expansion": False, "max_results": 20},
|
||||
]
|
||||
|
||||
for i, config in enumerate(search_configs):
|
||||
@@ -399,7 +399,7 @@ class TestEndToEndContextIntegration:
|
||||
)
|
||||
|
||||
# Should handle KG errors gracefully
|
||||
results = retriever_broken.retrieve("Test query", max_results=5, use_graph_expansion=True)
|
||||
results = retriever_broken.retrieve("Test query", max_results=5, graph_expansion=True)
|
||||
assert len(results) > 0, "Should handle KG errors gracefully"
|
||||
print("✅ Handles KG errors gracefully")
|
||||
|
||||
@@ -572,7 +572,7 @@ class TestRealWorldContextScenarios:
|
||||
context_results = retriever.retrieve(
|
||||
query="Premium customer investment and fraud assessment",
|
||||
max_results=15,
|
||||
use_graph_expansion=True
|
||||
graph_expansion=True
|
||||
)
|
||||
|
||||
print(f"✅ Retrieved {len(context_results)} context items")
|
||||
|
||||
@@ -52,10 +52,10 @@ class TestHealthcareDecisionSystem:
|
||||
return AgentContext(
|
||||
vector_store=mock_vector_store,
|
||||
knowledge_graph=mock_knowledge_graph,
|
||||
enable_decision_tracking=True,
|
||||
enable_advanced_analytics=True,
|
||||
enable_kg_algorithms=True,
|
||||
enable_vector_store_features=True
|
||||
decision_tracking=True,
|
||||
advanced_analytics=True,
|
||||
kg_algorithms=True,
|
||||
vector_store_features=True
|
||||
)
|
||||
|
||||
def test_healthcare_decision_workflow(self, healthcare_context):
|
||||
|
||||
Reference in New Issue
Block a user