mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
Compare commits
11
Commits
integrations
...
kg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ce5067aa3 | ||
|
|
d056e47ab7 | ||
|
|
8eafd2d024 | ||
|
|
7ba93f6772 | ||
|
|
d466203761 | ||
|
|
730dea7911 | ||
|
|
47764c3033 | ||
|
|
055d2fd98d | ||
|
|
ce66681715 | ||
|
|
655b553262 | ||
|
|
60bf8ec75e |
@@ -0,0 +1 @@
|
||||
# Initialization
|
||||
@@ -0,0 +1 @@
|
||||
# Intialization
|
||||
@@ -0,0 +1 @@
|
||||
# Initialization
|
||||
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- **Enhancement: Native `KnowledgeGraph` type support in `KGVisualizer`** (PR `kg` by @KaifAhmad1, closes #471): Added `semantica/kg/knowledge_graph.py` — a formal `KnowledgeGraph` dataclass (`entities`, `relationships`, `metadata`) that is now the canonical in-memory type produced and consumed by the Semantica KG pipeline. Exported from `semantica.kg`. `KGVisualizer` gains `_convert_knowledge_graph()` — an authoritative, non-mutating conversion path from `KnowledgeGraph` to the internal dict format — and `_normalize_graph()` now routes `isinstance(graph, KnowledgeGraph)` through it as an explicit fast-path before duck-typing. All five public entry points (`visualize_network`, `visualize_communities`, `visualize_centrality`, `visualize_entity_types`, `visualize_relationship_matrix`) accept `KnowledgeGraph` directly; no manual conversion required. All existing callers passing dicts or duck-typed objects are unaffected. 15 new tests in `TestFormalKnowledgeGraphType` (conversion shape, non-mutation, determinism, routing, all five entry points, import availability).
|
||||
|
||||
- **Fix: `KGVisualizer` now accepts `KnowledgeGraph` objects in all `visualize_*` methods** (PR `visualization` by @KaifAhmad1, closes #458): All five public methods (`visualize_network`, `visualize_communities`, `visualize_centrality`, `visualize_entity_types`, `visualize_relationship_matrix`) previously called `graph.get("entities", [])`, silently producing no output when passed a non-dict object. Added `_normalize_graph()` which duck-types the input — dicts pass through unchanged; any object exposing `.entities` / `.relationships` attributes (e.g. the result of `GraphBuilder.build()`) is converted to the canonical dict form; anything else raises a clear `ProcessingError` naming the offending type. 21 tests added in `tests/visualization/test_kg_visualizer_normalize_graph.py`.
|
||||
|
||||
- **Security: 12 vulnerability fixes across CRITICAL → LOW severity** (PR `security-enhancement` by @KaifAhmad1):
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
[](https://github.com/Hawksight-AI/semantica/actions)
|
||||
[](https://discord.gg/sV34vps5hH)
|
||||
[](https://x.com/BuildSemantica)
|
||||
[](https://openclaw.ai)
|
||||
|
||||
### ⭐ Give us a Star · 🍴 Fork us · 💬 Join our Discord · 🐦 Follow on X
|
||||
|
||||
@@ -45,7 +46,7 @@ Semantica is the **context and intelligence layer** you add on top of your exist
|
||||
- ✅ **Reasoning Engines** — forward chaining, Rete networks, deductive, abductive, and SPARQL. Explainable paths, not black boxes.
|
||||
- ✅ **Quality & Deduplication** — conflict detection, entity resolution, and pipeline validation built in.
|
||||
|
||||
> Works alongside LangChain, LlamaIndex, AutoGen, CrewAI, and any LLM — Semantica is the **accountability layer** on top, not a replacement.
|
||||
> Works alongside **Agno** and any LLM — Semantica is the **accountability layer** on top, not a replacement. LangChain, LangGraph, CrewAI, and more coming soon.
|
||||
|
||||
```bash
|
||||
pip install semantica
|
||||
@@ -55,39 +56,68 @@ pip install semantica
|
||||
|
||||
## 🔌 Works With Every AI Tool
|
||||
|
||||
Semantica ships **native plugin bundles** for Claude Code, Cursor, and Codex, an **MCP server** (`python -m semantica.mcp_server`) for Windsurf, Cline, Continue, VS Code, and Claude Desktop, and a **REST API** (FastAPI, port 8000) for any other tool.
|
||||
Semantica ships **native plugin bundles** for Claude Code, Cursor, and Codex, an **MCP server** (`python -m semantica.mcp_server`) for Windsurf, Cline, Continue, VS Code, Claude Desktop, and OpenClaw, and a **REST API** (FastAPI, port 8000) for any other tool.
|
||||
|
||||
<table>
|
||||
|
||||
<!-- ── Native Plugin Bundle ──────────────────────────────────────────── -->
|
||||
<tr>
|
||||
<th colspan="3" align="left">🔌 Native Plugin Bundle</th>
|
||||
<th colspan="5" align="left">⚡ MCP Server + Plugin</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://claude.com/product/claude-code"><img src="https://github.com/anthropics.png?size=120" alt="Claude Code" width="48" height="48" /></a><br/>
|
||||
<strong>Claude Code</strong><br/>
|
||||
<sub>Native plugin · 17 skills · 3 agents · hooks</sub>
|
||||
<sub>17 skills · 3 agents · hooks</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://cursor.com"><img src="https://www.freelogovectors.net/wp-content/uploads/2025/06/cursor-logo-freelogovectors.net_.png" alt="Cursor" width="48" height="48" /></a><br/>
|
||||
<strong>Cursor</strong><br/>
|
||||
<sub>Native plugin · 17 skills · 3 agents</sub>
|
||||
<sub>17 skills · 3 agents</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/openai/codex"><img src="https://github.com/openai.png?size=120" alt="Codex CLI" width="48" height="48" /></a><br/>
|
||||
<strong>Codex CLI</strong><br/>
|
||||
<sub>Native plugin · 17 skills · 3 agents</sub>
|
||||
<sub>17 skills · 3 agents</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://windsurf.com"><img src="https://exafunction.github.io/public/brand/windsurf-black-symbol.svg" alt="Windsurf" width="48" height="48" /></a><br/>
|
||||
<strong>Windsurf</strong><br/>
|
||||
<sub>MCP server + plugin</sub>
|
||||
<sub><a href="plugins/.windsurf-plugin/">plugin</a></sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://claude.ai/download"><img src="https://github.com/anthropics.png?size=120" alt="Claude Desktop" width="48" height="48" /></a><br/>
|
||||
<strong>Claude Desktop</strong><br/>
|
||||
<sub>MCP server</sub>
|
||||
<a href="https://github.com/cline/cline"><img src="https://github.com/cline.png?size=120" alt="Cline" width="48" height="48" /></a><br/>
|
||||
<strong>Cline</strong><br/>
|
||||
<sub><a href="plugins/.cline-plugin/">plugin</a></sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/continuedev/continue"><img src="https://github.com/continuedev.png?size=120" alt="Continue" width="48" height="48" /></a><br/>
|
||||
<strong>Continue</strong><br/>
|
||||
<sub><a href="plugins/.continue-plugin/">plugin</a></sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/microsoft/vscode"><img src="https://github.com/microsoft.png?size=120" alt="VS Code" width="48" height="48" /></a><br/>
|
||||
<strong>VS Code</strong><br/>
|
||||
<sub>MCP server + plugin</sub>
|
||||
<sub><a href="plugins/.vscode-plugin/">plugin</a></sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="integrations/openclaw/"><img src="https://github.com/openclaw.png?size=120" alt="OpenClaw" width="48" height="48" /></a><br/>
|
||||
<strong>OpenClaw</strong><br/>
|
||||
<sub>MCP + <a href="integrations/openclaw/">plugin</a></sub>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- ── MCP Server only · REST API ───────────────────────────────────── -->
|
||||
<tr>
|
||||
<th colspan="1" align="left">☁️ MCP Server</th>
|
||||
<th colspan="7" align="left">🌐 REST API</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://claude.ai/download"><img src="https://github.com/anthropics.png?size=120" alt="Claude Desktop" width="48" height="48" /></a><br/>
|
||||
<strong>Claude Desktop</strong><br/>
|
||||
<sub>MCP server</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/features/copilot"><img src="https://github.com/github.png?size=120" alt="GitHub Copilot" width="48" height="48" /></a><br/>
|
||||
@@ -95,23 +125,11 @@ Semantica ships **native plugin bundles** for Claude Code, Cursor, and Codex, an
|
||||
<sub>REST API</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/cline/cline"><img src="https://github.com/cline.png?size=120" alt="Cline" width="48" height="48" /></a><br/>
|
||||
<strong>Cline</strong><br/>
|
||||
<sub>MCP server + plugin</sub>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/RooCodeInc/Roo-Code"><img src="https://github.com/RooCodeInc.png?size=120" alt="Roo Code" width="48" height="48" /></a><br/>
|
||||
<strong>Roo Code</strong><br/>
|
||||
<sub>REST API</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/continuedev/continue"><img src="https://github.com/continuedev.png?size=120" alt="Continue" width="48" height="48" /></a><br/>
|
||||
<strong>Continue</strong><br/>
|
||||
<sub>MCP server + plugin</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/block/goose"><img src="https://github.com/block.png?size=120" alt="Goose" width="48" height="48" /></a><br/>
|
||||
<strong>Goose</strong><br/>
|
||||
<sub>REST API</sub>
|
||||
@@ -136,14 +154,91 @@ Semantica ships **native plugin bundles** for Claude Code, Cursor, and Codex, an
|
||||
<strong>Zed</strong><br/>
|
||||
<sub>REST API</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
</tr>
|
||||
|
||||
<!-- ── Any tool via REST ─────────────────────────────────────────────── -->
|
||||
<tr>
|
||||
<th colspan="8" align="left">🔧 Any Tool</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" colspan="8">
|
||||
<img src="https://img.shields.io/badge/109-endpoints-1f6feb?style=flat-square" alt="REST API" width="48" /><br/>
|
||||
<strong>Any agent</strong><br/>
|
||||
<sub>REST API</sub>
|
||||
<sub>109 REST endpoints · FastAPI · port 8000</sub>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
### Agentic Frameworks
|
||||
|
||||
Semantica integrates with **Agno** today. Coming soon: LangChain, LangGraph, CrewAI, LlamaIndex, AutoGen, OpenAI Agents SDK, Google ADK, and more.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th colspan="8" align="left">✅ Supported</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/agno-agi/agno"><img src="https://github.com/agno-agi.png?size=120" alt="Agno" width="48" height="48" /></a><br/>
|
||||
<strong>Agno</strong><br/>
|
||||
<sub>First-class · <code>pip install semantica[agno]</code></sub>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="8" align="left">🔜 Coming Soon</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/langchain-ai/langchain"><img src="https://github.com/langchain-ai.png?size=120" alt="LangChain" width="48" height="48" /></a><br/>
|
||||
<strong>LangChain</strong><br/>
|
||||
<sub>Coming soon</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/langchain-ai/langgraph"><img src="https://github.com/langchain-ai.png?size=120" alt="LangGraph" width="48" height="48" /></a><br/>
|
||||
<strong>LangGraph</strong><br/>
|
||||
<sub>Coming soon</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/crewAIInc/crewAI"><img src="https://github.com/crewAIInc.png?size=120" alt="CrewAI" width="48" height="48" /></a><br/>
|
||||
<strong>CrewAI</strong><br/>
|
||||
<sub>Coming soon</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/run-llama/llama_index"><img src="https://github.com/run-llama.png?size=120" alt="LlamaIndex" width="48" height="48" /></a><br/>
|
||||
<strong>LlamaIndex</strong><br/>
|
||||
<sub>Coming soon</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/microsoft/autogen"><img src="https://github.com/microsoft.png?size=120" alt="AutoGen" width="48" height="48" /></a><br/>
|
||||
<strong>AutoGen</strong><br/>
|
||||
<sub>Coming soon</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/openai/openai-agents-python"><img src="https://github.com/openai.png?size=120" alt="OpenAI Agents SDK" width="48" height="48" /></a><br/>
|
||||
<strong>OpenAI Agents</strong><br/>
|
||||
<sub>Coming soon</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/google/adk-python"><img src="https://github.com/google.png?size=120" alt="Google ADK" width="48" height="48" /></a><br/>
|
||||
<strong>Google ADK</strong><br/>
|
||||
<sub>Coming soon</sub>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
> **Agno — First-Class Integration** · `pip install semantica[agno]`
|
||||
>
|
||||
> Five integration modules live in [`integrations/agno/`](integrations/agno/):
|
||||
>
|
||||
> | Module | Class | What it does |
|
||||
> |---|---|---|
|
||||
> | `context_store.py` | `AgnoContextStore` | Graph-backed agent memory — store and retrieve structured context |
|
||||
> | `knowledge_graph.py` | `AgnoKnowledgeGraph` | Implements Agno's `AgentKnowledge` protocol; full extraction pipeline |
|
||||
> | `decision_kit.py` | `AgnoDecisionKit` | 6 decision-intelligence tools for Agno agents |
|
||||
> | `kg_toolkit.py` | `AgnoKGToolkit` | 7 KG pipeline tools (build, query, enrich, export) |
|
||||
> | `shared_context.py` | `AgnoSharedContext` | Shared context graph for multi-agent team coordination |
|
||||
|
||||
### Plugin Bundles (Claude Code · Cursor · Codex)
|
||||
|
||||
Native plugin bundles live under [`plugins/`](plugins/). Each directory contains a `plugin.json`, `marketplace.json`, and `README.md`.
|
||||
@@ -157,6 +252,7 @@ Native plugin bundles live under [`plugins/`](plugins/). Each directory contains
|
||||
| Cline | [`plugins/.cline-plugin/`](plugins/.cline-plugin/) | 17 skills · 3 agents · MCP config |
|
||||
| Continue | [`plugins/.continue-plugin/`](plugins/.continue-plugin/) | 17 skills · 3 agents · MCP config |
|
||||
| VS Code | [`plugins/.vscode-plugin/`](plugins/.vscode-plugin/) | 17 skills · 3 agents · MCP config |
|
||||
| OpenClaw | [`plugins/.openclaw-plugin/`](plugins/.openclaw-plugin/) | 17 skills · 3 agents · MCP config |
|
||||
|
||||
**17 domain skills:**
|
||||
|
||||
@@ -848,53 +944,6 @@ if result.valid:
|
||||
- **`semantica.llms`** — Groq, OpenAI, Novita AI, HuggingFace, LiteLLM
|
||||
- **[`explorer/`](explorer/)** — **Semantica Knowledge Explorer** — browser UI for live graph inspection, decisions, entity resolution, and ontology browsing (`npm run dev` in `explorer/`)
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 🔌 Integrations
|
||||
|
||||
### AI Coding Tools & IDEs
|
||||
|
||||
Start the Semantica server (`python -m semantica.server`, port 8000) and point any tool at `http://localhost:8000`. Tools marked **Native plugin** also get 17 skills, 3 agents, and hook config out of the box.
|
||||
|
||||
| Tool | Connection | Notes |
|
||||
|---|---|---|
|
||||
| [Claude Code](https://claude.com/product/claude-code) | **Native plugin** | `plugins/.claude-plugin/` — 17 skills, 3 agents, `hooks.json` |
|
||||
| [Cursor](https://cursor.com) | **Native plugin** | `plugins/.cursor-plugin/` — same 17 skills + 3 agents |
|
||||
| [Codex CLI](https://github.com/openai/codex) | **Native plugin** | `plugins/.codex-plugin/` — same 17 skills + 3 agents |
|
||||
| [Windsurf](https://windsurf.com) | **MCP server** + plugin | `plugins/.windsurf-plugin/` · add `python -m semantica.mcp_server` to `~/.codeium/windsurf/mcp_config.json` |
|
||||
| [Claude Desktop](https://claude.ai/download) | **MCP server** | Add `python -m semantica.mcp_server` to `claude_desktop_config.json` |
|
||||
| [VS Code](https://github.com/microsoft/vscode) | **MCP server** + plugin | `plugins/.vscode-plugin/` · add to `settings.json` under `mcp.servers` |
|
||||
| [GitHub Copilot](https://github.com/features/copilot) | REST API | Use via Copilot Chat custom tools |
|
||||
| [Cline](https://github.com/cline/cline) | **MCP server** + plugin | `plugins/.cline-plugin/` · add server in Cline MCP settings panel |
|
||||
| [Roo Code](https://github.com/RooCodeInc/Roo-Code) | **MCP server** | Add `python -m semantica.mcp_server` in Roo Code MCP settings |
|
||||
| [Continue](https://github.com/continuedev/continue) | **MCP server** + plugin | `plugins/.continue-plugin/` · add to `~/.continue/config.json` under `mcpServers` |
|
||||
| [Goose](https://github.com/block/goose) | REST API | Add to Goose toolset config |
|
||||
| [Kilo Code](https://github.com/Kilo-Org/kilocode) | REST API | Add as custom REST tool |
|
||||
| [Aider](https://github.com/Aider-AI/aider) | REST API | Pass context from the API into prompts |
|
||||
| [Amazon Q Developer](https://github.com/aws/amazon-q-developer-cli) | REST API | Use via Q Developer custom tools |
|
||||
| [Zed](https://zed.dev) | REST API | Integrate via Zed assistant context |
|
||||
| Any agent | REST API | 109 endpoints — drop-in with any HTTP client |
|
||||
|
||||
### REST API Server
|
||||
|
||||
Run `python -m semantica.server` (or `python -m semantica`) — FastAPI on port 8000 with the following route groups:
|
||||
|
||||
| Route group | Module | Endpoints |
|
||||
|---|---|---|
|
||||
| `/api/graph` | `routes/graph.py` | Nodes, edges, traversal, graph topology |
|
||||
| `/api/analytics` | `routes/analytics.py` | Centrality, communities, metrics |
|
||||
| `/api/decisions` | `routes/decisions.py` | Decision CRUD, precedent search, causal chains |
|
||||
| `/api/temporal` | `routes/temporal.py` | Point-in-time queries, snapshots, timelines |
|
||||
| `/api/export` | `routes/export_import.py` | Import/export in RDF, Parquet, JSON, CSV, GraphML |
|
||||
| `/api/annotations` | `routes/annotations.py` | Entity and edge annotation |
|
||||
| `/api/enrich` | `routes/enrich.py` | Graph enrichment — embeddings, vectors, metadata |
|
||||
| `/api/sparql` | `routes/sparql.py` | SPARQL query execution |
|
||||
| `/api/provenance` | `routes/provenance.py` | Data lineage and audit trails |
|
||||
| `/api/vocabulary` | `routes/vocabulary.py` | Ontology, SKOS concepts, schema definitions |
|
||||
| `/ws` | `ws.py` | WebSocket — real-time graph mutation events |
|
||||
| `/health` | `server.py` | Health check |
|
||||
|
||||
### Graph Databases
|
||||
- **Neo4j** — Cypher queries via `semantica.graph_store`
|
||||
- **FalkorDB** — native support; `DecisionQuery` and `CausalChainAnalyzer` work directly with FalkorDB row/header shapes
|
||||
@@ -925,67 +974,6 @@ Run `python -m semantica.server` (or `python -m semantica`) — FastAPI on port
|
||||
- **HuggingFace** — local and hosted models via `HuggingFaceProvider`
|
||||
- **Ollama** — local models including remote server support
|
||||
|
||||
### Agentic Frameworks
|
||||
|
||||
Semantica complements — not replaces — every major agentic framework. Use it as the accountability layer on top.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/agno-agi/agno"><img src="https://github.com/agno-agi.png?size=120" alt="Agno" width="40" height="40" /></a><br/>
|
||||
<strong>Agno</strong><br/>
|
||||
<sub>First-class · <code>pip install semantica[agno]</code></sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/langchain-ai/langchain"><img src="https://github.com/langchain-ai.png?size=120" alt="LangChain" width="40" height="40" /></a><br/>
|
||||
<strong>LangChain</strong><br/>
|
||||
<sub>Context layer</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/langchain-ai/langgraph"><img src="https://github.com/langchain-ai.png?size=120" alt="LangGraph" width="40" height="40" /></a><br/>
|
||||
<strong>LangGraph</strong><br/>
|
||||
<sub>Stateful agent graph</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/run-llama/llama_index"><img src="https://github.com/run-llama.png?size=120" alt="LlamaIndex" width="40" height="40" /></a><br/>
|
||||
<strong>LlamaIndex</strong><br/>
|
||||
<sub>GraphRAG retriever</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/microsoft/autogen"><img src="https://github.com/microsoft.png?size=120" alt="AutoGen" width="40" height="40" /></a><br/>
|
||||
<strong>AutoGen</strong><br/>
|
||||
<sub>Shared context graph</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/crewAIInc/crewAI"><img src="https://github.com/crewAIInc.png?size=120" alt="CrewAI" width="40" height="40" /></a><br/>
|
||||
<strong>CrewAI</strong><br/>
|
||||
<sub>Decision + provenance</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/openai/openai-agents-python"><img src="https://github.com/openai.png?size=120" alt="OpenAI Agents SDK" width="40" height="40" /></a><br/>
|
||||
<strong>OpenAI Agents</strong><br/>
|
||||
<sub>Context + KG tools</sub>
|
||||
</td>
|
||||
<td align="center" width="12.5%">
|
||||
<a href="https://github.com/google/adk-python"><img src="https://github.com/google.png?size=120" alt="Google ADK" width="40" height="40" /></a><br/>
|
||||
<strong>Google ADK</strong><br/>
|
||||
<sub>Context layer</sub>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
> **Agno — First-Class Integration** · `pip install semantica[agno]`
|
||||
>
|
||||
> Five integration modules live in [`integrations/agno/`](integrations/agno/):
|
||||
>
|
||||
> | Module | Class | What it does |
|
||||
> |---|---|---|
|
||||
> | `context_store.py` | `AgnoContextStore` | Graph-backed agent memory — store and retrieve structured context |
|
||||
> | `knowledge_graph.py` | `AgnoKnowledgeGraph` | Implements Agno's `AgentKnowledge` protocol; full extraction pipeline |
|
||||
> | `decision_kit.py` | `AgnoDecisionKit` | 6 decision-intelligence tools for Agno agents |
|
||||
> | `kg_toolkit.py` | `AgnoKGToolkit` | 7 KG pipeline tools (build, query, enrich, export) |
|
||||
> | `shared_context.py` | `AgnoSharedContext` | Shared context graph for multi-agent team coordination |
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Installation
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
# Semantica v0.3.0 — Release Notes
|
||||
|
||||
**Released:** 2026-03-10
|
||||
**PyPI:** `pip install semantica`
|
||||
**Tag:** [v0.3.0](https://github.com/Hawksight-AI/semantica/releases/tag/v0.3.0)
|
||||
**Classification:** Production/Stable
|
||||
|
||||
> First stable, full public release of Semantica. Covers everything shipped across three release stages: 0.3.0-alpha (2026-02-19), 0.3.0-beta (2026-03-07), and 0.3.0 stable (2026-03-10).
|
||||
|
||||
---
|
||||
|
||||
## Contributors
|
||||
|
||||
| Contributor | Role |
|
||||
|------------|------|
|
||||
| [@KaifAhmad1](https://github.com/KaifAhmad1) | Lead maintainer — context graph, decision intelligence, KG algorithms, semantic extraction, pipeline, provenance, bug fixes, release management |
|
||||
| [@ZohaibHassan16](https://github.com/ZohaibHassan16) | Deduplication v2 suite (candidate generation, two-stage scoring, semantic dedup), incremental/delta processing, benchmark suite |
|
||||
| [@Sameer6305](https://github.com/Sameer6305) | Apache AGE backend, PgVector store, Snowflake connector, Apache Arrow export |
|
||||
| [@tibisabau](https://github.com/tibisabau) | ArangoDB AQL export, Apache Parquet export |
|
||||
| [@d4ndr4d3](https://github.com/d4ndr4d3) | ResourceScheduler deadlock fix |
|
||||
|
||||
---
|
||||
|
||||
## v0.3.0 — Stable (2026-03-10)
|
||||
|
||||
### Context Graph Feature Completeness
|
||||
|
||||
**Temporal Validity Windows** (by @KaifAhmad1)
|
||||
|
||||
Nodes and edges now carry first-class `valid_from` / `valid_until` ISO datetime fields. These are stored directly on `ContextNode` and `ContextEdge` dataclasses — not in metadata — and survive full serialisation round-trips through `save_to_file()` / `load_from_file()` and `to_dict()` / `from_dict()`.
|
||||
|
||||
- `ContextNode.is_active(at_time=None)` and `ContextEdge.is_active(at_time=None)` — returns `True` if the node/edge is live at the given time (defaults to now). Handles both tz-aware and tz-naive datetime inputs correctly.
|
||||
- `ContextGraph.find_active_nodes(node_type=None, at_time=None)` — filters the entire graph and returns only nodes within their validity window.
|
||||
- `add_node(valid_from=..., valid_until=...)` and `add_edge(valid_from=..., valid_until=...)` — pass validity fields directly in the call signature.
|
||||
- Bug fix: `is_active()` previously crashed with `TypeError` when passed a tz-aware `datetime` (e.g. `datetime.now(timezone.utc)`). Fixed by normalising all inputs to tz-naive UTC via a new `_parse_iso_dt()` helper.
|
||||
- Bug fix: validity fields were silently lost in `add_nodes()`, `add_edges()`, `to_dict()`, and `from_dict()`. All four paths now correctly preserve and restore them.
|
||||
|
||||
**Weighted Multi-Hop BFS** (by @KaifAhmad1)
|
||||
|
||||
`ContextGraph.get_neighbors(node_id, hops=1, relationship_types=None, min_weight=0.0)` now accepts a `min_weight` threshold. Any edge with weight below the threshold is skipped during BFS traversal, allowing callers to confine multi-hop queries to high-confidence causal links. Default `0.0` is fully backward-compatible.
|
||||
|
||||
**Cross-Graph Navigation** (by @KaifAhmad1)
|
||||
|
||||
Separate `ContextGraph` instances can now be linked and navigated between — hierarchically, like separate knowledge domains that reference each other.
|
||||
|
||||
- `link_graph(other_graph, source_node_id, target_node_id, link_type="CROSS_GRAPH") -> str` — creates a navigable bridge and returns a `link_id`. Records a dedicated `"cross_graph_link"` typed marker node internally (not a phantom `"entity"`) and a marker edge.
|
||||
- `navigate_to(link_id) -> (other_graph, target_node_id)` — jumps to the target graph and entry node for a given link.
|
||||
- `graph_id` field — each `ContextGraph` now carries a stable UUID so instances can identify each other across save/load.
|
||||
- `save_to_file()` — now writes a `links` section alongside nodes and edges, containing `link_id`, `source_node_id`, `target_node_id`, and `other_graph_id` for every cross-graph link.
|
||||
- `load_from_file()` — restores `graph_id` and populates `_unresolved_links` from the `links` section.
|
||||
- `resolve_links(registry: Dict[str, ContextGraph]) -> int` — reconnects unresolved links post-load. Pass `{graph_id: graph_instance}` for each linked graph; returns the count of successfully resolved links. `navigate_to()` raises a clear `KeyError` with a `resolve_links()` hint if called before resolution.
|
||||
- Bug fix: the previous implementation auto-created the synthetic marker target as an `"entity"` node (phantom pollution). Fixed by explicitly pre-creating a `"cross_graph_link"` typed `ContextNode` before the marker edge.
|
||||
- 14 new tests in `tests/context/test_cross_graph_navigation.py` covering all scenarios including full save/load round-trips with partial registry resolution.
|
||||
|
||||
**Other Fixes** (by @KaifAhmad1)
|
||||
|
||||
- `PipelineBuilder.add_step()` return type annotation corrected from `"PipelineBuilder"` to `"PipelineStep"` — the implementation was already correct; only the annotation and docstring were stale.
|
||||
- `test_hybrid_search_performance` timing computation fixed — now accumulates a true `search_times` list instead of reusing the last loop iteration's `start_time`; threshold relaxed to `< 5.0s` for real `sentence-transformers` (384-dim) latency on development machines.
|
||||
|
||||
**Test Coverage Added**
|
||||
|
||||
- 14 cross-graph navigation tests (`tests/context/test_cross_graph_navigation.py`)
|
||||
- **Total: 335 context tests, 886+ tests across all modules — 0 failures**
|
||||
|
||||
---
|
||||
|
||||
## v0.3.0-beta — Beta (2026-03-07)
|
||||
|
||||
### Semantic Extraction Fixes
|
||||
|
||||
**Multi-Founder LLM Extraction & Reasoner Inference Fix** (PR #354, by @KaifAhmad1)
|
||||
|
||||
- `_parse_relation_result` in `methods.py` — unmatched subjects/objects now produce a synthetic `UNKNOWN` entity instead of silently dropping the relation. All co-founders returned by the LLM are preserved in the output.
|
||||
- Duplicate relation fix — an orphaned legacy block that appended every relation twice has been removed.
|
||||
- `extraction_method` parameter added — typed extraction paths now correctly record `"llm_typed"` in relation metadata instead of `"llm"`.
|
||||
- `_match_pattern` in `reasoner.py` rewritten — splits patterns on `?var` placeholders first, then escapes only literal segments. Pre-bound variables resolve to exact literals, repeated variables use backreferences, non-greedy `.+?` prevents over-consumption of separators.
|
||||
- Added `tests/reasoning/test_reasoner.py` (4 tests) and `tests/semantic_extract/test_relation_extractor.py` (6 tests).
|
||||
|
||||
**TTL Export Alias Fix** (PR #355, by @KaifAhmad1)
|
||||
|
||||
- `RDFExporter` now accepts `"ttl"`, `"nt"`, `"xml"`, `"rdf"`, and `"json-ld"` as format aliases in `export_to_rdf()`. Aliases resolve before format validation — zero public API changes.
|
||||
- Added `tests/export/test_rdf_exporter.py` (8 tests).
|
||||
|
||||
### Incremental / Delta Processing
|
||||
|
||||
**Native Delta Computation** (PR #349, by @ZohaibHassan16, reviewed and fixed by @KaifAhmad1)
|
||||
|
||||
- Native SPARQL-based diff between graph snapshots — only changed triples flow through the pipeline.
|
||||
- `delta_mode` configuration in `PipelineBuilder` for near-real-time workloads.
|
||||
- Version snapshot management with graph URI tracking and metadata storage.
|
||||
- `prune_versions()` for automatic snapshot retention cleanup.
|
||||
- Bug fixes: corrected SPARQL variable order, fixed class references, resolved duplicate dictionary keys.
|
||||
|
||||
### Deduplication v2
|
||||
|
||||
**Candidate Generation v2** (PR #338, by @ZohaibHassan16)
|
||||
|
||||
- New opt-in strategies: `blocking_v2` and `hybrid_v2`, replacing O(N²) pair enumeration.
|
||||
- Multi-key blocking with normalised token prefixes, type-aware keys, and optional phonetic (Soundex) blocking.
|
||||
- Deterministic `max_candidates_per_entity` budgeting with stable sorting.
|
||||
- **63.6% faster** in worst-case scenarios (0.259s → 0.094s for 100 entities).
|
||||
|
||||
**Two-Stage Scoring Prefilter** (PR #339, by @ZohaibHassan16)
|
||||
|
||||
- Fast gates for type mismatch, name-length ratio, and token overlap eliminate expensive semantic scoring for obvious non-matches.
|
||||
- Configurable thresholds: `min_length_ratio`, `min_token_overlap_ratio`, `required_shared_token`.
|
||||
- **18–25% faster** batch processing with prefilter enabled (`prefilter_enabled=False` by default).
|
||||
|
||||
**Semantic Relationship Deduplication v2** (PR #340, by @ZohaibHassan16, fixes by @KaifAhmad1)
|
||||
|
||||
- Canonicalisation engine with predicate synonym mapping (`works_for` → `employed_by`).
|
||||
- O(1) hash matching for exact canonical signatures.
|
||||
- Weighted scoring: 60% predicate + 40% object composition with explainable `semantic_match_score`.
|
||||
- **6.98x faster** than legacy mode (83ms vs 579ms).
|
||||
- `dedup_triplets()` infinite recursion bug fixed; function is now a first-class API in `methods.py`.
|
||||
|
||||
**Deduplication v2 Migration Guide** (PR #344, by @ZohaibHassan16, fixes by @KaifAhmad1)
|
||||
|
||||
- Comprehensive `MIGRATION_V2.md` documenting all v2 strategies with code examples.
|
||||
- Full backward compatibility maintained — legacy mode remains the default.
|
||||
|
||||
### Export Formats
|
||||
|
||||
**ArangoDB AQL Export** (PR #342, by @tibisabau)
|
||||
|
||||
- Full AQL INSERT statement generation for vertices and edges.
|
||||
- Configurable collection names with validation and sanitisation; batch processing (default: 1000).
|
||||
- `export_arango()` convenience function; `.aql` auto-detection in the unified exporter.
|
||||
- 17 tests, 100% pass rate.
|
||||
|
||||
**Apache Parquet Export** (PR #343, by @tibisabau)
|
||||
|
||||
- Columnar storage format with configurable compression: snappy, gzip, brotli, zstd, lz4, none.
|
||||
- Explicit Apache Arrow schemas with type safety; field normalisation for varied naming conventions.
|
||||
- `export_parquet()` convenience function; `.parquet` auto-detection.
|
||||
- Analytics-ready for pandas, Spark, Snowflake, BigQuery, Databricks.
|
||||
- 25 tests, 100% pass rate.
|
||||
|
||||
### Bug Fixes & Test Suite Stabilisation
|
||||
|
||||
**Test Suite Fixes** (by @KaifAhmad1)
|
||||
|
||||
Context module:
|
||||
- `retrieve_decision_precedents` — gated entity extraction on `use_hybrid_search=True` correctly.
|
||||
- `_extract_entities_from_query` — now uses `word[0].isupper()` to capture camelCase identifiers like `CreditCard`.
|
||||
- Added missing `expand_context` (BFS traversal) and `_get_decision_query` methods.
|
||||
- Fixed `hybrid_retrieval`, `dynamic_context_traversal`, and `multi_hop_context_assembly` for correct single-pass BFS.
|
||||
- Fixed `_retrieve_from_vector` fallback to `result["metadata"]["content"]` to prevent empty content and negative re-ranking scores.
|
||||
|
||||
KG module:
|
||||
- `calculate_pagerank` — added `alpha`/`max_iter` aliases; return format changed to `{"centrality": scores, "rankings": sorted_list}`.
|
||||
- `community_detector._to_networkx` — now returns a NetworkX graph directly when one is passed (previously lost all edges).
|
||||
- Added 9 domain-specific tracking methods to `AlgorithmTrackerWithProvenance`.
|
||||
- Created `provenance_tracker.py` with `ProvenanceTracker` (`track_entity`, `get_all_sources`, `clear`).
|
||||
|
||||
Pipeline module:
|
||||
- Retry loop fixed — now correctly iterates to `max_retries`.
|
||||
- `RecoveryAction` dataclass and `handle_failure(error, policy, retry_count)` added with LINEAR, EXPONENTIAL, and FIXED strategies.
|
||||
- `add_step()` fixed to return the created `PipelineStep`.
|
||||
- `validate` added as alias for `validate_pipeline` in `PipelineValidator`.
|
||||
|
||||
Other:
|
||||
- Fixed `NameError` for missing `Type` import in `utils/helpers.py`.
|
||||
- Vector store performance threshold relaxed (100ms → 500ms per decision for development machines).
|
||||
- Windows cp1252 encoding fix in test files (emoji → ASCII).
|
||||
- `ProvenanceTracker` added to `semantica/kg/__init__.py` exports.
|
||||
|
||||
**Results: ~840 tests passing, 36 skipped (external services), 0 failed**
|
||||
|
||||
---
|
||||
|
||||
## v0.3.0-alpha — Alpha (2026-02-19)
|
||||
|
||||
### Context & Decision Intelligence
|
||||
|
||||
**Context Engineering Enhancement** (PR #307, by @KaifAhmad1)
|
||||
|
||||
The foundational 0.3.0 feature — complete overhaul of the context module for production-grade decision intelligence:
|
||||
|
||||
- Full decision lifecycle: `record_decision()` → `add_decision()` → `add_causal_relationship()` → `trace_decision_chain()` → `analyze_decision_impact()` → `analyze_decision_influence()` → `find_similar_decisions()`
|
||||
- `AgentContext` unified wrapper with granular feature flags: `decision_tracking`, `kg_algorithms`, `graph_expansion`; methods: `store()`, `retrieve()`, `get_conversation_history()`, `get_statistics()`, `capture_cross_system_inputs()`
|
||||
- `AgentMemory` with working, conversation, and long-term memory tiers
|
||||
- `PolicyEngine` with versioned policy nodes, compliance checking (`check_decision_rules()`), and `PolicyException` model
|
||||
- Hybrid precedent search combining vector, structural, and category similarity with configurable weights
|
||||
- Decision influence analysis via centrality measures and causal chain tracking
|
||||
- GraphStore validation preventing runtime failures; secure logging
|
||||
- 9 critical bug fixes across logging, security, audit trails, API compatibility, Cypher queries, centrality access, validation
|
||||
|
||||
**Context Decision Tracking Fixes** (PR #315, by @KaifAhmad1)
|
||||
|
||||
- Fixed empty/None decision ID handling in `add_decision()`
|
||||
- Fixed None metadata handling preventing `TypeError`
|
||||
- Fixed causal chain depth logic and node exclusion
|
||||
- Fixed nonexistent node handling in `add_causal_relationship()`
|
||||
- Fixed precedent search direction in `find_precedents()`
|
||||
- Added missing `properties` field in `to_dict()`; added `from_dict()` method
|
||||
- Fixed UUID generation across all decision models
|
||||
- All 71 context tests passing
|
||||
|
||||
### Knowledge Graph Algorithms
|
||||
|
||||
**Improved Graph Algorithms** (PR #292, by @KaifAhmad1)
|
||||
|
||||
- 30+ graph algorithms across 7 categories
|
||||
- Node embeddings: Node2Vec, DeepWalk, Word2Vec via `NodeEmbedder`
|
||||
- Similarity: cosine, Euclidean, Manhattan, Correlation via `SimilarityCalculator`
|
||||
- Path finding: Dijkstra, A*, BFS, K-shortest paths via `PathFinder`
|
||||
- Link prediction: preferential attachment, Jaccard, Adamic-Adar via `LinkPredictor`
|
||||
- Centrality: degree, betweenness, closeness, PageRank via `CentralityAnalyzer`
|
||||
- Community detection: Louvain, Leiden, label propagation via `CommunityDetector`
|
||||
- Connectivity: components, bridges, density via `ConnectivityAnalyzer`
|
||||
- `GraphBuilderWithProvenance` and `AlgorithmTrackerWithProvenance` with full execution metadata
|
||||
|
||||
**Improved Vector Store for Decision Tracking** (PR #293, by @KaifAhmad1)
|
||||
|
||||
- `DecisionEmbeddingPipeline` with semantic and structural embeddings
|
||||
- `HybridSimilarityCalculator` with configurable weights (semantic: 0.7, structural: 0.3)
|
||||
- `ContextRetriever` with multi-hop reasoning
|
||||
- Convenience API: `quick_decision()`, `find_precedents()`, `explain()`, `similar_to()`, `batch_decisions()`, `filter_decisions()`
|
||||
- 34+ tests; performance: 0.028s per decision, 0.031s search, ~0.8KB memory per decision
|
||||
|
||||
### Graph Database Backends
|
||||
|
||||
**Apache AGE Backend Security Fixes** (PR #311, by @Sameer6305, fixes by @KaifAhmad1)
|
||||
|
||||
- `AgeStore` class with `GraphStore` API compatibility (openCypher via SQL on PostgreSQL)
|
||||
- SQL injection vulnerabilities fixed with input validation
|
||||
- psycopg2-binary dependency and migration guide added
|
||||
- Fixed parameter replacement and test mock leakage
|
||||
|
||||
**PgVector Store Support** (PR #303, by @Sameer6305, @KaifAhmad1)
|
||||
|
||||
- Native PostgreSQL vector storage using the pgvector extension
|
||||
- Multiple distance metrics: cosine, L2/Euclidean, inner product
|
||||
- HNSW and IVFFlat indexing for approximate nearest neighbour search
|
||||
- JSONB metadata storage with flexible filtering; batch operations
|
||||
- Connection pooling with psycopg3/psycopg2 fallback
|
||||
- SQL injection protection via `psycopg_sql.SQL()`; idempotent index and table management
|
||||
- 36+ tests with Docker integration
|
||||
|
||||
### Infrastructure
|
||||
|
||||
**ResourceScheduler Deadlock Fix** (PR #299, #301, by @d4ndr4d3, @KaifAhmad1)
|
||||
|
||||
- Replaced `threading.Lock()` with `threading.RLock()` to fix nested lock acquisition deadlock in `allocate_resources()`
|
||||
- Added `ValidationError` when no resources can be allocated
|
||||
- Progress tracking updates moved outside lock scope
|
||||
- 6 regression tests for deadlock prevention
|
||||
|
||||
**Security Configuration** (by @KaifAhmad1)
|
||||
|
||||
- Dependabot bi-weekly security updates with manual review
|
||||
- Automated security scans (Bandit, Safety, Semgrep) on schedule
|
||||
- Security-critical package grouping; zero auto-merge policy
|
||||
|
||||
---
|
||||
|
||||
## Summary by the Numbers
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total tests passing | **886+** |
|
||||
| Test failures | **0** |
|
||||
| Context tests | 335 |
|
||||
| KG tests | ~430 |
|
||||
| Semantic extraction tests | 70 (9 skipped — external LLM APIs) |
|
||||
| Reasoning tests | 19 |
|
||||
| Real-world scenario tests | 85 |
|
||||
| PyPI classifier | Production/Stable |
|
||||
| Python support | 3.8 – 3.12 |
|
||||
|
||||
---
|
||||
|
||||
## Upgrade
|
||||
|
||||
```bash
|
||||
pip install --upgrade semantica
|
||||
```
|
||||
|
||||
No breaking changes. All new parameters have safe defaults and all new methods are additive.
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md) for the full line-by-line diff.
|
||||
@@ -1,105 +0,0 @@
|
||||
# Deduplication & Conflict Resolution Strategies Summary
|
||||
|
||||
## Quick Reference by Use Case
|
||||
|
||||
| Use Case | Deduplication Method | Merge Strategy | Conflict Detection | Conflict Resolution |
|
||||
|----------|---------------------|----------------|-------------------|---------------------|
|
||||
| **Finance** |
|
||||
| `01_Financial_Data_Integration_MCP` | `DuplicateDetector` (incremental) | `keep_highest_confidence` | `temporal` | `most_recent` |
|
||||
| `02_Fraud_Detection` | `ClusterBuilder` (graph_based) | `merge_all` | `logical` | `expert_review` |
|
||||
| **Biomedical** |
|
||||
| `01_Drug_Discovery_Pipeline` | `EntityResolver` (semantic) | - | `relationship` | `voting` |
|
||||
| `02_Genomic_Variant_Analysis` | `DuplicateDetector` (group) | `keep_most_complete` | `value` | `credibility_weighted` |
|
||||
| **Cybersecurity** |
|
||||
| `01_Real_Time_Anomaly_Detection` | `DuplicateDetector` (pairwise) | `keep_first` | `entity` | `first_seen` |
|
||||
| `02_Threat_Intelligence_Hybrid_RAG` | `EntityResolver` (exact) | - | `type` | `highest_confidence` |
|
||||
| **Blockchain** |
|
||||
| `01_DeFi_Protocol_Intelligence` | `DuplicateDetector` (group) | `keep_last` | `relationship` | `voting` |
|
||||
| `02_Transaction_Network_Analysis` | `ClusterBuilder` (hierarchical) | `keep_most_complete` | `temporal` | `most_recent` |
|
||||
| **Intelligence** |
|
||||
| `01_Criminal_Network_Analysis` | `EntityResolver` (fuzzy) | - | `value` | `credibility_weighted` |
|
||||
| `02_Intelligence_Analysis_Orchestrator_Worker` | `DuplicateDetector` (batch) | `merge_all` | `entity` | `voting` |
|
||||
| **Renewable Energy** |
|
||||
| `01_Energy_Market_Analysis` | `DuplicateDetector` (pairwise) | `keep_highest_confidence` | `temporal` | `most_recent` |
|
||||
| **Supply Chain** |
|
||||
| `01_Supply_Chain_Data_Integration` | `DuplicateDetector` (incremental) | `keep_most_complete` | `value` | `credibility_weighted` |
|
||||
|
||||
---
|
||||
|
||||
## Strategy Rationale by Domain
|
||||
|
||||
### Finance
|
||||
- **Financial Data Integration**: Incremental for streaming data; most_recent for time-sensitive financial data
|
||||
- **Fraud Detection**: Graph-based clustering for fraud groups; expert_review for fraud assessment
|
||||
|
||||
### Biomedical
|
||||
- **Drug Discovery**: Semantic matching for drug compounds; voting for research source aggregation
|
||||
- **Genomic Variants**: Group method for related variants; credibility weighting for research sources
|
||||
|
||||
### Cybersecurity
|
||||
- **Real-Time Anomaly**: Pairwise for real-time streams; keep_first for first detection priority
|
||||
- **Threat Intelligence**: Exact matching for IOCs; highest_confidence for threat classification
|
||||
|
||||
### Blockchain
|
||||
- **DeFi Protocols**: Group method for related protocols; keep_last for latest protocol info
|
||||
- **Transaction Networks**: Hierarchical clustering for nested groups; temporal for time-sensitive data
|
||||
|
||||
### Intelligence
|
||||
- **Criminal Networks**: Fuzzy matching for intelligence data; credibility weighting for intelligence sources
|
||||
- **Intelligence Analysis**: Batch for multi-source integration; merge_all to combine all intelligence sources
|
||||
|
||||
### Renewable Energy
|
||||
- **Energy Markets**: Pairwise for real-time market data; most_recent for time-sensitive energy data
|
||||
|
||||
### Supply Chain
|
||||
- **Supply Chain Integration**: Incremental for continuous updates; credibility weighting for supply chain sources
|
||||
|
||||
---
|
||||
|
||||
## Method Distribution
|
||||
|
||||
### Deduplication Methods (9 total)
|
||||
- `pairwise`: 2 notebooks (real-time processing)
|
||||
- `batch`: 3 notebooks (large datasets)
|
||||
- `incremental`: 2 notebooks (streaming/continuous)
|
||||
- `group`: 2 notebooks (related entities)
|
||||
- `graph_based` (ClusterBuilder): 2 notebooks (interconnected entities)
|
||||
- `hierarchical` (ClusterBuilder): 1 notebook (nested groups)
|
||||
- `exact` (EntityResolver): 1 notebook (exact matching)
|
||||
- `semantic` (EntityResolver): 2 notebooks (semantic similarity)
|
||||
- `fuzzy` (EntityResolver): 1 notebook (fuzzy matching)
|
||||
|
||||
### Merge Strategies (5 total)
|
||||
- `keep_first`: 1 notebook (first detection priority)
|
||||
- `keep_last`: 1 notebook (latest information)
|
||||
- `keep_most_complete`: 5 notebooks (preserve all details)
|
||||
- `keep_highest_confidence`: 2 notebooks (most reliable data)
|
||||
- `merge_all`: 3 notebooks (combine all information)
|
||||
|
||||
### Conflict Detection Methods (6 total)
|
||||
- `value`: 4 notebooks (property value conflicts)
|
||||
- `type`: 2 notebooks (type/classification conflicts)
|
||||
- `entity`: 2 notebooks (entity-wide conflicts)
|
||||
- `relationship`: 3 notebooks (relationship conflicts)
|
||||
- `temporal`: 3 notebooks (time-sensitive conflicts)
|
||||
- `logical`: 2 notebooks (logical inconsistencies)
|
||||
|
||||
### Conflict Resolution Strategies (6 total)
|
||||
- `voting`: 5 notebooks (majority vote)
|
||||
- `credibility_weighted`: 4 notebooks (source credibility)
|
||||
- `most_recent`: 3 notebooks (latest data)
|
||||
- `first_seen`: 1 notebook (first detection)
|
||||
- `highest_confidence`: 2 notebooks (most confident)
|
||||
- `expert_review`: 1 notebook (manual review)
|
||||
|
||||
---
|
||||
|
||||
## Key Patterns
|
||||
|
||||
1. **Real-Time Systems**: Use `pairwise` + `keep_first` + `first_seen`
|
||||
2. **Time-Sensitive Data**: Use `temporal` + `most_recent`
|
||||
3. **Multi-Source Integration**: Use `batch` + `merge_all` + `voting`
|
||||
4. **Medical/Research**: Use `credibility_weighted` for authoritative sources
|
||||
5. **Fraud/Security**: Use `graph_based` + `logical` + `expert_review`
|
||||
6. **Exact Matching Required**: Use `exact` strategy (IOCs, identifiers)
|
||||
|
||||
Generated
+2
-2
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "semantica-explorer",
|
||||
"name": "semantica-knowledge-explorer",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "semantica-explorer",
|
||||
"name": "semantica-knowledge-explorer",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@monaco-editor/react": "^4.7.0",
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
# Semantica × OpenClaw Integration
|
||||
|
||||
Connect [OpenClaw](https://openclaw.ai) — the open-source personal AI agent — to Semantica's full knowledge-graph and decision-intelligence stack.
|
||||
|
||||
Two integration paths are available:
|
||||
|
||||
| Path | When to use |
|
||||
|---|---|
|
||||
| **MCP (recommended)** | OpenClaw Gateway is running; zero extra code needed |
|
||||
| **REST / native tool** | Embedding Semantica directly in a SOUL.md agent config |
|
||||
|
||||
---
|
||||
|
||||
## Path 1 — MCP Server (recommended)
|
||||
|
||||
### 1. Start the Semantica MCP server
|
||||
|
||||
```bash
|
||||
python -m semantica.mcp_server
|
||||
```
|
||||
|
||||
### 2. Add to `mcporter.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"semantica": {
|
||||
"command": "python",
|
||||
"args": ["-m", "semantica.mcp_server"],
|
||||
"transport": "stdio"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Restart the OpenClaw Gateway
|
||||
|
||||
```bash
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
All **12 Semantica tools** are now available to any OpenClaw agent:
|
||||
|
||||
| Tool | What it does |
|
||||
|---|---|
|
||||
| `extract_entities` | Named entity recognition from text |
|
||||
| `extract_relations` | Relation / triplet extraction from text |
|
||||
| `record_decision` | Record a decision with causal links |
|
||||
| `query_decisions` | Search recorded decisions |
|
||||
| `find_precedents` | Find past decisions similar to a query |
|
||||
| `get_causal_chain` | Trace cause-effect chains from a node |
|
||||
| `add_entity` | Add a node to the knowledge graph |
|
||||
| `add_relationship` | Add an edge between two nodes |
|
||||
| `run_reasoning` | Forward-chain rules over facts |
|
||||
| `get_graph_analytics` | Centrality, communities, topology stats |
|
||||
| `export_graph` | Export graph (JSON, RDF, GraphML, …) |
|
||||
| `get_graph_summary` | High-level graph overview |
|
||||
|
||||
**3 resources** are also exposed: `semantica://graph/summary`, `semantica://decisions/list`, `semantica://schema/info`.
|
||||
|
||||
---
|
||||
|
||||
## Path 2 — Native Tool (REST)
|
||||
|
||||
Use `OpenClawKGTool` when you prefer a direct Python integration without the MCP gateway.
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
pip install semantica[openclaw] # pulls in 'requests'
|
||||
```
|
||||
|
||||
### Quick start
|
||||
|
||||
```python
|
||||
from integrations.openclaw import OpenClawKGTool
|
||||
|
||||
tool = OpenClawKGTool(base_url="http://localhost:8000")
|
||||
|
||||
# Extract knowledge from text
|
||||
entities = tool.extract_entities("OpenClaw is an open-source AI agent built in Python.")
|
||||
relations = tool.extract_relations("Alice manages the OpenClaw project at Hawksight.")
|
||||
|
||||
# Record and query decisions
|
||||
tool.record_decision("Deploy model v2 to production", context="latency improved by 40%")
|
||||
precedents = tool.find_precedents("roll back production deployment")
|
||||
|
||||
# Graph analytics
|
||||
summary = tool.get_graph_summary()
|
||||
analytics = tool.get_graph_analytics()
|
||||
|
||||
# Export
|
||||
ttl = tool.export_graph(fmt="ttl")
|
||||
```
|
||||
|
||||
### Generate `mcporter.json` programmatically
|
||||
|
||||
```python
|
||||
from integrations.openclaw import OpenClawMCPConfig
|
||||
|
||||
cfg = OpenClawMCPConfig()
|
||||
print(cfg.to_json()) # → paste into mcporter.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SOUL.md agent snippet
|
||||
|
||||
Add Semantica to any OpenClaw agent by referencing the tool in your `SOUL.md`:
|
||||
|
||||
```markdown
|
||||
## Tools
|
||||
|
||||
- name: semantica_kg
|
||||
description: >
|
||||
Semantica knowledge-graph tool. Supports entity extraction, decision
|
||||
recording, graph querying, causal chain analysis, reasoning, and
|
||||
multi-format export.
|
||||
endpoint: http://localhost:8000
|
||||
auth: none
|
||||
|
||||
## Instructions
|
||||
|
||||
You have access to `semantica_kg`. Use it to:
|
||||
- Extract entities and relations from any text the user provides.
|
||||
- Record important decisions and retrieve precedents before recommending actions.
|
||||
- Run graph analytics and export results when the user asks for a summary.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.8+
|
||||
- `pip install semantica` (core)
|
||||
- `pip install semantica[openclaw]` (adds `requests` for the REST path)
|
||||
- OpenClaw ≥ latest — [openclaw.ai](https://openclaw.ai)
|
||||
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
Semantica × OpenClaw Integration
|
||||
==================================
|
||||
|
||||
First-class integration between the Semantica semantic intelligence stack and
|
||||
`OpenClaw <https://openclaw.ai>`_ — the open-source personal AI agent platform.
|
||||
|
||||
OpenClaw connects to external tools via MCP (Model Context Protocol). This
|
||||
integration exposes the full Semantica MCP surface (12 tools, 3 resources) to
|
||||
any OpenClaw agent and also ships a lightweight ``OpenClawKGTool`` that can be
|
||||
dropped directly into an OpenClaw SOUL.md tool-list as a native tool.
|
||||
|
||||
Public surface
|
||||
--------------
|
||||
OpenClawKGTool — Thin wrapper around the Semantica REST API usable as an
|
||||
OpenClaw native tool (no MCP gateway required)
|
||||
OpenClawMCPConfig — Helper that emits the ``mcporter.json`` snippet needed to
|
||||
wire Semantica's MCP server into an OpenClaw gateway
|
||||
|
||||
Quick start
|
||||
-----------
|
||||
pip install semantica
|
||||
|
||||
>>> from integrations.openclaw import OpenClawKGTool, OpenClawMCPConfig
|
||||
>>> print(OpenClawMCPConfig().to_json()) # paste into mcporter.json
|
||||
>>> tool = OpenClawKGTool(base_url="http://localhost:8000")
|
||||
>>> result = tool.extract("OpenClaw is an open-source AI agent framework.")
|
||||
|
||||
MCP quick start
|
||||
---------------
|
||||
Run the Semantica MCP server once::
|
||||
|
||||
python -m semantica.mcp_server
|
||||
|
||||
Then add the printed config snippet to your OpenClaw ``mcporter.json`` and
|
||||
restart the OpenClaw Gateway::
|
||||
|
||||
openclaw gateway restart
|
||||
|
||||
All 12 Semantica tools are then available as native OpenClaw agent tools.
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
Requires ``semantica >= 0.3.0``. The MCP path requires ``python >= 3.8`` and
|
||||
a running ``semantica.mcp_server`` instance. The REST path requires a running
|
||||
``semantica.server`` instance (``python -m semantica.server``, port 8000 by
|
||||
default).
|
||||
"""
|
||||
|
||||
from .mcp_tool import OpenClawKGTool, OpenClawMCPConfig
|
||||
|
||||
__all__ = [
|
||||
"OpenClawKGTool",
|
||||
"OpenClawMCPConfig",
|
||||
]
|
||||
|
||||
__version__ = "0.1.0"
|
||||
@@ -0,0 +1,253 @@
|
||||
"""
|
||||
OpenClaw ↔ Semantica bridge
|
||||
============================
|
||||
|
||||
Two integration paths:
|
||||
|
||||
1. **MCP (recommended)** — ``OpenClawMCPConfig`` emits the ``mcporter.json``
|
||||
snippet that wires Semantica's MCP server into the OpenClaw Gateway.
|
||||
All 12 Semantica MCP tools become native OpenClaw agent tools with no
|
||||
extra code.
|
||||
|
||||
2. **REST** — ``OpenClawKGTool`` is a plain Python class that calls the
|
||||
Semantica REST API (port 8000) and can be registered as an OpenClaw
|
||||
native tool via SOUL.md ``tools:`` entries.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# MCP config helper
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class OpenClawMCPConfig:
|
||||
"""
|
||||
Generates the ``mcporter.json`` entry needed to connect Semantica's MCP
|
||||
server to the OpenClaw Gateway.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
server_command:
|
||||
Shell command used to launch the Semantica MCP server.
|
||||
Defaults to ``"python -m semantica.mcp_server"``.
|
||||
transport:
|
||||
MCP transport protocol. OpenClaw supports ``"stdio"`` (default)
|
||||
and ``"sse"``.
|
||||
name:
|
||||
Key used in ``mcporter.json``. Defaults to ``"semantica"``.
|
||||
|
||||
Example
|
||||
-------
|
||||
>>> cfg = OpenClawMCPConfig()
|
||||
>>> print(cfg.to_json())
|
||||
# → paste into ~/.openclaw/mcporter.json, then:
|
||||
# → openclaw gateway restart
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
server_command: str = "python -m semantica.mcp_server",
|
||||
transport: str = "stdio",
|
||||
name: str = "semantica",
|
||||
) -> None:
|
||||
self.server_command = server_command
|
||||
self.transport = transport
|
||||
self.name = name
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Return the config as a plain dict."""
|
||||
parts = self.server_command.split()
|
||||
return {
|
||||
"mcpServers": {
|
||||
self.name: {
|
||||
"command": parts[0],
|
||||
"args": parts[1:],
|
||||
"transport": self.transport,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def to_json(self, indent: int = 2) -> str:
|
||||
"""Return the config as a JSON string."""
|
||||
return json.dumps(self.to_dict(), indent=indent)
|
||||
|
||||
def __repr__(self) -> str: # pragma: no cover
|
||||
return f"OpenClawMCPConfig(name={self.name!r}, transport={self.transport!r})"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# REST-based native tool
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class OpenClawKGTool:
|
||||
"""
|
||||
A Semantica knowledge-graph tool callable from an OpenClaw agent.
|
||||
|
||||
Wraps the Semantica REST API so that an OpenClaw agent configured with
|
||||
this tool (via SOUL.md ``tools:`` entries or programmatic registration)
|
||||
can extract entities, record decisions, query the graph, and more —
|
||||
without requiring the MCP gateway.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
base_url:
|
||||
Base URL of the running Semantica REST server.
|
||||
Defaults to ``"http://localhost:8000"``.
|
||||
timeout:
|
||||
Request timeout in seconds. Defaults to ``30``.
|
||||
|
||||
Notes
|
||||
-----
|
||||
``requests`` is used for HTTP calls. It is listed as an optional
|
||||
dependency under ``semantica[openclaw]``; install it with::
|
||||
|
||||
pip install semantica[openclaw]
|
||||
"""
|
||||
|
||||
TOOL_NAME = "semantica_kg"
|
||||
TOOL_DESCRIPTION = (
|
||||
"Semantica knowledge-graph tool. "
|
||||
"Supports entity extraction, decision recording, graph querying, "
|
||||
"causal chain analysis, reasoning, and multi-format export."
|
||||
)
|
||||
|
||||
def __init__(self, base_url: str = "http://localhost:8000", timeout: int = 30) -> None:
|
||||
self.base_url = base_url.rstrip("/")
|
||||
self.timeout = timeout
|
||||
self._session: Any = None
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Internal helpers
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _get_session(self) -> Any:
|
||||
if self._session is None:
|
||||
try:
|
||||
import requests
|
||||
self._session = requests.Session()
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"The 'requests' package is required for OpenClawKGTool. "
|
||||
"Install it with: pip install semantica[openclaw]"
|
||||
) from exc
|
||||
return self._session
|
||||
|
||||
def _post(self, endpoint: str, payload: Dict[str, Any]) -> Dict[str, Any]:
|
||||
session = self._get_session()
|
||||
url = f"{self.base_url}{endpoint}"
|
||||
response = session.post(url, json=payload, timeout=self.timeout)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
def _get(self, endpoint: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
||||
session = self._get_session()
|
||||
url = f"{self.base_url}{endpoint}"
|
||||
response = session.get(url, params=params or {}, timeout=self.timeout)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Extraction
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def extract(self, text: str) -> Dict[str, Any]:
|
||||
"""Extract entities and relations from *text*."""
|
||||
return self._post("/extract", {"text": text})
|
||||
|
||||
def extract_entities(self, text: str) -> List[Dict[str, Any]]:
|
||||
"""Return only the entity list from *text*."""
|
||||
result = self.extract(text)
|
||||
return result.get("entities", [])
|
||||
|
||||
def extract_relations(self, text: str) -> List[Dict[str, Any]]:
|
||||
"""Return only the relation list from *text*."""
|
||||
result = self.extract(text)
|
||||
return result.get("relations", [])
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Graph mutation
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def add_entity(self, label: str, entity_type: str = "Entity", **properties: Any) -> Dict[str, Any]:
|
||||
"""Add a node to the knowledge graph."""
|
||||
return self._post("/entities", {"label": label, "type": entity_type, **properties})
|
||||
|
||||
def add_relationship(
|
||||
self,
|
||||
source: str,
|
||||
target: str,
|
||||
relation_type: str,
|
||||
**properties: Any,
|
||||
) -> Dict[str, Any]:
|
||||
"""Add an edge between *source* and *target*."""
|
||||
return self._post(
|
||||
"/relationships",
|
||||
{"source": source, "target": target, "type": relation_type, **properties},
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Decisions
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def record_decision(
|
||||
self,
|
||||
decision_text: str,
|
||||
context: Optional[str] = None,
|
||||
**metadata: Any,
|
||||
) -> Dict[str, Any]:
|
||||
"""Record a decision in the graph."""
|
||||
payload: Dict[str, Any] = {"decision": decision_text}
|
||||
if context:
|
||||
payload["context"] = context
|
||||
payload.update(metadata)
|
||||
return self._post("/decisions", payload)
|
||||
|
||||
def query_decisions(self, query: str, limit: int = 10) -> List[Dict[str, Any]]:
|
||||
"""Search recorded decisions."""
|
||||
result = self._get("/decisions/search", {"q": query, "limit": limit})
|
||||
return result.get("decisions", [])
|
||||
|
||||
def find_precedents(self, decision_text: str, top_k: int = 5) -> List[Dict[str, Any]]:
|
||||
"""Find past decisions similar to *decision_text*."""
|
||||
result = self._post("/decisions/precedents", {"decision": decision_text, "top_k": top_k})
|
||||
return result.get("precedents", [])
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Analytics & reasoning
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def get_causal_chain(self, node_id: str, depth: int = 3) -> Dict[str, Any]:
|
||||
"""Retrieve the causal chain rooted at *node_id*."""
|
||||
return self._get("/causal-chain", {"node_id": node_id, "depth": depth})
|
||||
|
||||
def run_reasoning(self, rules: List[str], facts: List[str]) -> Dict[str, Any]:
|
||||
"""Run the Semantica forward-chaining reasoner."""
|
||||
return self._post("/reason", {"rules": rules, "facts": facts})
|
||||
|
||||
def get_graph_analytics(self) -> Dict[str, Any]:
|
||||
"""Return graph-level analytics (centrality, communities, etc.)."""
|
||||
return self._get("/analytics")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Export
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def export_graph(self, fmt: str = "json") -> str:
|
||||
"""Export the graph in *fmt* (``json``, ``ttl``, ``graphml``, …)."""
|
||||
result = self._get("/export", {"format": fmt})
|
||||
return result.get("data", "")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Summary
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def get_graph_summary(self) -> Dict[str, Any]:
|
||||
"""Return a high-level summary of the current graph."""
|
||||
return self._get("/graph/summary")
|
||||
|
||||
def __repr__(self) -> str: # pragma: no cover
|
||||
return f"OpenClawKGTool(base_url={self.base_url!r})"
|
||||
+171
-167
@@ -1,195 +1,171 @@
|
||||
# Semantica Plugins (Community Guide)
|
||||
|
||||
Semantica ships a shared plugin bundle under `plugins/` with skills, agents, and hooks for knowledge graphs, context graphs, decision intelligence, reasoning, explainability, provenance, ontology, and export workflows.
|
||||
> **v0.4.0** — 17 domain skills · 3 agents · 8 platform plugins · Knowledge Explorer UI
|
||||
|
||||
This README covers installation across every supported platform.
|
||||
Semantica ships a shared plugin bundle under `plugins/` that works across every major AI coding assistant. Connect any supported platform to Semantica's knowledge graph engine for semantic extraction, decision intelligence, reasoning, provenance, ontology, and export workflows.
|
||||
|
||||
## Supported Platforms
|
||||
---
|
||||
|
||||
| Platform | Method | Config file |
|
||||
|---|---|---|
|
||||
| Claude Code | Native plugin bundle | `plugins/.claude-plugin/plugin.json` |
|
||||
| Cursor | Native plugin bundle | `plugins/.cursor-plugin/plugin.json` |
|
||||
| Codex CLI | Native plugin bundle | `plugins/.codex-plugin/plugin.json` |
|
||||
| Windsurf | MCP server + plugin bundle | `plugins/.windsurf-plugin/plugin.json` |
|
||||
| Cline (VS Code) | MCP server + plugin bundle | `plugins/.cline-plugin/plugin.json` |
|
||||
| Continue | MCP server | `plugins/.continue-plugin/plugin.json` |
|
||||
| VS Code | MCP server | `plugins/.vscode-plugin/plugin.json` |
|
||||
| Claude Desktop | MCP server | — (see MCP section below) |
|
||||
| Any MCP client | MCP server | `python -m semantica.mcp_server` |
|
||||
## Platform Plugins
|
||||
|
||||
Semantica provides a dedicated plugin for each platform. Every plugin shares the same `skills/`, `agents/`, and `hooks/` bundle — only the manifest format differs.
|
||||
|
||||
| # | Platform | Plugin Folder | Setup |
|
||||
|---|----------|--------------|-------|
|
||||
| 1 | **Claude Code** | `.claude-plugin/` | `claude --plugin-dir ./plugins` |
|
||||
| 2 | **Cursor** | `.cursor-plugin/` | Cursor Marketplace → refresh |
|
||||
| 3 | **Codex** | `.codex-plugin/` | Marketplace UI → install |
|
||||
| 4 | **Cline** | `.cline-plugin/` | Cline MCP settings |
|
||||
| 5 | **Windsurf** | `.windsurf-plugin/` | `mcp_config.json` |
|
||||
| 6 | **Continue** | `.continue-plugin/` | `~/.continue/config.json` |
|
||||
| 7 | **OpenClaw** | `.openclaw-plugin/` | `mcporter.json` |
|
||||
| 8 | **VS Code** | `.vscode-plugin/` | `settings.json` MCP entry |
|
||||
|
||||
---
|
||||
|
||||
## What's Included
|
||||
|
||||
```
|
||||
plugins/
|
||||
├── skills/ # 17 domain skills (slash commands)
|
||||
├── agents/ # 3 specialized agents
|
||||
├── hooks/ # hooks.json
|
||||
├── .claude-plugin/ # Claude Code manifest + marketplace
|
||||
├── .cursor-plugin/ # Cursor manifest + marketplace
|
||||
├── .codex-plugin/ # Codex manifest + marketplace
|
||||
├── .cline-plugin/ # Cline manifest + marketplace
|
||||
├── .windsurf-plugin/ # Windsurf manifest + marketplace
|
||||
├── .continue-plugin/ # Continue manifest + marketplace
|
||||
├── .openclaw-plugin/ # OpenClaw manifest + marketplace
|
||||
└── .vscode-plugin/ # VS Code manifest + marketplace
|
||||
```
|
||||
|
||||
### Skills (17)
|
||||
|
||||
`extract` · `ingest` · `query` · `ontology` · `validate` · `deduplicate` · `embed` · `reason` · `decision` · `causal` · `temporal` · `provenance` · `policy` · `explain` · `export` · `change` · `visualize`
|
||||
|
||||
### Agents (3)
|
||||
|
||||
`decision-advisor` · `explainability` · `kg-assistant`
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Clone the repository:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Hawksight-AI/semantica.git
|
||||
cd semantica
|
||||
pip install semantica # Python 3.10+
|
||||
```
|
||||
|
||||
2. Ensure the plugin bundle exists at:
|
||||
---
|
||||
|
||||
```text
|
||||
plugins/
|
||||
skills/ ← 17 domain skills
|
||||
agents/ ← 3 specialized agents
|
||||
hooks/ ← hooks.json
|
||||
.claude-plugin/ ← Claude Code manifest
|
||||
.cursor-plugin/ ← Cursor manifest
|
||||
.codex-plugin/ ← Codex CLI manifest
|
||||
.windsurf-plugin/← Windsurf manifest + MCP config
|
||||
.cline-plugin/ ← Cline manifest + MCP config
|
||||
.continue-plugin/← Continue manifest + MCP config
|
||||
.vscode-plugin/ ← VS Code manifest + MCP config
|
||||
## Knowledge Explorer (v0.4.0)
|
||||
|
||||
Launch the interactive graph dashboard:
|
||||
|
||||
```bash
|
||||
semantica-explorer --graph my_graph.json --port 8000
|
||||
```
|
||||
|
||||
## Plugin Contents
|
||||
Open **http://localhost:5174** to explore:
|
||||
|
||||
- `skills/`: 17 domain skills (`causal`, `decision`, `explain`, `reason`, `temporal`, etc.)
|
||||
- `agents/`: specialized agents (`decision-advisor`, `explainability`, `kg-assistant`)
|
||||
- `hooks/hooks.json`: plugin hook configuration
|
||||
- `.claude-plugin/plugin.json`: Claude manifest
|
||||
- `.cursor-plugin/plugin.json`: Cursor manifest
|
||||
- `.codex-plugin/plugin.json`: Codex manifest
|
||||
- `*/marketplace.json`: local marketplace definitions
|
||||
- **Graph** — interactive canvas with ForceAtlas2 layout, path highlight, community coloring
|
||||
- **Decisions** — causal chains and outcome analysis
|
||||
- **Reasoning** — run deductive / abductive rules
|
||||
- **SPARQL** — Monaco editor for graph queries
|
||||
- **Vocabulary** — ontology concept tree
|
||||
- **Lineage** — provenance lineage diagram
|
||||
- **Import / Export** — JSON, RDF, Parquet, GraphML
|
||||
|
||||
## Install and Use in Claude Code
|
||||
---
|
||||
|
||||
### Local install (fastest)
|
||||
## Installation by Platform
|
||||
|
||||
From the repository root:
|
||||
### Claude Code
|
||||
|
||||
```bash
|
||||
claude --plugin-dir ./plugins
|
||||
```
|
||||
|
||||
If your Claude setup uses plugin commands in-session, use:
|
||||
Or inside a session:
|
||||
|
||||
```bash
|
||||
/plugin install ./plugins
|
||||
```
|
||||
|
||||
### Install from a GitHub marketplace
|
||||
Verify:
|
||||
|
||||
Add a marketplace hosted in git:
|
||||
|
||||
```bash
|
||||
/plugin marketplace add <owner>/semantica
|
||||
```
|
||||
|
||||
Install Semantica from that marketplace:
|
||||
|
||||
```bash
|
||||
/plugin install semantica@<marketplace-name>
|
||||
```
|
||||
|
||||
### Verify in Claude
|
||||
|
||||
Run one of these in chat:
|
||||
|
||||
```text
|
||||
/semantica:decision list
|
||||
/semantica:explain decision <decision_id>
|
||||
```
|
||||
|
||||
If the plugin is installed correctly, Claude should recognize the `/semantica:*` skills.
|
||||
---
|
||||
|
||||
## Install and Use in Codex
|
||||
### Cursor
|
||||
|
||||
Cursor reads `.cursor-plugin/plugin.json` and `.cursor-plugin/marketplace.json` automatically. Publish the `plugins/` directory and refresh in Cursor Marketplace to pick up updates.
|
||||
|
||||
Verify:
|
||||
|
||||
```
|
||||
/semantica:visualize topology
|
||||
/semantica:reason deductive "IF Person(x) THEN Mortal(x)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Codex
|
||||
|
||||
1. Ensure your repo marketplace exists at `.agents/plugins/marketplace.json`.
|
||||
2. Point the plugin entry `source.path` to `./plugins` (or your chosen plugin directory).
|
||||
2. Set `source.path` to `./plugins` in the plugin entry.
|
||||
3. Restart Codex and install from the marketplace UI.
|
||||
|
||||
Codex manifest used by this bundle:
|
||||
Verify:
|
||||
|
||||
- `.codex-plugin/plugin.json`
|
||||
|
||||
### Verify in Codex
|
||||
|
||||
After install, run a Semantica skill command in chat, for example:
|
||||
|
||||
```text
|
||||
```
|
||||
/semantica:causal chain --subject <decision_id> --depth 3
|
||||
```
|
||||
|
||||
## Install and Use in Cursor
|
||||
---
|
||||
|
||||
Cursor reads plugin metadata from:
|
||||
### Cline
|
||||
|
||||
- `.cursor-plugin/plugin.json`
|
||||
- `.cursor-plugin/marketplace.json`
|
||||
|
||||
If you maintain a team/community plugin repo, publish this `plugins/` directory and refresh/reinstall in Cursor Marketplace to pick up updates.
|
||||
|
||||
### Verify in Cursor
|
||||
|
||||
Try one of these commands:
|
||||
|
||||
```text
|
||||
/semantica:reason deductive "IF Person(x) THEN Mortal(x)"
|
||||
/semantica:visualize topology
|
||||
```
|
||||
|
||||
## First Commands to Try
|
||||
|
||||
After installing on any platform, these are good smoke tests:
|
||||
|
||||
1. `/semantica:decision record <category> "<scenario>" "<reasoning>" <outcome> <confidence>`
|
||||
2. `/semantica:decision list`
|
||||
3. `/semantica:causal chain --subject <decision_id> --depth 3`
|
||||
4. `/semantica:explain decision <decision_id>`
|
||||
5. `/semantica:validate graph`
|
||||
|
||||
## MCP Server (Windsurf · Cline · Continue · VS Code · Claude Desktop · Any tool)
|
||||
|
||||
Semantica includes a full MCP server (`semantica/mcp_server.py`) that exposes 12 tools and 3 resources over stdio — compatible with any MCP-aware tool.
|
||||
|
||||
### Start the server
|
||||
|
||||
```bash
|
||||
python -m semantica.mcp_server
|
||||
```
|
||||
|
||||
### Configure in your tool
|
||||
|
||||
**Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"semantica": {
|
||||
"command": "python",
|
||||
"args": ["-m", "semantica.mcp_server"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Windsurf** — `~/.codeium/windsurf/mcp_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"semantica": {
|
||||
"command": "python",
|
||||
"args": ["-m", "semantica.mcp_server"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Cline** — Cline MCP settings panel → Add server:
|
||||
In Cline MCP settings, add:
|
||||
|
||||
```json
|
||||
{
|
||||
"semantica": {
|
||||
"command": "python",
|
||||
"args": ["-m", "semantica.mcp_server"]
|
||||
"args": ["-m", "semantica.mcp_server"],
|
||||
"env": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Continue** — `~/.continue/config.json`:
|
||||
---
|
||||
|
||||
### Windsurf
|
||||
|
||||
Add to `~/.codeium/windsurf/mcp_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"semantica": {
|
||||
"command": "python",
|
||||
"args": ["-m", "semantica.mcp_server"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Continue
|
||||
|
||||
Add to `~/.continue/config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -203,7 +179,50 @@ python -m semantica.mcp_server
|
||||
}
|
||||
```
|
||||
|
||||
**VS Code** — `settings.json`:
|
||||
All 17 Semantica skills appear in the `@semantica` context provider dropdown.
|
||||
|
||||
---
|
||||
|
||||
### OpenClaw
|
||||
|
||||
Add to `~/.openclaw/mcporter.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"semantica": {
|
||||
"command": "python",
|
||||
"args": ["-m", "semantica.mcp_server"],
|
||||
"transport": "stdio"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then restart the gateway:
|
||||
|
||||
```bash
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### VS Code
|
||||
|
||||
Add to `settings.json` (GitHub Copilot Chat):
|
||||
|
||||
```json
|
||||
{
|
||||
"github.copilot.chat.mcp.servers": {
|
||||
"semantica": {
|
||||
"command": "python",
|
||||
"args": ["-m", "semantica.mcp_server"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or for the VS Code MCP extension:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -216,40 +235,25 @@ python -m semantica.mcp_server
|
||||
}
|
||||
```
|
||||
|
||||
### Available MCP tools
|
||||
---
|
||||
|
||||
| Tool | Description |
|
||||
|---|---|
|
||||
| `extract_entities` | Named entity recognition from text |
|
||||
| `extract_relations` | Relation and triplet extraction from text |
|
||||
| `record_decision` | Record a decision with full context and metadata |
|
||||
| `query_decisions` | Query recorded decisions by natural language or category |
|
||||
| `find_precedents` | Find past decisions similar to a scenario |
|
||||
| `get_causal_chain` | Trace upstream/downstream causal chain from a decision |
|
||||
| `add_entity` | Add a node/entity to the knowledge graph |
|
||||
| `add_relationship` | Add a directed edge between two entities |
|
||||
| `run_reasoning` | Run IF/THEN rules over facts to derive new facts |
|
||||
| `get_graph_analytics` | PageRank centrality and community detection |
|
||||
| `export_graph` | Export graph as Turtle, JSON-LD, N-Triples, or JSON |
|
||||
| `get_graph_summary` | Node count, decision count, graph status |
|
||||
## First Commands to Try
|
||||
|
||||
### Available MCP resources
|
||||
After installing on any platform:
|
||||
|
||||
| URI | Description |
|
||||
|---|---|
|
||||
| `semantica://graph/summary` | High-level graph statistics |
|
||||
| `semantica://decisions/list` | All recorded decisions |
|
||||
| `semantica://schema/info` | Server info and capability list |
|
||||
```
|
||||
/semantica:decision record <category> "<scenario>" "<reasoning>" <outcome> <confidence>
|
||||
/semantica:decision list
|
||||
/semantica:causal chain --subject <decision_id> --depth 3
|
||||
/semantica:explain decision <decision_id>
|
||||
/semantica:validate graph
|
||||
/semantica:visualize topology
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `SEMANTICA_KG_PATH` | Path to a persisted graph to load on start |
|
||||
| `SEMANTICA_LOG_LEVEL` | Log level: DEBUG, INFO, WARNING (default: WARNING) |
|
||||
---
|
||||
|
||||
## Community Notes
|
||||
|
||||
- Keep plugin name/version/keywords updated in each manifest before publishing.
|
||||
- Keep skill frontmatter consistent (`name` + `description`) for reliable discovery.
|
||||
- For open-source sharing, include this folder as-is so skills, agents, and hooks remain bundled.
|
||||
- Keep `name` / `version` / `keywords` updated in each manifest before publishing.
|
||||
- Keep skill frontmatter (`name` + `description`) consistent for reliable discovery.
|
||||
- Include `plugins/` as-is when sharing — skills, agents, and hooks must stay bundled.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Semantica — Cline Plugin
|
||||
|
||||
Adds all 17 Semantica skills, 3 agents, and hook configuration to Cline (VS Code extension).
|
||||
> **v0.4.0** — Adds all 17 Semantica skills, 3 agents, and hook configuration to Cline (VS Code extension).
|
||||
|
||||
## MCP Server Setup (recommended)
|
||||
|
||||
@@ -16,9 +16,17 @@ In Cline settings, add a new MCP server:
|
||||
}
|
||||
```
|
||||
|
||||
Cline will discover all 12 Semantica tools automatically on connection.
|
||||
Cline will discover all 17 Semantica skills and 3 agents automatically on connection.
|
||||
|
||||
## Knowledge Explorer
|
||||
|
||||
```bash
|
||||
semantica-explorer --graph my_graph.json --port 8000
|
||||
```
|
||||
|
||||
Open `http://localhost:5174` for the interactive dashboard.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.8+
|
||||
- Python 3.10+
|
||||
- `pip install semantica`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Semantica — Continue Plugin
|
||||
|
||||
Adds Semantica as an MCP server and context provider to [Continue.dev](https://continue.dev).
|
||||
> **v0.4.0** — Adds Semantica as an MCP server and context provider to [Continue.dev](https://continue.dev).
|
||||
|
||||
## MCP Server Setup
|
||||
|
||||
@@ -18,9 +18,17 @@ Add to `~/.continue/config.json`:
|
||||
}
|
||||
```
|
||||
|
||||
Continue will show all Semantica tools in the `@semantica` context provider dropdown.
|
||||
Continue will show all 17 Semantica skills in the `@semantica` context provider dropdown.
|
||||
|
||||
## Knowledge Explorer
|
||||
|
||||
```bash
|
||||
semantica-explorer --graph my_graph.json --port 8000
|
||||
```
|
||||
|
||||
Open `http://localhost:5174` for the interactive graph dashboard.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.8+
|
||||
- Python 3.10+
|
||||
- `pip install semantica`
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# Semantica — OpenClaw Plugin
|
||||
|
||||
> **v0.4.0** — Adds all 17 Semantica skills, 3 agents, and the full MCP integration to [OpenClaw](https://openclaw.ai) — the open-source personal AI agent platform.
|
||||
|
||||
## MCP Server Setup (recommended)
|
||||
|
||||
### 1. Start the Semantica MCP server
|
||||
|
||||
```bash
|
||||
python -m semantica.mcp_server
|
||||
```
|
||||
|
||||
### 2. Add to `mcporter.json`
|
||||
|
||||
Paste the following into your OpenClaw `mcporter.json` (usually `~/.openclaw/mcporter.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"semantica": {
|
||||
"command": "python",
|
||||
"args": ["-m", "semantica.mcp_server"],
|
||||
"transport": "stdio"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Restart the OpenClaw Gateway
|
||||
|
||||
```bash
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
OpenClaw will automatically discover all 17 Semantica tools and 3 agents.
|
||||
|
||||
## Skills
|
||||
|
||||
All 17 skills under [`plugins/skills/`](../skills/) are available once the plugin is loaded:
|
||||
|
||||
`extract` · `ingest` · `query` · `ontology` · `validate` · `deduplicate` · `embed` · `reason` · `decision` · `causal` · `temporal` · `provenance` · `policy` · `explain` · `export` · `change` · `visualize`
|
||||
|
||||
## Native Tool (REST, no MCP gateway)
|
||||
|
||||
For agents that cannot use the MCP gateway, use the `OpenClawKGTool` REST wrapper:
|
||||
|
||||
```python
|
||||
from integrations.openclaw import OpenClawKGTool
|
||||
|
||||
tool = OpenClawKGTool(base_url="http://localhost:8000")
|
||||
entities = tool.extract_entities("Alice manages the project.")
|
||||
tool.record_decision("Deploy model v2 to production")
|
||||
summary = tool.get_graph_summary()
|
||||
```
|
||||
|
||||
See [`integrations/openclaw/README.md`](../../integrations/openclaw/README.md) for the full guide, including SOUL.md agent snippets.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.10+
|
||||
- `pip install semantica`
|
||||
- OpenClaw — [openclaw.ai](https://openclaw.ai)
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "semantica-openclaw",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "semantica",
|
||||
"description": "Semantica plugin for OpenClaw: knowledge graph skills, decision intelligence, reasoning, extraction, and visualization.",
|
||||
"source": "./",
|
||||
"category": "Productivity",
|
||||
"tags": [
|
||||
"knowledge-graph",
|
||||
"reasoning",
|
||||
"semantica",
|
||||
"openclaw",
|
||||
"mcp"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "semantica-openclaw",
|
||||
"displayName": "Semantica OpenClaw Plugin",
|
||||
"description": "Semantica plugin for OpenClaw: knowledge graph skills, decision intelligence, reasoning, extraction, and visualization via MCP and native REST tool.",
|
||||
"version": "0.1.0",
|
||||
"author": {
|
||||
"name": "Semantica Contributors"
|
||||
},
|
||||
"homepage": "https://github.com/Hawksight-AI/semantica",
|
||||
"repository": "https://github.com/Hawksight-AI/semantica",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"semantica",
|
||||
"knowledge graph",
|
||||
"openclaw",
|
||||
"context graphs",
|
||||
"decision intelligence",
|
||||
"explainability",
|
||||
"causal analysis",
|
||||
"provenance",
|
||||
"ontology",
|
||||
"graph analytics",
|
||||
"semantic extraction",
|
||||
"visualization",
|
||||
"reasoning",
|
||||
"mcp"
|
||||
],
|
||||
"skills": "../skills",
|
||||
"agents": "../agents",
|
||||
"hooks": "../hooks/hooks.json",
|
||||
"mcp": {
|
||||
"server": "python -m semantica.mcp_server",
|
||||
"transport": "stdio"
|
||||
},
|
||||
"openclaw": {
|
||||
"mcporter": {
|
||||
"mcpServers": {
|
||||
"semantica": {
|
||||
"command": "python",
|
||||
"args": ["-m", "semantica.mcp_server"],
|
||||
"transport": "stdio"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# Semantica — VS Code Plugin
|
||||
|
||||
Adds Semantica as an MCP server to VS Code (via GitHub Copilot Chat or any MCP-aware extension).
|
||||
> **v0.4.0** — Adds Semantica as an MCP server to VS Code (via GitHub Copilot Chat or any MCP-aware extension).
|
||||
|
||||
## MCP Server Setup
|
||||
|
||||
@@ -30,7 +30,19 @@ Or if using the VS Code MCP extension directly:
|
||||
}
|
||||
```
|
||||
|
||||
VS Code will discover all 17 Semantica skills and 3 agents automatically on connection.
|
||||
|
||||
## Knowledge Explorer
|
||||
|
||||
Launch the interactive graph dashboard from the terminal:
|
||||
|
||||
```bash
|
||||
semantica-explorer --graph my_graph.json --port 8000
|
||||
```
|
||||
|
||||
Open `http://localhost:5174` to explore nodes, edges, decisions, SPARQL, lineage, and more.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.8+
|
||||
- Python 3.10+
|
||||
- `pip install semantica`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Semantica — Windsurf Plugin
|
||||
|
||||
Adds all 17 Semantica skills, 3 agents, and hook configuration to Windsurf.
|
||||
> **v0.4.0** — Adds all 17 Semantica skills, 3 agents, and hook configuration to Windsurf.
|
||||
|
||||
## MCP Server Setup (recommended)
|
||||
|
||||
@@ -17,13 +17,23 @@ Add to your Windsurf MCP config (`~/.codeium/windsurf/mcp_config.json`):
|
||||
}
|
||||
```
|
||||
|
||||
Windsurf will then have access to all 12 Semantica tools (extract, record_decision, query_decisions, find_precedents, get_causal_chain, add_entity, add_relationship, run_reasoning, get_graph_analytics, export_graph, and more) directly in the AI panel.
|
||||
Windsurf will have access to all 17 Semantica skills (`extract`, `record_decision`, `query_decisions`, `find_precedents`, `get_causal_chain`, `add_entity`, `add_relationship`, `run_reasoning`, `get_graph_analytics`, `export_graph`, and more) directly in the AI panel.
|
||||
|
||||
## Skills
|
||||
|
||||
All 17 skills under `plugins/skills/` are available as slash commands once the plugin is loaded.
|
||||
All 17 skills under `plugins/skills/` are available as slash commands once the plugin is loaded:
|
||||
|
||||
`extract` · `ingest` · `query` · `ontology` · `validate` · `deduplicate` · `embed` · `reason` · `decision` · `causal` · `temporal` · `provenance` · `policy` · `explain` · `export` · `change` · `visualize`
|
||||
|
||||
## Knowledge Explorer
|
||||
|
||||
```bash
|
||||
semantica-explorer --graph my_graph.json --port 8000
|
||||
```
|
||||
|
||||
Open `http://localhost:5174` for the interactive graph dashboard.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.8+
|
||||
- Python 3.10+
|
||||
- `pip install semantica`
|
||||
|
||||
@@ -10,7 +10,7 @@ Main exports:
|
||||
- Config: Configuration management
|
||||
"""
|
||||
|
||||
__version__ = "0.3.0"
|
||||
__version__ = "0.4.0"
|
||||
__author__ = "Semantica Contributors"
|
||||
__license__ = "MIT"
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Request, WebSocket, WebSocketDisconnect
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse, JSONResponse
|
||||
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from .. import __version__
|
||||
@@ -127,6 +127,17 @@ def create_app(session: Optional[GraphSession] = None) -> FastAPI:
|
||||
except WebSocketDisconnect:
|
||||
manager.disconnect(websocket)
|
||||
|
||||
@app.get("/", include_in_schema=False)
|
||||
async def root():
|
||||
index_path = Path(__file__).resolve().parent.parent / "static" / "index.html"
|
||||
if index_path.is_file():
|
||||
return FileResponse(index_path)
|
||||
return HTMLResponse(
|
||||
'<!doctype html><html lang="en"><head><meta charset="UTF-8">'
|
||||
'<title>Semantica Knowledge Explorer</title></head>'
|
||||
'<body><div id="root"></div></body></html>'
|
||||
)
|
||||
|
||||
@app.get("/api/health")
|
||||
async def health():
|
||||
return {"status": "healthy"}
|
||||
|
||||
@@ -8,7 +8,7 @@ modify Semantica core.
|
||||
import asyncio
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
|
||||
from ..dependencies import get_session
|
||||
from ..schemas import AnnotationCreate, AnnotationResponse
|
||||
@@ -35,7 +35,7 @@ async def create_annotation(
|
||||
"""Create a new annotation on a node."""
|
||||
node = await asyncio.to_thread(session.get_node, body.node_id)
|
||||
if node is None:
|
||||
raise KeyError(body.node_id)
|
||||
raise HTTPException(status_code=404, detail=f"Node '{body.node_id}' not found")
|
||||
|
||||
ann_data = body.model_dump()
|
||||
ann_id = await asyncio.to_thread(session.add_annotation, ann_data)
|
||||
@@ -61,5 +61,5 @@ async def delete_annotation(
|
||||
"""Delete an annotation by ID."""
|
||||
deleted = await asyncio.to_thread(session.delete_annotation, annotation_id)
|
||||
if not deleted:
|
||||
raise KeyError(annotation_id)
|
||||
raise HTTPException(status_code=404, detail=f"Annotation '{annotation_id}' not found")
|
||||
return None
|
||||
|
||||
@@ -5,7 +5,7 @@ Decision routes using ContextGraph-native fallbacks.
|
||||
import asyncio
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
|
||||
from ..dependencies import get_session
|
||||
from ..schemas import CausalChainResponse, ComplianceResponse, DecisionResponse
|
||||
@@ -59,7 +59,7 @@ async def get_decision(
|
||||
):
|
||||
node = await asyncio.to_thread(session.get_node, decision_id)
|
||||
if node is None:
|
||||
raise KeyError(decision_id)
|
||||
raise HTTPException(status_code=404, detail=f"Decision '{decision_id}' not found")
|
||||
return _node_to_decision(node)
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ async def get_causal_chain(
|
||||
):
|
||||
node = await asyncio.to_thread(session.get_node, decision_id)
|
||||
if node is None:
|
||||
raise KeyError(decision_id)
|
||||
raise HTTPException(status_code=404, detail=f"Decision '{decision_id}' not found")
|
||||
|
||||
neighbors = await asyncio.to_thread(session.get_neighbors, decision_id, 5)
|
||||
chain = [
|
||||
@@ -94,7 +94,7 @@ async def get_precedents(
|
||||
):
|
||||
node = await asyncio.to_thread(session.get_node, decision_id)
|
||||
if node is None:
|
||||
raise KeyError(decision_id)
|
||||
raise HTTPException(status_code=404, detail=f"Decision '{decision_id}' not found")
|
||||
|
||||
properties = node.get("properties", {})
|
||||
category = str(properties.get("category", ""))
|
||||
@@ -132,7 +132,7 @@ async def check_compliance(
|
||||
):
|
||||
node = await asyncio.to_thread(session.get_node, decision_id)
|
||||
if node is None:
|
||||
raise KeyError(decision_id)
|
||||
raise HTTPException(status_code=404, detail=f"Decision '{decision_id}' not found")
|
||||
|
||||
edges, _ = await asyncio.to_thread(session.get_edges, skip=0, limit=999_999)
|
||||
violation_types = {"violates", "non_compliant", "breaches"}
|
||||
|
||||
@@ -6,7 +6,7 @@ import asyncio
|
||||
import re
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
|
||||
from ..dependencies import get_session
|
||||
from ..schemas import (
|
||||
@@ -173,11 +173,12 @@ async def extract_entities(
|
||||
relations=[_safe_dict(relation) for relation in rel_list],
|
||||
)
|
||||
except ImportError:
|
||||
raise ValueError(
|
||||
"semantic_extract module not available. Ensure spacy and transformers are installed."
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="semantic_extract module not available. Ensure spacy and transformers are installed.",
|
||||
)
|
||||
except Exception as exc:
|
||||
raise ValueError(f"Extraction failed: {exc}")
|
||||
raise HTTPException(status_code=422, detail=f"Extraction failed: {exc}")
|
||||
|
||||
|
||||
@router.post("/api/enrich/links", response_model=LinkPredictionResponse)
|
||||
@@ -187,11 +188,11 @@ async def predict_links(
|
||||
):
|
||||
predictor = session.link_predictor
|
||||
if predictor is None:
|
||||
raise ValueError("LinkPredictor not available; KG extras may not be installed.")
|
||||
raise HTTPException(status_code=503, detail="LinkPredictor not available; KG extras may not be installed.")
|
||||
|
||||
node = await asyncio.to_thread(session.get_node, body.node_id)
|
||||
if node is None:
|
||||
raise KeyError(body.node_id)
|
||||
raise HTTPException(status_code=404, detail=f"Node '{body.node_id}' not found")
|
||||
|
||||
nodes, _ = await asyncio.to_thread(session.get_nodes, skip=0, limit=999_999)
|
||||
edges, _ = await asyncio.to_thread(session.get_edges, skip=0, limit=999_999)
|
||||
@@ -248,9 +249,9 @@ async def detect_duplicates(
|
||||
duplicate_list = duplicates if isinstance(duplicates, list) else getattr(duplicates, "duplicates", [])
|
||||
return DedupResponse(duplicates=[_safe_dict(item) for item in duplicate_list], total_flagged=len(duplicate_list))
|
||||
except ImportError:
|
||||
raise ValueError("Deduplication module not available.")
|
||||
raise HTTPException(status_code=503, detail="Deduplication module not available.")
|
||||
except Exception as exc:
|
||||
raise ValueError(f"Dedup scan failed: {exc}")
|
||||
raise HTTPException(status_code=422, detail=f"Dedup scan failed: {exc}")
|
||||
|
||||
|
||||
@router.post("/api/reason", response_model=ReasoningResponse)
|
||||
@@ -295,7 +296,7 @@ async def merge_nodes(
|
||||
|
||||
node = await asyncio.to_thread(session.get_node, primary_id)
|
||||
if node is None:
|
||||
raise ValueError(f"Primary node {primary_id} not found")
|
||||
raise HTTPException(status_code=404, detail=f"Primary node '{primary_id}' not found")
|
||||
|
||||
def _do_merge() -> tuple[list[str], int]:
|
||||
removed: list[str] = []
|
||||
|
||||
@@ -6,7 +6,7 @@ import asyncio
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
|
||||
from ..dependencies import get_session
|
||||
from ..schemas import (
|
||||
@@ -83,7 +83,7 @@ async def get_node(
|
||||
):
|
||||
node = await asyncio.to_thread(session.get_node, node_id)
|
||||
if node is None:
|
||||
raise KeyError(node_id)
|
||||
raise HTTPException(status_code=404, detail=f"Node '{node_id}' not found")
|
||||
return _node_response(node)
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ async def find_path(
|
||||
):
|
||||
path_finder = session.path_finder
|
||||
if path_finder is None:
|
||||
raise ValueError("PathFinder not available; KG extras may not be installed.")
|
||||
raise HTTPException(status_code=503, detail="PathFinder not available; KG extras may not be installed.")
|
||||
|
||||
graph_dict = await asyncio.to_thread(session.build_graph_dict)
|
||||
path_fn = (
|
||||
@@ -158,7 +158,10 @@ async def find_path(
|
||||
if algorithm == _PathAlgorithm.dijkstra
|
||||
else path_finder.bfs_shortest_path
|
||||
)
|
||||
result = await asyncio.to_thread(path_fn, graph_dict, node_id, target)
|
||||
try:
|
||||
result = await asyncio.to_thread(path_fn, graph_dict, node_id, target)
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=404, detail=f"No path found from '{node_id}' to '{target}': {exc}")
|
||||
|
||||
path_nodes = result.get("path", []) if isinstance(result, dict) else (result or [])
|
||||
total_weight = result.get("total_weight", 0.0) if isinstance(result, dict) else 0.0
|
||||
|
||||
@@ -103,7 +103,7 @@ async def temporal_patterns(
|
||||
|
||||
detector = TemporalPatternDetector()
|
||||
graph_dict = await asyncio.to_thread(session.build_graph_dict)
|
||||
patterns = await asyncio.to_thread(detector.detect_patterns, graph_dict)
|
||||
patterns = await asyncio.to_thread(detector.detect_temporal_patterns, graph_dict)
|
||||
if isinstance(patterns, dict):
|
||||
patterns = patterns.get("patterns", [])
|
||||
return TemporalPatternResponse(patterns=patterns if isinstance(patterns, list) else [])
|
||||
|
||||
@@ -126,12 +126,14 @@ from .temporal_query import (
|
||||
TemporalPatternDetector,
|
||||
TemporalVersionManager,
|
||||
)
|
||||
from .knowledge_graph import KnowledgeGraph
|
||||
from .temporal_model import BiTemporalFact, TemporalBound
|
||||
from .temporal_normalizer import TemporalNormalizer
|
||||
from .temporal_query_rewriter import TemporalQueryRewriter, TemporalQueryResult
|
||||
|
||||
__all__ = [
|
||||
# Core Classes
|
||||
"KnowledgeGraph",
|
||||
"GraphBuilder",
|
||||
"GraphBuilderWithProvenance",
|
||||
"EntityResolver",
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
KnowledgeGraph dataclass — canonical in-memory representation.
|
||||
|
||||
This is the formal type produced by the Semantica KG pipeline and consumed
|
||||
by visualizers, exporters, and other downstream components. It is a thin,
|
||||
immutable-friendly wrapper around three plain collections so that isinstance
|
||||
checks, type hints, and IDEs can surface the type rather than relying on
|
||||
bare dicts.
|
||||
|
||||
Keeping this in its own file avoids circular imports between the kg and
|
||||
visualization sub-packages.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
@dataclass
|
||||
class KnowledgeGraph:
|
||||
"""
|
||||
Canonical in-memory knowledge graph.
|
||||
|
||||
Attributes:
|
||||
entities: List of entity dicts with at minimum ``id`` and ``type`` keys.
|
||||
relationships: List of relationship dicts with at minimum ``source``,
|
||||
``target``, and ``type`` keys.
|
||||
metadata: Arbitrary graph-level metadata (e.g. build timestamps,
|
||||
entity-resolution flags).
|
||||
"""
|
||||
|
||||
entities: List[Dict[str, Any]] = field(default_factory=list)
|
||||
relationships: List[Dict[str, Any]] = field(default_factory=list)
|
||||
metadata: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Convenience helpers
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""Return the number of entities (mirrors the most common 'size' query)."""
|
||||
return len(self.entities)
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
return bool(self.entities or self.relationships)
|
||||
@@ -53,6 +53,14 @@ except (ImportError, OSError):
|
||||
|
||||
from ..utils.exceptions import ProcessingError
|
||||
from ..utils.logging import get_logger
|
||||
|
||||
# Optional import — keeps the visualizer usable even if the kg sub-package
|
||||
# is not installed, and avoids circular-import risk at module level.
|
||||
try:
|
||||
from ..kg.knowledge_graph import KnowledgeGraph as _KnowledgeGraph
|
||||
except Exception: # pragma: no cover
|
||||
_KnowledgeGraph = None # type: ignore[assignment,misc]
|
||||
|
||||
from ..utils.progress_tracker import get_progress_tracker
|
||||
from .utils.color_schemes import ColorPalette, ColorScheme
|
||||
from .utils.export_formats import (
|
||||
@@ -118,18 +126,45 @@ class KGVisualizer:
|
||||
"Install with: pip install plotly"
|
||||
)
|
||||
|
||||
def _normalize_graph(self, graph: Any) -> Dict[str, Any]:
|
||||
def _convert_knowledge_graph(self, kg: Any) -> Dict[str, Any]:
|
||||
"""
|
||||
Normalize graph input to the expected dict format.
|
||||
Convert a KnowledgeGraph instance to the internal dict format.
|
||||
|
||||
Accepts either:
|
||||
- A dict with "entities" and "relationships" keys (canonical format)
|
||||
- Any object that exposes .entities and .relationships attributes
|
||||
(e.g. a KnowledgeGraph dataclass returned by GraphBuilder.build())
|
||||
Non-mutating. Preserves node types, labels, properties, edge types,
|
||||
weights, and direction.
|
||||
|
||||
Args:
|
||||
kg: A ``KnowledgeGraph`` instance.
|
||||
|
||||
Returns:
|
||||
Dict with "entities", "relationships", and "metadata" keys.
|
||||
"""
|
||||
entities = getattr(kg, "entities", None) or []
|
||||
relationships = getattr(kg, "relationships", None) or []
|
||||
metadata = getattr(kg, "metadata", None) or {}
|
||||
return {
|
||||
"entities": list(entities),
|
||||
"relationships": list(relationships),
|
||||
"metadata": dict(metadata),
|
||||
}
|
||||
|
||||
def _normalize_graph(self, graph: Any) -> Dict[str, Any]:
|
||||
"""
|
||||
Normalize graph input to the expected dict format.
|
||||
|
||||
Accepts:
|
||||
- A ``KnowledgeGraph`` instance (routed through ``_convert_knowledge_graph``)
|
||||
- A dict with "entities" and "relationships" keys (canonical format)
|
||||
- Any object that exposes .entities and .relationships attributes
|
||||
(duck-typed, e.g. custom dataclasses)
|
||||
|
||||
Returns:
|
||||
Dict with "entities", "relationships", and "metadata" keys.
|
||||
"""
|
||||
# Explicit fast-path for the formal KnowledgeGraph type
|
||||
if _KnowledgeGraph is not None and isinstance(graph, _KnowledgeGraph):
|
||||
return self._convert_knowledge_graph(graph)
|
||||
|
||||
if isinstance(graph, dict):
|
||||
return graph
|
||||
|
||||
|
||||
@@ -372,7 +372,7 @@ class TestEnrichment:
|
||||
|
||||
def test_extract(self, client):
|
||||
response = client.post("/api/enrich/extract", json={"text": "Alice works at Acme Corp."})
|
||||
assert response.status_code in (200, 422)
|
||||
assert response.status_code in (200, 422, 503)
|
||||
|
||||
def test_link_prediction(self, client):
|
||||
response = client.post("/api/enrich/links", json={"node_id": "python", "top_n": 5})
|
||||
|
||||
@@ -283,5 +283,166 @@ class TestAllVisualizeMethodsAcceptKGObject(unittest.TestCase):
|
||||
self.viz._normalize_graph.assert_called_once_with(self.kg)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Issue #471 — formal KnowledgeGraph type support
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestFormalKnowledgeGraphType(unittest.TestCase):
|
||||
"""
|
||||
Regression tests for issue #471.
|
||||
|
||||
The formal ``semantica.kg.KnowledgeGraph`` dataclass must be accepted by
|
||||
every public visualize_* method without requiring any manual conversion.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
try:
|
||||
from semantica.kg.knowledge_graph import KnowledgeGraph
|
||||
cls.KnowledgeGraph = KnowledgeGraph
|
||||
except ImportError:
|
||||
cls.KnowledgeGraph = None
|
||||
|
||||
def _make_kg(self):
|
||||
if self.KnowledgeGraph is None:
|
||||
self.skipTest("semantica.kg.KnowledgeGraph not available")
|
||||
return self.KnowledgeGraph(
|
||||
entities=ENTITIES,
|
||||
relationships=RELATIONSHIPS,
|
||||
metadata={"version": "test"},
|
||||
)
|
||||
|
||||
def test_convert_knowledge_graph_entities(self):
|
||||
kg = self._make_kg()
|
||||
viz = _make_viz()
|
||||
result = viz._convert_knowledge_graph(kg)
|
||||
self.assertEqual(result["entities"], ENTITIES)
|
||||
|
||||
def test_convert_knowledge_graph_relationships(self):
|
||||
kg = self._make_kg()
|
||||
viz = _make_viz()
|
||||
result = viz._convert_knowledge_graph(kg)
|
||||
self.assertEqual(result["relationships"], RELATIONSHIPS)
|
||||
|
||||
def test_convert_knowledge_graph_metadata(self):
|
||||
kg = self._make_kg()
|
||||
viz = _make_viz()
|
||||
result = viz._convert_knowledge_graph(kg)
|
||||
self.assertEqual(result["metadata"], {"version": "test"})
|
||||
|
||||
def test_convert_knowledge_graph_does_not_mutate(self):
|
||||
kg = self._make_kg()
|
||||
original_entities = list(kg.entities)
|
||||
original_relationships = list(kg.relationships)
|
||||
viz = _make_viz()
|
||||
viz._convert_knowledge_graph(kg)
|
||||
self.assertEqual(kg.entities, original_entities)
|
||||
self.assertEqual(kg.relationships, original_relationships)
|
||||
|
||||
def test_convert_knowledge_graph_is_deterministic(self):
|
||||
kg = self._make_kg()
|
||||
viz = _make_viz()
|
||||
self.assertEqual(viz._convert_knowledge_graph(kg), viz._convert_knowledge_graph(kg))
|
||||
|
||||
def test_normalize_graph_routes_kg_type(self):
|
||||
kg = self._make_kg()
|
||||
viz = _make_viz()
|
||||
viz._convert_knowledge_graph = MagicMock(return_value=GRAPH_DICT)
|
||||
viz._normalize_graph(kg)
|
||||
viz._convert_knowledge_graph.assert_called_once_with(kg)
|
||||
|
||||
def test_normalize_graph_returns_dict_for_kg_type(self):
|
||||
kg = self._make_kg()
|
||||
viz = _make_viz()
|
||||
result = viz._normalize_graph(kg)
|
||||
self.assertIsInstance(result, dict)
|
||||
self.assertIn("entities", result)
|
||||
self.assertIn("relationships", result)
|
||||
|
||||
def _run_visualize_network(self, graph_arg):
|
||||
mock_fig = MagicMock()
|
||||
mock_go = sys.modules["plotly.graph_objects"]
|
||||
mock_go.Figure.return_value = mock_fig
|
||||
mock_go.Scatter.return_value = MagicMock()
|
||||
mock_go.Layout.return_value = MagicMock()
|
||||
viz = _make_viz()
|
||||
fake_pos = {"e1": (0.0, 0.0), "e2": (1.0, 1.0)}
|
||||
viz.force_layout = MagicMock()
|
||||
viz.force_layout.compute_layout.return_value = fake_pos
|
||||
viz.hierarchical_layout = MagicMock()
|
||||
viz.circular_layout = MagicMock()
|
||||
with (
|
||||
patch(
|
||||
"semantica.visualization.kg_visualizer.ColorPalette.get_entity_type_colors",
|
||||
return_value={"Person": "#ff0000"},
|
||||
),
|
||||
patch(
|
||||
"semantica.visualization.kg_visualizer.ColorPalette.get_colors",
|
||||
return_value=["#ff0000"],
|
||||
),
|
||||
):
|
||||
return viz.visualize_network(graph_arg, output="interactive")
|
||||
|
||||
def test_visualize_network_accepts_knowledge_graph(self):
|
||||
self.assertIsNotNone(self._run_visualize_network(self._make_kg()))
|
||||
|
||||
def test_visualize_communities_accepts_knowledge_graph(self):
|
||||
kg = self._make_kg()
|
||||
viz = _make_viz()
|
||||
viz._normalize_graph = MagicMock(return_value=GRAPH_DICT)
|
||||
viz._visualize_network_plotly = MagicMock(return_value=MagicMock())
|
||||
communities = {"node_assignments": {"e1": 0, "e2": 1}, "num_communities": 2}
|
||||
with patch(
|
||||
"semantica.visualization.kg_visualizer.ColorPalette.get_community_colors",
|
||||
return_value=["#ff0000", "#00ff00"],
|
||||
):
|
||||
viz.visualize_communities(kg, communities=communities)
|
||||
viz._normalize_graph.assert_called_once_with(kg)
|
||||
|
||||
def test_visualize_centrality_accepts_knowledge_graph(self):
|
||||
kg = self._make_kg()
|
||||
viz = _make_viz()
|
||||
viz._normalize_graph = MagicMock(return_value=GRAPH_DICT)
|
||||
viz._visualize_network_plotly = MagicMock(return_value=MagicMock())
|
||||
viz.visualize_centrality(kg, centrality={"centrality": {}})
|
||||
viz._normalize_graph.assert_called_once_with(kg)
|
||||
|
||||
def test_visualize_entity_types_accepts_knowledge_graph(self):
|
||||
kg = self._make_kg()
|
||||
viz = _make_viz()
|
||||
viz._normalize_graph = MagicMock(return_value=GRAPH_DICT)
|
||||
sys.modules["plotly.express"].bar.return_value = MagicMock()
|
||||
viz.visualize_entity_types(kg)
|
||||
viz._normalize_graph.assert_called_once_with(kg)
|
||||
|
||||
def test_visualize_relationship_matrix_accepts_knowledge_graph(self):
|
||||
kg = self._make_kg()
|
||||
viz = _make_viz()
|
||||
viz._normalize_graph = MagicMock(return_value=GRAPH_DICT)
|
||||
sys.modules["plotly.graph_objects"].Figure.return_value = MagicMock()
|
||||
sys.modules["plotly.graph_objects"].Heatmap.return_value = MagicMock()
|
||||
viz.visualize_relationship_matrix(kg)
|
||||
viz._normalize_graph.assert_called_once_with(kg)
|
||||
|
||||
def test_knowledge_graph_importable_from_kg_module(self):
|
||||
if self.KnowledgeGraph is None:
|
||||
self.skipTest("semantica.kg.KnowledgeGraph not available")
|
||||
try:
|
||||
import semantica.kg as _kg_module
|
||||
_ = _kg_module.KnowledgeGraph
|
||||
except (ImportError, AttributeError) as exc:
|
||||
self.fail(f"KnowledgeGraph not exported from semantica.kg: {exc}")
|
||||
|
||||
def test_knowledge_graph_empty_defaults(self):
|
||||
kg = self.KnowledgeGraph()
|
||||
self.assertEqual(kg.entities, [])
|
||||
self.assertEqual(kg.relationships, [])
|
||||
self.assertFalse(bool(kg))
|
||||
|
||||
def test_knowledge_graph_len(self):
|
||||
kg = self._make_kg()
|
||||
self.assertEqual(len(kg), len(ENTITIES))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user