continuous-intelligence-layer 0.1.0__py3-none-any.whl
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.
- continuous_intelligence_layer/__init__.py +28 -0
- continuous_intelligence_layer/_core/__init__.py +6 -0
- continuous_intelligence_layer/_core/exporter.py +517 -0
- continuous_intelligence_layer/_core/graph_exporter.py +92 -0
- continuous_intelligence_layer/_core/utils.py +170 -0
- continuous_intelligence_layer/anthropic/__init__.py +9 -0
- continuous_intelligence_layer/anthropic/init.py +232 -0
- continuous_intelligence_layer/anthropic/instrumentation.py +91 -0
- continuous_intelligence_layer/crewai/__init__.py +9 -0
- continuous_intelligence_layer/crewai/init.py +228 -0
- continuous_intelligence_layer/crewai/instrumentation.py +83 -0
- continuous_intelligence_layer/langgraph/__init__.py +12 -0
- continuous_intelligence_layer/langgraph/init.py +253 -0
- continuous_intelligence_layer/langgraph/instrumentation.py +71 -0
- continuous_intelligence_layer/openai/__init__.py +9 -0
- continuous_intelligence_layer/openai/init.py +229 -0
- continuous_intelligence_layer/openai/instrumentation.py +67 -0
- continuous_intelligence_layer-0.1.0.dist-info/METADATA +633 -0
- continuous_intelligence_layer-0.1.0.dist-info/RECORD +38 -0
- continuous_intelligence_layer-0.1.0.dist-info/WHEEL +4 -0
- continuous_intelligence_layer-0.1.0.dist-info/licenses/LICENSE +21 -0
- evaluators/__init__.py +32 -0
- evaluators/base_evaluator.py +181 -0
- evaluators/crewai_input_evaluator.py +249 -0
- evaluators/input_evaluator.py +121 -0
- evaluators/models.py +180 -0
- evaluators/output_evaluator.py +247 -0
- evaluators/runner.py +313 -0
- evaluators/tool_agent_evaluator.py +305 -0
- graph_builder/__init__.py +6 -0
- graph_builder/builder.py +212 -0
- graph_builder/models.py +159 -0
- graph_builder/mongo_store.py +588 -0
- llm_router/__init__.py +3 -0
- llm_router/router.py +71 -0
- rca_engine/__init__.py +5 -0
- rca_engine/incident_report.py +162 -0
- rca_engine/rca_engine.py +202 -0
|
@@ -0,0 +1,633 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: continuous-intelligence-layer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Multi-Agent Intelligent Validation & RCA Framework
|
|
5
|
+
Project-URL: Homepage, https://github.com/Jugal-lachhwani/Multi_agent_intelligence_layer
|
|
6
|
+
Project-URL: Repository, https://github.com/Jugal-lachhwani/Multi_agent_intelligence_layer
|
|
7
|
+
Author-email: dmlabs <dmlabs6@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agents,langgraph,llm,observability,opentelemetry,rca,tracing
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
17
|
+
Classifier: Topic :: System :: Monitoring
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Requires-Dist: anthropic>=0.34.0
|
|
20
|
+
Requires-Dist: bcrypt>=4.0.0
|
|
21
|
+
Requires-Dist: colorama>=0.4.6
|
|
22
|
+
Requires-Dist: fastapi>=0.110.0
|
|
23
|
+
Requires-Dist: google-genai>=1.0.0
|
|
24
|
+
Requires-Dist: langchain-community>=0.2.0
|
|
25
|
+
Requires-Dist: langchain-openai>=0.1.0
|
|
26
|
+
Requires-Dist: langchain>=0.2.0
|
|
27
|
+
Requires-Dist: langgraph>=0.2.0
|
|
28
|
+
Requires-Dist: networkx>=3.3
|
|
29
|
+
Requires-Dist: openai>=1.30.0
|
|
30
|
+
Requires-Dist: openinference-instrumentation-langchain>=0.1.0
|
|
31
|
+
Requires-Dist: openinference-semantic-conventions>=0.1.0
|
|
32
|
+
Requires-Dist: opentelemetry-api>=1.25.0
|
|
33
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.25.0
|
|
34
|
+
Requires-Dist: opentelemetry-sdk>=1.25.0
|
|
35
|
+
Requires-Dist: passlib[bcrypt]>=1.7.4
|
|
36
|
+
Requires-Dist: pydantic>=2.7.0
|
|
37
|
+
Requires-Dist: pyjwt>=2.8.0
|
|
38
|
+
Requires-Dist: pymongo>=4.8.0
|
|
39
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
40
|
+
Requires-Dist: python-multipart>=0.0.9
|
|
41
|
+
Requires-Dist: requests>=2.31.0
|
|
42
|
+
Requires-Dist: rich>=13.7.0
|
|
43
|
+
Requires-Dist: tenacity>=8.3.0
|
|
44
|
+
Requires-Dist: uvicorn>=0.29.0
|
|
45
|
+
Provides-Extra: all
|
|
46
|
+
Requires-Dist: openinference-instrumentation-anthropic>=1.0.0; extra == 'all'
|
|
47
|
+
Requires-Dist: openinference-instrumentation-crewai>=1.0.0; extra == 'all'
|
|
48
|
+
Requires-Dist: openinference-instrumentation-llama-index>=3.0.0; extra == 'all'
|
|
49
|
+
Requires-Dist: openinference-instrumentation-openai>=0.1.19; extra == 'all'
|
|
50
|
+
Provides-Extra: anthropic
|
|
51
|
+
Requires-Dist: openinference-instrumentation-anthropic>=1.0.0; extra == 'anthropic'
|
|
52
|
+
Provides-Extra: crewai
|
|
53
|
+
Requires-Dist: openinference-instrumentation-crewai>=1.0.0; extra == 'crewai'
|
|
54
|
+
Provides-Extra: dev
|
|
55
|
+
Requires-Dist: build>=1.2.0; extra == 'dev'
|
|
56
|
+
Requires-Dist: ipykernel; extra == 'dev'
|
|
57
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
58
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
59
|
+
Requires-Dist: twine>=5.0.0; extra == 'dev'
|
|
60
|
+
Provides-Extra: llamaindex
|
|
61
|
+
Requires-Dist: openinference-instrumentation-llama-index>=3.0.0; extra == 'llamaindex'
|
|
62
|
+
Provides-Extra: openai
|
|
63
|
+
Requires-Dist: openinference-instrumentation-openai>=0.1.19; extra == 'openai'
|
|
64
|
+
Description-Content-Type: text/markdown
|
|
65
|
+
|
|
66
|
+
# Multi-Agent Intelligence Layer
|
|
67
|
+
|
|
68
|
+
**A zero-infrastructure, OpenTelemetry-based observability and validation layer for LangGraph / Agentic AI systems.**
|
|
69
|
+
|
|
70
|
+
This project automatically instruments any LangChain/LangGraph agent, captures full execution traces (nodes, LLMs, tools, tokens, latency), builds an interactive **Execution Graph** in MongoDB, and runs a comprehensive **Validation and Root Cause Analysis (RCA) Engine** over the results.
|
|
71
|
+
|
|
72
|
+
Trace data never touches MongoDB directly from the agent's machine — the SDK
|
|
73
|
+
POSTs the built graph to the API over HTTP (`POST /traces/ingest`), using the
|
|
74
|
+
same `api_key` already used for project sync. Only the API process holds
|
|
75
|
+
`MONGODB_URI`; agent machines need nothing but an `api_key` and network
|
|
76
|
+
access to the API.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 🏗️ Complete Architecture
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
Your LangGraph Agent
|
|
84
|
+
│
|
|
85
|
+
▼
|
|
86
|
+
Continuous Intelligence Layer SDK (Zero-config OpenTelemetry + OpenInference)
|
|
87
|
+
│
|
|
88
|
+
├──▶ JSONL Exporter (Local trace backup)
|
|
89
|
+
│
|
|
90
|
+
└──▶ GraphSpanExporter (Buffers spans & builds graph)
|
|
91
|
+
│
|
|
92
|
+
▼
|
|
93
|
+
POST /traces/ingest (x-api-key auth)
|
|
94
|
+
│
|
|
95
|
+
▼
|
|
96
|
+
FastAPI Backend
|
|
97
|
+
│
|
|
98
|
+
▼
|
|
99
|
+
MongoDB (Atlas or self-hosted)
|
|
100
|
+
(executions / nodes / evaluations / rca_reports)
|
|
101
|
+
│
|
|
102
|
+
▼
|
|
103
|
+
Evaluation Runner Pipeline
|
|
104
|
+
┌──────────────────────┼──────────────────────┐
|
|
105
|
+
▼ ▼ ▼
|
|
106
|
+
Input Evaluator Output Evaluator Tool/Agent Evaluator
|
|
107
|
+
│ │ │
|
|
108
|
+
└──────────────────────┼──────────────────────┘
|
|
109
|
+
▼
|
|
110
|
+
Validation Results
|
|
111
|
+
(Saved to JSONL & MongoDB)
|
|
112
|
+
│
|
|
113
|
+
▼
|
|
114
|
+
Root Cause Analysis (RCA) Engine
|
|
115
|
+
(Analyzes failures & saves to MongoDB)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 🚀 Quick Start
|
|
121
|
+
|
|
122
|
+
### 1. Prerequisites
|
|
123
|
+
- Python 3.11+
|
|
124
|
+
- A MongoDB instance — the easiest path is a free [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) cluster (no local install/Docker needed); a local `mongod` also works.
|
|
125
|
+
`MONGODB_URI` is only needed by the **API server** process — it can live
|
|
126
|
+
fully private (Atlas network access rules / same VPC as the API) since
|
|
127
|
+
agent machines running `continuous_intelligence_layer.<framework>.init()` never connect to it
|
|
128
|
+
directly; they only need an `api_key` and HTTP access to the API.
|
|
129
|
+
|
|
130
|
+
### 2. Setup
|
|
131
|
+
|
|
132
|
+
**Just want to instrument an agent against a hosted/existing AgentOPS API?**
|
|
133
|
+
Install the published SDK directly — no repo clone needed:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
pip install continuous-intelligence-layer
|
|
137
|
+
|
|
138
|
+
# Or with a specific framework's instrumentor extra:
|
|
139
|
+
pip install "continuous-intelligence-layer[crewai]"
|
|
140
|
+
pip install "continuous-intelligence-layer[openai]"
|
|
141
|
+
pip install "continuous-intelligence-layer[anthropic]"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Running the full stack (API + UI + MongoDB) yourself?** Clone the repo:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Clone the repository
|
|
148
|
+
git clone https://github.com/Jugal-lachhwani/Multi_agent_intelligence_layer.git
|
|
149
|
+
cd Multi_agent_intelligence_layer
|
|
150
|
+
|
|
151
|
+
# Create a virtual environment and install
|
|
152
|
+
python -m venv .venv
|
|
153
|
+
source .venv/bin/activate
|
|
154
|
+
pip install -e .
|
|
155
|
+
|
|
156
|
+
# Setup environment variables (requires OpenAI API Key for evaluation & RCA,
|
|
157
|
+
# and a MongoDB connection string)
|
|
158
|
+
cp .env.example .env
|
|
159
|
+
# Edit .env and set:
|
|
160
|
+
# OPENAI_API_KEY="sk-..."
|
|
161
|
+
# MONGODB_URI="mongodb+srv://<user>:<password>@<cluster>.mongodb.net/?retryWrites=true&w=majority"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 3. MongoDB
|
|
165
|
+
|
|
166
|
+
No separate service to start — the app connects directly to whatever `MONGODB_URI` in `.env` points at (Atlas cluster or local `mongod`). Collections and indexes are created automatically the first time the API starts or `seed_db.py` runs.
|
|
167
|
+
|
|
168
|
+
### 4. Start the AgentOPS UI and API
|
|
169
|
+
|
|
170
|
+
The AgentOPS layer includes a full observability dashboard to view traces, token usage, and evaluation results.
|
|
171
|
+
|
|
172
|
+
1. **Start the FastAPI Backend:**
|
|
173
|
+
```bash
|
|
174
|
+
# Seed a default demo user + project into MongoDB (safe to re-run — idempotent)
|
|
175
|
+
python seed_db.py
|
|
176
|
+
|
|
177
|
+
# Start the API server (runs on http://localhost:8080)
|
|
178
|
+
uvicorn api.main:app --reload --port 8080
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
2. **Start the React Frontend:**
|
|
182
|
+
```bash
|
|
183
|
+
# In a new terminal window
|
|
184
|
+
cd ui
|
|
185
|
+
npm install
|
|
186
|
+
npm run dev
|
|
187
|
+
```
|
|
188
|
+
Open **[http://localhost:5173/projects/proj_default_123](http://localhost:5173/projects/proj_default_123)** in your browser to view the dashboard!
|
|
189
|
+
|
|
190
|
+
### 5. Run the Pipeline
|
|
191
|
+
|
|
192
|
+
1. **Run the Demo Agent:**
|
|
193
|
+
This executes the multi-agent LangGraph demo and POSTs the built graph to
|
|
194
|
+
the API's `/traces/ingest` endpoint, which is the only thing that writes
|
|
195
|
+
it to MongoDB.
|
|
196
|
+
```bash
|
|
197
|
+
AGENTOPS_API_KEY="ao_..." python examples/multi_agent_demo.py "Explain quantum computing simply"
|
|
198
|
+
```
|
|
199
|
+
`AGENTOPS_API_KEY` should be an API key from a registered user (see `POST /register` then `POST /api_key`, or use the one printed by `seed_db.py`). The demo agent's machine needs this key and the API's `base_url` (`http://localhost:8080` by default) — it does **not** need `MONGODB_URI`.
|
|
200
|
+
|
|
201
|
+
2. **Run the Evaluator and RCA Engine:**
|
|
202
|
+
This evaluates the execution, saves validation results, and generates a Root Cause Analysis report.
|
|
203
|
+
*(Make sure you grab the `execution_id` from the output of the demo script).*
|
|
204
|
+
```bash
|
|
205
|
+
python -c "
|
|
206
|
+
from evaluators.runner import EvaluationRunner
|
|
207
|
+
# Replace with your actual execution ID
|
|
208
|
+
runner = EvaluationRunner('YOUR_EXECUTION_ID_HERE')
|
|
209
|
+
runner.run()
|
|
210
|
+
"
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 6. View the Results in MongoDB (Advanced)
|
|
214
|
+
|
|
215
|
+
The dashboard UI is the intended way to inspect traces, but the raw documents
|
|
216
|
+
are also queryable directly — via [MongoDB Atlas's Data Explorer](https://www.mongodb.com/docs/atlas/atlas-ui/data-explorer/)
|
|
217
|
+
in the browser (if using Atlas), or the `mongosh` shell / any GUI client
|
|
218
|
+
(Compass, Studio 3T) pointed at your `MONGODB_URI`.
|
|
219
|
+
|
|
220
|
+
1. **View the Execution Graph** (nodes for one execution):
|
|
221
|
+
```js
|
|
222
|
+
db.nodes.find({ execution_id: "YOUR_EXECUTION_ID" })
|
|
223
|
+
db.executions.findOne({ _id: "YOUR_EXECUTION_ID" }) // summary + edges
|
|
224
|
+
```
|
|
225
|
+
2. **View Evaluation Verdicts:**
|
|
226
|
+
```js
|
|
227
|
+
db.evaluations.find(
|
|
228
|
+
{ execution_id: "YOUR_EXECUTION_ID", confidence: { $gt: 0.3 } },
|
|
229
|
+
{ node_name: 1, evaluator: 1, status: 1, severity: 1, reason: 1 }
|
|
230
|
+
).sort({ timestamp: 1 })
|
|
231
|
+
```
|
|
232
|
+
3. **View the Root Cause Analysis (RCA) Report:**
|
|
233
|
+
```js
|
|
234
|
+
db.rca_reports.findOne(
|
|
235
|
+
{ _id: "YOUR_EXECUTION_ID" },
|
|
236
|
+
{ overall_status: 1, root_cause: 1, recommendations: 1 }
|
|
237
|
+
)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## 📊 Example Evaluation & RCA Output
|
|
243
|
+
|
|
244
|
+
Below is an example of the Evaluation Engine successfully detecting a "silent failure" where a search tool returned irrelevant information, causing downstream agents to struggle.
|
|
245
|
+
|
|
246
|
+
### Node Executions & Metrics
|
|
247
|
+
*(Extracted from the MongoDB `nodes` collection)*
|
|
248
|
+
|
|
249
|
+
| Output | Status | Latency_ms |
|
|
250
|
+
|--------|--------|------------|
|
|
251
|
+
| `[Supervisor] I’ll first use the Research Agent...` | OK | 2387.188 |
|
|
252
|
+
| `[web_search] Results for 'Explain quantum computing simply': Recent AI agent research highlights...` | OK | 0.340 |
|
|
253
|
+
| `[document_retriever] Retrieved 1 document... Document: 'General Overview'` | OK | 0.344 |
|
|
254
|
+
| `[Research Agent] - The web results are not relevant to explaining quantum computing...` | OK | 2699.448 |
|
|
255
|
+
| `[Writer Agent] # Quantum Computing, Simply Explained...` (Truncated mid-sentence) | OK | 6346.446 |
|
|
256
|
+
|
|
257
|
+
### Evaluation Verdicts
|
|
258
|
+
|
|
259
|
+
| Node Name | Evaluator | Status | Reason |
|
|
260
|
+
|-----------|-----------|--------|--------|
|
|
261
|
+
| `supervisor` | `OutputEvaluator` | **PASS** | "The output is well-formed, preserves the user query, and provides an appropriate orchestration plan..." |
|
|
262
|
+
| `web_search` | `OutputEvaluator` | **FAIL** (High) | "The output is completely unrelated to the request to explain quantum computing simply and instead discusses AI-agent architectures." |
|
|
263
|
+
| `document_retriever` | `ToolAgentEvaluator` | **FAIL** (High) | "The returned document contains no substantive quantum-computing information. The result is effectively empty." |
|
|
264
|
+
| `research_agent` | `OutputEvaluator` | **WARNING** (Med) | "Honestly reports that retrieved sources are inadequate... However, it does not provide substantive research for a downstream writer." |
|
|
265
|
+
| `writer_agent` | `InputEvaluator` | **WARNING** (Med) | "The supplied research is largely irrelevant... which could confuse the writer." |
|
|
266
|
+
| `LangGraph` | `OutputEvaluator` | **FAIL** (Med) | "The response is relevant and generally accurate, but the writer's explanation is visibly truncated mid-sentence..." |
|
|
267
|
+
|
|
268
|
+
### Root Cause Analysis (RCA) Report
|
|
269
|
+
|
|
270
|
+
```json
|
|
271
|
+
{
|
|
272
|
+
"overall_status": "PARTIAL",
|
|
273
|
+
"root_cause": "The primary root cause was a research-tool grounding failure: the web_search node returned semantically unrelated AI-agent content for a quantum-computing query, and the system accepted that output instead of detecting and recovering from the relevance mismatch.",
|
|
274
|
+
"confidence": 0.91,
|
|
275
|
+
"propagation_chain": [
|
|
276
|
+
"LangGraph",
|
|
277
|
+
"supervisor",
|
|
278
|
+
"research_agent",
|
|
279
|
+
"web_search",
|
|
280
|
+
"document_retriever",
|
|
281
|
+
"research_agent",
|
|
282
|
+
"writer_agent",
|
|
283
|
+
"LangGraph"
|
|
284
|
+
],
|
|
285
|
+
"contributing_factors": [
|
|
286
|
+
"The document_retriever node also returned non-substantive content (only a generic document label), leaving the research agent without usable grounded material.",
|
|
287
|
+
"No tool-output relevance, topic-consistency, or minimum-content validation gate stopped unrelated or empty retrieval results before they reached downstream agents.",
|
|
288
|
+
"The research agent appears to have continued despite both retrieval sources being unusable, rather than retrying with a reformulated query, selecting an alternate source, or explicitly reporting insufficient evidence.",
|
|
289
|
+
"The writer agent likely relied on general model knowledge because the provided research context was weak or invalid, reducing traceability and reliability even though the visible content was broadly relevant.",
|
|
290
|
+
"The final LangGraph output was truncated mid-sentence, indicating missing output-length budgeting, incomplete-response detection, or response serialization/stream-finalization safeguards.",
|
|
291
|
+
"The initially empty top-level query field was noted as mildly ambiguous; although the supervisor correctly used the message content, this creates avoidable risk for downstream components that rely on the query state field."
|
|
292
|
+
],
|
|
293
|
+
"recommendations": [
|
|
294
|
+
"Add a mandatory semantic relevance check after web_search and document_retriever. Require returned content to match the requested topic using query-document similarity thresholds, keyword/entity overlap, and an LLM relevance classifier.",
|
|
295
|
+
"Reject and retry tool results when they are unrelated, empty, generic, below a minimum substantive-content threshold, or lack extractable facts. For this request, a result focused on AI agents should trigger an automatic retry with a quantum-computing-specific query.",
|
|
296
|
+
"Implement a retrieval fallback policy: reformulate the query, use a second search provider or corpus, request multiple results, and stop only after obtaining at least one validated source containing relevant explanatory material.",
|
|
297
|
+
"Require the research agent to emit structured evidence with source snippets, topic labels, and a research-quality status. Prevent handoff to the writer when evidence quality is below threshold unless the writer is explicitly instructed to answer from general knowledge.",
|
|
298
|
+
"Add a supervisor-level quality gate that checks whether research findings answer the original user question before routing to the writer agent.",
|
|
299
|
+
"Fix final-response truncation by enforcing token/output budgets, reserving completion tokens for conclusions, validating that the final response ends cleanly, and retrying or continuing generation when termination occurs mid-sentence.",
|
|
300
|
+
"Populate and normalize the top-level query field from the user message at graph entry so all nodes consume a single canonical request representation.",
|
|
301
|
+
"Track tool relevance failures as explicit failed or degraded node states rather than reporting zero failed nodes when validation shows unusable tool outputs."
|
|
302
|
+
]
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## 🛠️ Usage in Your Own Code
|
|
309
|
+
|
|
310
|
+
The SDK is designed to be **plug-and-play**. You don't need to change any of your LangGraph nodes or edges. Just add two lines to the very top of your main script:
|
|
311
|
+
|
|
312
|
+
```python
|
|
313
|
+
from continuous_intelligence_layer.langgraph import init # or .crewai / .openai
|
|
314
|
+
|
|
315
|
+
# Initialize before importing LangGraph/LangChain
|
|
316
|
+
init(
|
|
317
|
+
session_id="my-conversation-123", # Groups multiple runs together
|
|
318
|
+
store="mongodb" # Saves the execution graph to MongoDB
|
|
319
|
+
# run_evaluations=True is the default — evaluations + RCA run automatically
|
|
320
|
+
# right after the trace is ingested. Pass run_evaluations=False if you'd
|
|
321
|
+
# rather trigger them yourself later (via the API or the UI's "Run
|
|
322
|
+
# Evaluations" button).
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# ... run your normal LangGraph code here ...
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## 📂 Project Structure
|
|
331
|
+
|
|
332
|
+
- **`continuous_intelligence_layer/`**: The core SDK. One subpackage per agent framework (`langgraph/`, `crewai/`, `openai/`), each with its own `init()` that monkey-patches that framework to automatically emit OTel spans. Framework-agnostic pieces (JSONL exporter, `GraphSpanExporter`, which POSTs the built graph to the API's `/traces/ingest` endpoint with `x-api-key` auth instead of writing to MongoDB directly) live in the shared internal `_core/` module.
|
|
333
|
+
- **`ui/`**: React-based frontend dashboard for viewing execution traces, token costs, and evaluation results.
|
|
334
|
+
- **`api/`**: FastAPI backend that serves traces and evaluations from MongoDB to the frontend UI, and is the **only** process that writes trace data to MongoDB — via `POST /traces/ingest`, called by the SDK. Also owns `users`/`projects` auth data (also in MongoDB).
|
|
335
|
+
- **`evaluators/`**: The Evaluation Pipeline containing `InputEvaluator`, `OutputEvaluator`, and `ToolAgentEvaluator`.
|
|
336
|
+
- **`rca_engine/`**: Synthesizes the evaluation results across the graph to generate the final Root Cause Analysis and fixes.
|
|
337
|
+
- **`graph_builder/`**: Converts raw OpenTelemetry spans into structured `ExecutionNode` and `ExecutionEdge` Pydantic models. `MongoStore` (idempotent upserts, one document per node) is used only from within the API process, not from the SDK.
|
|
338
|
+
- **`examples/`**: Contains `multi_agent_demo.py`, a realistic implementation of a hierarchical agent system used for testing the SDK.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
Models_used =
|
|
343
|
+
- examples/multi_agent_demo.py (demo agent) → gpt-5.6-luna (reads VALIDATOR_MODEL, not AGENT_MODEL as .env.example implies)
|
|
344
|
+
- examples/support_triage_multi_agent.py (demo agent) → not set in .env, so it falls back to its own default, gpt-4o-mini (reads SUPPORT_AGENT_MODEL)
|
|
345
|
+
- evaluators/ (Input/Output/ToolAgent, via base_evaluator.py) → gpt-5.6-luna (reads VALIDATOR_MODEL)
|
|
346
|
+
- rca_engine/ → gpt-5.6-terra (reads RCA_MODEL)"
|
|
347
|
+
|
|
348
|
+
## 🔎 In-Depth Feature Reference (Built System)
|
|
349
|
+
|
|
350
|
+
This section documents what is **actually implemented** in each module of the
|
|
351
|
+
built system, verified by a full code read-through (audit date: 2026-08-03).
|
|
352
|
+
It excludes `examples/` — those are demo agents used to exercise the SDK, not
|
|
353
|
+
part of the product itself. For the full bug/fix history behind these
|
|
354
|
+
findings, see [`ISSUES.md`](./ISSUES.md).
|
|
355
|
+
|
|
356
|
+
### `continuous_intelligence_layer/` — SDK
|
|
357
|
+
|
|
358
|
+
- Each framework subpackage exposes its own **`init(api_key, service_name, session_id=None, execution_id=None, store="mongodb", write_jsonl=False, base_url="http://localhost:8080", verbose=True, run_evaluations=True)`**
|
|
359
|
+
— `continuous_intelligence_layer.langgraph.init()` (covers LangGraph and
|
|
360
|
+
plain LangChain, since both share the same OpenInference instrumentor),
|
|
361
|
+
`continuous_intelligence_layer.crewai.init()`, and
|
|
362
|
+
`continuous_intelligence_layer.openai.init()`. The framework is selected by
|
|
363
|
+
which subpackage you import, not by a `frameworks=` argument. Each is
|
|
364
|
+
idempotent within a process (a second call is a no-op) and provides
|
|
365
|
+
`reset()` for test suites that need to re-init.
|
|
366
|
+
- Verifies `api_key` against the backend at startup and auto-registers the
|
|
367
|
+
project via `POST /projects/sync` — `service_name` becomes the project name.
|
|
368
|
+
The returned `project_id`, together with `api_key` and `base_url`, is
|
|
369
|
+
threaded into `GraphSpanExporter` so it can authenticate the later
|
|
370
|
+
`/traces/ingest` call — the SDK never needs `MONGODB_URI`.
|
|
371
|
+
- **`run_evaluations` (default `True`)** is threaded into `GraphSpanExporter`
|
|
372
|
+
and sent as a `run_evaluations` query param on its `/traces/ingest` POST.
|
|
373
|
+
The SDK itself never runs evaluations or waits on them — it just tells the
|
|
374
|
+
API whether to kick them off. Pass `run_evaluations=False` to keep the
|
|
375
|
+
pre-existing manual-only flow (evaluations only run when triggered via the
|
|
376
|
+
API or the UI's "Run Evaluations" button).
|
|
377
|
+
- Resource attributes attached to every span: `service.name`, `project.id`,
|
|
378
|
+
`execution.id`, `session.id`, `sdk.name`, `sdk.version`.
|
|
379
|
+
- Each subpackage's `instrumentation.py::instrument()` activates that
|
|
380
|
+
framework's single OpenInference instrumentor (`LangChainInstrumentor`,
|
|
381
|
+
`CrewAIInstrumentor`, or `OpenAIInstrumentor`, guarded against
|
|
382
|
+
double-patching); `uninstrument()` restores original callbacks. A missing
|
|
383
|
+
`openinference-instrumentation-*` package degrades gracefully with a fix-it
|
|
384
|
+
message instead of crashing.
|
|
385
|
+
- **Span → record extraction** (`ExecutionSpanExporter._extract`) captures:
|
|
386
|
+
trace/span/parent IDs, latency (ms), node-type classification (from
|
|
387
|
+
OpenInference span kind, with a keyword-based fallback on span name),
|
|
388
|
+
status/error (from OTel span events), token usage (prompt/completion/total),
|
|
389
|
+
prompt/response (both legacy and current OpenInference attribute keys),
|
|
390
|
+
tool name/description/retrieved docs, and any remaining attributes as
|
|
391
|
+
free-form `metadata`.
|
|
392
|
+
- **Two export paths**: `ExecutionSpanExporter` writes durable JSONL
|
|
393
|
+
(`SimpleSpanProcessor`, synchronous per-span); `GraphSpanExporter` buffers
|
|
394
|
+
spans **in memory** and, at `TracerProvider` shutdown, builds the graph and
|
|
395
|
+
`POST`s it as JSON to `{base_url}/traces/ingest` with an `x-api-key` header
|
|
396
|
+
(see Known Gaps below) — it never imports or connects to `MongoStore`.
|
|
397
|
+
- `_core/utils.py` (re-exported from every framework subpackage) provides
|
|
398
|
+
`load_traces()`, `print_trace_summary()` (terminal pretty-printer with
|
|
399
|
+
per-span status icons and an aggregate footer), and `spans_to_dataframe()`
|
|
400
|
+
(pandas export).
|
|
401
|
+
|
|
402
|
+
### `graph_builder/` — DAG construction & persistence
|
|
403
|
+
|
|
404
|
+
- **Data model** (`models.py`): `ExecutionNode` (~20 fields — identity,
|
|
405
|
+
`node_type` enum, LLM/tool-specific fields, `TokenUsage`, timestamps,
|
|
406
|
+
`metadata`, `status`, `validation_results`), `ExecutionEdge`
|
|
407
|
+
(`source_id`/`target_id`/`edge_type`), `ExecutionGraph` (nodes + edges, with
|
|
408
|
+
helpers: `get_node`, `get_children`, `get_root_nodes`, `get_nodes_by_type`,
|
|
409
|
+
`get_failed_nodes`, `summary()`).
|
|
410
|
+
- **Builder algorithm** (`builder.py::TraceToGraphBuilder.build`): sorts spans
|
|
411
|
+
by timestamp, maps each span to an `ExecutionNode` keyed by `span_id`,
|
|
412
|
+
creates a `CALLS` edge from `parent_span_id → node_id` when the parent span
|
|
413
|
+
is present in the same batch, then groups nodes by `parent_id` and chains
|
|
414
|
+
each sibling group into a timestamp-ordered `NEXT` edge list. Only `CALLS`
|
|
415
|
+
and `NEXT` are ever produced — `RETURNS`/`USES`/`READS`/`WRITES` exist as
|
|
416
|
+
enum values but are never emitted.
|
|
417
|
+
- **MongoStore** (`mongo_store.py`): only ever instantiated inside the API
|
|
418
|
+
process now — `save_graph()` is called from `POST /traces/ingest`, not
|
|
419
|
+
from the SDK. Idempotent `update_one(..., upsert=True)`
|
|
420
|
+
writes, one document per node in a `nodes` collection (keyed by `node_id`)
|
|
421
|
+
— deliberately **not** one document per execution embedding a `nodes`
|
|
422
|
+
array, since that risks hitting MongoDB's 16MB per-document limit on large
|
|
423
|
+
executions or long LLM outputs. A lightweight `executions` header document
|
|
424
|
+
(status, latency, node count, timestamps, embedded `edges` array, root
|
|
425
|
+
input/output snippets) is written alongside every save, so the trace-list
|
|
426
|
+
view never has to fetch full node bodies. Indexes on `execution_id`,
|
|
427
|
+
`project_id`, `session_id`, and compound indexes for the KPI/trace-list
|
|
428
|
+
query patterns are created once at startup. Read helpers: `get_graph`,
|
|
429
|
+
`get_session_graph`, `get_llm_spans`, `get_tool_spans`, `get_failed_nodes`,
|
|
430
|
+
`get_all_execution_ids`, `get_all_session_ids`, plus `get_trace_summaries`/
|
|
431
|
+
`get_trace_detail` (purpose-built to avoid the old per-row full-graph
|
|
432
|
+
fetch). Also exposes the write path used by evaluators/RCA:
|
|
433
|
+
`write_evaluation_result` (one document per evaluation in an `evaluations`
|
|
434
|
+
collection, referencing `node_id`/`project_id` as plain fields rather than
|
|
435
|
+
a graph edge), `update_node_evaluation` (flattened eval props on the node
|
|
436
|
+
document for fast filtering, plus denormalizing `has_evaluation`/`status`
|
|
437
|
+
onto the execution header), `write_rca_result` (one document per
|
|
438
|
+
`execution_id` in `rca_reports`), plus `clear_execution` / `clear_session`
|
|
439
|
+
maintenance methods (wrapped in a MongoDB multi-document transaction so the
|
|
440
|
+
node/evaluation/RCA/header deletes for one execution are all-or-nothing).
|
|
441
|
+
|
|
442
|
+
### `evaluators/` — Evaluation Engine
|
|
443
|
+
|
|
444
|
+
Three evaluators, orchestrated by `EvaluationRunner`, all sharing one
|
|
445
|
+
`BaseEvaluator` (OpenAI `gpt-4o-mini` by default via `VALIDATOR_MODEL`,
|
|
446
|
+
JSON-mode responses, no retry logic — any failure degrades to a generic
|
|
447
|
+
`FAIL`/low-confidence result rather than crashing the run):
|
|
448
|
+
|
|
449
|
+
- **`InputEvaluator`** — runs on every node. Checks completeness, context
|
|
450
|
+
relevance, well-formedness, prompt-injection detection, and ambiguity.
|
|
451
|
+
Detected injection **always** forces `status=FAIL`, `severity=CRITICAL`,
|
|
452
|
+
overriding whatever the LLM itself returned.
|
|
453
|
+
- **`OutputEvaluator`** — runs on every node. Auto-detects structured
|
|
454
|
+
(dict/JSON) vs. unstructured (text) output. Structured checks: relevance,
|
|
455
|
+
structural correctness, internal consistency, handoff validity, schema
|
|
456
|
+
violations. Unstructured checks: relevance, completeness, hallucination
|
|
457
|
+
(with specific unsupported-claim evidence), toxicity. Detected toxicity
|
|
458
|
+
always forces `status=FAIL`, `severity=CRITICAL`.
|
|
459
|
+
- **`ToolAgentEvaluator`** — runs only on Tool/Retriever nodes, and on
|
|
460
|
+
Agent/Router nodes that have at least one tool-type child. Tool-node mode
|
|
461
|
+
grades input/output quality given the calling agent's context; agent-node
|
|
462
|
+
mode grades whether tool selection was appropriate (input/output quality of
|
|
463
|
+
the tool call itself is intentionally left to the tool-node evaluation).
|
|
464
|
+
- **`EvaluationRunner.run()`**: loads the graph from MongoDB, evaluates every
|
|
465
|
+
node with all 3 evaluators sequentially (no parallelism), builds a
|
|
466
|
+
`NodeEvaluationSummary` per node (overall status + worst severity rollup),
|
|
467
|
+
persists each result to MongoDB immediately, appends everything to a JSONL
|
|
468
|
+
log, then automatically invokes the RCA Engine and persists its report.
|
|
469
|
+
**Not idempotent**: because `EvaluationResult.evaluation_id` is a fresh
|
|
470
|
+
random UUID each run, re-running the pipeline for the same `execution_id`
|
|
471
|
+
creates duplicate `evaluations` documents (the flattened eval props on the
|
|
472
|
+
node document and the `rca_reports` document *are* overwritten cleanly on
|
|
473
|
+
rerun, since those are keyed by stable ids).
|
|
474
|
+
- **Triggering**: `EvaluationRunner` itself has no idea whether it was invoked
|
|
475
|
+
manually or automatically — both paths call the exact same constructor/`run()`.
|
|
476
|
+
It's invoked from two call sites: `POST .../run-evaluations` (`api/routers/traces.py`,
|
|
477
|
+
synchronous, request/response cycle) and, since `init(run_evaluations=True)`
|
|
478
|
+
became the SDK default, from a `BackgroundTasks` job scheduled inside
|
|
479
|
+
`POST /traces/ingest` right after a trace is saved. The one-shot guard on
|
|
480
|
+
the manual endpoint (`count_evaluations(...) > 0` → 400) is what keeps the
|
|
481
|
+
two triggers from racing into duplicate writes: once auto-evaluation has
|
|
482
|
+
run for a trace, a later manual "Run Evaluations" click just 400s instead
|
|
483
|
+
of re-running.
|
|
484
|
+
|
|
485
|
+
### `rca_engine/` — Root Cause Analysis
|
|
486
|
+
|
|
487
|
+
- **`RCAEngine.analyze(graph)`** takes an in-memory `ExecutionGraph` whose
|
|
488
|
+
nodes already have `validation_results` attached (done by the runner, not
|
|
489
|
+
a separate DB fetch). One LLM call (`gpt-4o` by default via `RCA_MODEL`)
|
|
490
|
+
produces `overall_status`, `root_cause`, `confidence`, `propagation_chain`,
|
|
491
|
+
`contributing_factors`, and `recommendations`.
|
|
492
|
+
- **`evidence` is deterministic, not LLM-generated** — it's built directly
|
|
493
|
+
from every `FAIL`-status evaluation entry in code, which keeps root-cause
|
|
494
|
+
claims grounded in actual evaluator findings rather than model invention.
|
|
495
|
+
- Any LLM/parsing failure degrades to a fixed fallback `RCAResult`
|
|
496
|
+
(`overall_status` derived from whether any failures exist) instead of
|
|
497
|
+
raising — the evaluation run is never blocked by an RCA failure.
|
|
498
|
+
- Persisted as a standalone document in `rca_reports`, keyed by
|
|
499
|
+
`execution_id` (safe to re-run, always overwrites in place via upsert).
|
|
500
|
+
- **`IncidentReportGenerator`** (`incident_report.py`) is a separate,
|
|
501
|
+
fully-working Markdown report exporter (status badge, overview table, ASCII
|
|
502
|
+
propagation-chain diagram, evidence table, node summary table) — it is
|
|
503
|
+
**not currently wired into the automatic evaluation pipeline** (no caller
|
|
504
|
+
outside `examples/`), so it exists as a ready-to-use feature rather than
|
|
505
|
+
dead code.
|
|
506
|
+
|
|
507
|
+
### LLM Models Actually Configured
|
|
508
|
+
|
|
509
|
+
All LLM calls in this project go through the OpenAI SDK (`OPENAI_API_KEY`).
|
|
510
|
+
There is no single global "the LLM" — four independent env vars pick the
|
|
511
|
+
model per component:
|
|
512
|
+
|
|
513
|
+
| Component | Env var | Code default (`.env.example`) | Currently set in `.env` |
|
|
514
|
+
|---|---|---|---|
|
|
515
|
+
| `evaluators/base_evaluator.py` (all 3 evaluators) | `VALIDATOR_MODEL` | `gpt-4o-mini` | `gpt-5.6-luna` |
|
|
516
|
+
| `rca_engine/rca_engine.py` | `RCA_MODEL` | `gpt-4o` | `gpt-5.6-terra` |
|
|
517
|
+
| `examples/multi_agent_demo.py` (demo agent's own LLM) | `VALIDATOR_MODEL` *(reuses the evaluator's var — see note)* | `gpt-4o-mini` | `gpt-5.6-luna` |
|
|
518
|
+
| `examples/support_triage_multi_agent.py` (demo agent's own LLM) | `SUPPORT_AGENT_MODEL` | `gpt-4o-mini` | *(not set in `.env` — falls back to default)* |
|
|
519
|
+
|
|
520
|
+
- `.env.example` documents an `AGENT_MODEL` var as controlling "the demo
|
|
521
|
+
agent", but `examples/multi_agent_demo.py` actually reads `VALIDATOR_MODEL`,
|
|
522
|
+
not `AGENT_MODEL` — so that demo agent currently shares a model with the
|
|
523
|
+
evaluators rather than having its own knob, and `AGENT_MODEL` is unused/dead.
|
|
524
|
+
- `gpt-5.6-luna` / `gpt-5.6-terra` are custom/internal aliases currently set
|
|
525
|
+
in the live `.env`, not OpenAI's public model names — swap them for real
|
|
526
|
+
model IDs (e.g. `gpt-4o-mini` / `gpt-4o`) if pointing at the standard
|
|
527
|
+
OpenAI API.
|
|
528
|
+
|
|
529
|
+
### `api/` — FastAPI Backend
|
|
530
|
+
|
|
531
|
+
- **Auth**: two schemes — JWT bearer tokens (7-day expiry, `HS256`, bcrypt
|
|
532
|
+
password hashing) for the dashboard, and a static per-user API key
|
|
533
|
+
(`ao_<32 hex chars>`) for agent-SDK ingestion. `SECRET_KEY` is required from
|
|
534
|
+
the environment with no insecure fallback.
|
|
535
|
+
- **Endpoints**:
|
|
536
|
+
- Auth: `POST /register`, `POST /token`, `GET /me`, `POST /api_key`.
|
|
537
|
+
- Projects: `GET/POST /projects`, `POST /projects/sync` (idempotent
|
|
538
|
+
find-or-create per `(user, service_name)` — the mechanism behind the
|
|
539
|
+
"service_name = project" design), `DELETE /projects/{id}`.
|
|
540
|
+
- Traces: `GET /projects/{project_id}/traces` (per-project rollup: status,
|
|
541
|
+
latency, evaluation presence), `GET /projects/{project_id}/traces/{execution_id}`
|
|
542
|
+
(full `{graph, evaluations, rca}` payload), `POST /projects/{project_id}/traces/{execution_id}/run-evaluations`
|
|
543
|
+
(synchronous — runs `EvaluationRunner` **inline** in the request/response
|
|
544
|
+
cycle; guarded to only run once per execution, with no reset/re-run path —
|
|
545
|
+
this is the manual trigger, still available regardless of whether
|
|
546
|
+
auto-evaluation already ran).
|
|
547
|
+
- Ingest: `POST /traces/ingest` — the SDK's only write path into MongoDB.
|
|
548
|
+
Accepts a serialized `ExecutionGraph` plus a `run_evaluations` query param
|
|
549
|
+
(default `True`, set by the SDK from `init(run_evaluations=...)`).
|
|
550
|
+
Authenticates via the same `x-api-key` header `/projects/sync` uses,
|
|
551
|
+
verifies the payload's `project_id` belongs to that api key's user (403
|
|
552
|
+
otherwise), re-stamps `project_id` onto every node server-side (never
|
|
553
|
+
trusts the client's per-node values), then calls `MongoStore.save_graph()`.
|
|
554
|
+
This is what lets `MONGODB_URI` stay private to the API process. When
|
|
555
|
+
`run_evaluations` is true, it then schedules `EvaluationRunner(...).run()`
|
|
556
|
+
(which triggers RCA too) as a FastAPI `BackgroundTasks` job **after** the
|
|
557
|
+
response is sent, so the SDK's shutdown-time POST isn't held open for the
|
|
558
|
+
LLM-bound evaluation/RCA pipeline. A background failure is only logged
|
|
559
|
+
server-side (`print`) — there's no request left to report it to — so a
|
|
560
|
+
trace can still be evaluated later via the manual `run-evaluations`
|
|
561
|
+
endpoint if the background run fails.
|
|
562
|
+
- **Multi-tenancy**: every project/trace endpoint scopes by `user_id` and
|
|
563
|
+
`project_id` (both plain MongoDB query filters now — no FK/graph traversal
|
|
564
|
+
involved), closing the cross-tenant leakage class of bug described in
|
|
565
|
+
`ISSUES.md` #1.
|
|
566
|
+
- **Data model**: a single MongoDB database (`agentops` by default) holds
|
|
567
|
+
everything — `users` (username, bcrypt hash, nullable API key, unique
|
|
568
|
+
indexes), `projects` (`_id` = slugified name, `user_id` field, compound
|
|
569
|
+
unique index on `(user_id, name)`), and `executions`/`nodes`/`evaluations`/
|
|
570
|
+
`rca_reports` for all execution/evaluation/RCA data. No SQLite, no second
|
|
571
|
+
database to run.
|
|
572
|
+
|
|
573
|
+
### `ui/` — React Dashboard
|
|
574
|
+
|
|
575
|
+
- **5 pages**: `Login`, `Register`, `Dashboard` (project grid + API key
|
|
576
|
+
management), `ProjectView` (trace list table), `TraceView` (the primary
|
|
577
|
+
trace-inspection surface).
|
|
578
|
+
- `Dashboard` and `ProjectView` auto-refresh every 3 seconds and surface
|
|
579
|
+
run/failure counts per project.
|
|
580
|
+
- **`TraceView`**: renders the span hierarchy as a hand-rolled recursive tree
|
|
581
|
+
component (not a graph library — `reactflow` is an installed dependency but
|
|
582
|
+
currently unused/unrendered anywhere). Each row shows a colored evaluation-
|
|
583
|
+
status dot (red/amber/green) and, for LLM nodes, the model name and an
|
|
584
|
+
estimated per-call cost (client-side, against a small hardcoded pricing
|
|
585
|
+
table). The right pane has Details / Evaluations / RCA Report tabs; the RCA
|
|
586
|
+
summary banner is trace-level and stays visible regardless of the selected
|
|
587
|
+
node. The "Run Evaluations" button calls the backend synchronously and
|
|
588
|
+
disappears once evaluations exist for the trace (no re-run affordance in
|
|
589
|
+
the UI either) — with `init(run_evaluations=True)` (the SDK default), the
|
|
590
|
+
button will typically already be hidden by the time a trace is opened,
|
|
591
|
+
since evaluation runs automatically in the background right after ingest.
|
|
592
|
+
- Several controls are currently **decorative placeholders** with no backing
|
|
593
|
+
logic: the ProjectView search bar, its "With errors"/"Tags" filter buttons,
|
|
594
|
+
its row checkboxes, and two Sidebar nav items ("Test suites", "Experiments").
|
|
595
|
+
|
|
596
|
+
### Known Gaps & Next-Phase Backlog
|
|
597
|
+
|
|
598
|
+
Captured here so they can be triaged deliberately rather than rediscovered.
|
|
599
|
+
See `ISSUES.md` for the full audit trail of what's already been fixed.
|
|
600
|
+
|
|
601
|
+
- **Non-idempotent evaluation writes** — re-running evaluations for an
|
|
602
|
+
execution creates duplicate `evaluations` documents; the API also only
|
|
603
|
+
allows running evaluations once per trace, with no delete/reset endpoint.
|
|
604
|
+
- **Auto-triggered evaluation has no retry/observability** — the
|
|
605
|
+
`BackgroundTasks` job `POST /traces/ingest` schedules when
|
|
606
|
+
`run_evaluations=True` (the default) has no retry, no dead-letter queue,
|
|
607
|
+
and no status surfaced anywhere if it fails — a failure is only a `print`
|
|
608
|
+
in the API server's own logs. The trace itself still ingests successfully
|
|
609
|
+
either way; a user who notices missing evaluations can always fall back to
|
|
610
|
+
the manual "Run Evaluations" button/endpoint.
|
|
611
|
+
- **Trace data is only sent at process shutdown** (buffer-then-flush in
|
|
612
|
+
`GraphSpanExporter`, now a single `POST /traces/ingest` instead of a direct
|
|
613
|
+
Mongo write) — long-running/persistent agent processes show nothing in the
|
|
614
|
+
UI until they exit. Unchanged by the Neo4j → MongoDB migration or the
|
|
615
|
+
move to routing writes through the API; would need a real per-span write
|
|
616
|
+
path to fix.
|
|
617
|
+
- **Fan-out/fan-in topology is flattened** into a single linear `NEXT` chain
|
|
618
|
+
(see `builder.py` note in `CLAUDE.md`) — a supervisor's parallel branches
|
|
619
|
+
aren't distinguishable from a genuinely linear pipeline today.
|
|
620
|
+
- **No pagination anywhere** — API list endpoints and every UI list view load
|
|
621
|
+
the entire dataset in one shot. (The trace-list endpoint's old N+1 —
|
|
622
|
+
fetching the full graph per execution just to compute a summary row — was
|
|
623
|
+
fixed as part of the MongoDB migration: a lightweight `executions` header
|
|
624
|
+
document now carries the summary fields directly, so listing traces no
|
|
625
|
+
longer touches node bodies at all. Pagination itself is still not
|
|
626
|
+
implemented.)
|
|
627
|
+
- **Permissive CORS** (`allow_origins=["*"]` with `allow_credentials=True`),
|
|
628
|
+
no JWT revocation/logout flow, and a single non-expiring API key per user.
|
|
629
|
+
- **No true graph visualization yet** — `reactflow` is installed but unused;
|
|
630
|
+
`TraceView` uses a recursive-tree approximation instead of a node-link view.
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|