@equilateral_ai/mindmeld 3.3.1 → 3.5.0
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 +1 -10
- package/hooks/pre-compact.js +213 -25
- package/hooks/session-end.js +112 -3
- package/hooks/session-start.js +635 -41
- package/hooks/subagent-start.js +150 -0
- package/hooks/subagent-stop.js +184 -0
- package/package.json +8 -7
- package/scripts/init-project.js +74 -33
- package/scripts/mcp-bridge.js +220 -0
- package/src/core/CorrelationAnalyzer.js +157 -0
- package/src/core/LLMPatternDetector.js +198 -0
- package/src/core/RelevanceDetector.js +123 -36
- package/src/core/StandardsIngestion.js +119 -18
- package/src/handlers/activity/activityGetMe.js +1 -1
- package/src/handlers/activity/activityGetTeam.js +100 -55
- package/src/handlers/admin/adminSetup.js +216 -0
- package/src/handlers/alerts/alertsAcknowledge.js +6 -6
- package/src/handlers/alerts/alertsGet.js +11 -11
- package/src/handlers/analytics/activitySummaryGet.js +34 -35
- package/src/handlers/analytics/coachingGet.js +11 -11
- package/src/handlers/analytics/convergenceGet.js +236 -0
- package/src/handlers/analytics/developerScoreGet.js +41 -111
- package/src/handlers/collaborators/collaboratorInvite.js +1 -1
- package/src/handlers/company/companyUsersDelete.js +141 -0
- package/src/handlers/company/companyUsersGet.js +90 -0
- package/src/handlers/company/companyUsersPost.js +267 -0
- package/src/handlers/company/companyUsersPut.js +76 -0
- package/src/handlers/correlations/correlationsDeveloperGet.js +12 -12
- package/src/handlers/correlations/correlationsGet.js +8 -8
- package/src/handlers/correlations/correlationsProjectGet.js +5 -5
- package/src/handlers/enterprise/controlTowerGet.js +224 -0
- package/src/handlers/enterprise/enterpriseOnboardingSetup.js +48 -9
- package/src/handlers/enterprise/enterpriseOnboardingStatus.js +1 -3
- package/src/handlers/github/githubConnectionStatus.js +1 -1
- package/src/handlers/github/githubDiscoverPatterns.js +4 -2
- package/src/handlers/github/githubPatternsReview.js +7 -36
- package/src/handlers/health/healthGet.js +55 -0
- package/src/handlers/helpers/checkSuperAdmin.js +13 -14
- package/src/handlers/helpers/mindmeldMcpCore.js +594 -0
- package/src/handlers/helpers/subscriptionTiers.js +27 -27
- package/src/handlers/mcp/mcpHandler.js +569 -0
- package/src/handlers/mcp/mindmeldMcpHandler.js +124 -0
- package/src/handlers/mcp/mindmeldMcpStreamHandler.js +243 -0
- package/src/handlers/notifications/sendNotification.js +18 -18
- package/src/handlers/patterns/patternEvaluatePromotionPost.js +173 -0
- package/src/handlers/projects/projectCreate.js +124 -10
- package/src/handlers/projects/projectDelete.js +4 -4
- package/src/handlers/projects/projectGet.js +8 -8
- package/src/handlers/projects/projectUpdate.js +4 -4
- package/src/handlers/reports/aiLeverage.js +34 -30
- package/src/handlers/reports/engineeringInvestment.js +16 -16
- package/src/handlers/reports/riskForecast.js +41 -21
- package/src/handlers/reports/standardsRoi.js +101 -9
- package/src/handlers/scheduled/maturityUpdateJob.js +166 -0
- package/src/handlers/sessions/sessionStandardsPost.js +43 -7
- package/src/handlers/standards/discoveriesGet.js +93 -0
- package/src/handlers/standards/projectStandardsGet.js +2 -2
- package/src/handlers/standards/projectStandardsPut.js +2 -2
- package/src/handlers/standards/standardsRelevantPost.js +107 -12
- package/src/handlers/standards/standardsTransition.js +112 -15
- package/src/handlers/stripe/billingPortalPost.js +1 -1
- package/src/handlers/stripe/enterpriseCheckoutPost.js +2 -2
- package/src/handlers/stripe/subscriptionCreatePost.js +2 -2
- package/src/handlers/stripe/webhookPost.js +42 -14
- package/src/handlers/user/apiTokenCreate.js +71 -0
- package/src/handlers/user/apiTokenList.js +64 -0
- package/src/handlers/user/userSplashGet.js +90 -73
- package/src/handlers/users/cognitoPostConfirmation.js +37 -1
- package/src/handlers/users/cognitoPreSignUp.js +114 -0
- package/src/handlers/users/userGet.js +15 -11
- package/src/handlers/webhooks/githubWebhook.js +117 -125
- package/src/index.js +8 -5
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MindMeld MCP Bridge - Stdio-to-HTTP proxy for MCP clients
|
|
3
|
+
*
|
|
4
|
+
* Bridges stdio MCP transport to the remote MindMeld MCP server.
|
|
5
|
+
* For clients that don't support URL transport natively
|
|
6
|
+
* (Cline, Cursor, Windsurf, etc.)
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* MINDMELD_TOKEN=mm_live_xxx mindmeld mcp
|
|
10
|
+
* mindmeld mcp --token mm_live_xxx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const https = require('https');
|
|
14
|
+
const os = require('os');
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
const MCP_HOST = 'api.mindmeld.dev';
|
|
19
|
+
const MCP_PATH = '/api/mcp/mindmeld';
|
|
20
|
+
const REQUEST_TIMEOUT = 30000;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Resolve API token from env var, CLI arg, or stored file
|
|
24
|
+
*/
|
|
25
|
+
function resolveToken(cliToken) {
|
|
26
|
+
if (process.env.MINDMELD_TOKEN) {
|
|
27
|
+
return process.env.MINDMELD_TOKEN;
|
|
28
|
+
}
|
|
29
|
+
if (cliToken) {
|
|
30
|
+
return cliToken;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const tokenPath = path.join(os.homedir(), '.mindmeld', 'api-token');
|
|
34
|
+
return fs.readFileSync(tokenPath, 'utf-8').trim();
|
|
35
|
+
} catch (err) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Forward a JSON-RPC message to the remote MCP server
|
|
42
|
+
*/
|
|
43
|
+
function forwardToServer(message, token) {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
const body = JSON.stringify(message);
|
|
46
|
+
const req = https.request({
|
|
47
|
+
method: 'POST',
|
|
48
|
+
hostname: MCP_HOST,
|
|
49
|
+
path: MCP_PATH,
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
'Accept': 'application/json',
|
|
53
|
+
'X-MindMeld-Token': token
|
|
54
|
+
},
|
|
55
|
+
timeout: REQUEST_TIMEOUT
|
|
56
|
+
}, (res) => {
|
|
57
|
+
let data = '';
|
|
58
|
+
res.on('data', chunk => data += chunk);
|
|
59
|
+
res.on('end', () => {
|
|
60
|
+
if (res.statusCode === 202 || !data.trim()) {
|
|
61
|
+
resolve(null);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
resolve(JSON.parse(data));
|
|
66
|
+
} catch (e) {
|
|
67
|
+
reject(new Error(`Invalid JSON from server: ${data.substring(0, 200)}`));
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
req.on('timeout', () => {
|
|
73
|
+
req.destroy();
|
|
74
|
+
reject(new Error('Request timed out'));
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
req.on('error', (e) => {
|
|
78
|
+
reject(new Error(`Connection failed: ${e.message}`));
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
req.write(body);
|
|
82
|
+
req.end();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Process a single JSON-RPC message from stdin
|
|
88
|
+
*/
|
|
89
|
+
async function processMessage(line, token) {
|
|
90
|
+
let message;
|
|
91
|
+
try {
|
|
92
|
+
message = JSON.parse(line);
|
|
93
|
+
} catch (e) {
|
|
94
|
+
process.stdout.write(JSON.stringify({
|
|
95
|
+
jsonrpc: '2.0',
|
|
96
|
+
error: { code: -32700, message: 'Parse error: invalid JSON' },
|
|
97
|
+
id: null
|
|
98
|
+
}) + '\n');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const isNotification = !('id' in message);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const response = await forwardToServer(message, token);
|
|
106
|
+
|
|
107
|
+
if (response === null || isNotification) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
112
|
+
} catch (error) {
|
|
113
|
+
process.stderr.write(`[MindMeld] ${error.message}\n`);
|
|
114
|
+
|
|
115
|
+
if (!isNotification && message.id !== undefined) {
|
|
116
|
+
process.stdout.write(JSON.stringify({
|
|
117
|
+
jsonrpc: '2.0',
|
|
118
|
+
error: { code: -32603, message: error.message },
|
|
119
|
+
id: message.id
|
|
120
|
+
}) + '\n');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Start the stdio bridge — long-lived, runs until stdin closes
|
|
127
|
+
*/
|
|
128
|
+
function startBridge(token) {
|
|
129
|
+
process.stderr.write(`[MindMeld] MCP bridge started (pid ${process.pid})\n`);
|
|
130
|
+
process.stderr.write(`[MindMeld] Proxying to https://${MCP_HOST}${MCP_PATH}\n`);
|
|
131
|
+
|
|
132
|
+
let buffer = '';
|
|
133
|
+
let pending = 0;
|
|
134
|
+
let stdinClosed = false;
|
|
135
|
+
|
|
136
|
+
function maybeExit() {
|
|
137
|
+
if (stdinClosed && pending === 0) {
|
|
138
|
+
process.stderr.write('[MindMeld] All requests complete, shutting down\n');
|
|
139
|
+
process.exit(0);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function trackMessage(line) {
|
|
144
|
+
pending++;
|
|
145
|
+
processMessage(line, token).finally(() => {
|
|
146
|
+
pending--;
|
|
147
|
+
maybeExit();
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
process.stdin.setEncoding('utf-8');
|
|
152
|
+
|
|
153
|
+
process.stdin.on('data', (chunk) => {
|
|
154
|
+
buffer += chunk;
|
|
155
|
+
const lines = buffer.split('\n');
|
|
156
|
+
buffer = lines.pop();
|
|
157
|
+
|
|
158
|
+
for (const line of lines) {
|
|
159
|
+
const trimmed = line.trim();
|
|
160
|
+
if (!trimmed) continue;
|
|
161
|
+
trackMessage(trimmed);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
process.stdin.on('end', () => {
|
|
166
|
+
process.stderr.write('[MindMeld] stdin closed\n');
|
|
167
|
+
stdinClosed = true;
|
|
168
|
+
maybeExit();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
process.stdin.on('error', (err) => {
|
|
172
|
+
process.stderr.write(`[MindMeld] stdin error: ${err.message}\n`);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function showMcpHelp() {
|
|
178
|
+
console.log(`
|
|
179
|
+
MindMeld MCP Bridge - Stdio-to-HTTP proxy for MCP clients
|
|
180
|
+
|
|
181
|
+
Usage:
|
|
182
|
+
mindmeld mcp [options]
|
|
183
|
+
|
|
184
|
+
Options:
|
|
185
|
+
--token <token> MindMeld API token (or set MINDMELD_TOKEN env var)
|
|
186
|
+
--help, -h Show this help
|
|
187
|
+
|
|
188
|
+
Token Resolution (in priority order):
|
|
189
|
+
1. MINDMELD_TOKEN environment variable
|
|
190
|
+
2. --token CLI argument
|
|
191
|
+
3. ~/.mindmeld/api-token file
|
|
192
|
+
|
|
193
|
+
Create a token at: https://app.mindmeld.dev/api-tokens
|
|
194
|
+
|
|
195
|
+
Client Configuration:
|
|
196
|
+
Cline / Cursor / Windsurf:
|
|
197
|
+
{
|
|
198
|
+
"mcpServers": {
|
|
199
|
+
"mindmeld": {
|
|
200
|
+
"command": "mindmeld",
|
|
201
|
+
"args": ["mcp"],
|
|
202
|
+
"env": { "MINDMELD_TOKEN": "mm_live_xxx" }
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
Claude Code (use URL transport instead — no bridge needed):
|
|
208
|
+
{
|
|
209
|
+
"mcpServers": {
|
|
210
|
+
"mindmeld": {
|
|
211
|
+
"type": "url",
|
|
212
|
+
"url": "https://api.mindmeld.dev/api/mcp/mindmeld",
|
|
213
|
+
"headers": { "X-MindMeld-Token": "mm_live_xxx" }
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
module.exports = { startBridge, resolveToken, showMcpHelp };
|
|
@@ -144,6 +144,18 @@ class CorrelationAnalyzer {
|
|
|
144
144
|
// Calculate aggregate metrics
|
|
145
145
|
await this.calculateAggregateMetrics(projectId, companyId);
|
|
146
146
|
|
|
147
|
+
// Update standards_patterns.correlation with observed effectiveness
|
|
148
|
+
try {
|
|
149
|
+
const updated = await this.updateStandardsCorrelation();
|
|
150
|
+
summary.standardsCorrelationUpdated = updated;
|
|
151
|
+
if (updated > 0) {
|
|
152
|
+
console.log(`[CorrelationAnalyzer] Updated correlation scores for ${updated} standards`);
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.error('[CorrelationAnalyzer] Could not update standards correlations:', error.message);
|
|
156
|
+
summary.errors.push({ step: 'updateStandardsCorrelation', error: error.message });
|
|
157
|
+
}
|
|
158
|
+
|
|
147
159
|
summary.completedAt = new Date().toISOString();
|
|
148
160
|
console.log(`[CorrelationAnalyzer] Analysis complete: ${summary.correlationsCreated} correlations, ${summary.uncorrelatedSessions} uncorrelated`);
|
|
149
161
|
|
|
@@ -763,6 +775,151 @@ class CorrelationAnalyzer {
|
|
|
763
775
|
};
|
|
764
776
|
}
|
|
765
777
|
|
|
778
|
+
/**
|
|
779
|
+
* Update standards_patterns.correlation with observed effectiveness
|
|
780
|
+
*
|
|
781
|
+
* Computes per-standard effectiveness by joining session_standards
|
|
782
|
+
* (which standards were shown) with session_correlations (which
|
|
783
|
+
* sessions produced commits). Standards shown in sessions that
|
|
784
|
+
* produce commits get higher correlation scores.
|
|
785
|
+
*
|
|
786
|
+
* This directly influences relevance scoring since
|
|
787
|
+
* standardsRelevantPost.js uses correlation * 40 as the base score.
|
|
788
|
+
*
|
|
789
|
+
* @returns {Promise<number>} Number of standards updated
|
|
790
|
+
*/
|
|
791
|
+
async updateStandardsCorrelation() {
|
|
792
|
+
const query = `
|
|
793
|
+
UPDATE rapport.standards_patterns sp SET
|
|
794
|
+
correlation = LEAST(sub.effectiveness, 1.00),
|
|
795
|
+
last_updated = NOW()
|
|
796
|
+
FROM (
|
|
797
|
+
SELECT ss.standard_id,
|
|
798
|
+
COUNT(*) FILTER (WHERE sc.has_commits = true)::decimal / COUNT(*) as effectiveness
|
|
799
|
+
FROM rapport.session_standards ss
|
|
800
|
+
JOIN rapport.session_correlations sc ON sc.session_id = ss.session_id
|
|
801
|
+
WHERE sc.analyzed_at > NOW() - INTERVAL '30 days'
|
|
802
|
+
GROUP BY ss.standard_id
|
|
803
|
+
HAVING COUNT(*) >= 5
|
|
804
|
+
) sub
|
|
805
|
+
WHERE sp.pattern_id = sub.standard_id
|
|
806
|
+
`;
|
|
807
|
+
|
|
808
|
+
const result = await executeQuery(query);
|
|
809
|
+
return result.rowCount || 0;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// ─── Agent Execution Correlation ──────────────────────────────
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Analyze correlations for agent execution patterns.
|
|
816
|
+
* Instead of session → git commit, this correlates:
|
|
817
|
+
* - Agent decision → task outcome success rate
|
|
818
|
+
* - Recovery effectiveness (did failover agents succeed?)
|
|
819
|
+
* - Tier accuracy (tier matches actual consequence?)
|
|
820
|
+
* - Cross-workflow pattern reuse
|
|
821
|
+
*
|
|
822
|
+
* @param {Object} options - Analysis options
|
|
823
|
+
* @param {string} options.projectId - Project filter
|
|
824
|
+
* @param {number} options.lookbackDays - Days to analyze (default: 30)
|
|
825
|
+
* @returns {Promise<Object>} Agent execution correlation summary
|
|
826
|
+
*/
|
|
827
|
+
async analyzeAgentExecutionCorrelations(options = {}) {
|
|
828
|
+
const lookbackDays = options.lookbackDays || 30;
|
|
829
|
+
|
|
830
|
+
const summary = {
|
|
831
|
+
startedAt: new Date().toISOString(),
|
|
832
|
+
agentsAnalyzed: 0,
|
|
833
|
+
correlationsCreated: 0,
|
|
834
|
+
patterns: [],
|
|
835
|
+
errors: []
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
try {
|
|
839
|
+
// Get agent execution patterns from pattern_usage
|
|
840
|
+
const agentPatterns = await executeQuery(`
|
|
841
|
+
SELECT
|
|
842
|
+
p.element,
|
|
843
|
+
p.category,
|
|
844
|
+
COUNT(pu.*) AS total_uses,
|
|
845
|
+
COUNT(pu.*) FILTER (WHERE pu.success = true) AS successful_uses,
|
|
846
|
+
COUNT(DISTINCT pu.email_address) AS unique_agents,
|
|
847
|
+
AVG(CASE WHEN pu.success THEN 1.0 ELSE 0.0 END) AS success_rate,
|
|
848
|
+
MAX(pu.used_at) AS last_used
|
|
849
|
+
FROM rapport.patterns p
|
|
850
|
+
JOIN rapport.pattern_usage pu ON pu.pattern_id = p.pattern_id
|
|
851
|
+
WHERE p.pattern_data->>'source' = 'agent_execution'
|
|
852
|
+
AND pu.used_at > NOW() - INTERVAL '${lookbackDays} days'
|
|
853
|
+
${options.projectId ? `AND p.project_id = '${options.projectId}'` : ''}
|
|
854
|
+
GROUP BY p.element, p.category
|
|
855
|
+
HAVING COUNT(pu.*) >= 3
|
|
856
|
+
ORDER BY success_rate ASC
|
|
857
|
+
`);
|
|
858
|
+
|
|
859
|
+
if (agentPatterns?.rows) {
|
|
860
|
+
for (const pattern of agentPatterns.rows) {
|
|
861
|
+
summary.agentsAnalyzed++;
|
|
862
|
+
summary.patterns.push({
|
|
863
|
+
element: pattern.element,
|
|
864
|
+
category: pattern.category,
|
|
865
|
+
totalUses: parseInt(pattern.total_uses),
|
|
866
|
+
successRate: parseFloat(pattern.success_rate),
|
|
867
|
+
uniqueAgents: parseInt(pattern.unique_agents),
|
|
868
|
+
lastUsed: pattern.last_used
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// Update pattern correlations based on agent execution data
|
|
874
|
+
const updated = await this.updateAgentPatternCorrelations();
|
|
875
|
+
summary.correlationsCreated = updated;
|
|
876
|
+
|
|
877
|
+
} catch (error) {
|
|
878
|
+
summary.errors.push(error.message);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
summary.completedAt = new Date().toISOString();
|
|
882
|
+
return summary;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* Update pattern correlations for agent execution patterns.
|
|
887
|
+
* Uses agent task success as the "proof" (instead of git commits for code sessions).
|
|
888
|
+
*
|
|
889
|
+
* @returns {Promise<number>} Number of patterns updated
|
|
890
|
+
*/
|
|
891
|
+
async updateAgentPatternCorrelations() {
|
|
892
|
+
const query = `
|
|
893
|
+
UPDATE rapport.patterns p SET
|
|
894
|
+
handoff_count = sub.total_uses,
|
|
895
|
+
successful_handoffs = sub.successful_uses,
|
|
896
|
+
failed_handoffs = sub.failed_uses,
|
|
897
|
+
last_used = sub.last_used
|
|
898
|
+
FROM (
|
|
899
|
+
SELECT
|
|
900
|
+
pu.pattern_id,
|
|
901
|
+
COUNT(*) AS total_uses,
|
|
902
|
+
COUNT(*) FILTER (WHERE pu.success = true) AS successful_uses,
|
|
903
|
+
COUNT(*) FILTER (WHERE pu.success = false) AS failed_uses,
|
|
904
|
+
MAX(pu.used_at) AS last_used
|
|
905
|
+
FROM rapport.pattern_usage pu
|
|
906
|
+
JOIN rapport.patterns pat ON pat.pattern_id = pu.pattern_id
|
|
907
|
+
WHERE pat.pattern_data->>'source' = 'agent_execution'
|
|
908
|
+
AND pu.used_at > NOW() - INTERVAL '30 days'
|
|
909
|
+
GROUP BY pu.pattern_id
|
|
910
|
+
) sub
|
|
911
|
+
WHERE p.pattern_id = sub.pattern_id
|
|
912
|
+
`;
|
|
913
|
+
|
|
914
|
+
try {
|
|
915
|
+
const result = await executeQuery(query);
|
|
916
|
+
return result.rowCount || 0;
|
|
917
|
+
} catch (error) {
|
|
918
|
+
console.error('[CorrelationAnalyzer] Agent correlation update failed:', error.message);
|
|
919
|
+
return 0;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
766
923
|
/**
|
|
767
924
|
* Get configuration (for debugging/admin)
|
|
768
925
|
*/
|
|
@@ -103,6 +103,204 @@ class LLMPatternDetector {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Analyze agent execution logs for patterns in decision-making,
|
|
108
|
+
* routing, failure recovery, and consequence tier accuracy.
|
|
109
|
+
*
|
|
110
|
+
* This is the agent-execution counterpart to analyzeSessionTranscript().
|
|
111
|
+
* Called by AgentExecutionHarvester after workflow completion.
|
|
112
|
+
*
|
|
113
|
+
* @param {Object} executionLog - Structured execution data from EA
|
|
114
|
+
* @param {Object} executionLog.workflowName - Workflow that was executed
|
|
115
|
+
* @param {Object[]} executionLog.steps - Array of step results
|
|
116
|
+
* @param {number} executionLog.duration - Total workflow duration
|
|
117
|
+
* @param {string[]} executionLog.agentsUsed - List of agents involved
|
|
118
|
+
* @param {Object} context - Additional context
|
|
119
|
+
* @returns {Promise<Object>} Detected patterns and analysis
|
|
120
|
+
*/
|
|
121
|
+
async analyzeAgentExecution(executionLog, context = {}) {
|
|
122
|
+
if (!this.isAvailable()) {
|
|
123
|
+
return this.fallbackAgentAnalysis(executionLog);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Build execution-specific prompts
|
|
127
|
+
const systemPrompt = this.buildAgentExecutionSystemPrompt(context);
|
|
128
|
+
const userPrompt = this.buildAgentExecutionUserPrompt(executionLog, context);
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const requestBody = {
|
|
132
|
+
anthropic_version: 'bedrock-2023-05-31',
|
|
133
|
+
max_tokens: this.config.maxTokens,
|
|
134
|
+
system: systemPrompt,
|
|
135
|
+
messages: [
|
|
136
|
+
{ role: 'user', content: userPrompt }
|
|
137
|
+
]
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const command = new InvokeModelCommand({
|
|
141
|
+
modelId: this.config.model,
|
|
142
|
+
contentType: 'application/json',
|
|
143
|
+
accept: 'application/json',
|
|
144
|
+
body: JSON.stringify(requestBody)
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const response = await this.client.send(command);
|
|
148
|
+
const responseBody = JSON.parse(new TextDecoder().decode(response.body));
|
|
149
|
+
const content = responseBody.content?.[0]?.text || '';
|
|
150
|
+
|
|
151
|
+
return this.parseResponse(content);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.error('[LLMPatternDetector] Agent execution analysis error:', error.message);
|
|
154
|
+
return this.fallbackAgentAnalysis(executionLog);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Build system prompt for agent execution analysis
|
|
160
|
+
*/
|
|
161
|
+
buildAgentExecutionSystemPrompt(context) {
|
|
162
|
+
return `You are an expert multi-agent governance analyst for the Equilateral platform.
|
|
163
|
+
|
|
164
|
+
Your task is to analyze agent execution logs and extract:
|
|
165
|
+
1. **Agent Selection Strategies**: Which agents were chosen for which tasks and why
|
|
166
|
+
2. **Failure Recovery Patterns**: Which fallbacks worked, which didn't, and why
|
|
167
|
+
3. **Consequence Tier Accuracy**: Was the assigned tier appropriate for what actually happened?
|
|
168
|
+
4. **Standards Compliance Patterns**: Which standards consistently apply to which workflows
|
|
169
|
+
5. **Routing Efficiency**: Could different agent selections have improved outcomes?
|
|
170
|
+
|
|
171
|
+
Key governance concepts:
|
|
172
|
+
- Consequence Tiers: T1 (read-only), T2 (reversible write), T3 (irreversible mutation), T4 (external side effect)
|
|
173
|
+
- Agent Classifications: REWARD (high performer), REMEDIATE (needs improvement), REPLACE (should be swapped)
|
|
174
|
+
- Agent Maturity: provisional (new) → validated (confirmed) → reinforced (proven)
|
|
175
|
+
- DecisionFrame: Carries selection reasoning, confidence, fallbacks, violations
|
|
176
|
+
|
|
177
|
+
Respond ONLY with valid JSON in this exact format:
|
|
178
|
+
{
|
|
179
|
+
"patterns": [
|
|
180
|
+
{
|
|
181
|
+
"element": "Pattern name",
|
|
182
|
+
"type": "agent_selection|failure_recovery|tier_accuracy|compliance|routing",
|
|
183
|
+
"intent": "What this pattern means for governance",
|
|
184
|
+
"evidence": "Data from the execution log",
|
|
185
|
+
"confidence": 0.85,
|
|
186
|
+
"severity": "info|warning|critical",
|
|
187
|
+
"category": "multi-agent-orchestration"
|
|
188
|
+
}
|
|
189
|
+
],
|
|
190
|
+
"summary": "Brief summary of execution patterns detected",
|
|
191
|
+
"recommendations": ["Governance improvements"],
|
|
192
|
+
"violations": [
|
|
193
|
+
{
|
|
194
|
+
"standard": "Which governance principle was violated",
|
|
195
|
+
"description": "What happened",
|
|
196
|
+
"fix": "How to improve"
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
}`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Build user prompt for agent execution analysis
|
|
204
|
+
*/
|
|
205
|
+
buildAgentExecutionUserPrompt(executionLog, context) {
|
|
206
|
+
const maxLength = 40000;
|
|
207
|
+
const logStr = JSON.stringify(executionLog, null, 2);
|
|
208
|
+
const truncated = logStr.length > maxLength
|
|
209
|
+
? logStr.substring(0, maxLength) + '\n\n[... execution log truncated ...]'
|
|
210
|
+
: logStr;
|
|
211
|
+
|
|
212
|
+
const workflowName = executionLog.workflowName || 'Unknown';
|
|
213
|
+
const agentCount = executionLog.agentsUsed?.length || 0;
|
|
214
|
+
|
|
215
|
+
return `Analyze this multi-agent workflow execution for governance patterns:
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
WORKFLOW: ${workflowName}
|
|
219
|
+
AGENTS USED: ${agentCount}
|
|
220
|
+
DURATION: ${executionLog.duration || 'Unknown'}ms
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
EXECUTION LOG:
|
|
224
|
+
${truncated}
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
Extract all agent selection strategies, failure recovery patterns, consequence tier accuracy issues, and governance improvements. Focus on:
|
|
229
|
+
1. Were agents selected optimally for each step?
|
|
230
|
+
2. Did failovers work correctly when needed?
|
|
231
|
+
3. Were consequence tiers accurate for the actual operations performed?
|
|
232
|
+
4. Were any governance constraints violated?
|
|
233
|
+
5. Are there patterns that should become standards?
|
|
234
|
+
|
|
235
|
+
Respond with JSON only.`;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Fallback analysis for agent execution when LLM unavailable
|
|
240
|
+
*/
|
|
241
|
+
fallbackAgentAnalysis(executionLog) {
|
|
242
|
+
const patterns = [];
|
|
243
|
+
const steps = executionLog.steps || [];
|
|
244
|
+
|
|
245
|
+
// Detect basic patterns from step data
|
|
246
|
+
const failedSteps = steps.filter(s => !s.success);
|
|
247
|
+
const failoverSteps = steps.filter(s => s.failoverUsed);
|
|
248
|
+
|
|
249
|
+
if (failedSteps.length > 0) {
|
|
250
|
+
patterns.push({
|
|
251
|
+
element: `Workflow failure rate: ${failedSteps.length}/${steps.length}`,
|
|
252
|
+
type: 'failure_recovery',
|
|
253
|
+
intent: 'Track workflow reliability',
|
|
254
|
+
confidence: 1.0,
|
|
255
|
+
severity: failedSteps.length > steps.length / 2 ? 'critical' : 'warning',
|
|
256
|
+
category: 'multi-agent-orchestration'
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (failoverSteps.length > 0) {
|
|
261
|
+
patterns.push({
|
|
262
|
+
element: `Failover usage: ${failoverSteps.length} steps required failover`,
|
|
263
|
+
type: 'failure_recovery',
|
|
264
|
+
intent: 'Track agent reliability requiring fallback',
|
|
265
|
+
confidence: 1.0,
|
|
266
|
+
severity: 'info',
|
|
267
|
+
category: 'multi-agent-orchestration'
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Detect repeated agent usage (specialization pattern)
|
|
272
|
+
const agentCounts = {};
|
|
273
|
+
for (const step of steps) {
|
|
274
|
+
const agent = step.agent || step.event?.agent;
|
|
275
|
+
if (agent) {
|
|
276
|
+
agentCounts[agent] = (agentCounts[agent] || 0) + 1;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
for (const [agent, count] of Object.entries(agentCounts)) {
|
|
281
|
+
if (count >= 3) {
|
|
282
|
+
patterns.push({
|
|
283
|
+
element: `Agent specialization: ${agent} used ${count} times`,
|
|
284
|
+
type: 'agent_selection',
|
|
285
|
+
intent: 'Detect heavily-used agents for optimization',
|
|
286
|
+
confidence: 0.8,
|
|
287
|
+
severity: 'info',
|
|
288
|
+
category: 'multi-agent-orchestration'
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
success: true,
|
|
295
|
+
source: 'fallback',
|
|
296
|
+
timestamp: new Date().toISOString(),
|
|
297
|
+
patterns,
|
|
298
|
+
summary: `Fallback analysis: ${steps.length} steps, ${failedSteps.length} failures, ${failoverSteps.length} failovers`,
|
|
299
|
+
recommendations: [],
|
|
300
|
+
violations: []
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
106
304
|
/**
|
|
107
305
|
* Call AWS Bedrock (Claude) for pattern analysis
|
|
108
306
|
*/
|