diff --git a/docs/reference/context.md b/docs/reference/context.md
index 235a654e..d2be4cd7 100644
--- a/docs/reference/context.md
+++ b/docs/reference/context.md
@@ -12,11 +12,11 @@ icon: "brain"
| --- | --- |
| `AgentContext` | Primary entry point — memory, retrieval, decisions, graph traversal, checkpoints |
| `ContextGraph` | In-memory knowledge graph with centrality, community detection, and decision tracking |
-| `AgentMemory` | RAG-backed persistent memory: `store(text)`, `retrieve(query, max_results)` |
-| `EntityLinker` | Link entity mentions to canonical URIs across multiple sources |
-| `ContextRetriever` | Hybrid vector + graph retrieval with min-score and temporal decay options |
+| `AgentMemory` | Vector-backed persistent memory: `store(text)`, `retrieve(query, max_results)` |
+| `EntityLinker` | Link entity mentions to URIs; create typed edges between entity IDs |
+| `ContextRetriever` | Hybrid vector + graph retrieval with min-score and graph expansion options |
| `DecisionRecorder` | Record decisions with embeddings, causal chains, and metadata |
-| `PolicyEngine` | Compliance checking: `check_compliance()`, `get_applicable_policies()` |
+| `PolicyEngine` | Policy management: `add_policy()`, `check_compliance()`, `get_applicable_policies()` |
| `CausalChainAnalyzer` | Trace how decisions influenced each other: `get_causal_chain(decision_id)` |
## What You Get
@@ -29,16 +29,16 @@ icon: "brain"
Thread-safe in-memory knowledge graph with centrality analysis, community detection, temporal validity, cross-graph links, and decision management.
- Embedding-backed memory with TTL, tagging, importance scoring, and LRU eviction.
+ Embedding-backed memory with retention policy and LRU eviction.
Records decisions with causal chains, confidence scores, temporal validity windows, and cross-system context capture.
- Validates decisions against configurable lambda rules before they're recorded; creates approval chains for human-in-the-loop gating.
+ Manages policy versions, checks compliance for recorded decisions, and tracks policy exceptions in the graph.
- Maps entity mentions to canonical URIs — prevents "Apple", "Apple Inc.", and "AAPL" from becoming three separate nodes.
+ Maps entity text to URIs and creates typed links between entity IDs — prevents "Apple", "Apple Inc.", and "AAPL" from becoming three separate nodes.
Hybrid retrieval fusing vector similarity, graph traversal, and agent memory for richer context than pure vector search.
@@ -48,7 +48,40 @@ icon: "brain"
-
+## Getting Started
+
+```python
+from semantica.context import AgentContext, ContextGraph
+from semantica.vector_store import VectorStore
+
+context = AgentContext(
+ vector_store=VectorStore(backend="faiss", dimension=768),
+ knowledge_graph=ContextGraph(advanced_analytics=True),
+ decision_tracking=True, # requires knowledge_graph to be set
+)
+
+# Store a fact
+memory_id = context.store(
+ "GPT-4 outperforms GPT-3.5 on reasoning benchmarks by 40%",
+ metadata={"source": "openai_blog", "date": "2024-01"}
+)
+
+# Retrieve by semantic similarity
+results = context.retrieve("LLM benchmark comparisons", max_results=5)
+for r in results:
+ print("{} (score: {:.3f})".format(r["content"], r["score"]))
+
+# Record a decision
+decision_id = context.record_decision(
+ category="model_selection",
+ scenario="Choose LLM for production reasoning pipeline",
+ reasoning="GPT-4 benchmark advantage justifies 3x cost increase",
+ outcome="selected_gpt4",
+ confidence=0.91,
+ entities=["gpt-4", "gpt-3.5"],
+ decision_maker="pipeline_agent",
+)
+```
## Quick Start
@@ -59,11 +92,11 @@ icon: "brain"
from semantica.vector_store import VectorStore
context = AgentContext(
- vector_store=VectorStore(backend="faiss", dimension=768, index_path="context.faiss"),
+ vector_store=VectorStore(backend="faiss", dimension=768),
knowledge_graph=ContextGraph(advanced_analytics=True),
decision_tracking=True,
- retention_days=90, # auto-expire memories older than 90 days
- max_memories=50_000,
+ retention_days=90,
+ max_memories=50000,
)
```
@@ -76,7 +109,7 @@ icon: "brain"
results = context.retrieve("LLM benchmark comparisons", max_results=5)
for r in results:
- print(f"{r['content']} (score: {r['score']:.3f})")
+ print("{} (score: {:.3f})".format(r["content"], r["score"]))
```
@@ -97,16 +130,16 @@ icon: "brain"
# Search past decisions — prevents contradictory choices across runs
precedents = context.find_precedents("model selection reasoning", limit=5)
for p in precedents:
- print(f"[{p.category}] {p.outcome} (confidence: {p.confidence:.2f})")
- print(f" Reasoning: {p.reasoning}")
+ print("[{}] {} (confidence: {:.2f})".format(p.category, p.outcome, p.confidence))
+ print(" Reasoning: {}".format(p.reasoning))
- # Trace what downstream decisions were influenced by this one
+ # Trace downstream decisions influenced by this one
chain = context.get_causal_chain(decision_id, direction="downstream", max_depth=5)
- print(f"Downstream decisions: {len(chain)}")
+ print("Downstream decisions: {}".format(len(chain)))
- # Full explainability — upstream causes + downstream effects + relationship paths
+ # Full explainability
explanation = context.trace_decision_explainability(decision_id)
- print(f"Total connections: {explanation['total_connections']}")
+ print("Total connections: {}".format(explanation["total_connections"]))
```
@@ -121,7 +154,7 @@ The main entry point. Wraps memory, graph, and decision tracking behind a single
| --------- | ---- | ------- | ----------- |
| `vector_store` | `VectorStore` | **required** | Backend for embedding-based memory retrieval |
| `knowledge_graph` | `ContextGraph` | `None` | Enables graph-backed relationships and GraphRAG |
-| `decision_tracking` | `bool` | `False` | Activates `DecisionRecorder` for every decision |
+| `decision_tracking` | `bool` | `False` | Activates `DecisionRecorder` — requires `knowledge_graph` to also be set |
| `retention_days` | `Optional[int]` | `30` | Auto-expire memories older than N days; `None` = keep forever |
| `max_memories` | `int` | `10000` | Hard cap before LRU eviction |
| `graph_expansion` | `bool` | `True` | Auto-expands graph from stored memories |
@@ -130,11 +163,15 @@ The main entry point. Wraps memory, graph, and decision tracking behind a single
| `advanced_analytics` | `bool` | `True` | Enables PageRank, centrality, and community analysis |
| `kg_algorithms` | `bool` | `True` | Adds path-finding and link prediction |
+
+ `decision_tracking=True` has no effect unless `knowledge_graph` is also provided. Both must be set at construction time for decision tracking to be active.
+
+
### Memory Methods
| Method | Returns | Description |
| ------ | ------- | ----------- |
-| `store(content, metadata, conversation_id, user_id)` | `str` | Embed and store a fact or list of facts |
+| `store(content, metadata, conversation_id, user_id)` | `str` or `Dict` | Store a fact (str → memory ID) or list of documents (list → stats dict) |
| `batch_store(items)` | `List[str]` | Store multiple items at once — returns list of memory IDs |
| `retrieve(query, max_results, min_score, use_graph, conversation_id)` | `List[Dict]` | Semantic retrieval; auto-selects GraphRAG if `knowledge_graph` is set |
| `forget(memory_id, conversation_id, days_old)` | `int` | Delete memories by ID, conversation, or age |
@@ -157,10 +194,14 @@ context.store("Agent recommended Docker + Kubernetes", conversation_id="conv_001
# Retrieve full conversation history
history = context.conversation("conv_001", max_items=50)
for turn in history:
- print(f"[{turn['timestamp']}] {turn['content']}")
+ print("[{}] {}".format(turn["timestamp"], turn["content"]))
# Retrieve across all conversations with a query
-results = context.retrieve("deployment recommendations", conversation_id="conv_001", max_results=10)
+results = context.retrieve(
+ "deployment recommendations",
+ conversation_id="conv_001",
+ max_results=10,
+)
```
### Multi-Hop GraphRAG
@@ -168,6 +209,7 @@ results = context.retrieve("deployment recommendations", conversation_id="conv_0
Requires `knowledge_graph` to be set at construction:
```python
+import os
from semantica.llms import Groq
llm = Groq(model="llama-3.3-70b-versatile", api_key=os.getenv("GROQ_API_KEY"))
@@ -179,15 +221,15 @@ result = context.query_with_reasoning(
)
print(result["response"])
-print(f"Confidence: {result['confidence']:.2f}")
-print(f"Sources used: {result['num_sources']}")
+print("Confidence: {:.2f}".format(result["confidence"]))
+print("Sources used: {}".format(result["num_sources"]))
```
### Decision Methods
| Method | Returns | Description |
| ------ | ------- | ----------- |
-| `record_decision(category, scenario, reasoning, outcome, confidence, entities, decision_maker, valid_from, valid_until)` | `str` | Record a decision; raises `RuntimeError` if `decision_tracking=False` |
+| `record_decision(category, scenario, reasoning, outcome, confidence, entities, decision_maker, valid_from, valid_until)` | `str` | Record a decision; raises `RuntimeError` if `decision_tracking=False` or no `knowledge_graph` |
| `find_precedents(scenario, category, limit, use_hybrid_search, max_hops, as_of)` | `List[Decision]` | Find similar past decisions by semantic + structural similarity |
| `query_decisions(query, max_hops, use_hybrid_search)` | `List[Decision]` | Broad context-aware decision search |
| `get_causal_chain(decision_id, direction, max_depth)` | `List[Decision]` | Trace `"upstream"` causes or `"downstream"` effects |
@@ -208,8 +250,8 @@ context.checkpoint("after_inference")
# See exactly what was added/removed
diff = context.diff_checkpoints("before_inference", "after_inference")
-print(f"Decisions added: {len(diff['decisions_added'])}")
-print(f"Relationships added: {len(diff['relationships_added'])}")
+print("Decisions added: {}".format(len(diff["decisions_added"])))
+print("Relationships added: {}".format(len(diff["relationships_added"])))
# Persist a checkpoint to disk via TemporalVersionManager
context.flush_checkpoint("after_inference")
@@ -241,18 +283,17 @@ decision_id = graph.record_decision(
similar = graph.find_precedents_by_scenario("web framework", limit=3)
stats = graph.stats()
-print(f"Nodes: {stats['node_count']}, Edges: {stats['edge_count']}")
+print("Nodes: {}, Edges: {}".format(stats["node_count"], stats["edge_count"]))
```
### Constructor Options
| Parameter | Type | Default | Description |
| --------- | ---- | ------- | ----------- |
-| `advanced_analytics` | `bool` | `False` | PageRank, betweenness centrality |
-| `centrality_analysis` | `bool` | `False` | Full centrality suite |
-| `community_detection` | `bool` | `False` | Louvain community clustering |
-| `node_embeddings` | `bool` | `False` | Node2Vec embeddings for structural similarity |
-| `enable_causality` | `bool` | `False` | Causal chain tracking between decision nodes |
+| `advanced_analytics` | `bool` | `True` | PageRank, betweenness centrality |
+| `centrality_analysis` | `bool` | `True` | Full centrality suite |
+| `community_detection` | `bool` | `True` | Louvain community clustering |
+| `node_embeddings` | `bool` | `True` | Node2Vec embeddings for structural similarity |
### ContextGraph — Full Method Reference
@@ -277,9 +318,8 @@ print(f"Nodes: {stats['node_count']}, Edges: {stats['edge_count']}")
| `load_from_file(path)` | `None` | Load graph from JSON |
| `build_from_conversations(conversations, link_entities)` | `Dict` | Build graph from conversation data |
| `link_graph(other_graph, source_node_id, target_node_id, link_type)` | `str` | Create cross-graph navigation link; returns `link_id` |
-| `navigate_to(link_id)` | `Tuple[ContextGraph, str]` | Follow a cross-graph link to `(target_graph, target_node_id)` |
+| `navigate_to(link_id)` | `Tuple` | Follow a cross-graph link to `(target_graph, target_node_id)` |
| `cross_graph_path(source_node_id, target_graph, target_node_id, max_hops)` | `Dict` | Shortest path across linked graphs |
-| `resolve_links(graphs)` | `int` | Reconnect cross-graph links after `load_from_file` |
| `clear()` | `None` | Reset graph state and all indexes |
### Cross-Graph Navigation
@@ -310,12 +350,12 @@ path = domain_graph.cross_graph_path(
target_node_id="deploy_k8s",
max_hops=5,
)
-print(f"Reachable: {path['reachable']}, hops: {path['hop_count']}")
+print("Reachable: {}, hops: {}".format(path["reachable"], path["hop_count"]))
```
## AgentMemory (Low-Level)
-For fine-grained control over memory storage, TTL, and importance scoring:
+For fine-grained control over memory storage and retrieval:
```python
from semantica.context import AgentMemory
@@ -323,90 +363,141 @@ from semantica.vector_store import VectorStore
memory = AgentMemory(
vector_store=VectorStore(backend="faiss", dimension=768),
- capacity=10_000,
- ttl_days=90,
+ max_memory_size=10000,
+ retention_policy="90_days", # or "unlimited"
)
memory_id = memory.store(
"Critical compliance rule: all trades must be pre-approved",
- importance=0.95,
- tags=["compliance", "trading"],
+ metadata={"type": "compliance"},
)
results = memory.retrieve(
query="trade approval requirements",
max_results=5,
- min_importance=0.5,
- tags=["compliance"],
+ min_score=0.0,
)
-memory.update(memory_id, importance=1.0)
-memory.forget(memory_id)
-all_memories = memory.get_all()
+memory.delete_memory(memory_id)
+memory.clear_memory(conversation_id="conv_001")
+
+history = memory.get_conversation_history(conversation_id="conv_001", max_items=100)
```
| Parameter | Type | Default | Description |
| --------- | ---- | ------- | ----------- |
| `vector_store` | `VectorStore` | **required** | Embedding backend for semantic retrieval |
-| `capacity` | `int` | `1000` | Max items before LRU eviction |
-| `ttl_days` | `Optional[int]` | `None` | Days before automatic expiry; `None` = keep forever |
+| `max_memory_size` | `int` | `10000` | Max items before LRU eviction |
+| `retention_policy` | `str` | `"unlimited"` | `"N_days"` (e.g. `"30_days"`) or `"unlimited"` |
## PolicyEngine
-Validate decisions against configurable rules before they're committed:
+`PolicyEngine` manages versioned policies stored in the knowledge graph. Policies are stored as nodes and can be linked to decisions:
```python
from semantica.context import PolicyEngine
+from semantica.context import ContextGraph
+from semantica.context.decision_models import Policy, Decision
+from datetime import datetime
-policy = PolicyEngine()
-policy.add_rule("confidence_threshold", lambda d: d.confidence >= 0.7)
-policy.add_rule("requires_reasoning", lambda d: len(d.reasoning) >= 20)
+graph = ContextGraph()
+policy = PolicyEngine(graph_store=graph)
-is_valid, violations = policy.validate(decision_data)
+# Create and store a policy
+p = Policy(
+ policy_id="policy_001",
+ name="Confidence Threshold Policy",
+ description="All decisions must have confidence >= 0.7",
+ rules={"min_confidence": 0.7, "requires_reasoning": True},
+ category="decision_quality",
+ version="1.0",
+ created_at=datetime.now(),
+ updated_at=datetime.now(),
+)
+policy.add_policy(p)
-if is_valid:
- context.record_decision(**decision_data)
-else:
- # Create approval chain for human-in-the-loop review
- chain = policy.create_approval_chain(
- decision_data,
- approvers=["manager@company.com", "compliance@company.com"],
- )
- print(f"Approval chain created: {chain.chain_id}")
+# Check compliance of a specific decision
+decision = Decision(
+ decision_id="dec_001",
+ category="loan_approval",
+ scenario="First-time homebuyer",
+ reasoning="Good credit score and stable employment",
+ outcome="approved",
+ confidence=0.94,
+ timestamp=datetime.now(),
+ decision_maker="loan_agent",
+)
+compliant = policy.check_compliance(decision, "policy_001")
+print("Compliant:", compliant)
+
+# Get applicable policies for a category
+policies = policy.get_applicable_policies(category="decision_quality")
+for p in policies:
+ print("{} v{}".format(p.name, p.version))
```
## EntityLinker
-Maps extracted entity mentions to canonical URIs — essential for cross-document entity resolution:
+Maps entity text to URIs and creates typed links between entity IDs:
```python
from semantica.context import EntityLinker
-linker = EntityLinker()
+linker = EntityLinker(similarity_threshold=0.8)
+# Assign a URI to an entity
+uri = linker.assign_uri("apple_inc", "Apple Inc.", "ORGANIZATION")
+print(uri) # "https://semantica.dev/entity/apple_inc.#organization"
+
+# Link entities from extracted text
entities = [
- {"text": "Apple Inc.", "type": "ORGANIZATION"},
- {"text": "Apple", "type": "ORGANIZATION"},
- {"text": "AAPL", "type": "ORGANIZATION"},
+ {"id": "e1", "text": "Apple Inc.", "type": "ORGANIZATION"},
+ {"id": "e2", "text": "Apple", "type": "ORGANIZATION"},
]
-linked = linker.link_entities(entities, sources=["reuters", "sec_filings"])
-
+linked = linker.link(text="Apple Inc. was founded by Steve Jobs.", entities=entities)
for e in linked:
- print(f"{e.text} → {e.canonical_form} ({e.uri})")
- print(f" confidence: {e.confidence:.2f}, sources: {e.sources}")
+ print("{} → {} (confidence: {:.2f})".format(e.text, e.uri, e.confidence))
+
+# Explicitly link two entity IDs
+linker.link_entities(
+ entity1_id="apple_inc",
+ entity2_id="aapl",
+ link_type="same_as",
+ confidence=0.99,
+)
+
+# Build the full entity web
+web = linker.build_entity_web()
+print("Entities:", web["statistics"]["total_entities"])
+print("Links: ", web["statistics"]["total_links"])
```
+`LinkedEntity` fields returned by `link()`:
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `entity_id` | `str` | Entity identifier |
+| `uri` | `str` | Generated URI (e.g. `"https://semantica.dev/entity/apple_inc."`) |
+| `text` | `str` | Surface form text |
+| `type` | `str` | Entity type |
+| `linked_entities` | `List[EntityLink]` | Related entity links with `source_entity_id`, `target_entity_id`, `link_type`, `confidence` |
+| `context` | `Dict` | Entity metadata |
+| `confidence` | `float` | Overall confidence score |
+
## ContextRetriever
-Hybrid retrieval combining vector similarity, graph traversal, and memory — surfaces results that pure vector search misses:
+Hybrid retrieval combining vector similarity, graph traversal, and memory:
```python
from semantica.context import ContextRetriever
retriever = ContextRetriever(
+ memory_store=memory,
+ knowledge_graph=context_graph,
vector_store=vector_store,
- context_graph=context_graph,
- agent_memory=memory,
+ use_graph_expansion=True,
+ max_expansion_hops=2,
+ hybrid_alpha=0.5,
)
results = retriever.retrieve(
@@ -417,7 +508,7 @@ results = retriever.retrieve(
)
for r in results:
- print(f"[{r['source']}] score={r['score']:.3f}: {r['content'][:80]}")
+ print("[{}] score={:.3f}: {}".format(r.source, r.score, r.content[:80]))
```
## Data Structures
@@ -428,17 +519,19 @@ for r in results:
```python
@dataclass
class Decision:
- decision_id: str
- category: str
- scenario: str
- reasoning: str
- outcome: str
- confidence: float # 0.0 – 1.0
- decision_maker: str # default: "ai_agent"
- timestamp: datetime
- valid_from: Optional[str] # ISO datetime — temporal validity start
- valid_until: Optional[str] # ISO datetime — temporal validity end
- metadata: Dict[str, Any] # arbitrary key/value store
+ decision_id: str
+ category: str
+ scenario: str
+ reasoning: str
+ outcome: str
+ confidence: float # 0.0 - 1.0
+ timestamp: datetime
+ decision_maker: str
+ reasoning_embedding: Optional[List[float]] # generated embedding
+ node2vec_embedding: Optional[List[float]] # structural embedding
+ valid_from: Optional[str] # ISO datetime
+ valid_until: Optional[str] # ISO datetime
+ metadata: Dict[str, Any]
```
@@ -447,14 +540,11 @@ class Decision:
```python
@dataclass
class Precedent:
- decision_id: str
- similarity: float # 0–1 match score against queried scenario
- category: str
- scenario: str
- outcome: str
- reasoning: str
- confidence: float
- timestamp: datetime
+ precedent_id: str
+ source_decision_id: str
+ similarity_score: float # 0-1 match score
+ relationship_type: str # "similar_scenario" | "same_policy" | "exception_precedent"
+ metadata: Dict[str, Any]
```
@@ -463,13 +553,15 @@ class Precedent:
```python
@dataclass
class Policy:
- policy_id: str
- name: str
- description: str
- rules: List[Dict] # list of rule definitions
- active: bool
- created_at: datetime
- version: int
+ policy_id: str
+ name: str
+ description: str
+ rules: Dict[str, Any] # rule definitions
+ category: str
+ version: str # e.g. "1.0", "2.1"
+ created_at: datetime
+ updated_at: datetime
+ metadata: Dict[str, Any]
```
@@ -478,13 +570,14 @@ class Policy:
```python
@dataclass
class PolicyException:
- exception_id: str
- policy_rule: str # name of the violated rule
- decision_id: str # decision that triggered the exception
- justification: str # why the exception was granted
- approved_by: str # approver identity
- timestamp: datetime
- expiry: Optional[datetime]
+ exception_id: str
+ decision_id: str
+ policy_id: str
+ reason: str
+ approver: str
+ approval_timestamp: datetime
+ justification: str
+ metadata: Dict[str, Any]
```
@@ -493,20 +586,13 @@ class PolicyException:
```python
@dataclass
class ApprovalChain:
- chain_id: str
- decision_id: str
- steps: List[ApprovalStep]
- status: str # "pending" | "approved" | "rejected"
- created_at: datetime
-
-@dataclass
-class ApprovalStep:
- step_id: str
- approver: str
- required: bool
- status: str # "pending" | "approved" | "rejected"
- comment: Optional[str]
- timestamp: Optional[datetime]
+ approval_id: str
+ decision_id: str
+ approver: str
+ approval_method: str # "slack_dm" | "zoom_call" | "email" | "system"
+ approval_context: str
+ timestamp: datetime
+ metadata: Dict[str, Any]
```
@@ -515,12 +601,22 @@ class ApprovalStep:
```python
@dataclass
class LinkedEntity:
- text: str
- canonical_form: str # normalized primary name
- uri: str # e.g. "http://dbpedia.org/resource/Apple_Inc."
- confidence: float
- sources: List[str] # source documents that mention this entity
- aliases: List[str] # all observed surface forms
+ entity_id: str
+ uri: str
+ text: str
+ type: str
+ linked_entities: List[EntityLink]
+ context: Dict[str, Any]
+ confidence: float
+
+@dataclass
+class EntityLink:
+ source_entity_id: str
+ target_entity_id: str
+ link_type: str # "same_as" | "related_to" | "part_of"
+ confidence: float
+ source: Optional[str]
+ metadata: Dict[str, Any]
```
@@ -531,11 +627,12 @@ class LinkedEntity:
```python
- from semantica.context import AgentContext
+ from semantica.context import AgentContext, ContextGraph
from semantica.vector_store import VectorStore
health_agent = AgentContext(
vector_store=VectorStore(backend="faiss", dimension=768),
+ knowledge_graph=ContextGraph(),
decision_tracking=True,
)
@@ -545,55 +642,78 @@ class LinkedEntity:
decision_id = health_agent.record_decision(
category="treatment_plan",
scenario="Hypertension with comorbid diabetes",
- reasoning="ACE inhibitors are renoprotective in diabetic patients — preferred over beta blockers",
+ reasoning="ACE inhibitors are renoprotective in diabetic patients",
outcome="prescribed_lisinopril",
confidence=0.91,
)
precedents = health_agent.find_precedents("hypertension diabetes", limit=5)
for p in precedents:
- print(f"Past decision: {p.outcome} (confidence: {p.confidence:.2f})")
+ print("Past: {} (confidence: {:.2f})".format(p.outcome, p.confidence))
chain = health_agent.get_causal_chain(decision_id, direction="downstream")
- print(f"Follow-up decisions triggered: {len(chain)}")
+ print("Follow-up decisions triggered: {}".format(len(chain)))
```
```python
- from semantica.context import AgentContext, PolicyEngine
+ from semantica.context import AgentContext, ContextGraph, PolicyEngine
+ from semantica.context.decision_models import Policy, Decision
from semantica.vector_store import VectorStore
+ from datetime import datetime
- policy = PolicyEngine()
- policy.add_rule("min_confidence", lambda d: d["confidence"] >= 0.8)
- policy.add_rule("has_reasoning", lambda d: len(d["reasoning"]) >= 30)
+ graph = ContextGraph()
+ policy = PolicyEngine(graph_store=graph)
+
+ # Add compliance policy
+ p = Policy(
+ policy_id="lending_policy",
+ name="Lending Policy",
+ description="Min confidence 0.8 for loan decisions",
+ rules={"min_confidence": 0.8},
+ category="loan_approval",
+ version="1.0",
+ created_at=datetime.now(),
+ updated_at=datetime.now(),
+ )
+ policy.add_policy(p)
loan_agent = AgentContext(
vector_store=VectorStore(backend="faiss", dimension=768),
+ knowledge_graph=graph,
decision_tracking=True,
)
-
loan_agent.store("Applicant: credit score 750, DTI 28%, stable employment 4yr")
- decision_data = dict(
+ # Check compliance before recording
+ d = Decision(
+ decision_id="dec_loan_001",
category="loan_approval",
scenario="First-time homebuyer — 30yr fixed, 20% down",
- reasoning="Credit score above threshold, DTI within limits, stable income verified",
+ reasoning="Credit score above threshold, DTI within limits",
outcome="approved_300k",
confidence=0.94,
+ timestamp=datetime.now(),
+ decision_maker="loan_agent",
)
-
- is_valid, violations = policy.validate(decision_data)
- if is_valid:
- decision_id = loan_agent.record_decision(**decision_data)
- else:
- chain = policy.create_approval_chain(decision_data, approvers=["underwriter@bank.com"])
- print(f"Sent for review: {chain.chain_id}")
+ compliant = policy.check_compliance(d, "lending_policy")
+ if compliant:
+ loan_agent.record_decision(
+ category=d.category,
+ scenario=d.scenario,
+ reasoning=d.reasoning,
+ outcome=d.outcome,
+ confidence=d.confidence,
+ )
```
```python
+ from semantica.context import AgentContext, ContextGraph
+ from semantica.vector_store import VectorStore
+
context = AgentContext(
- vector_store=VectorStore(backend="faiss", dimension=768, index_path="ctx.faiss"),
+ vector_store=VectorStore(backend="faiss", dimension=768),
knowledge_graph=ContextGraph(),
decision_tracking=True,
)
@@ -609,7 +729,7 @@ class LinkedEntity:
# Later — restore and continue
restored = AgentContext(
- vector_store=VectorStore(backend="faiss", dimension=768, index_path="ctx.faiss"),
+ vector_store=VectorStore(backend="faiss", dimension=768),
knowledge_graph=ContextGraph(),
decision_tracking=True,
)
@@ -623,11 +743,11 @@ class LinkedEntity:
## Tips and Common Pitfalls
- **Persist your vector store between runs.** Pass `index_path="context.faiss"` to `VectorStore` — without it the FAISS index lives only in memory and is lost on shutdown. An agent that forgets everything on restart isn't an agent.
+ **`decision_tracking=True` silently does nothing without `knowledge_graph`.** Both must be set at construction. Passing only `decision_tracking=True` without a `knowledge_graph` instance leaves the decision backend uninitialised — `record_decision()` will raise `RuntimeError`.
- **Enable `decision_tracking=True` from the start.** Adding it retroactively means historical decisions are not linked to the causal chain — you lose the ability to trace how one decision influenced later ones. Enable it at initialization, even if you're not using it immediately.
+ **Persist your vector store between runs.** Pass `index_path="context.faiss"` to `VectorStore` — without it the FAISS index lives only in memory and is lost on shutdown.
@@ -639,21 +759,17 @@ class LinkedEntity:
- **Set `retention_days` to avoid memory bloat.** Without it `AgentMemory` accumulates indefinitely (the default `AgentContext.retention_days=30` prunes automatically). Compliance-critical agents may need `retention_days=None` with explicit archival via `export()`.
+ **Set `retention_days` to avoid memory bloat.** The default `AgentContext.retention_days=30` prunes automatically. Compliance-critical agents may need `retention_days=None` with explicit archival via `export()`.
+
+
+
+ **Use `checkpoint()` + `diff_checkpoints()` to audit reasoning loops.** Take a snapshot before and after a reasoning pass to see exactly which decisions and relationships were added.
- **Gate irreversible decisions with `PolicyEngine`.** Decisions recorded with `record_decision()` become part of the causal chain immediately. Validate first with `policy.validate()` and create an `ApprovalChain` for human review — don't record until approved.
+ **`EntityLinker.link_entities()` links two entity IDs, not a list.** Call `link_entities(entity1_id, entity2_id, link_type)` to create a typed edge between two known IDs. For linking entities extracted from text, use `link(text, entities=[...])` instead.
-
- **Use `checkpoint()` + `diff_checkpoints()` to audit reasoning loops.** Take a snapshot before and after a reasoning pass to see exactly which decisions and relationships were added. This is the cleanest way to detect divergent agent behaviour across runs.
-
-
-
- **`EntityLinker` prevents graph proliferation.** Without it, "Apple", "Apple Inc.", and "AAPL" land as three separate nodes. Run `EntityLinker.link_entities()` on mentions before storing them to maintain a canonical graph.
-
-
Embedding storage backend for memory retrieval.
@@ -673,4 +789,3 @@ class LinkedEntity:
- [Context Module](https://github.com/semantica-agi/semantica/blob/main/cookbook/introduction/19_Context_Module.ipynb) — memory and decision tracking · Intermediate
- [Advanced Context Engineering](https://github.com/semantica-agi/semantica/blob/main/cookbook/advanced/11_Advanced_Context_Engineering.ipynb) — production FAISS + Neo4j setup · Advanced
-- [Decision Tracking with KG Algorithms](https://github.com/semantica-agi/semantica/blob/main/cookbook/advanced/12_Decision_Tracking_KG.ipynb) — precedent search, policy enforcement · Advanced