aisquare 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aisquare-1.0.0/LICENSE +21 -0
- aisquare-1.0.0/PKG-INFO +317 -0
- aisquare-1.0.0/README.md +271 -0
- aisquare-1.0.0/aisquare/__init__.py +6 -0
- aisquare-1.0.0/aisquare/explainability/__init__.py +86 -0
- aisquare-1.0.0/aisquare/explainability/adapters/__init__.py +84 -0
- aisquare-1.0.0/aisquare/explainability/adapters/agno.py +78 -0
- aisquare-1.0.0/aisquare/explainability/adapters/base.py +56 -0
- aisquare-1.0.0/aisquare/explainability/decorators.py +83 -0
- aisquare-1.0.0/aisquare/explainability/doctor.py +109 -0
- aisquare-1.0.0/aisquare/explainability/exporter.py +149 -0
- aisquare-1.0.0/aisquare/explainability/hooks.py +53 -0
- aisquare-1.0.0/aisquare/explainability/inbox.py +107 -0
- aisquare-1.0.0/aisquare/explainability/main.py +351 -0
- aisquare-1.0.0/aisquare/explainability/py.typed +0 -0
- aisquare-1.0.0/aisquare/explainability/serialisation.py +63 -0
- aisquare-1.0.0/aisquare/explainability/sweeper.py +274 -0
- aisquare-1.0.0/aisquare/explainability/tracers.py +564 -0
- aisquare-1.0.0/aisquare.egg-info/PKG-INFO +317 -0
- aisquare-1.0.0/aisquare.egg-info/SOURCES.txt +41 -0
- aisquare-1.0.0/aisquare.egg-info/dependency_links.txt +1 -0
- aisquare-1.0.0/aisquare.egg-info/entry_points.txt +2 -0
- aisquare-1.0.0/aisquare.egg-info/requires.txt +27 -0
- aisquare-1.0.0/aisquare.egg-info/top_level.txt +1 -0
- aisquare-1.0.0/pyproject.toml +84 -0
- aisquare-1.0.0/setup.cfg +4 -0
- aisquare-1.0.0/tests/test_auth.py +63 -0
- aisquare-1.0.0/tests/test_exporter.py +204 -0
- aisquare-1.0.0/tests/test_extractor.py +366 -0
- aisquare-1.0.0/tests/test_hooks.py +210 -0
- aisquare-1.0.0/tests/test_inbox.py +100 -0
- aisquare-1.0.0/tests/test_integration_stack.py +267 -0
- aisquare-1.0.0/tests/test_main.py +87 -0
- aisquare-1.0.0/tests/test_models.py +223 -0
- aisquare-1.0.0/tests/test_policy.py +260 -0
- aisquare-1.0.0/tests/test_queue.py +119 -0
- aisquare-1.0.0/tests/test_react_flow.py +461 -0
- aisquare-1.0.0/tests/test_schema.py +9 -0
- aisquare-1.0.0/tests/test_security.py +118 -0
- aisquare-1.0.0/tests/test_structural.py +261 -0
- aisquare-1.0.0/tests/test_sweeper.py +65 -0
- aisquare-1.0.0/tests/test_ui.py +371 -0
- aisquare-1.0.0/tests/test_utils.py +223 -0
aisquare-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AISquare
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
aisquare-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aisquare
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Explainability SDK for tracing, graphing, and policy auditing of AI agents
|
|
5
|
+
Author: AISquare
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/AISquareHQ/aisquare-explainability
|
|
8
|
+
Project-URL: Documentation, https://github.com/AISquareHQ/aisquare-explainability/tree/main/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/AISquareHQ/aisquare-explainability
|
|
10
|
+
Project-URL: Issues, https://github.com/AISquareHQ/aisquare-explainability/issues
|
|
11
|
+
Keywords: ai,agents,observability,tracing,governance,explainability
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Provides-Extra: explainability
|
|
23
|
+
Requires-Dist: httpx<1.0,>=0.27; extra == "explainability"
|
|
24
|
+
Requires-Dist: aiosqlite<1.0,>=0.20; extra == "explainability"
|
|
25
|
+
Requires-Dist: opentelemetry-sdk<2.0,>=1.24; extra == "explainability"
|
|
26
|
+
Requires-Dist: opentelemetry-api<2.0,>=1.24; extra == "explainability"
|
|
27
|
+
Provides-Extra: gateway
|
|
28
|
+
Requires-Dist: fastapi<1.0,>=0.111; extra == "gateway"
|
|
29
|
+
Requires-Dist: uvicorn<1.0,>=0.30; extra == "gateway"
|
|
30
|
+
Requires-Dist: pydantic<3.0,>=2.7; extra == "gateway"
|
|
31
|
+
Requires-Dist: redis<6.0,>=5.0; extra == "gateway"
|
|
32
|
+
Requires-Dist: neo4j<6.0,>=5.20; extra == "gateway"
|
|
33
|
+
Requires-Dist: asyncpg<1.0,>=0.29; extra == "gateway"
|
|
34
|
+
Requires-Dist: openai<2.0,>=1.30; extra == "gateway"
|
|
35
|
+
Requires-Dist: prometheus-client<1.0,>=0.20; extra == "gateway"
|
|
36
|
+
Requires-Dist: sse-starlette<3.0,>=2.0; extra == "gateway"
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
41
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
42
|
+
Provides-Extra: agno
|
|
43
|
+
Requires-Dist: agno>=0.1; extra == "agno"
|
|
44
|
+
Requires-Dist: openinference-instrumentation-agno>=0.1; extra == "agno"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
# AISquare Explainability SDK
|
|
48
|
+
|
|
49
|
+
An explainability and governance stack for AI agents. Captures execution traces from any Python agent (Agno, LangChain, plain Python), delivers them to a FastAPI gateway, and projects them into a Neo4j graph with RML semantic analysis and policy detection.
|
|
50
|
+
|
|
51
|
+
## How it works
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Your Agent Code
|
|
55
|
+
│ OpenInference / OTel spans
|
|
56
|
+
▼
|
|
57
|
+
SDK (aisquare.explainability/)
|
|
58
|
+
│ serialised to local SQLite inbox — no gateway dependency in the hot path
|
|
59
|
+
▼
|
|
60
|
+
InboxSweeper (background thread)
|
|
61
|
+
│ POST /v1/traces/ingest
|
|
62
|
+
▼
|
|
63
|
+
Gateway (FastAPI — gateway/)
|
|
64
|
+
├── Structural Worker → Neo4j (Run / Span / Artifact / Policy graph)
|
|
65
|
+
├── RML Extractor → Postgres (claims, assumptions, evidence, inference chain)
|
|
66
|
+
└── Policy Detector → Neo4j + Postgres (PolicyCandidate nodes, crystallization loop)
|
|
67
|
+
▼
|
|
68
|
+
Explainability Studio UI (modular-ai-space frontend)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Repo layout
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
aisquare.explainability/ SDK — capture, inbox, sweeper, adapters, manual tracers
|
|
75
|
+
gateway/ FastAPI ingest gateway + worker pipeline
|
|
76
|
+
graph/ Neo4j Cypher and React Flow transformation helpers
|
|
77
|
+
examples/ Runnable agent examples
|
|
78
|
+
docs/ Guides, concepts, API reference
|
|
79
|
+
tests/ Unit and integration tests
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## What the SDK captures
|
|
83
|
+
|
|
84
|
+
The SDK collects two layers of signal:
|
|
85
|
+
|
|
86
|
+
**Auto-instrumentation** (zero-code): The `AgnoAdapter` installs `openinference-instrumentation-agno`, which automatically wraps every Agno agent run, LLM call, and tool invocation as an OTel span.
|
|
87
|
+
|
|
88
|
+
**Manual tracers** (governance-grade): Seven context-manager tracers you can add to any Python code — framework-agnostic:
|
|
89
|
+
|
|
90
|
+
| Tracer | Purpose |
|
|
91
|
+
|--------|---------|
|
|
92
|
+
| `AgentRunTracer` | Wraps a full agent run as the root span |
|
|
93
|
+
| `LLMCallTracer` | Records an LLM inference call with I/O and token counts |
|
|
94
|
+
| `ToolCallTracer` | Records a tool invocation with parameters, result, and errors |
|
|
95
|
+
| `RetrievalTracer` | Records a RAG retrieval with documents and scores |
|
|
96
|
+
| `HumanInterventionTracer` | Records a human-in-the-loop review or correction |
|
|
97
|
+
| `RoutingTracer` | Records a routing/delegation decision with selected and rejected paths |
|
|
98
|
+
| `MemoryTracer` | Records memory read/write operations |
|
|
99
|
+
|
|
100
|
+
The manual tracers also provide decorators: `@trace_tool` and `@trace_retrieval`.
|
|
101
|
+
|
|
102
|
+
## What the gateway adds
|
|
103
|
+
|
|
104
|
+
The gateway worker pipeline runs after each trace is ingested:
|
|
105
|
+
|
|
106
|
+
- **Structural projection**: Every span becomes a `Run`, `Span`, `Artifact`, or policy node in Neo4j with typed edges (`CONTAINS`, `EXECUTED`, `PRODUCED`, `CONSUMED`, `FLAGGED_AS`).
|
|
107
|
+
- **RML extraction**: GPT-4o-mini analyzes AGENT and LLM spans to produce claims, assumptions, evidence attribution, inference chain, and policy triggers. Confidence is a blended score: 40% LLM-reported + 60% deterministic structural signals.
|
|
108
|
+
- **Policy detection**: Recurring system-prompt instructions are counted across traces. When an instruction exceeds the occurrence threshold it is promoted to a `PolicyCandidate` node for human review and activation.
|
|
109
|
+
|
|
110
|
+
## Data model
|
|
111
|
+
|
|
112
|
+
**Neo4j nodes**: `Studio`, `Run`, `Span`, `Event`, `Artifact`, `Agent`, `Tool`, `Human`, `PolicyCandidate`, `Policy`
|
|
113
|
+
|
|
114
|
+
**Neo4j relationships**: `HOSTS`, `CONTAINS`, `NEXT`, `EXECUTED`, `INTERVENED`, `CONSUMED`, `PRODUCED`, `REFERENCES`, `FLAGGED_AS`, `PROPOSES`
|
|
115
|
+
|
|
116
|
+
**Postgres tables**: `ingest_batches`, `trace_states`, `processed_traces`, `rml_analyses`, `policy_observations`, `artifact_content`, `extraction_failures`, `studio_config`
|
|
117
|
+
|
|
118
|
+
**SDK local durability**: SQLite inbox (`explainability_inbox.db`)
|
|
119
|
+
|
|
120
|
+
## Local setup
|
|
121
|
+
|
|
122
|
+
### 1. Install dependencies
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pip install -e ".[dev,agno]"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 2. Start infrastructure
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
docker compose up -d
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Starts Neo4j (bolt://localhost:7687), Postgres (localhost:5433), and Redis (localhost:6379).
|
|
135
|
+
|
|
136
|
+
### 3. Configure environment
|
|
137
|
+
|
|
138
|
+
Copy `.env.example` to `.env` and fill in the required values:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Database
|
|
142
|
+
NEO4J_URI=bolt://localhost:7687
|
|
143
|
+
NEO4J_USER=neo4j
|
|
144
|
+
NEO4J_PASSWORD=password
|
|
145
|
+
POSTGRES_DSN=postgresql://postgres:postgres@localhost:5433/explainability
|
|
146
|
+
REDIS_URL=redis://localhost:6379/0
|
|
147
|
+
|
|
148
|
+
# Auth
|
|
149
|
+
ENV=development
|
|
150
|
+
ALLOW_TEST_AUTH_BYPASS=true
|
|
151
|
+
|
|
152
|
+
# SDK → gateway
|
|
153
|
+
EXPLAINABILITY_GATEWAY_URL=http://127.0.0.1:8000
|
|
154
|
+
EXPLAINABILITY_API_KEY=test-key
|
|
155
|
+
|
|
156
|
+
# LLM extraction
|
|
157
|
+
OPENAI_API_KEY=sk-...
|
|
158
|
+
EXTRACTOR_MODEL=gpt-4o-mini
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 4. Run the gateway
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
uvicorn gateway.main:app --host 0.0.0.0 --port 8000
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Health checks:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
curl http://127.0.0.1:8000/live # → {"status":"ok"}
|
|
171
|
+
curl http://127.0.0.1:8000/ready # → {"neo4j":"ok","postgres":"ok","redis":"ok"}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 5. Run an example
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
python examples/basics/openai_chat.py
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 6. Start the frontend
|
|
181
|
+
|
|
182
|
+
The UI lives in the `modular-ai-space` repository:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
cd ../modular-ai-space
|
|
186
|
+
npm install
|
|
187
|
+
npm run dev:localdev # http://localhost:3001
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## SDK usage
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
import aisquare.explainability as sdk
|
|
194
|
+
|
|
195
|
+
# Reads EXPLAINABILITY_GATEWAY_URL and EXPLAINABILITY_API_KEY from environment
|
|
196
|
+
sdk.init_from_env(service_name="my-agent")
|
|
197
|
+
|
|
198
|
+
# Run your agent — Agno is auto-instrumented, all spans captured automatically
|
|
199
|
+
agent.print_response("...")
|
|
200
|
+
|
|
201
|
+
# IMPORTANT for short-lived scripts: flush ensures traces reach the gateway
|
|
202
|
+
# before the process exits. Long-running services don't need this.
|
|
203
|
+
sdk.flush()
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Manual instrumentation (any framework)
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
import aisquare.explainability as sdk
|
|
210
|
+
|
|
211
|
+
sdk.init_from_env()
|
|
212
|
+
|
|
213
|
+
with sdk.AgentRunTracer(agent_name="MyAgent", run_id="abc-123") as run:
|
|
214
|
+
run.set_input("User query")
|
|
215
|
+
|
|
216
|
+
with sdk.LLMCallTracer(model="gpt-4o-mini", provider="openai") as llm:
|
|
217
|
+
response = call_openai(...)
|
|
218
|
+
llm.set_input_messages([{"role": "user", "content": "..."}])
|
|
219
|
+
llm.set_output_messages([{"role": "assistant", "content": response}])
|
|
220
|
+
llm.set_token_counts(prompt=100, completion=50)
|
|
221
|
+
|
|
222
|
+
with sdk.RoutingTracer(decision_type="tool_selection") as rt:
|
|
223
|
+
rt.set_selected("web_search", reason="Query requires fresh data")
|
|
224
|
+
rt.set_rejected([{"name": "cached_search", "reason": "Cache is stale"}])
|
|
225
|
+
|
|
226
|
+
run.set_output("Agent final answer")
|
|
227
|
+
|
|
228
|
+
sdk.flush()
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Examples
|
|
232
|
+
|
|
233
|
+
| File | What it shows |
|
|
234
|
+
|------|---------------|
|
|
235
|
+
| `examples/basics/openai_chat.py` | Simplest traced Agno agent |
|
|
236
|
+
| `examples/agents/deep_nesting.py` | 3-level agent delegation team |
|
|
237
|
+
| `examples/agents/multi_agent_branching.py` | Multi-agent research team |
|
|
238
|
+
| `examples/agents/routing_decision.py` | Tool routing and conditional paths |
|
|
239
|
+
| `examples/agents/tool_heavy_workflow.py` | Many tool calls in one run |
|
|
240
|
+
| `examples/governance/error_handling.py` | Error nodes (red) in graph |
|
|
241
|
+
| `examples/governance/policy_detection.py` | 3 runs → policy candidate detection |
|
|
242
|
+
| `examples/governance/policy_workflow.py` | Full detect → review → activate cycle |
|
|
243
|
+
| `examples/governance/e2e_governed_workflow.py` | Complete governed workflow with activation |
|
|
244
|
+
| `examples/streaming/monitor_execution.py` | SSE-based live execution monitoring |
|
|
245
|
+
|
|
246
|
+
## API surface
|
|
247
|
+
|
|
248
|
+
**Ingest:**
|
|
249
|
+
```
|
|
250
|
+
POST /v1/traces/ingest
|
|
251
|
+
Authorization: Bearer <api-key>
|
|
252
|
+
Content-Type: application/json
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Studio UI reads:**
|
|
256
|
+
```
|
|
257
|
+
GET /v1/studios/{id}/ui/runs
|
|
258
|
+
GET /v1/studios/{id}/ui/runs/{run_id}
|
|
259
|
+
GET /v1/studios/{id}/ui/runs/{run_id}/graph?mode=span|event
|
|
260
|
+
GET /v1/studios/{id}/ui/runs/{run_id}/xtrace
|
|
261
|
+
GET /v1/studios/{id}/ui/runs/{run_id}/rml
|
|
262
|
+
GET /v1/studios/{id}/ui/runs/{run_id}/nodes/{node_id}
|
|
263
|
+
GET /v1/studios/{id}/ui/policies
|
|
264
|
+
GET /v1/studios/{id}/ui/agents
|
|
265
|
+
GET /v1/studios/{id}/ui/setup
|
|
266
|
+
GET /v1/studios/{id}/artifacts/{artifact_id}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**Policy management:**
|
|
270
|
+
```
|
|
271
|
+
PATCH /v1/studios/{id}/policies/{fingerprint}/activate
|
|
272
|
+
PATCH /v1/studios/{id}/policy-config
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Admin:**
|
|
276
|
+
```
|
|
277
|
+
GET /metrics
|
|
278
|
+
GET /v1/admin/worker-health
|
|
279
|
+
GET /v1/admin/circuit-breakers
|
|
280
|
+
POST /v1/admin/recover
|
|
281
|
+
GET /v1/admin/extraction/failures
|
|
282
|
+
GET /v1/admin/policy-candidates
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Documentation
|
|
286
|
+
|
|
287
|
+
Guides:
|
|
288
|
+
- [Getting started](docs/getting-started.md) — full local setup walkthrough
|
|
289
|
+
- [Quickstart (5 min)](docs/guides/quickstart-5min.md) — first trace fast
|
|
290
|
+
- [SDK usage guide](docs/guides/sdk-usage.md) — manual instrumentation patterns
|
|
291
|
+
|
|
292
|
+
Reference:
|
|
293
|
+
- [SDK API reference](docs/reference/sdk-api.md) — all SDK classes and functions
|
|
294
|
+
- [REST API reference](docs/reference/rest-api.md) — all gateway endpoints
|
|
295
|
+
|
|
296
|
+
Concepts:
|
|
297
|
+
- [RML](docs/concepts/rml.md) — Reasoning Markup Language
|
|
298
|
+
- [Policy system](docs/concepts/policy-system.md) — detection and enforcement
|
|
299
|
+
- [Graph modes](docs/concepts/graph-modes.md) — span vs event views
|
|
300
|
+
- [Architecture](docs/architecture.md) — system design
|
|
301
|
+
|
|
302
|
+
## Tests
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
python -m pytest -q
|
|
306
|
+
python -m ruff check .
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Docker-backed integration test:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
RUN_DOCKER_INTEGRATION=1 python -m pytest tests/test_integration_stack.py -q
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## License
|
|
316
|
+
|
|
317
|
+
MIT
|
aisquare-1.0.0/README.md
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# AISquare Explainability SDK
|
|
2
|
+
|
|
3
|
+
An explainability and governance stack for AI agents. Captures execution traces from any Python agent (Agno, LangChain, plain Python), delivers them to a FastAPI gateway, and projects them into a Neo4j graph with RML semantic analysis and policy detection.
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Your Agent Code
|
|
9
|
+
│ OpenInference / OTel spans
|
|
10
|
+
▼
|
|
11
|
+
SDK (aisquare.explainability/)
|
|
12
|
+
│ serialised to local SQLite inbox — no gateway dependency in the hot path
|
|
13
|
+
▼
|
|
14
|
+
InboxSweeper (background thread)
|
|
15
|
+
│ POST /v1/traces/ingest
|
|
16
|
+
▼
|
|
17
|
+
Gateway (FastAPI — gateway/)
|
|
18
|
+
├── Structural Worker → Neo4j (Run / Span / Artifact / Policy graph)
|
|
19
|
+
├── RML Extractor → Postgres (claims, assumptions, evidence, inference chain)
|
|
20
|
+
└── Policy Detector → Neo4j + Postgres (PolicyCandidate nodes, crystallization loop)
|
|
21
|
+
▼
|
|
22
|
+
Explainability Studio UI (modular-ai-space frontend)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Repo layout
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
aisquare.explainability/ SDK — capture, inbox, sweeper, adapters, manual tracers
|
|
29
|
+
gateway/ FastAPI ingest gateway + worker pipeline
|
|
30
|
+
graph/ Neo4j Cypher and React Flow transformation helpers
|
|
31
|
+
examples/ Runnable agent examples
|
|
32
|
+
docs/ Guides, concepts, API reference
|
|
33
|
+
tests/ Unit and integration tests
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## What the SDK captures
|
|
37
|
+
|
|
38
|
+
The SDK collects two layers of signal:
|
|
39
|
+
|
|
40
|
+
**Auto-instrumentation** (zero-code): The `AgnoAdapter` installs `openinference-instrumentation-agno`, which automatically wraps every Agno agent run, LLM call, and tool invocation as an OTel span.
|
|
41
|
+
|
|
42
|
+
**Manual tracers** (governance-grade): Seven context-manager tracers you can add to any Python code — framework-agnostic:
|
|
43
|
+
|
|
44
|
+
| Tracer | Purpose |
|
|
45
|
+
|--------|---------|
|
|
46
|
+
| `AgentRunTracer` | Wraps a full agent run as the root span |
|
|
47
|
+
| `LLMCallTracer` | Records an LLM inference call with I/O and token counts |
|
|
48
|
+
| `ToolCallTracer` | Records a tool invocation with parameters, result, and errors |
|
|
49
|
+
| `RetrievalTracer` | Records a RAG retrieval with documents and scores |
|
|
50
|
+
| `HumanInterventionTracer` | Records a human-in-the-loop review or correction |
|
|
51
|
+
| `RoutingTracer` | Records a routing/delegation decision with selected and rejected paths |
|
|
52
|
+
| `MemoryTracer` | Records memory read/write operations |
|
|
53
|
+
|
|
54
|
+
The manual tracers also provide decorators: `@trace_tool` and `@trace_retrieval`.
|
|
55
|
+
|
|
56
|
+
## What the gateway adds
|
|
57
|
+
|
|
58
|
+
The gateway worker pipeline runs after each trace is ingested:
|
|
59
|
+
|
|
60
|
+
- **Structural projection**: Every span becomes a `Run`, `Span`, `Artifact`, or policy node in Neo4j with typed edges (`CONTAINS`, `EXECUTED`, `PRODUCED`, `CONSUMED`, `FLAGGED_AS`).
|
|
61
|
+
- **RML extraction**: GPT-4o-mini analyzes AGENT and LLM spans to produce claims, assumptions, evidence attribution, inference chain, and policy triggers. Confidence is a blended score: 40% LLM-reported + 60% deterministic structural signals.
|
|
62
|
+
- **Policy detection**: Recurring system-prompt instructions are counted across traces. When an instruction exceeds the occurrence threshold it is promoted to a `PolicyCandidate` node for human review and activation.
|
|
63
|
+
|
|
64
|
+
## Data model
|
|
65
|
+
|
|
66
|
+
**Neo4j nodes**: `Studio`, `Run`, `Span`, `Event`, `Artifact`, `Agent`, `Tool`, `Human`, `PolicyCandidate`, `Policy`
|
|
67
|
+
|
|
68
|
+
**Neo4j relationships**: `HOSTS`, `CONTAINS`, `NEXT`, `EXECUTED`, `INTERVENED`, `CONSUMED`, `PRODUCED`, `REFERENCES`, `FLAGGED_AS`, `PROPOSES`
|
|
69
|
+
|
|
70
|
+
**Postgres tables**: `ingest_batches`, `trace_states`, `processed_traces`, `rml_analyses`, `policy_observations`, `artifact_content`, `extraction_failures`, `studio_config`
|
|
71
|
+
|
|
72
|
+
**SDK local durability**: SQLite inbox (`explainability_inbox.db`)
|
|
73
|
+
|
|
74
|
+
## Local setup
|
|
75
|
+
|
|
76
|
+
### 1. Install dependencies
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install -e ".[dev,agno]"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. Start infrastructure
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
docker compose up -d
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Starts Neo4j (bolt://localhost:7687), Postgres (localhost:5433), and Redis (localhost:6379).
|
|
89
|
+
|
|
90
|
+
### 3. Configure environment
|
|
91
|
+
|
|
92
|
+
Copy `.env.example` to `.env` and fill in the required values:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Database
|
|
96
|
+
NEO4J_URI=bolt://localhost:7687
|
|
97
|
+
NEO4J_USER=neo4j
|
|
98
|
+
NEO4J_PASSWORD=password
|
|
99
|
+
POSTGRES_DSN=postgresql://postgres:postgres@localhost:5433/explainability
|
|
100
|
+
REDIS_URL=redis://localhost:6379/0
|
|
101
|
+
|
|
102
|
+
# Auth
|
|
103
|
+
ENV=development
|
|
104
|
+
ALLOW_TEST_AUTH_BYPASS=true
|
|
105
|
+
|
|
106
|
+
# SDK → gateway
|
|
107
|
+
EXPLAINABILITY_GATEWAY_URL=http://127.0.0.1:8000
|
|
108
|
+
EXPLAINABILITY_API_KEY=test-key
|
|
109
|
+
|
|
110
|
+
# LLM extraction
|
|
111
|
+
OPENAI_API_KEY=sk-...
|
|
112
|
+
EXTRACTOR_MODEL=gpt-4o-mini
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 4. Run the gateway
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
uvicorn gateway.main:app --host 0.0.0.0 --port 8000
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Health checks:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
curl http://127.0.0.1:8000/live # → {"status":"ok"}
|
|
125
|
+
curl http://127.0.0.1:8000/ready # → {"neo4j":"ok","postgres":"ok","redis":"ok"}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 5. Run an example
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
python examples/basics/openai_chat.py
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 6. Start the frontend
|
|
135
|
+
|
|
136
|
+
The UI lives in the `modular-ai-space` repository:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
cd ../modular-ai-space
|
|
140
|
+
npm install
|
|
141
|
+
npm run dev:localdev # http://localhost:3001
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## SDK usage
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
import aisquare.explainability as sdk
|
|
148
|
+
|
|
149
|
+
# Reads EXPLAINABILITY_GATEWAY_URL and EXPLAINABILITY_API_KEY from environment
|
|
150
|
+
sdk.init_from_env(service_name="my-agent")
|
|
151
|
+
|
|
152
|
+
# Run your agent — Agno is auto-instrumented, all spans captured automatically
|
|
153
|
+
agent.print_response("...")
|
|
154
|
+
|
|
155
|
+
# IMPORTANT for short-lived scripts: flush ensures traces reach the gateway
|
|
156
|
+
# before the process exits. Long-running services don't need this.
|
|
157
|
+
sdk.flush()
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Manual instrumentation (any framework)
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
import aisquare.explainability as sdk
|
|
164
|
+
|
|
165
|
+
sdk.init_from_env()
|
|
166
|
+
|
|
167
|
+
with sdk.AgentRunTracer(agent_name="MyAgent", run_id="abc-123") as run:
|
|
168
|
+
run.set_input("User query")
|
|
169
|
+
|
|
170
|
+
with sdk.LLMCallTracer(model="gpt-4o-mini", provider="openai") as llm:
|
|
171
|
+
response = call_openai(...)
|
|
172
|
+
llm.set_input_messages([{"role": "user", "content": "..."}])
|
|
173
|
+
llm.set_output_messages([{"role": "assistant", "content": response}])
|
|
174
|
+
llm.set_token_counts(prompt=100, completion=50)
|
|
175
|
+
|
|
176
|
+
with sdk.RoutingTracer(decision_type="tool_selection") as rt:
|
|
177
|
+
rt.set_selected("web_search", reason="Query requires fresh data")
|
|
178
|
+
rt.set_rejected([{"name": "cached_search", "reason": "Cache is stale"}])
|
|
179
|
+
|
|
180
|
+
run.set_output("Agent final answer")
|
|
181
|
+
|
|
182
|
+
sdk.flush()
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Examples
|
|
186
|
+
|
|
187
|
+
| File | What it shows |
|
|
188
|
+
|------|---------------|
|
|
189
|
+
| `examples/basics/openai_chat.py` | Simplest traced Agno agent |
|
|
190
|
+
| `examples/agents/deep_nesting.py` | 3-level agent delegation team |
|
|
191
|
+
| `examples/agents/multi_agent_branching.py` | Multi-agent research team |
|
|
192
|
+
| `examples/agents/routing_decision.py` | Tool routing and conditional paths |
|
|
193
|
+
| `examples/agents/tool_heavy_workflow.py` | Many tool calls in one run |
|
|
194
|
+
| `examples/governance/error_handling.py` | Error nodes (red) in graph |
|
|
195
|
+
| `examples/governance/policy_detection.py` | 3 runs → policy candidate detection |
|
|
196
|
+
| `examples/governance/policy_workflow.py` | Full detect → review → activate cycle |
|
|
197
|
+
| `examples/governance/e2e_governed_workflow.py` | Complete governed workflow with activation |
|
|
198
|
+
| `examples/streaming/monitor_execution.py` | SSE-based live execution monitoring |
|
|
199
|
+
|
|
200
|
+
## API surface
|
|
201
|
+
|
|
202
|
+
**Ingest:**
|
|
203
|
+
```
|
|
204
|
+
POST /v1/traces/ingest
|
|
205
|
+
Authorization: Bearer <api-key>
|
|
206
|
+
Content-Type: application/json
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Studio UI reads:**
|
|
210
|
+
```
|
|
211
|
+
GET /v1/studios/{id}/ui/runs
|
|
212
|
+
GET /v1/studios/{id}/ui/runs/{run_id}
|
|
213
|
+
GET /v1/studios/{id}/ui/runs/{run_id}/graph?mode=span|event
|
|
214
|
+
GET /v1/studios/{id}/ui/runs/{run_id}/xtrace
|
|
215
|
+
GET /v1/studios/{id}/ui/runs/{run_id}/rml
|
|
216
|
+
GET /v1/studios/{id}/ui/runs/{run_id}/nodes/{node_id}
|
|
217
|
+
GET /v1/studios/{id}/ui/policies
|
|
218
|
+
GET /v1/studios/{id}/ui/agents
|
|
219
|
+
GET /v1/studios/{id}/ui/setup
|
|
220
|
+
GET /v1/studios/{id}/artifacts/{artifact_id}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Policy management:**
|
|
224
|
+
```
|
|
225
|
+
PATCH /v1/studios/{id}/policies/{fingerprint}/activate
|
|
226
|
+
PATCH /v1/studios/{id}/policy-config
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Admin:**
|
|
230
|
+
```
|
|
231
|
+
GET /metrics
|
|
232
|
+
GET /v1/admin/worker-health
|
|
233
|
+
GET /v1/admin/circuit-breakers
|
|
234
|
+
POST /v1/admin/recover
|
|
235
|
+
GET /v1/admin/extraction/failures
|
|
236
|
+
GET /v1/admin/policy-candidates
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Documentation
|
|
240
|
+
|
|
241
|
+
Guides:
|
|
242
|
+
- [Getting started](docs/getting-started.md) — full local setup walkthrough
|
|
243
|
+
- [Quickstart (5 min)](docs/guides/quickstart-5min.md) — first trace fast
|
|
244
|
+
- [SDK usage guide](docs/guides/sdk-usage.md) — manual instrumentation patterns
|
|
245
|
+
|
|
246
|
+
Reference:
|
|
247
|
+
- [SDK API reference](docs/reference/sdk-api.md) — all SDK classes and functions
|
|
248
|
+
- [REST API reference](docs/reference/rest-api.md) — all gateway endpoints
|
|
249
|
+
|
|
250
|
+
Concepts:
|
|
251
|
+
- [RML](docs/concepts/rml.md) — Reasoning Markup Language
|
|
252
|
+
- [Policy system](docs/concepts/policy-system.md) — detection and enforcement
|
|
253
|
+
- [Graph modes](docs/concepts/graph-modes.md) — span vs event views
|
|
254
|
+
- [Architecture](docs/architecture.md) — system design
|
|
255
|
+
|
|
256
|
+
## Tests
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
python -m pytest -q
|
|
260
|
+
python -m ruff check .
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Docker-backed integration test:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
RUN_DOCKER_INTEGRATION=1 python -m pytest tests/test_integration_stack.py -q
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## License
|
|
270
|
+
|
|
271
|
+
MIT
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AISquare Explainability SDK.
|
|
3
|
+
|
|
4
|
+
Captures execution traces via OpenTelemetry, buffers them durably in a local
|
|
5
|
+
SQLite inbox, and dispatches them to the Explainability Gateway for structural
|
|
6
|
+
graph loading and RML extraction.
|
|
7
|
+
|
|
8
|
+
Quick start::
|
|
9
|
+
|
|
10
|
+
import aisquare.explainability as sdk
|
|
11
|
+
sdk.init_from_env()
|
|
12
|
+
|
|
13
|
+
Manual instrumentation (works with any Python code — no framework required)::
|
|
14
|
+
|
|
15
|
+
from aisquare.explainability import AgentRunTracer, LLMCallTracer
|
|
16
|
+
|
|
17
|
+
with AgentRunTracer(agent_name="MyAgent", run_id="abc") as run:
|
|
18
|
+
run.set_input("User query")
|
|
19
|
+
with LLMCallTracer(model="gpt-4o-mini") as llm:
|
|
20
|
+
...
|
|
21
|
+
run.set_output("Agent response")
|
|
22
|
+
|
|
23
|
+
Auto-instrumentation (adapters detect and hook into frameworks)::
|
|
24
|
+
|
|
25
|
+
# Auto-detect installed platforms (Agno, LangChain, CrewAI, …)
|
|
26
|
+
sdk.init_from_env() # auto_instrument=True by default
|
|
27
|
+
|
|
28
|
+
# Or specify explicitly
|
|
29
|
+
sdk.init_from_env(auto_instrument=["agno", "langchain"])
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
__version__ = "1.0.0"
|
|
33
|
+
|
|
34
|
+
# --- Core init ---
|
|
35
|
+
# --- Adapter access (advanced) ---
|
|
36
|
+
from aisquare.explainability.adapters import ( # noqa: F401
|
|
37
|
+
all_adapters,
|
|
38
|
+
available_adapters,
|
|
39
|
+
get_adapter,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# --- Decorators (platform-agnostic) ---
|
|
43
|
+
from aisquare.explainability.decorators import ( # noqa: F401
|
|
44
|
+
trace_retrieval,
|
|
45
|
+
trace_tool,
|
|
46
|
+
)
|
|
47
|
+
from aisquare.explainability.main import flush, init, init_from_env # noqa: F401
|
|
48
|
+
|
|
49
|
+
# --- Manual tracers (platform-agnostic) ---
|
|
50
|
+
from aisquare.explainability.tracers import ( # noqa: F401
|
|
51
|
+
AgentRunTracer,
|
|
52
|
+
HumanInterventionTracer,
|
|
53
|
+
LLMCallTracer,
|
|
54
|
+
MemoryTracer,
|
|
55
|
+
RetrievalTracer,
|
|
56
|
+
RoutingTracer,
|
|
57
|
+
ToolCallTracer,
|
|
58
|
+
artifact_id,
|
|
59
|
+
get_tracer,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
__all__ = [
|
|
63
|
+
# Init
|
|
64
|
+
"init",
|
|
65
|
+
"init_from_env",
|
|
66
|
+
"flush",
|
|
67
|
+
# Tracers
|
|
68
|
+
"AgentRunTracer",
|
|
69
|
+
"LLMCallTracer",
|
|
70
|
+
"ToolCallTracer",
|
|
71
|
+
"RetrievalTracer",
|
|
72
|
+
"HumanInterventionTracer",
|
|
73
|
+
"RoutingTracer",
|
|
74
|
+
"MemoryTracer",
|
|
75
|
+
"artifact_id",
|
|
76
|
+
"get_tracer",
|
|
77
|
+
# Decorators
|
|
78
|
+
"trace_tool",
|
|
79
|
+
"trace_retrieval",
|
|
80
|
+
# Adapters
|
|
81
|
+
"available_adapters",
|
|
82
|
+
"all_adapters",
|
|
83
|
+
"get_adapter",
|
|
84
|
+
# Meta
|
|
85
|
+
"__version__",
|
|
86
|
+
]
|