Merge pull request #325 from Hawksight-AI/context

Enhanced Context Module with User-Friendly Documentation & Features
This commit is contained in:
Mohd Kaif
2026-02-16 19:40:16 +05:30
committed by GitHub
17 changed files with 2189 additions and 2319 deletions
+278 -103
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+22 -6
View File
@@ -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
+117 -94
View File
@@ -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)
}
}
+885 -18
View File
@@ -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
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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
+19 -19
View File
@@ -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")
+8 -8
View File
@@ -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")
+10 -10
View File
@@ -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."""
+6 -6
View File
@@ -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")
+26 -26
View File
@@ -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):