mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
Implements the full Semantica × Agno integration stack as described in issue #249, wiring Semantica's semantic intelligence layer into Agno's agent/team primitives via five focused components. ## New components ### integrations/agno/ - `AgnoContextStore` — graph-backed MemoryDb (AgentMemory/storage) - `AgnoKnowledgeGraph` — relational AgentKnowledge with multi-hop GraphRAG - `AgnoDecisionKit` — Agno Toolkit: 6 decision-intelligence tools - `AgnoKGToolkit` — Agno Toolkit: 7 knowledge-graph tools - `AgnoSharedContext` — team-level shared ContextGraph with role scoping ### tests/integrations/agno/ - 110 tests, 0 failures - conftest.py installs comprehensive agno stubs for offline testing - Covers MemoryDb protocol, tool registration, shared memory pool, thread-safety, GraphRAG search, NER/relation extraction, and inference ### cookbook/integrations/ - agno_decision_intelligence.ipynb (finance/loan underwriting) - agno_graphrag_context.ipynb (regulatory compliance GraphRAG) - agno_multi_agent_shared_context.ipynb (multi-agent product strategy team) ### docs/integrations/agno.md - Full reference documentation with examples for all 5 components ## pyproject.toml - Added `agno = ["agno>=1.0.0"]` optional dependency - Added agno to the `all` extra ## Design notes - Zero breaking changes — fully additive - Graceful degradation when agno is not installed - Auto-creates VectorStore(backend="faiss") when none provided - _tools always populated for inspection regardless of agno install state - Works with both real agno package and offline stubs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
20 KiB
20 KiB
In [ ]:
import sys, os
sys.path.insert(0, os.path.abspath("../../"))
# ── Semantica core (not Agno-specific) ──────────────────────────────────────
from semantica.context import AgentContext, ContextGraph
from semantica.context import PolicyEngine, DecisionQuery, CausalChainAnalyzer
from semantica.vector_store import VectorStore
# ── Agno integration layer ───────────────────────────────────────────────────
from integrations.agno import AgnoContextStore, AgnoDecisionKit, AGNO_AVAILABLE
print(f"Semantica imports OK")
print(f"Agno installed: {AGNO_AVAILABLE}")In [ ]:
# ── Vector store (FAISS, no external service needed) ────────────────────────
vector_store = VectorStore(backend="faiss", dimension=768)
print("VectorStore ready (FAISS)")
# ── In-memory context graph with full analytics ──────────────────────────────
knowledge_graph = ContextGraph(
advanced_analytics=True,
# Switch to neo4j for production:
# backend="neo4j", uri="bolt://localhost:7687"
)
print("ContextGraph ready (in-memory)")In [ ]:
# Build a pure-Semantica AgentContext for seeding historical data
seed_context = AgentContext(
vector_store=vector_store,
knowledge_graph=knowledge_graph,
decision_tracking=True,
)
historical_loans = [
dict(
category="loan_approval",
scenario="Applicant: credit score 740, income $95k, DTI 28%, down payment 20%",
reasoning="Strong credit history, debt load well below 35% threshold, adequate down payment",
outcome="approved",
confidence=0.96,
),
dict(
category="loan_approval",
scenario="Applicant: credit score 620, income $45k, DTI 42%, down payment 5%",
reasoning="Credit score below 650 floor, DTI exceeds 40% maximum, insufficient down payment",
outcome="rejected",
confidence=0.97,
),
dict(
category="loan_approval",
scenario="Applicant: credit score 700, income $72k, DTI 33%, down payment 15%",
reasoning="Adequate credit, moderate DTI within range, down payment slightly below ideal",
outcome="approved_with_conditions",
confidence=0.82,
),
dict(
category="loan_approval",
scenario="Applicant: credit score 780, income $130k, DTI 22%, down payment 30%",
reasoning="Excellent credit, low debt load, strong down payment — low-risk profile",
outcome="approved",
confidence=0.99,
),
dict(
category="loan_approval",
scenario="Applicant: credit score 660, income $58k, DTI 38%, down payment 10%",
reasoning="Borderline credit, high DTI, minimal down payment — escalated to senior review",
outcome="escalated",
confidence=0.70,
),
]
for loan in historical_loans:
did = seed_context.record_decision(**loan)
print(f" Seeded [{loan['outcome']:25s}] → {did}")
print(f"\n{len(historical_loans)} historical decisions loaded into Semantica KG")In [ ]:
LENDING_POLICY_RULES = [
"credit_score >= 650",
"dti <= 40",
"down_payment_pct >= 10",
"confidence >= 0.70",
]
# Verify directly with Semantica's PolicyEngine before wiring to Agno
policy_engine = PolicyEngine(graph_store=knowledge_graph)
test_application = {"credit_score": 720, "dti": 31, "down_payment_pct": 18, "confidence": 0.88}
try:
result = policy_engine.check_compliance(test_application, LENDING_POLICY_RULES)
print(f"Policy check result: compliant={getattr(result, 'compliant', 'N/A')}")
print(f"Violations: {getattr(result, 'violations', [])}")
except Exception as e:
print(f"PolicyEngine fallback (expected without full rule engine): {e}")
print("\nPolicy rules defined:", LENDING_POLICY_RULES)In [ ]:
# ── AgnoContextStore: wraps AgentContext as Agno MemoryDb ────────────────────
store = AgnoContextStore(
vector_store=vector_store, # Same store — shares seeded decisions
knowledge_graph=knowledge_graph, # Same graph — shares seeded decisions
decision_tracking=True,
graph_expansion=True,
session_id="loan_underwriter_v1",
)
print("AgnoContextStore ready")
# ── AgnoDecisionKit: exposes Semantica decision tools to Agno's LLM ──────────
decision_kit = AgnoDecisionKit(
context=store.context, # Reuse same AgentContext — shared decision history
max_precedents=5,
causal_depth=3,
enable_policy_check=True,
)
print(f"AgnoDecisionKit ready — {len(decision_kit._tools)} tools registered")
print(" Tools:", [fn.__name__ for fn in decision_kit._tools])In [ ]:
if AGNO_AVAILABLE:
from agno.agent import Agent
from agno.memory import AgentMemory
from agno.models.openai import OpenAIChat # or any Agno-supported model
agent = Agent(
name="LoanUnderwriter",
model=OpenAIChat(id="gpt-4o"),
memory=AgentMemory(db=store),
tools=[decision_kit],
show_tool_calls=True,
description=(
"You are a senior loan underwriter. Before approving or rejecting any application:"
" (1) find_precedents for similar past cases,"
" (2) check_policy compliance,"
" (3) record_decision with full reasoning."
" Always cite precedents and policy rule results in your explanation."
),
)
print("Agno Agent assembled and ready")
else:
print("Agno not installed — demonstrating tool calls directly below")In [ ]:
import json
# ── 5a. Find Precedents ───────────────────────────────────────────────────────
print("=" * 60)
print("TOOL: find_precedents")
print("=" * 60)
new_application_scenario = (
"Applicant: credit score 715, income $82k, DTI 30%, down payment 18%"
)
precedents_json = decision_kit.find_precedents(
scenario=new_application_scenario,
category="loan_approval",
limit=3,
)
precedents = json.loads(precedents_json)
print(f"Found {precedents['count']} similar past decisions:")
for p in precedents['precedents']:
print(f" [{p.get('outcome','?'):25s}] confidence={p.get('confidence',0):.2f}")
print(f" {p.get('scenario','')[:80]}")In [ ]:
# ── 5b. Check Policy ─────────────────────────────────────────────────────────
print("=" * 60)
print("TOOL: check_policy")
print("=" * 60)
decision_data = json.dumps({
"credit_score": 715,
"dti": 30,
"down_payment_pct": 18,
"confidence": 0.88,
"outcome": "approved",
})
policy_json = decision_kit.check_policy(
decision_data=decision_data,
policy_rules=json.dumps(LENDING_POLICY_RULES),
)
policy_result = json.loads(policy_json)
print(f"Compliant: {policy_result.get('compliant')}")
print(f"Violations: {policy_result.get('violations', [])}")
print(f"Warnings: {policy_result.get('warnings', [])}")In [ ]:
# ── 5c. Record Decision ──────────────────────────────────────────────────────
print("=" * 60)
print("TOOL: record_decision")
print("=" * 60)
record_json = decision_kit.record_decision(
category="loan_approval",
scenario=new_application_scenario,
reasoning=(
"3 similar precedents found — 2 approved, 1 escalated. "
"Credit score 715 exceeds 650 floor. DTI 30% well within 40% limit. "
"Down payment 18% above 10% minimum. All policy rules satisfied."
),
outcome="approved",
confidence=0.91,
entities="loan_applicant, credit_bureau, lending_policy_v2",
)
record_result = json.loads(record_json)
decision_id = record_result['decision_id']
print(f"Decision recorded: {decision_id}")
print(f"Status: {record_result['status']}")In [ ]:
# ── 5d. Analyze Impact ───────────────────────────────────────────────────────
print("=" * 60)
print("TOOL: analyze_impact")
print("=" * 60)
impact_json = decision_kit.analyze_impact(decision_id=decision_id)
impact = json.loads(impact_json)
print("Impact analysis:")
for k, v in impact.items():
if k != "decision_id":
print(f" {k}: {v}")In [ ]:
# ── 5e. Decision Summary ─────────────────────────────────────────────────────
print("=" * 60)
print("TOOL: get_decision_summary")
print("=" * 60)
summary_json = decision_kit.get_decision_summary(category="loan_approval")
summary = json.loads(summary_json)
print("Decision history summary:")
for k, v in summary.items():
if k not in ("category_filter",):
print(f" {k}: {v}")In [ ]:
NEW_CASE = (
"New mortgage application received:\n"
" Credit score: 715, Annual income: $82,000\n"
" Debt-to-income: 30%, Down payment: 18%\n"
" Loan amount: $320,000 for a primary residence in Austin TX\n"
"Should we approve this application?"
)
if AGNO_AVAILABLE:
agent.print_response(NEW_CASE)
else:
print("[Agno not installed — skipping live agent run]")
print()
print("Expected agent reasoning flow:")
print(" 1. find_precedents('credit score 715, DTI 30%, down payment 18%')")
print(" → 2 approved, 1 escalated among similar cases")
print(" 2. check_policy(credit_score=715, dti=30, down_payment_pct=18)")
print(" → compliant=True, violations=[]")
print(" 3. record_decision(outcome='approved', confidence=0.91)")
print(" → decision_id recorded in Semantica KG")
print()
print(" Recommendation: APPROVE — 3 precedents + full policy compliance")In [ ]:
# Query decision history directly from Semantica
insights = store.context.get_context_insights()
print("Session Insights (Semantica native):")
if isinstance(insights, dict):
for k, v in insights.items():
print(f" {k}: {v}")
else:
print(f" {insights}")In [ ]:
# Precedent search directly via Semantica's AgentContext
# (same data, no Agno in the loop)
precedents = store.context.find_precedents_advanced(
scenario="borderline mortgage application",
category="loan_approval",
)
print(f"\nPrecedent search via Semantica directly → {len(precedents or [])} results")