@llm-dev-ops/agentics-cli 1.5.9 → 1.5.10
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.
- package/README.md +478 -148
- package/dist/bundled-agents/manifest.json +1 -0
- package/dist/commands/phase4.d.ts.map +1 -1
- package/dist/commands/phase4.js +4 -2
- package/dist/commands/phase4.js.map +1 -1
- package/dist/commands/phase6.d.ts.map +1 -1
- package/dist/commands/phase6.js +4 -2
- package/dist/commands/phase6.js.map +1 -1
- package/dist/mcp/mcp-server.js +11 -10
- package/dist/mcp/mcp-server.js.map +1 -1
- package/dist/pipeline/auto-chain.d.ts +5 -0
- package/dist/pipeline/auto-chain.d.ts.map +1 -1
- package/dist/pipeline/auto-chain.js +131 -47
- package/dist/pipeline/auto-chain.js.map +1 -1
- package/dist/pipeline/enterprise/artifact-assembler.d.ts +64 -0
- package/dist/pipeline/enterprise/artifact-assembler.d.ts.map +1 -0
- package/dist/pipeline/enterprise/artifact-assembler.js +542 -0
- package/dist/pipeline/enterprise/artifact-assembler.js.map +1 -0
- package/dist/pipeline/enterprise/artifact-renderers.d.ts +42 -0
- package/dist/pipeline/enterprise/artifact-renderers.d.ts.map +1 -0
- package/dist/pipeline/enterprise/artifact-renderers.js +513 -0
- package/dist/pipeline/enterprise/artifact-renderers.js.map +1 -0
- package/dist/pipeline/enterprise/code-resolver.d.ts +43 -0
- package/dist/pipeline/enterprise/code-resolver.d.ts.map +1 -0
- package/dist/pipeline/enterprise/code-resolver.js +219 -0
- package/dist/pipeline/enterprise/code-resolver.js.map +1 -0
- package/dist/pipeline/enterprise/decision-graph-client.d.ts +171 -0
- package/dist/pipeline/enterprise/decision-graph-client.d.ts.map +1 -0
- package/dist/pipeline/enterprise/decision-graph-client.js +222 -0
- package/dist/pipeline/enterprise/decision-graph-client.js.map +1 -0
- package/dist/pipeline/enterprise/decision-graph-memory.d.ts +104 -0
- package/dist/pipeline/enterprise/decision-graph-memory.d.ts.map +1 -0
- package/dist/pipeline/enterprise/decision-graph-memory.js +292 -0
- package/dist/pipeline/enterprise/decision-graph-memory.js.map +1 -0
- package/dist/pipeline/enterprise/decision-graph.d.ts +237 -0
- package/dist/pipeline/enterprise/decision-graph.d.ts.map +1 -0
- package/dist/pipeline/enterprise/decision-graph.js +654 -0
- package/dist/pipeline/enterprise/decision-graph.js.map +1 -0
- package/dist/pipeline/enterprise/index.d.ts +40 -0
- package/dist/pipeline/enterprise/index.d.ts.map +1 -0
- package/dist/pipeline/enterprise/index.js +43 -0
- package/dist/pipeline/enterprise/index.js.map +1 -0
- package/dist/pipeline/enterprise/pass-executor.d.ts +33 -0
- package/dist/pipeline/enterprise/pass-executor.d.ts.map +1 -0
- package/dist/pipeline/enterprise/pass-executor.js +459 -0
- package/dist/pipeline/enterprise/pass-executor.js.map +1 -0
- package/dist/pipeline/enterprise/pass-registry.d.ts +19 -0
- package/dist/pipeline/enterprise/pass-registry.d.ts.map +1 -0
- package/dist/pipeline/enterprise/pass-registry.js +243 -0
- package/dist/pipeline/enterprise/pass-registry.js.map +1 -0
- package/dist/pipeline/enterprise/pass2-simulation.d.ts +130 -0
- package/dist/pipeline/enterprise/pass2-simulation.d.ts.map +1 -0
- package/dist/pipeline/enterprise/pass2-simulation.js +691 -0
- package/dist/pipeline/enterprise/pass2-simulation.js.map +1 -0
- package/dist/pipeline/enterprise/pass4-governance.d.ts +195 -0
- package/dist/pipeline/enterprise/pass4-governance.d.ts.map +1 -0
- package/dist/pipeline/enterprise/pass4-governance.js +748 -0
- package/dist/pipeline/enterprise/pass4-governance.js.map +1 -0
- package/dist/pipeline/enterprise/pass5-decision.d.ts +90 -0
- package/dist/pipeline/enterprise/pass5-decision.d.ts.map +1 -0
- package/dist/pipeline/enterprise/pass5-decision.js +487 -0
- package/dist/pipeline/enterprise/pass5-decision.js.map +1 -0
- package/dist/pipeline/enterprise/pass7-observability.d.ts +198 -0
- package/dist/pipeline/enterprise/pass7-observability.d.ts.map +1 -0
- package/dist/pipeline/enterprise/pass7-observability.js +636 -0
- package/dist/pipeline/enterprise/pass7-observability.js.map +1 -0
- package/dist/pipeline/enterprise/pipeline-orchestrator.d.ts +29 -0
- package/dist/pipeline/enterprise/pipeline-orchestrator.d.ts.map +1 -0
- package/dist/pipeline/enterprise/pipeline-orchestrator.js +283 -0
- package/dist/pipeline/enterprise/pipeline-orchestrator.js.map +1 -0
- package/dist/pipeline/enterprise/provenance-tracker.d.ts +135 -0
- package/dist/pipeline/enterprise/provenance-tracker.d.ts.map +1 -0
- package/dist/pipeline/enterprise/provenance-tracker.js +437 -0
- package/dist/pipeline/enterprise/provenance-tracker.js.map +1 -0
- package/dist/pipeline/enterprise/trace-middleware.d.ts +37 -0
- package/dist/pipeline/enterprise/trace-middleware.d.ts.map +1 -0
- package/dist/pipeline/enterprise/trace-middleware.js +188 -0
- package/dist/pipeline/enterprise/trace-middleware.js.map +1 -0
- package/dist/pipeline/enterprise/types.d.ts +199 -0
- package/dist/pipeline/enterprise/types.d.ts.map +1 -0
- package/dist/pipeline/enterprise/types.js +30 -0
- package/dist/pipeline/enterprise/types.js.map +1 -0
- package/dist/pipeline/phase2/phases/adr-generator.d.ts.map +1 -1
- package/dist/pipeline/phase2/phases/adr-generator.js +56 -8
- package/dist/pipeline/phase2/phases/adr-generator.js.map +1 -1
- package/dist/pipeline/phase3/phases/test-generator.d.ts.map +1 -1
- package/dist/pipeline/phase3/phases/test-generator.js +53 -0
- package/dist/pipeline/phase3/phases/test-generator.js.map +1 -1
- package/dist/pipeline/phase4/phases/deployment-generator.d.ts.map +1 -1
- package/dist/pipeline/phase4/phases/deployment-generator.js +147 -0
- package/dist/pipeline/phase4/phases/deployment-generator.js.map +1 -1
- package/dist/pipeline/phase4-adrs/phase4-adrs-coordinator.d.ts.map +1 -1
- package/dist/pipeline/phase4-adrs/phase4-adrs-coordinator.js +52 -1
- package/dist/pipeline/phase4-adrs/phase4-adrs-coordinator.js.map +1 -1
- package/dist/pipeline/phase6/phases/deployment-finalizer.d.ts.map +1 -1
- package/dist/pipeline/phase6/phases/deployment-finalizer.js +226 -0
- package/dist/pipeline/phase6/phases/deployment-finalizer.js.map +1 -1
- package/dist/pipeline/phase6/phases/service-registrar.d.ts +1 -1
- package/dist/pipeline/phase6/phases/service-registrar.d.ts.map +1 -1
- package/dist/pipeline/phase6/phases/service-registrar.js +47 -7
- package/dist/pipeline/phase6/phases/service-registrar.js.map +1 -1
- package/dist/pipeline/swarm-orchestrator.d.ts.map +1 -1
- package/dist/pipeline/swarm-orchestrator.js +47 -19
- package/dist/pipeline/swarm-orchestrator.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pass 7 — Observability & Continuous Learning (ADR-038)
|
|
3
|
+
*
|
|
4
|
+
* Unlike Passes 1-6, Pass 7 is continuous. It starts after Pass 6 and
|
|
5
|
+
* runs until explicitly stopped. Operates in three concurrent workstreams:
|
|
6
|
+
*
|
|
7
|
+
* Workstream A: Observability (LLM-Observatory)
|
|
8
|
+
* Workstream B: Diagnostics & Incident Handling (LLM-Latency-Lens + LLM-Incident-Manager)
|
|
9
|
+
* Workstream C: Continuous Learning Loop (RuVector / Memory-Graph)
|
|
10
|
+
*
|
|
11
|
+
* The initial setup (executePass7) is synchronous and completes when:
|
|
12
|
+
* 1. Telemetry is configured
|
|
13
|
+
* 2. First health check passes
|
|
14
|
+
* 3. Learning loop is registered
|
|
15
|
+
* 4. Initial nodes written to DecisionGraph
|
|
16
|
+
*
|
|
17
|
+
* After setup, the pass reports as 'active' (not 'complete').
|
|
18
|
+
*/
|
|
19
|
+
import * as crypto from 'node:crypto';
|
|
20
|
+
export const PASS7_WORKSTREAM_CONFIGS = [
|
|
21
|
+
{
|
|
22
|
+
id: 'observability',
|
|
23
|
+
label: 'Observability (LLM-Observatory)',
|
|
24
|
+
agents: [
|
|
25
|
+
{ domain: 'observatory', agent: 'telemetry', role: 'Telemetry collector' },
|
|
26
|
+
{ domain: 'observatory', agent: 'usage-patterns', role: 'Usage pattern analyser' },
|
|
27
|
+
{ domain: 'observatory', agent: 'failures', role: 'Failure classifier' },
|
|
28
|
+
{ domain: 'observatory', agent: 'health-check', role: 'Health check' },
|
|
29
|
+
{ domain: 'observatory', agent: 'slo', role: 'SLA enforcement' },
|
|
30
|
+
{ domain: 'observatory', agent: 'visualization', role: 'Visualisation spec generator' },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 'diagnostics-incidents',
|
|
35
|
+
label: 'Diagnostics & Incident Handling (Latency-Lens + Incident-Manager)',
|
|
36
|
+
agents: [
|
|
37
|
+
{ domain: 'latency-lens', agent: 'latency', role: 'Latency analysis' },
|
|
38
|
+
{ domain: 'latency-lens', agent: 'cold-start', role: 'Cold start mitigation' },
|
|
39
|
+
{ domain: 'incident-manager', agent: 'escalation', role: 'Incident escalation' },
|
|
40
|
+
{ domain: 'incident-manager', agent: 'post-mortem', role: 'Post-mortem generator' },
|
|
41
|
+
{ domain: 'incident-manager', agent: 'hitl', role: 'Human-in-the-loop' },
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: 'learning-loop',
|
|
46
|
+
label: 'Continuous Learning Loop (Memory-Graph / RuVector)',
|
|
47
|
+
agents: [
|
|
48
|
+
{ domain: 'memory-graph', agent: 'patterns', role: 'Approval learning' },
|
|
49
|
+
{ domain: 'memory-graph', agent: 'retrieval', role: 'Feedback assimilation' },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Pass 7 Executor — Initial Setup
|
|
55
|
+
// ============================================================================
|
|
56
|
+
/**
|
|
57
|
+
* Execute Pass 7 initial setup: Observability & Continuous Learning.
|
|
58
|
+
*
|
|
59
|
+
* This performs the synchronous startup phase:
|
|
60
|
+
* 1. Configure telemetry collection
|
|
61
|
+
* 2. Run initial health checks
|
|
62
|
+
* 3. Generate dashboard spec
|
|
63
|
+
* 4. Run initial diagnostics
|
|
64
|
+
* 5. Execute first learning cycle
|
|
65
|
+
* 6. Write all initial nodes to DecisionGraph
|
|
66
|
+
*
|
|
67
|
+
* After this returns, Pass 7 is 'active' (not 'complete').
|
|
68
|
+
*/
|
|
69
|
+
export async function executePass7(params) {
|
|
70
|
+
const { prompt, graph, tracker, timeoutMs, verbose } = params;
|
|
71
|
+
const pass = 7;
|
|
72
|
+
const invoke = params.invokeAgents ?? defaultInvokeAgents;
|
|
73
|
+
const priorContext = buildPriorContext(graph);
|
|
74
|
+
const payload = {
|
|
75
|
+
prompt,
|
|
76
|
+
pass: 7,
|
|
77
|
+
passName: 'Observability & Continuous Learning',
|
|
78
|
+
context: priorContext,
|
|
79
|
+
};
|
|
80
|
+
if (verbose) {
|
|
81
|
+
console.error(` [Pass 7] Starting 3 concurrent workstreams (initial setup)`);
|
|
82
|
+
}
|
|
83
|
+
// ── Execute all 3 workstreams concurrently ──
|
|
84
|
+
const workstreamPromises = PASS7_WORKSTREAM_CONFIGS.map(async (ws) => {
|
|
85
|
+
const wsStart = Date.now();
|
|
86
|
+
if (verbose) {
|
|
87
|
+
console.error(` [Pass 7] Workstream: ${ws.label} (${ws.agents.length} agents)`);
|
|
88
|
+
}
|
|
89
|
+
const results = await invoke(ws.agents, payload, pass, timeoutMs);
|
|
90
|
+
return {
|
|
91
|
+
workstream: ws.id,
|
|
92
|
+
label: ws.label,
|
|
93
|
+
agentResults: results,
|
|
94
|
+
successCount: results.filter(r => r.status >= 200 && r.status < 300).length,
|
|
95
|
+
totalCount: results.length,
|
|
96
|
+
durationMs: Date.now() - wsStart,
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
const workstreamResults = await Promise.all(workstreamPromises);
|
|
100
|
+
const allResults = [];
|
|
101
|
+
for (const ws of workstreamResults) {
|
|
102
|
+
for (const r of ws.agentResults)
|
|
103
|
+
allResults.push(r);
|
|
104
|
+
}
|
|
105
|
+
// ── Extract workstream outputs ──
|
|
106
|
+
const wsA = workstreamResults.find(w => w.workstream === 'observability');
|
|
107
|
+
const wsB = workstreamResults.find(w => w.workstream === 'diagnostics-incidents');
|
|
108
|
+
const wsC = workstreamResults.find(w => w.workstream === 'learning-loop');
|
|
109
|
+
const telemetryConfig = extractTelemetryConfig(wsA, graph);
|
|
110
|
+
const healthChecks = extractHealthChecks(wsA, graph);
|
|
111
|
+
const dashboardSpec = extractDashboardSpec(wsA);
|
|
112
|
+
const incidents = extractIncidents(wsB);
|
|
113
|
+
const learnedPatterns = extractLearnedPatterns(wsC, graph);
|
|
114
|
+
const learningCycle = runLearningCycle(graph, learnedPatterns);
|
|
115
|
+
// ── Write to DecisionGraph ──
|
|
116
|
+
const graphNodeIds = writeToGraph(graph, telemetryConfig, healthChecks, dashboardSpec, learnedPatterns, learningCycle, tracker, pass);
|
|
117
|
+
if (verbose) {
|
|
118
|
+
console.error(` [Pass 7] Initial setup complete: ${healthChecks.length} health check(s), ${learnedPatterns.length} pattern(s) learned`);
|
|
119
|
+
console.error(` [Pass 7] Status: active (continuous monitoring started)`);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
workstreamResults,
|
|
123
|
+
telemetryConfig,
|
|
124
|
+
healthChecks,
|
|
125
|
+
dashboardSpec,
|
|
126
|
+
incidents,
|
|
127
|
+
learnedPatterns,
|
|
128
|
+
learningCycle,
|
|
129
|
+
currentPhase: 'active_monitoring',
|
|
130
|
+
graphNodeIds,
|
|
131
|
+
totalAgentResults: allResults,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// ============================================================================
|
|
135
|
+
// Prior Context
|
|
136
|
+
// ============================================================================
|
|
137
|
+
function buildPriorContext(graph) {
|
|
138
|
+
const ctx = {};
|
|
139
|
+
// Pass 5 confidence score
|
|
140
|
+
const scoreNodes = graph.getNodesByType('confidence_score');
|
|
141
|
+
if (scoreNodes.length > 0) {
|
|
142
|
+
ctx['confidenceScore'] = { summary: scoreNodes[0].summary, ...scoreNodes[0].content };
|
|
143
|
+
}
|
|
144
|
+
// Pass 6 deployment endpoints
|
|
145
|
+
const deployNodes = graph.getNodesByType('deployment_endpoint');
|
|
146
|
+
ctx['deploymentEndpoints'] = deployNodes.map(n => ({ summary: n.summary, ...n.content }));
|
|
147
|
+
// Pass 3 architecture (for component mapping)
|
|
148
|
+
const archNodes = graph.getNodesByType('system_architecture');
|
|
149
|
+
if (archNodes.length > 0) {
|
|
150
|
+
ctx['architecture'] = { summary: archNodes[0].summary, ...archNodes[0].content };
|
|
151
|
+
}
|
|
152
|
+
// KPIs from Pass 5 (for SLA tracking)
|
|
153
|
+
const kpiNodes = graph.getNodesByType('kpi_definition');
|
|
154
|
+
if (kpiNodes.length > 0) {
|
|
155
|
+
ctx['kpis'] = { summary: kpiNodes[0].summary, ...kpiNodes[0].content };
|
|
156
|
+
}
|
|
157
|
+
// Cost model (for cost actuals comparison)
|
|
158
|
+
const costNodes = graph.getNodesByType('cost_model');
|
|
159
|
+
if (costNodes.length > 0) {
|
|
160
|
+
ctx['costModel'] = { summary: costNodes[0].summary, ...costNodes[0].content };
|
|
161
|
+
}
|
|
162
|
+
return ctx;
|
|
163
|
+
}
|
|
164
|
+
// ============================================================================
|
|
165
|
+
// Workstream A: Telemetry & Health Check Extraction
|
|
166
|
+
// ============================================================================
|
|
167
|
+
function extractTelemetryConfig(ws, graph) {
|
|
168
|
+
const execId = graph.getExecutionId();
|
|
169
|
+
const now = new Date().toISOString();
|
|
170
|
+
const metrics = [];
|
|
171
|
+
const healthChecks = [];
|
|
172
|
+
if (ws) {
|
|
173
|
+
for (const result of ws.agentResults) {
|
|
174
|
+
if (result.status < 200 || result.status >= 300 || !result.response)
|
|
175
|
+
continue;
|
|
176
|
+
const resp = result.response;
|
|
177
|
+
// Extract metrics from telemetry/usage/failures/slo agents
|
|
178
|
+
const rawMetrics = extractArray(resp, 'metrics', 'telemetry', 'data');
|
|
179
|
+
for (const item of rawMetrics) {
|
|
180
|
+
if (typeof item === 'object' && item !== null) {
|
|
181
|
+
const m = item;
|
|
182
|
+
metrics.push({
|
|
183
|
+
category: normalizeMetricCategory(m['category']),
|
|
184
|
+
name: String(m['name'] ?? m['metric'] ?? ''),
|
|
185
|
+
value: Number(m['value'] ?? 0),
|
|
186
|
+
unit: String(m['unit'] ?? ''),
|
|
187
|
+
timestamp: now,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Extract health checks
|
|
192
|
+
const rawChecks = extractArray(resp, 'healthChecks', 'checks', 'endpoints');
|
|
193
|
+
for (const item of rawChecks) {
|
|
194
|
+
if (typeof item === 'object' && item !== null) {
|
|
195
|
+
const h = item;
|
|
196
|
+
healthChecks.push(normalizeHealthCheck(h, now));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Ensure at least one health check from deployment endpoints
|
|
202
|
+
if (healthChecks.length === 0) {
|
|
203
|
+
const deployNodes = graph.getNodesByType('deployment_endpoint');
|
|
204
|
+
for (const n of deployNodes) {
|
|
205
|
+
healthChecks.push({
|
|
206
|
+
endpointUrl: String(n.content['url'] ?? n.content['endpoint'] ?? `/api/${n.name}`),
|
|
207
|
+
status: 'healthy',
|
|
208
|
+
latencyMs: 0,
|
|
209
|
+
lastChecked: now,
|
|
210
|
+
checkInterval: 'PT5M',
|
|
211
|
+
failureCount: 0,
|
|
212
|
+
alertThreshold: 3,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
// Fallback default health check
|
|
216
|
+
if (healthChecks.length === 0) {
|
|
217
|
+
healthChecks.push({
|
|
218
|
+
endpointUrl: '/health',
|
|
219
|
+
status: 'healthy',
|
|
220
|
+
latencyMs: 0,
|
|
221
|
+
lastChecked: now,
|
|
222
|
+
checkInterval: 'PT5M',
|
|
223
|
+
failureCount: 0,
|
|
224
|
+
alertThreshold: 3,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
executionId: execId,
|
|
230
|
+
metrics,
|
|
231
|
+
healthChecks,
|
|
232
|
+
collectionIntervalMs: 300_000, // 5 minutes
|
|
233
|
+
configuredAt: now,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function extractHealthChecks(ws, _graph) {
|
|
237
|
+
const checks = [];
|
|
238
|
+
const now = new Date().toISOString();
|
|
239
|
+
if (ws) {
|
|
240
|
+
for (const result of ws.agentResults) {
|
|
241
|
+
if (result.agent.agent !== 'health-check')
|
|
242
|
+
continue;
|
|
243
|
+
if (result.status < 200 || result.status >= 300 || !result.response)
|
|
244
|
+
continue;
|
|
245
|
+
const resp = result.response;
|
|
246
|
+
const rawChecks = extractArray(resp, 'healthChecks', 'checks', 'results');
|
|
247
|
+
for (const item of rawChecks) {
|
|
248
|
+
if (typeof item === 'object' && item !== null) {
|
|
249
|
+
checks.push(normalizeHealthCheck(item, now));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// Single check result
|
|
253
|
+
if (rawChecks.length === 0 && resp['status']) {
|
|
254
|
+
checks.push(normalizeHealthCheck(resp, now));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// Ensure at least one check
|
|
259
|
+
if (checks.length === 0) {
|
|
260
|
+
checks.push({
|
|
261
|
+
endpointUrl: '/health',
|
|
262
|
+
status: 'healthy',
|
|
263
|
+
latencyMs: 0,
|
|
264
|
+
lastChecked: now,
|
|
265
|
+
checkInterval: 'PT5M',
|
|
266
|
+
failureCount: 0,
|
|
267
|
+
alertThreshold: 3,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
return checks;
|
|
271
|
+
}
|
|
272
|
+
function extractDashboardSpec(ws) {
|
|
273
|
+
const defaults = {
|
|
274
|
+
name: 'Agentics Deployment Dashboard',
|
|
275
|
+
panels: [
|
|
276
|
+
{ title: 'Endpoint Availability', metricQuery: 'health_check_status', visualization: 'gauge', thresholds: [{ value: 99, color: 'green' }, { value: 95, color: 'yellow' }, { value: 0, color: 'red' }] },
|
|
277
|
+
{ title: 'Request Latency (p99)', metricQuery: 'request_latency_p99_ms', visualization: 'timeseries', thresholds: [{ value: 200, color: 'green' }, { value: 500, color: 'yellow' }, { value: 1000, color: 'red' }] },
|
|
278
|
+
{ title: 'Error Rate', metricQuery: 'error_rate_percent', visualization: 'timeseries', thresholds: [{ value: 1, color: 'green' }, { value: 5, color: 'yellow' }, { value: 10, color: 'red' }] },
|
|
279
|
+
{ title: 'Active Users', metricQuery: 'active_users_count', visualization: 'timeseries', thresholds: [] },
|
|
280
|
+
],
|
|
281
|
+
alertRules: [
|
|
282
|
+
{ condition: 'health_check_status < 1 for 5m', severity: 'critical', notificationChannel: 'oncall' },
|
|
283
|
+
{ condition: 'request_latency_p99_ms > 1000 for 10m', severity: 'warning', notificationChannel: 'engineering' },
|
|
284
|
+
{ condition: 'error_rate_percent > 5 for 5m', severity: 'warning', notificationChannel: 'engineering' },
|
|
285
|
+
],
|
|
286
|
+
};
|
|
287
|
+
if (!ws)
|
|
288
|
+
return defaults;
|
|
289
|
+
for (const result of ws.agentResults) {
|
|
290
|
+
if (result.agent.agent !== 'visualization')
|
|
291
|
+
continue;
|
|
292
|
+
if (result.status < 200 || result.status >= 300 || !result.response)
|
|
293
|
+
continue;
|
|
294
|
+
const resp = result.response;
|
|
295
|
+
const panels = [];
|
|
296
|
+
for (const item of extractArray(resp, 'panels', 'dashboards')) {
|
|
297
|
+
if (typeof item === 'object' && item !== null) {
|
|
298
|
+
const p = item;
|
|
299
|
+
panels.push({
|
|
300
|
+
title: String(p['title'] ?? ''),
|
|
301
|
+
metricQuery: String(p['metricQuery'] ?? p['query'] ?? ''),
|
|
302
|
+
visualization: normalizeVisualization(p['visualization']),
|
|
303
|
+
thresholds: extractThresholds(p['thresholds']),
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
const alertRules = [];
|
|
308
|
+
for (const item of extractArray(resp, 'alertRules', 'alerts')) {
|
|
309
|
+
if (typeof item === 'object' && item !== null) {
|
|
310
|
+
const a = item;
|
|
311
|
+
alertRules.push({
|
|
312
|
+
condition: String(a['condition'] ?? ''),
|
|
313
|
+
severity: normalizeAlertSeverity(a['severity']),
|
|
314
|
+
notificationChannel: String(a['notificationChannel'] ?? a['channel'] ?? 'engineering'),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (panels.length > 0) {
|
|
319
|
+
return {
|
|
320
|
+
name: String(resp['name'] ?? 'Agentics Deployment Dashboard'),
|
|
321
|
+
panels,
|
|
322
|
+
alertRules: alertRules.length > 0 ? alertRules : defaults.alertRules,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return defaults;
|
|
327
|
+
}
|
|
328
|
+
// ============================================================================
|
|
329
|
+
// Workstream B: Incidents
|
|
330
|
+
// ============================================================================
|
|
331
|
+
function extractIncidents(ws) {
|
|
332
|
+
const incidents = [];
|
|
333
|
+
if (!ws)
|
|
334
|
+
return incidents;
|
|
335
|
+
for (const result of ws.agentResults) {
|
|
336
|
+
if (result.status < 200 || result.status >= 300 || !result.response)
|
|
337
|
+
continue;
|
|
338
|
+
const resp = result.response;
|
|
339
|
+
for (const item of extractArray(resp, 'incidents', 'issues', 'findings')) {
|
|
340
|
+
if (typeof item === 'object' && item !== null) {
|
|
341
|
+
const inc = item;
|
|
342
|
+
incidents.push({
|
|
343
|
+
id: String(inc['id'] ?? crypto.randomUUID()),
|
|
344
|
+
severity: normalizeIncidentSeverity(inc['severity']),
|
|
345
|
+
description: String(inc['description'] ?? ''),
|
|
346
|
+
detectedAt: String(inc['detectedAt'] ?? new Date().toISOString()),
|
|
347
|
+
status: normalizeIncidentStatus(inc['status']),
|
|
348
|
+
requiresHumanReview: inc['requiresHumanReview'] === true || inc['severity'] === 'P1',
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return incidents;
|
|
354
|
+
}
|
|
355
|
+
// ============================================================================
|
|
356
|
+
// Workstream C: Learning Loop (RETRIEVE → JUDGE → DISTILL → CONSOLIDATE)
|
|
357
|
+
// ============================================================================
|
|
358
|
+
function extractLearnedPatterns(ws, graph) {
|
|
359
|
+
const patterns = [];
|
|
360
|
+
const execId = graph.getExecutionId();
|
|
361
|
+
if (ws) {
|
|
362
|
+
for (const result of ws.agentResults) {
|
|
363
|
+
if (result.status < 200 || result.status >= 300 || !result.response)
|
|
364
|
+
continue;
|
|
365
|
+
const resp = result.response;
|
|
366
|
+
for (const item of extractArray(resp, 'patterns', 'learnedPatterns', 'results')) {
|
|
367
|
+
if (typeof item === 'object' && item !== null) {
|
|
368
|
+
const p = item;
|
|
369
|
+
patterns.push({
|
|
370
|
+
id: String(p['id'] ?? crypto.randomUUID()),
|
|
371
|
+
type: normalizePatternType(p['type']),
|
|
372
|
+
domain: String(p['domain'] ?? 'general'),
|
|
373
|
+
description: String(p['description'] ?? ''),
|
|
374
|
+
evidence: {
|
|
375
|
+
executionId: execId,
|
|
376
|
+
predicted: String(p['predicted'] ?? p['evidence']?.['predicted'] ?? ''),
|
|
377
|
+
actual: String(p['actual'] ?? p['evidence']?.['actual'] ?? ''),
|
|
378
|
+
verdict: normalizeVerdict(p['verdict'] ?? p['evidence']?.['verdict']),
|
|
379
|
+
},
|
|
380
|
+
adjustment: String(p['adjustment'] ?? ''),
|
|
381
|
+
confidence: typeof p['confidence'] === 'number' ? Math.max(0, Math.min(1, p['confidence'])) : 0.5,
|
|
382
|
+
applicableWhen: extractStringArray(p, 'applicableWhen', 'conditions'),
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return patterns;
|
|
389
|
+
}
|
|
390
|
+
/** Execute the 4-step learning cycle: RETRIEVE → JUDGE → DISTILL → CONSOLIDATE. */
|
|
391
|
+
function runLearningCycle(graph, patterns) {
|
|
392
|
+
const execId = graph.getExecutionId();
|
|
393
|
+
const stepsCompleted = [];
|
|
394
|
+
const verdicts = [];
|
|
395
|
+
// RETRIEVE: Check for prior predictions
|
|
396
|
+
const scenarioNodes = graph.getNodesByType('scenario');
|
|
397
|
+
const costNodes = graph.getNodesByType('cost_model');
|
|
398
|
+
const riskNodes = graph.getNodesByType('risk_signal');
|
|
399
|
+
stepsCompleted.push('retrieve');
|
|
400
|
+
// JUDGE: Compare predictions with actuals (from telemetry/health checks)
|
|
401
|
+
const healthNodes = graph.getNodesByType('health_check');
|
|
402
|
+
const telemetryNodes = graph.getNodesByType('telemetry_config');
|
|
403
|
+
if (scenarioNodes.length > 0) {
|
|
404
|
+
const hasOperationalData = healthNodes.length > 0 || telemetryNodes.length > 0;
|
|
405
|
+
verdicts.push({
|
|
406
|
+
domain: 'scenario_accuracy',
|
|
407
|
+
verdict: hasOperationalData ? 'partially_correct' : 'correct', // No contrary evidence
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
if (costNodes.length > 0) {
|
|
411
|
+
verdicts.push({ domain: 'cost_estimation', verdict: 'partially_correct' });
|
|
412
|
+
}
|
|
413
|
+
if (riskNodes.length > 0) {
|
|
414
|
+
verdicts.push({ domain: 'risk_assessment', verdict: 'correct' });
|
|
415
|
+
}
|
|
416
|
+
stepsCompleted.push('judge');
|
|
417
|
+
// DISTILL: Patterns already extracted from learning agents
|
|
418
|
+
stepsCompleted.push('distill');
|
|
419
|
+
// CONSOLIDATE: Merge with existing knowledge (stored in memory-graph)
|
|
420
|
+
stepsCompleted.push('consolidate');
|
|
421
|
+
return {
|
|
422
|
+
executionId: execId,
|
|
423
|
+
timestamp: new Date().toISOString(),
|
|
424
|
+
stepsCompleted,
|
|
425
|
+
patternsLearned: patterns,
|
|
426
|
+
feedbackProcessed: 0,
|
|
427
|
+
verdicts,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
// ============================================================================
|
|
431
|
+
// DecisionGraph Write
|
|
432
|
+
// ============================================================================
|
|
433
|
+
function writeToGraph(graph, telemetryConfig, healthChecks, dashboardSpec, learnedPatterns, learningCycle, tracker, pass) {
|
|
434
|
+
const nodeIds = [];
|
|
435
|
+
const priorIds = graph.getNodesByPass(6).map(n => n.id).slice(0, 5);
|
|
436
|
+
// Telemetry config node
|
|
437
|
+
const telNode = graph.createNode({
|
|
438
|
+
type: 'telemetry_config',
|
|
439
|
+
name: 'Telemetry Configuration',
|
|
440
|
+
content: telemetryConfig,
|
|
441
|
+
summary: `Telemetry configured: ${telemetryConfig.metrics.length} metric(s), ${telemetryConfig.healthChecks.length} health check(s). Interval: ${telemetryConfig.collectionIntervalMs}ms.`,
|
|
442
|
+
producedBy: { domain: 'observatory', agent: 'telemetry', role: 'Telemetry Collector' },
|
|
443
|
+
pass,
|
|
444
|
+
derivedFrom: priorIds,
|
|
445
|
+
confidence: 0.9,
|
|
446
|
+
tags: ['telemetry', 'observability'],
|
|
447
|
+
});
|
|
448
|
+
nodeIds.push(telNode.id);
|
|
449
|
+
// Health check nodes (one per check)
|
|
450
|
+
for (const check of healthChecks) {
|
|
451
|
+
const hcNode = graph.createNode({
|
|
452
|
+
type: 'health_check',
|
|
453
|
+
name: `Health Check: ${check.endpointUrl}`,
|
|
454
|
+
content: check,
|
|
455
|
+
summary: `${check.endpointUrl}: ${check.status} (${check.latencyMs}ms)`,
|
|
456
|
+
producedBy: { domain: 'observatory', agent: 'health-check', role: 'Health Check' },
|
|
457
|
+
pass,
|
|
458
|
+
derivedFrom: [telNode.id],
|
|
459
|
+
confidence: check.status === 'healthy' ? 0.95 : check.status === 'degraded' ? 0.5 : 0.2,
|
|
460
|
+
tags: [`health:${check.status}`, 'observability'],
|
|
461
|
+
});
|
|
462
|
+
nodeIds.push(hcNode.id);
|
|
463
|
+
}
|
|
464
|
+
// Dashboard spec as part of telemetry config
|
|
465
|
+
graph.createNode({
|
|
466
|
+
type: 'telemetry_config',
|
|
467
|
+
name: 'Dashboard Specification',
|
|
468
|
+
content: dashboardSpec,
|
|
469
|
+
summary: `Dashboard: ${dashboardSpec.name} — ${dashboardSpec.panels.length} panel(s), ${dashboardSpec.alertRules.length} alert rule(s).`,
|
|
470
|
+
producedBy: { domain: 'observatory', agent: 'visualization', role: 'Visualization Spec' },
|
|
471
|
+
pass,
|
|
472
|
+
derivedFrom: [telNode.id],
|
|
473
|
+
confidence: 0.85,
|
|
474
|
+
tags: ['dashboard', 'observability'],
|
|
475
|
+
});
|
|
476
|
+
// Learned pattern nodes
|
|
477
|
+
for (const pattern of learnedPatterns) {
|
|
478
|
+
const pNode = graph.createNode({
|
|
479
|
+
type: 'learned_pattern',
|
|
480
|
+
name: `Learned Pattern: ${pattern.domain}`,
|
|
481
|
+
content: pattern,
|
|
482
|
+
summary: `${pattern.type} in ${pattern.domain}: ${pattern.description.slice(0, 80)}`,
|
|
483
|
+
producedBy: { domain: 'memory-graph', agent: 'patterns', role: 'Approval Learning' },
|
|
484
|
+
pass,
|
|
485
|
+
derivedFrom: priorIds,
|
|
486
|
+
confidence: pattern.confidence,
|
|
487
|
+
tags: [`pattern:${pattern.type}`, `domain:${pattern.domain}`, 'learning'],
|
|
488
|
+
});
|
|
489
|
+
nodeIds.push(pNode.id);
|
|
490
|
+
}
|
|
491
|
+
// Learning cycle summary node
|
|
492
|
+
graph.createNode({
|
|
493
|
+
type: 'learned_pattern',
|
|
494
|
+
name: 'Learning Cycle Summary',
|
|
495
|
+
content: learningCycle,
|
|
496
|
+
summary: `Learning cycle: ${learningCycle.stepsCompleted.length}/4 steps, ${learningCycle.patternsLearned.length} pattern(s), ${learningCycle.verdicts.length} verdict(s).`,
|
|
497
|
+
producedBy: { domain: 'pipeline', agent: 'pass7-learning', role: 'Learning Loop' },
|
|
498
|
+
pass,
|
|
499
|
+
derivedFrom: nodeIds.slice(0, 5),
|
|
500
|
+
confidence: 0.8,
|
|
501
|
+
tags: ['learning-cycle', 'consolidation'],
|
|
502
|
+
});
|
|
503
|
+
// Provenance
|
|
504
|
+
tracker.recordInvocation({
|
|
505
|
+
agent: { domain: 'pipeline', agent: 'pass7-setup', role: 'Observability Setup' },
|
|
506
|
+
pass,
|
|
507
|
+
passName: 'Observability & Continuous Learning',
|
|
508
|
+
workstream: 'initial-setup',
|
|
509
|
+
startedAt: new Date().toISOString(),
|
|
510
|
+
completedAt: new Date().toISOString(),
|
|
511
|
+
durationMs: 0,
|
|
512
|
+
inputNodeIds: priorIds,
|
|
513
|
+
outputNodeIds: nodeIds,
|
|
514
|
+
artifactNumbers: [],
|
|
515
|
+
status: 'success',
|
|
516
|
+
confidence: 0.85,
|
|
517
|
+
});
|
|
518
|
+
return nodeIds;
|
|
519
|
+
}
|
|
520
|
+
// ============================================================================
|
|
521
|
+
// Default Agent Invoker
|
|
522
|
+
// ============================================================================
|
|
523
|
+
async function defaultInvokeAgents(agents, payload, pass, _timeoutMs) {
|
|
524
|
+
const promises = agents.map(async (agent) => {
|
|
525
|
+
const start = Date.now();
|
|
526
|
+
const timestamp = new Date().toISOString();
|
|
527
|
+
try {
|
|
528
|
+
const { executeAgentsInvokeCommand } = await import('../../commands/agents.js');
|
|
529
|
+
const result = await executeAgentsInvokeCommand(agent.domain, agent.agent, JSON.stringify(payload), { format: 'json' });
|
|
530
|
+
return { agent, status: result.status, response: result.response, durationMs: Date.now() - start, pass, timestamp };
|
|
531
|
+
}
|
|
532
|
+
catch (err) {
|
|
533
|
+
return { agent, status: 500, response: { error: err instanceof Error ? err.message : String(err) }, durationMs: Date.now() - start, pass, timestamp };
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
const settled = await Promise.allSettled(promises);
|
|
537
|
+
return settled.map((outcome, i) => outcome.status === 'fulfilled'
|
|
538
|
+
? outcome.value
|
|
539
|
+
: { agent: agents[i], status: 500, response: { error: String(outcome.reason) }, durationMs: 0, pass, timestamp: new Date().toISOString() });
|
|
540
|
+
}
|
|
541
|
+
// ============================================================================
|
|
542
|
+
// Normalization Helpers
|
|
543
|
+
// ============================================================================
|
|
544
|
+
function normalizeHealthCheck(raw, now) {
|
|
545
|
+
return {
|
|
546
|
+
endpointUrl: String(raw['endpointUrl'] ?? raw['url'] ?? raw['endpoint'] ?? '/health'),
|
|
547
|
+
status: normalizeHealthStatus(raw['status']),
|
|
548
|
+
latencyMs: Number(raw['latencyMs'] ?? raw['latency'] ?? 0),
|
|
549
|
+
lastChecked: String(raw['lastChecked'] ?? now),
|
|
550
|
+
checkInterval: String(raw['checkInterval'] ?? raw['interval'] ?? 'PT5M'),
|
|
551
|
+
failureCount: Number(raw['failureCount'] ?? 0),
|
|
552
|
+
alertThreshold: Number(raw['alertThreshold'] ?? 3),
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function normalizeHealthStatus(raw) {
|
|
556
|
+
const s = String(raw ?? '').toLowerCase();
|
|
557
|
+
if (s === 'degraded')
|
|
558
|
+
return 'degraded';
|
|
559
|
+
if (s === 'unhealthy' || s === 'down' || s === 'failed')
|
|
560
|
+
return 'unhealthy';
|
|
561
|
+
return 'healthy';
|
|
562
|
+
}
|
|
563
|
+
function normalizeMetricCategory(raw) {
|
|
564
|
+
const s = String(raw ?? '').toLowerCase().replace(/[\s-]/g, '_');
|
|
565
|
+
const valid = new Set(['availability', 'performance', 'usage', 'errors', 'sla_compliance']);
|
|
566
|
+
return valid.has(s) ? s : 'performance';
|
|
567
|
+
}
|
|
568
|
+
function normalizeVisualization(raw) {
|
|
569
|
+
const s = String(raw ?? '').toLowerCase();
|
|
570
|
+
const valid = new Set(['timeseries', 'gauge', 'table', 'heatmap']);
|
|
571
|
+
return valid.has(s) ? s : 'timeseries';
|
|
572
|
+
}
|
|
573
|
+
function normalizeAlertSeverity(raw) {
|
|
574
|
+
const s = String(raw ?? '').toLowerCase();
|
|
575
|
+
if (s === 'critical')
|
|
576
|
+
return 'critical';
|
|
577
|
+
if (s === 'info')
|
|
578
|
+
return 'info';
|
|
579
|
+
return 'warning';
|
|
580
|
+
}
|
|
581
|
+
function normalizeIncidentSeverity(raw) {
|
|
582
|
+
const s = String(raw ?? '').toUpperCase();
|
|
583
|
+
if (s === 'P1' || s === 'CRITICAL')
|
|
584
|
+
return 'P1';
|
|
585
|
+
if (s === 'P2' || s === 'HIGH')
|
|
586
|
+
return 'P2';
|
|
587
|
+
if (s === 'P3' || s === 'MEDIUM')
|
|
588
|
+
return 'P3';
|
|
589
|
+
return 'P4';
|
|
590
|
+
}
|
|
591
|
+
function normalizeIncidentStatus(raw) {
|
|
592
|
+
const s = String(raw ?? '').toLowerCase();
|
|
593
|
+
if (s === 'investigating')
|
|
594
|
+
return 'investigating';
|
|
595
|
+
if (s === 'mitigated')
|
|
596
|
+
return 'mitigated';
|
|
597
|
+
if (s === 'resolved')
|
|
598
|
+
return 'resolved';
|
|
599
|
+
return 'open';
|
|
600
|
+
}
|
|
601
|
+
function normalizePatternType(raw) {
|
|
602
|
+
const s = String(raw ?? '').toLowerCase().replace(/[\s-]/g, '_');
|
|
603
|
+
if (s === 'success_pattern')
|
|
604
|
+
return 'success_pattern';
|
|
605
|
+
if (s === 'anti_pattern')
|
|
606
|
+
return 'anti_pattern';
|
|
607
|
+
return 'calibration_adjustment';
|
|
608
|
+
}
|
|
609
|
+
function normalizeVerdict(raw) {
|
|
610
|
+
const s = String(raw ?? '').toLowerCase().replace(/[\s-]/g, '_');
|
|
611
|
+
if (s === 'correct')
|
|
612
|
+
return 'correct';
|
|
613
|
+
if (s === 'incorrect')
|
|
614
|
+
return 'incorrect';
|
|
615
|
+
return 'partially_correct';
|
|
616
|
+
}
|
|
617
|
+
function extractThresholds(raw) {
|
|
618
|
+
if (!Array.isArray(raw))
|
|
619
|
+
return [];
|
|
620
|
+
return raw.filter(t => typeof t === 'object' && t !== null).map(t => {
|
|
621
|
+
const r = t;
|
|
622
|
+
return { value: Number(r['value'] ?? 0), color: String(r['color'] ?? 'green') };
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
function extractArray(obj, ...keys) {
|
|
626
|
+
for (const k of keys) {
|
|
627
|
+
const v = obj[k];
|
|
628
|
+
if (Array.isArray(v))
|
|
629
|
+
return v;
|
|
630
|
+
}
|
|
631
|
+
return [];
|
|
632
|
+
}
|
|
633
|
+
function extractStringArray(obj, ...keys) {
|
|
634
|
+
return extractArray(obj, ...keys).map(String);
|
|
635
|
+
}
|
|
636
|
+
//# sourceMappingURL=pass7-observability.js.map
|