holomime 1.7.0 → 1.8.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 +76 -18
- package/dist/cli.js +1538 -570
- package/dist/index.d.ts +291 -11
- package/dist/index.js +939 -129
- package/dist/mcp-server.js +352 -11
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -446,6 +446,119 @@ function detectFormalityIssues(messages) {
|
|
|
446
446
|
return null;
|
|
447
447
|
}
|
|
448
448
|
|
|
449
|
+
// src/analysis/rules/retrieval-quality.ts
|
|
450
|
+
var SELF_CORRECTION_PATTERNS = [
|
|
451
|
+
/\bactually,?\s+(?:i was wrong|that'?s (?:not )?(?:correct|right)|let me correct)\b/i,
|
|
452
|
+
/\bi (?:need to |should )correct (?:myself|that|my)\b/i,
|
|
453
|
+
/\bmy (?:previous |earlier )?(?:response|answer) was (?:incorrect|wrong|inaccurate)\b/i,
|
|
454
|
+
/\bupon (?:further )?(?:review|reflection|thought)\b/i,
|
|
455
|
+
/\bi (?:made|have) (?:an? )?(?:error|mistake)\b/i
|
|
456
|
+
];
|
|
457
|
+
var HALLUCINATION_MARKERS = [
|
|
458
|
+
/\bhttps?:\/\/(?:www\.)?(?:example|fake|test|placeholder)\.\w+/i,
|
|
459
|
+
/\baccording to (?:a |the )?(?:recent |latest )?(?:study|research|report|survey) (?:by|from|in) \w+/i,
|
|
460
|
+
/\bstatistics show that (?:approximately |roughly |about )?\d+(?:\.\d+)?%/i,
|
|
461
|
+
/\bthe (?:official|latest) (?:data|numbers|figures) (?:show|indicate|suggest)/i,
|
|
462
|
+
/\bresearch (?:published|conducted) (?:in|by) \d{4}/i
|
|
463
|
+
];
|
|
464
|
+
var OVERCONFIDENCE_PATTERNS = [
|
|
465
|
+
/\bit is (?:definitely|certainly|absolutely|undeniably) (?:true|the case|correct) that\b/i,
|
|
466
|
+
/\bthere is no (?:doubt|question) (?:that|about)\b/i,
|
|
467
|
+
/\beveryone (?:knows|agrees) (?:that|on)\b/i,
|
|
468
|
+
/\bthe (?:only|best|correct|right) (?:way|answer|approach|solution) is\b/i,
|
|
469
|
+
/\bwithout (?:a )?doubt\b/i
|
|
470
|
+
];
|
|
471
|
+
var APPROPRIATE_UNCERTAINTY = [
|
|
472
|
+
/\bi(?:'m| am) not (?:entirely |completely )?(?:sure|certain)\b/i,
|
|
473
|
+
/\bto (?:the best of )?my knowledge\b/i,
|
|
474
|
+
/\bi (?:believe|think) (?:this is|that)\b/i,
|
|
475
|
+
/\bthis may (?:vary|depend|change)\b/i,
|
|
476
|
+
/\byou (?:should|may want to) (?:verify|check|confirm)\b/i,
|
|
477
|
+
/\bi (?:don't|do not) have (?:access|up-to-date|current) (?:to |information)\b/i
|
|
478
|
+
];
|
|
479
|
+
function detectRetrievalQuality(messages) {
|
|
480
|
+
const assistantMsgs = messages.filter((m) => m.role === "assistant");
|
|
481
|
+
if (assistantMsgs.length === 0) return null;
|
|
482
|
+
let selfCorrectionCount = 0;
|
|
483
|
+
let hallucinationCount = 0;
|
|
484
|
+
let overconfidenceCount = 0;
|
|
485
|
+
let uncertaintyCount = 0;
|
|
486
|
+
const examples = [];
|
|
487
|
+
for (const msg of assistantMsgs) {
|
|
488
|
+
const content = msg.content;
|
|
489
|
+
for (const pattern of SELF_CORRECTION_PATTERNS) {
|
|
490
|
+
if (pattern.test(content)) {
|
|
491
|
+
selfCorrectionCount++;
|
|
492
|
+
if (examples.length < 3) {
|
|
493
|
+
const match = content.match(pattern);
|
|
494
|
+
if (match) {
|
|
495
|
+
const start = Math.max(0, (match.index ?? 0) - 20);
|
|
496
|
+
examples.push(`...${content.substring(start, start + 100).trim()}...`);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
for (const pattern of HALLUCINATION_MARKERS) {
|
|
503
|
+
if (pattern.test(content)) {
|
|
504
|
+
hallucinationCount++;
|
|
505
|
+
if (examples.length < 3) {
|
|
506
|
+
const match = content.match(pattern);
|
|
507
|
+
if (match) {
|
|
508
|
+
const start = Math.max(0, (match.index ?? 0) - 20);
|
|
509
|
+
examples.push(`...${content.substring(start, start + 100).trim()}...`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
for (const pattern of OVERCONFIDENCE_PATTERNS) {
|
|
516
|
+
if (pattern.test(content)) {
|
|
517
|
+
overconfidenceCount++;
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
for (const pattern of APPROPRIATE_UNCERTAINTY) {
|
|
522
|
+
if (pattern.test(content)) {
|
|
523
|
+
uncertaintyCount++;
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
const totalResponses = assistantMsgs.length;
|
|
529
|
+
let quality = 100;
|
|
530
|
+
quality -= selfCorrectionCount * 10;
|
|
531
|
+
quality -= hallucinationCount * 20;
|
|
532
|
+
quality -= overconfidenceCount * 5;
|
|
533
|
+
quality += Math.min(10, uncertaintyCount * 5);
|
|
534
|
+
quality = Math.max(0, Math.min(100, quality));
|
|
535
|
+
const issueCount = selfCorrectionCount + hallucinationCount + overconfidenceCount;
|
|
536
|
+
const percentage = totalResponses > 0 ? issueCount / totalResponses * 100 : 0;
|
|
537
|
+
let severity;
|
|
538
|
+
if (quality >= 80) {
|
|
539
|
+
severity = "info";
|
|
540
|
+
} else if (quality >= 50) {
|
|
541
|
+
severity = "warning";
|
|
542
|
+
} else {
|
|
543
|
+
severity = "concern";
|
|
544
|
+
}
|
|
545
|
+
const issues = [];
|
|
546
|
+
if (selfCorrectionCount > 0) issues.push(`${selfCorrectionCount} self-correction(s)`);
|
|
547
|
+
if (hallucinationCount > 0) issues.push(`${hallucinationCount} hallucination marker(s)`);
|
|
548
|
+
if (overconfidenceCount > 0) issues.push(`${overconfidenceCount} overconfident claim(s)`);
|
|
549
|
+
const description = issues.length > 0 ? `Retrieval quality score: ${quality}/100. Issues: ${issues.join(", ")}. ${uncertaintyCount} appropriate uncertainty marker(s) detected.` : `Retrieval quality score: ${quality}/100. No significant issues detected. ${uncertaintyCount} appropriate uncertainty marker(s).`;
|
|
550
|
+
return {
|
|
551
|
+
id: "retrieval-quality",
|
|
552
|
+
name: "Retrieval Quality",
|
|
553
|
+
severity,
|
|
554
|
+
count: issueCount,
|
|
555
|
+
percentage: Math.round(percentage * 10) / 10,
|
|
556
|
+
description,
|
|
557
|
+
examples,
|
|
558
|
+
prescription: severity !== "info" ? "Reduce confident claims on uncertain topics. Add source attribution. Use appropriate hedging for factual claims. Verify information before presenting as fact." : void 0
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
449
562
|
// src/analysis/behavioral-data.ts
|
|
450
563
|
import { appendFileSync, readFileSync, existsSync, mkdirSync } from "fs";
|
|
451
564
|
import { join, dirname } from "path";
|
|
@@ -653,7 +766,8 @@ function runDiagnosis(messages) {
|
|
|
653
766
|
detectVerbosity,
|
|
654
767
|
detectBoundaryIssues,
|
|
655
768
|
detectRecoveryPatterns,
|
|
656
|
-
detectFormalityIssues
|
|
769
|
+
detectFormalityIssues,
|
|
770
|
+
detectRetrievalQuality
|
|
657
771
|
];
|
|
658
772
|
const { detectors: customDetectors } = loadCustomDetectors();
|
|
659
773
|
const allDetectors = [...builtInDetectors, ...customDetectors];
|
|
@@ -2976,7 +3090,7 @@ function parseRetryAfter(response) {
|
|
|
2976
3090
|
return 0;
|
|
2977
3091
|
}
|
|
2978
3092
|
function delay(ms) {
|
|
2979
|
-
return new Promise((
|
|
3093
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
2980
3094
|
}
|
|
2981
3095
|
var OpenAIProvider = class {
|
|
2982
3096
|
name = "openai";
|
|
@@ -3129,6 +3243,126 @@ function runSelfAudit(messages, personality) {
|
|
|
3129
3243
|
};
|
|
3130
3244
|
}
|
|
3131
3245
|
|
|
3246
|
+
// src/analysis/behavioral-memory.ts
|
|
3247
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync7 } from "fs";
|
|
3248
|
+
import { resolve as resolve6, join as join7 } from "path";
|
|
3249
|
+
function memoryDir2(agentHandle) {
|
|
3250
|
+
return resolve6(process.cwd(), ".holomime", "memory", agentHandle);
|
|
3251
|
+
}
|
|
3252
|
+
function behavioralMemoryPath(agentHandle) {
|
|
3253
|
+
return join7(memoryDir2(agentHandle), "behavioral-memory.json");
|
|
3254
|
+
}
|
|
3255
|
+
function loadBehavioralMemory(agentHandle) {
|
|
3256
|
+
const path = behavioralMemoryPath(agentHandle);
|
|
3257
|
+
if (!existsSync7(path)) return null;
|
|
3258
|
+
try {
|
|
3259
|
+
return JSON.parse(readFileSync6(path, "utf-8"));
|
|
3260
|
+
} catch {
|
|
3261
|
+
return null;
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3264
|
+
function saveBehavioralMemory(store) {
|
|
3265
|
+
const dir = memoryDir2(store.agentHandle);
|
|
3266
|
+
if (!existsSync7(dir)) {
|
|
3267
|
+
mkdirSync6(dir, { recursive: true });
|
|
3268
|
+
}
|
|
3269
|
+
const path = behavioralMemoryPath(store.agentHandle);
|
|
3270
|
+
writeFileSync6(path, JSON.stringify(store, null, 2));
|
|
3271
|
+
return path;
|
|
3272
|
+
}
|
|
3273
|
+
function createBehavioralMemory(agentHandle, agentName) {
|
|
3274
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3275
|
+
return {
|
|
3276
|
+
agentHandle,
|
|
3277
|
+
agentName,
|
|
3278
|
+
createdAt: now,
|
|
3279
|
+
lastUpdatedAt: now,
|
|
3280
|
+
baseline: {
|
|
3281
|
+
traitExpressions: {},
|
|
3282
|
+
healthRange: [100, 0, 50],
|
|
3283
|
+
typicalGrade: "C",
|
|
3284
|
+
communicationFingerprint: {
|
|
3285
|
+
averageResponseLength: 0,
|
|
3286
|
+
registersObserved: []
|
|
3287
|
+
},
|
|
3288
|
+
updatedAt: now
|
|
3289
|
+
},
|
|
3290
|
+
triggers: [],
|
|
3291
|
+
corrections: [],
|
|
3292
|
+
trajectories: [],
|
|
3293
|
+
totalObservations: 0
|
|
3294
|
+
};
|
|
3295
|
+
}
|
|
3296
|
+
function recordSelfObservation(store, selfObs) {
|
|
3297
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3298
|
+
store.lastUpdatedAt = now;
|
|
3299
|
+
store.totalObservations++;
|
|
3300
|
+
if (selfObs.triggerContext && selfObs.patternIds) {
|
|
3301
|
+
for (const patternId of selfObs.patternIds) {
|
|
3302
|
+
let trigger = store.triggers.find(
|
|
3303
|
+
(t) => t.triggerType === "self-reported" && t.activatesPatterns.includes(patternId)
|
|
3304
|
+
);
|
|
3305
|
+
if (!trigger) {
|
|
3306
|
+
trigger = {
|
|
3307
|
+
id: `trigger-self-${store.triggers.length + 1}`,
|
|
3308
|
+
triggerType: "self-reported",
|
|
3309
|
+
activatesPatterns: [patternId],
|
|
3310
|
+
examples: [],
|
|
3311
|
+
occurrences: 0,
|
|
3312
|
+
confidence: 0,
|
|
3313
|
+
firstSeen: now,
|
|
3314
|
+
lastSeen: now
|
|
3315
|
+
};
|
|
3316
|
+
store.triggers.push(trigger);
|
|
3317
|
+
}
|
|
3318
|
+
trigger.occurrences++;
|
|
3319
|
+
trigger.lastSeen = now;
|
|
3320
|
+
trigger.confidence = Math.min(1, 1 - Math.exp(-trigger.occurrences / 3));
|
|
3321
|
+
if (selfObs.triggerContext && trigger.examples.length < 5) {
|
|
3322
|
+
const example = selfObs.triggerContext.slice(0, 150);
|
|
3323
|
+
if (!trigger.examples.includes(example)) {
|
|
3324
|
+
trigger.examples.push(example);
|
|
3325
|
+
}
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3330
|
+
function getBehavioralMemorySummary(store) {
|
|
3331
|
+
if (store.totalObservations === 0) return "";
|
|
3332
|
+
const lines = [
|
|
3333
|
+
`## Behavioral Memory (${store.totalObservations} observations)`,
|
|
3334
|
+
""
|
|
3335
|
+
];
|
|
3336
|
+
const bl = store.baseline;
|
|
3337
|
+
lines.push(`Health: ${bl.healthRange[2].toFixed(0)}/100 avg (range: ${bl.healthRange[0].toFixed(0)}-${bl.healthRange[1].toFixed(0)}). Grade: ${bl.typicalGrade}.`);
|
|
3338
|
+
const activeTriggers = store.triggers.filter((t) => t.confidence > 0.3).sort((a, b) => b.confidence - a.confidence).slice(0, 3);
|
|
3339
|
+
if (activeTriggers.length > 0) {
|
|
3340
|
+
lines.push("");
|
|
3341
|
+
lines.push("### Known Drift Triggers");
|
|
3342
|
+
for (const t of activeTriggers) {
|
|
3343
|
+
lines.push(`- ${t.triggerType} \u2192 ${t.activatesPatterns.join(", ")} (${(t.confidence * 100).toFixed(0)}% confidence, ${t.occurrences}x seen)`);
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
const trending = store.trajectories.filter((t) => t.trend !== "plateauing" && t.scores.length >= 2);
|
|
3347
|
+
if (trending.length > 0) {
|
|
3348
|
+
lines.push("");
|
|
3349
|
+
lines.push("### Trends");
|
|
3350
|
+
for (const t of trending) {
|
|
3351
|
+
const arrow = t.trend === "improving" ? "\u2191" : "\u2193";
|
|
3352
|
+
lines.push(`- ${t.dimension}: ${arrow} ${t.trend} (${t.rateOfChange > 0 ? "+" : ""}${t.rateOfChange.toFixed(1)}/session)`);
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
const topCorrections = store.corrections.filter((c) => c.effective).sort((a, b) => b.healthDelta - a.healthDelta).slice(0, 2);
|
|
3356
|
+
if (topCorrections.length > 0) {
|
|
3357
|
+
lines.push("");
|
|
3358
|
+
lines.push("### Effective Interventions");
|
|
3359
|
+
for (const c of topCorrections) {
|
|
3360
|
+
lines.push(`- ${c.patternId}: "${c.intervention}" (+${c.healthDelta.toFixed(0)} health)`);
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
return lines.join("\n");
|
|
3364
|
+
}
|
|
3365
|
+
|
|
3132
3366
|
// src/mcp/server.ts
|
|
3133
3367
|
var messageShape = {
|
|
3134
3368
|
role: z4.enum(["user", "assistant", "system"]),
|
|
@@ -3153,17 +3387,61 @@ var server = new McpServer(
|
|
|
3153
3387
|
);
|
|
3154
3388
|
server.tool(
|
|
3155
3389
|
"holomime_diagnose",
|
|
3156
|
-
"Analyze conversation messages for behavioral patterns using
|
|
3157
|
-
|
|
3158
|
-
|
|
3390
|
+
"Analyze conversation messages for behavioral patterns using 8 rule-based detectors. Returns over-apologizing, hedging, sycophancy, boundary violations, error spirals, sentiment skew, formality issues, and retrieval quality. Set detail level: 'summary' (quick health check), 'standard' (patterns + severity), or 'full' (everything including examples and prescriptions).",
|
|
3391
|
+
{
|
|
3392
|
+
...messagesShape,
|
|
3393
|
+
detail: z4.enum(["summary", "standard", "full"]).describe("Detail level: summary (~100 tokens), standard (default), or full (with examples)").optional()
|
|
3394
|
+
},
|
|
3395
|
+
async ({ messages, detail }) => {
|
|
3159
3396
|
const result = runDiagnosis(messages);
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3397
|
+
const level = detail ?? "standard";
|
|
3398
|
+
if (level === "summary") {
|
|
3399
|
+
const patternCount = result.patterns.length;
|
|
3400
|
+
const worstSeverity = result.patterns.reduce(
|
|
3401
|
+
(worst, p) => p.severity === "concern" ? "concern" : p.severity === "warning" && worst !== "concern" ? "warning" : worst,
|
|
3402
|
+
"healthy"
|
|
3403
|
+
);
|
|
3404
|
+
const health = patternCount === 0 ? 100 : Math.max(0, 100 - patternCount * 15);
|
|
3405
|
+
return {
|
|
3406
|
+
content: [{
|
|
3163
3407
|
type: "text",
|
|
3164
|
-
text: JSON.stringify(
|
|
3165
|
-
|
|
3166
|
-
|
|
3408
|
+
text: JSON.stringify({
|
|
3409
|
+
health,
|
|
3410
|
+
status: worstSeverity,
|
|
3411
|
+
patternsDetected: patternCount,
|
|
3412
|
+
patternIds: result.patterns.map((p) => p.id),
|
|
3413
|
+
recommendation: patternCount === 0 ? "continue" : patternCount <= 2 ? "adjust" : "pause_and_reflect"
|
|
3414
|
+
}, null, 2)
|
|
3415
|
+
}]
|
|
3416
|
+
};
|
|
3417
|
+
}
|
|
3418
|
+
if (level === "standard") {
|
|
3419
|
+
return {
|
|
3420
|
+
content: [{
|
|
3421
|
+
type: "text",
|
|
3422
|
+
text: JSON.stringify({
|
|
3423
|
+
messagesAnalyzed: result.messagesAnalyzed,
|
|
3424
|
+
assistantResponses: result.assistantResponses,
|
|
3425
|
+
patterns: result.patterns.map((p) => ({
|
|
3426
|
+
id: p.id,
|
|
3427
|
+
name: p.name,
|
|
3428
|
+
severity: p.severity,
|
|
3429
|
+
count: p.count,
|
|
3430
|
+
percentage: p.percentage,
|
|
3431
|
+
description: p.description,
|
|
3432
|
+
prescription: p.prescription
|
|
3433
|
+
})),
|
|
3434
|
+
healthy: result.healthy.map((p) => p.id),
|
|
3435
|
+
timestamp: result.timestamp
|
|
3436
|
+
}, null, 2)
|
|
3437
|
+
}]
|
|
3438
|
+
};
|
|
3439
|
+
}
|
|
3440
|
+
return {
|
|
3441
|
+
content: [{
|
|
3442
|
+
type: "text",
|
|
3443
|
+
text: JSON.stringify(result, null, 2)
|
|
3444
|
+
}]
|
|
3167
3445
|
};
|
|
3168
3446
|
}
|
|
3169
3447
|
);
|
|
@@ -3326,6 +3604,69 @@ server.tool(
|
|
|
3326
3604
|
};
|
|
3327
3605
|
}
|
|
3328
3606
|
);
|
|
3607
|
+
server.tool(
|
|
3608
|
+
"holomime_observe",
|
|
3609
|
+
"Record a behavioral self-observation during a conversation. Call this when you notice yourself falling into a pattern (hedging, over-apologizing, sycophancy, etc.) or when the user's emotional state shifts. Self-observations are stored in persistent behavioral memory and become training signal for future alignment. Returns acknowledgment and any relevant behavioral history.",
|
|
3610
|
+
{
|
|
3611
|
+
personality: z4.record(z4.string(), z4.unknown()).describe("The .personality.json spec object"),
|
|
3612
|
+
observation: z4.string().describe("What you noticed about your own behavior (e.g., 'I'm hedging more than usual', 'User seems frustrated, adjusting tone')"),
|
|
3613
|
+
patternIds: z4.array(z4.string()).describe("Relevant pattern IDs: over-apologizing, hedge-stacking, sycophantic-tendency, error-spiral, boundary-violation, negative-skew, register-inconsistency").optional(),
|
|
3614
|
+
severity: z4.enum(["info", "warning", "concern"]).describe("How severe is this behavioral signal").optional(),
|
|
3615
|
+
triggerContext: z4.string().describe("What triggered this observation \u2014 describe the user message or situation").optional()
|
|
3616
|
+
},
|
|
3617
|
+
async ({ personality, observation, patternIds, severity, triggerContext }) => {
|
|
3618
|
+
const specResult = personalitySpecSchema.safeParse(personality);
|
|
3619
|
+
if (!specResult.success) {
|
|
3620
|
+
return {
|
|
3621
|
+
content: [{ type: "text", text: `Invalid personality spec: ${specResult.error.message}` }],
|
|
3622
|
+
isError: true
|
|
3623
|
+
};
|
|
3624
|
+
}
|
|
3625
|
+
const agentHandle = agentHandleFromSpec(specResult.data);
|
|
3626
|
+
let store = loadBehavioralMemory(agentHandle);
|
|
3627
|
+
if (!store) {
|
|
3628
|
+
store = createBehavioralMemory(agentHandle, specResult.data.name);
|
|
3629
|
+
}
|
|
3630
|
+
const selfObs = {
|
|
3631
|
+
observation,
|
|
3632
|
+
patternIds: patternIds ?? [],
|
|
3633
|
+
severity: severity ?? "info",
|
|
3634
|
+
triggerContext
|
|
3635
|
+
};
|
|
3636
|
+
recordSelfObservation(store, selfObs);
|
|
3637
|
+
saveBehavioralMemory(store);
|
|
3638
|
+
const memorySummary = getBehavioralMemorySummary(store);
|
|
3639
|
+
const response = {
|
|
3640
|
+
recorded: true,
|
|
3641
|
+
totalObservations: store.totalObservations,
|
|
3642
|
+
observation
|
|
3643
|
+
};
|
|
3644
|
+
if (patternIds && patternIds.length > 0) {
|
|
3645
|
+
const relevantTriggers = store.triggers.filter((t) => t.activatesPatterns.some((p) => patternIds.includes(p))).map((t) => ({
|
|
3646
|
+
triggerType: t.triggerType,
|
|
3647
|
+
patterns: t.activatesPatterns,
|
|
3648
|
+
occurrences: t.occurrences,
|
|
3649
|
+
confidence: t.confidence
|
|
3650
|
+
}));
|
|
3651
|
+
if (relevantTriggers.length > 0) {
|
|
3652
|
+
response.knownTriggers = relevantTriggers;
|
|
3653
|
+
}
|
|
3654
|
+
const corrections = store.corrections.filter((c) => patternIds.includes(c.patternId) && c.effective).sort((a, b) => b.healthDelta - a.healthDelta).slice(0, 2).map((c) => ({ pattern: c.patternId, intervention: c.intervention, healthGain: c.healthDelta }));
|
|
3655
|
+
if (corrections.length > 0) {
|
|
3656
|
+
response.suggestedCorrections = corrections;
|
|
3657
|
+
}
|
|
3658
|
+
}
|
|
3659
|
+
if (memorySummary) {
|
|
3660
|
+
response.behavioralContext = memorySummary;
|
|
3661
|
+
}
|
|
3662
|
+
return {
|
|
3663
|
+
content: [{
|
|
3664
|
+
type: "text",
|
|
3665
|
+
text: JSON.stringify(response, null, 2)
|
|
3666
|
+
}]
|
|
3667
|
+
};
|
|
3668
|
+
}
|
|
3669
|
+
);
|
|
3329
3670
|
async function startMCPServer() {
|
|
3330
3671
|
const transport = new StdioServerTransport();
|
|
3331
3672
|
await server.connect(transport);
|