noormme 1.2.0 → 1.2.1

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.
Files changed (132) hide show
  1. package/README.md +60 -6
  2. package/dist/cjs/agentic/ActionJournal.d.ts +5 -2
  3. package/dist/cjs/agentic/ActionJournal.js +13 -5
  4. package/dist/cjs/agentic/CapabilityManager.d.ts +7 -0
  5. package/dist/cjs/agentic/CapabilityManager.js +84 -7
  6. package/dist/cjs/agentic/CognitiveRepository.js +3 -6
  7. package/dist/cjs/agentic/Cortex.d.ts +4 -0
  8. package/dist/cjs/agentic/Cortex.js +38 -17
  9. package/dist/cjs/agentic/EpisodicMemory.d.ts +5 -1
  10. package/dist/cjs/agentic/EpisodicMemory.js +11 -4
  11. package/dist/cjs/agentic/PersonaManager.js +37 -31
  12. package/dist/cjs/agentic/PolicyEnforcer.d.ts +6 -1
  13. package/dist/cjs/agentic/PolicyEnforcer.js +74 -17
  14. package/dist/cjs/agentic/ResourceMonitor.d.ts +9 -0
  15. package/dist/cjs/agentic/ResourceMonitor.js +36 -2
  16. package/dist/cjs/agentic/SessionManager.js +24 -17
  17. package/dist/cjs/agentic/VectorIndexer.d.ts +1 -0
  18. package/dist/cjs/agentic/VectorIndexer.js +26 -17
  19. package/dist/cjs/agentic/improvement/AblationEngine.d.ts +4 -6
  20. package/dist/cjs/agentic/improvement/AblationEngine.js +57 -37
  21. package/dist/cjs/agentic/improvement/ActionRefiner.js +30 -14
  22. package/dist/cjs/agentic/improvement/ConflictResolver.d.ts +3 -1
  23. package/dist/cjs/agentic/improvement/ConflictResolver.js +59 -47
  24. package/dist/cjs/agentic/improvement/CortexJanitor.js +11 -0
  25. package/dist/cjs/agentic/improvement/CuriosityEngine.d.ts +1 -1
  26. package/dist/cjs/agentic/improvement/CuriosityEngine.js +48 -21
  27. package/dist/cjs/agentic/improvement/EvolutionRitual.js +26 -14
  28. package/dist/cjs/agentic/improvement/EvolutionaryPilot.js +16 -4
  29. package/dist/cjs/agentic/improvement/GoalArchitect.d.ts +6 -2
  30. package/dist/cjs/agentic/improvement/GoalArchitect.js +72 -34
  31. package/dist/cjs/agentic/improvement/GovernanceManager.d.ts +9 -3
  32. package/dist/cjs/agentic/improvement/GovernanceManager.js +232 -92
  33. package/dist/cjs/agentic/improvement/HiveLink.d.ts +7 -3
  34. package/dist/cjs/agentic/improvement/HiveLink.js +135 -113
  35. package/dist/cjs/agentic/improvement/KnowledgeDistiller.js +43 -35
  36. package/dist/cjs/agentic/improvement/QuotaManager.d.ts +41 -0
  37. package/dist/cjs/agentic/improvement/QuotaManager.js +185 -0
  38. package/dist/cjs/agentic/improvement/RecursiveReasoner.js +50 -25
  39. package/dist/cjs/agentic/improvement/ReflectionEngine.d.ts +4 -1
  40. package/dist/cjs/agentic/improvement/ReflectionEngine.js +3 -1
  41. package/dist/cjs/agentic/improvement/RitualOrchestrator.js +27 -16
  42. package/dist/cjs/agentic/improvement/RuleEngine.d.ts +1 -1
  43. package/dist/cjs/agentic/improvement/RuleEngine.js +10 -4
  44. package/dist/cjs/agentic/improvement/SelfEvolution.js +21 -17
  45. package/dist/cjs/agentic/improvement/SelfTestRegistry.d.ts +5 -0
  46. package/dist/cjs/agentic/improvement/SelfTestRegistry.js +129 -109
  47. package/dist/cjs/agentic/improvement/SkillSynthesizer.d.ts +1 -0
  48. package/dist/cjs/agentic/improvement/SkillSynthesizer.js +22 -13
  49. package/dist/cjs/agentic/improvement/StrategicPlanner.d.ts +1 -0
  50. package/dist/cjs/agentic/improvement/StrategicPlanner.js +26 -19
  51. package/dist/cjs/agentic/telemetry/CognitiveSynthesizer.d.ts +5 -0
  52. package/dist/cjs/agentic/telemetry/CognitiveSynthesizer.js +54 -12
  53. package/dist/cjs/agentic/telemetry/EventHarvester.d.ts +1 -1
  54. package/dist/cjs/agentic/telemetry/EventHarvester.js +10 -3
  55. package/dist/cjs/agentic/telemetry/ResearchAlchemist.d.ts +7 -2
  56. package/dist/cjs/agentic/telemetry/ResearchAlchemist.js +49 -8
  57. package/dist/cjs/agentic/telemetry/TelemetryOrchestrator.d.ts +4 -1
  58. package/dist/cjs/agentic/telemetry/TelemetryOrchestrator.js +38 -11
  59. package/dist/cjs/cli/commands/inspect.js +40 -1
  60. package/dist/cjs/cli/commands/watch.js +31 -25
  61. package/dist/cjs/dialect/sqlite/sqlite-introspector.js +15 -5
  62. package/dist/cjs/helpers/agent-schema.js +1 -0
  63. package/dist/cjs/migration/data_migrator.js +4 -4
  64. package/dist/cjs/migration/schema_differ.js +37 -15
  65. package/dist/cjs/types/index.d.ts +12 -0
  66. package/dist/cjs/util/safe-sql-helpers.js +7 -10
  67. package/dist/esm/agentic/ActionJournal.d.ts +5 -2
  68. package/dist/esm/agentic/ActionJournal.js +13 -5
  69. package/dist/esm/agentic/CapabilityManager.d.ts +7 -0
  70. package/dist/esm/agentic/CapabilityManager.js +84 -7
  71. package/dist/esm/agentic/CognitiveRepository.js +3 -6
  72. package/dist/esm/agentic/Cortex.d.ts +4 -0
  73. package/dist/esm/agentic/Cortex.js +38 -17
  74. package/dist/esm/agentic/EpisodicMemory.d.ts +5 -1
  75. package/dist/esm/agentic/EpisodicMemory.js +11 -4
  76. package/dist/esm/agentic/PersonaManager.js +37 -31
  77. package/dist/esm/agentic/PolicyEnforcer.d.ts +6 -1
  78. package/dist/esm/agentic/PolicyEnforcer.js +74 -17
  79. package/dist/esm/agentic/ResourceMonitor.d.ts +9 -0
  80. package/dist/esm/agentic/ResourceMonitor.js +36 -2
  81. package/dist/esm/agentic/SessionManager.js +24 -17
  82. package/dist/esm/agentic/VectorIndexer.d.ts +1 -0
  83. package/dist/esm/agentic/VectorIndexer.js +26 -17
  84. package/dist/esm/agentic/improvement/AblationEngine.d.ts +4 -6
  85. package/dist/esm/agentic/improvement/AblationEngine.js +57 -37
  86. package/dist/esm/agentic/improvement/ActionRefiner.js +30 -14
  87. package/dist/esm/agentic/improvement/ConflictResolver.d.ts +3 -1
  88. package/dist/esm/agentic/improvement/ConflictResolver.js +59 -47
  89. package/dist/esm/agentic/improvement/CortexJanitor.js +11 -0
  90. package/dist/esm/agentic/improvement/CuriosityEngine.d.ts +1 -1
  91. package/dist/esm/agentic/improvement/CuriosityEngine.js +48 -21
  92. package/dist/esm/agentic/improvement/EvolutionRitual.js +26 -14
  93. package/dist/esm/agentic/improvement/EvolutionaryPilot.js +16 -4
  94. package/dist/esm/agentic/improvement/GoalArchitect.d.ts +6 -2
  95. package/dist/esm/agentic/improvement/GoalArchitect.js +72 -34
  96. package/dist/esm/agentic/improvement/GovernanceManager.d.ts +9 -3
  97. package/dist/esm/agentic/improvement/GovernanceManager.js +232 -92
  98. package/dist/esm/agentic/improvement/HiveLink.d.ts +7 -3
  99. package/dist/esm/agentic/improvement/HiveLink.js +135 -113
  100. package/dist/esm/agentic/improvement/KnowledgeDistiller.js +43 -35
  101. package/dist/esm/agentic/improvement/QuotaManager.d.ts +41 -0
  102. package/dist/esm/agentic/improvement/QuotaManager.js +182 -0
  103. package/dist/esm/agentic/improvement/RecursiveReasoner.js +50 -25
  104. package/dist/esm/agentic/improvement/ReflectionEngine.d.ts +4 -1
  105. package/dist/esm/agentic/improvement/ReflectionEngine.js +3 -1
  106. package/dist/esm/agentic/improvement/RitualOrchestrator.js +27 -16
  107. package/dist/esm/agentic/improvement/RuleEngine.d.ts +1 -1
  108. package/dist/esm/agentic/improvement/RuleEngine.js +10 -4
  109. package/dist/esm/agentic/improvement/SelfEvolution.js +21 -17
  110. package/dist/esm/agentic/improvement/SelfTestRegistry.d.ts +5 -0
  111. package/dist/esm/agentic/improvement/SelfTestRegistry.js +129 -109
  112. package/dist/esm/agentic/improvement/SkillSynthesizer.d.ts +1 -0
  113. package/dist/esm/agentic/improvement/SkillSynthesizer.js +22 -13
  114. package/dist/esm/agentic/improvement/StrategicPlanner.d.ts +1 -0
  115. package/dist/esm/agentic/improvement/StrategicPlanner.js +26 -19
  116. package/dist/esm/agentic/telemetry/CognitiveSynthesizer.d.ts +5 -0
  117. package/dist/esm/agentic/telemetry/CognitiveSynthesizer.js +54 -12
  118. package/dist/esm/agentic/telemetry/EventHarvester.d.ts +1 -1
  119. package/dist/esm/agentic/telemetry/EventHarvester.js +10 -3
  120. package/dist/esm/agentic/telemetry/ResearchAlchemist.d.ts +7 -2
  121. package/dist/esm/agentic/telemetry/ResearchAlchemist.js +49 -8
  122. package/dist/esm/agentic/telemetry/TelemetryOrchestrator.d.ts +4 -1
  123. package/dist/esm/agentic/telemetry/TelemetryOrchestrator.js +38 -11
  124. package/dist/esm/cli/commands/inspect.js +40 -1
  125. package/dist/esm/cli/commands/watch.js +31 -25
  126. package/dist/esm/dialect/sqlite/sqlite-introspector.js +15 -5
  127. package/dist/esm/helpers/agent-schema.js +1 -0
  128. package/dist/esm/migration/data_migrator.js +4 -4
  129. package/dist/esm/migration/schema_differ.js +37 -15
  130. package/dist/esm/types/index.d.ts +12 -0
  131. package/dist/esm/util/safe-sql-helpers.js +7 -10
  132. package/package.json +1 -1
@@ -38,11 +38,14 @@ class StrategicPlanner {
38
38
  .selectFrom(this.personasTable)
39
39
  .selectAll()
40
40
  .execute();
41
+ const allParsedPersonas = personas.map((p) => this.parsePersona(p));
42
+ const globalBlacklistDuration = this.config.strategy?.globalBlacklistDuration || 3600000; // 1 hour
43
+ const localBlacklistDuration = this.config.strategy?.localBlacklistDuration || 86400000; // 24 hours
41
44
  for (const p of personas) {
42
45
  const persona = this.parsePersona(p);
43
46
  // 1. Verification Monitor
44
47
  if (persona.metadata?.evolution_status === 'verifying') {
45
- const result = await this.verifyEvolution(persona);
48
+ const result = await this.verifyEvolution(persona, allParsedPersonas);
46
49
  if (result)
47
50
  mutations.push(result);
48
51
  continue;
@@ -52,20 +55,15 @@ class StrategicPlanner {
52
55
  const report = await this.analyzePersona(persona.id);
53
56
  // 3. Blacklist Check (Local & Global Phase 5)
54
57
  const lastMutation = persona.metadata?.last_failed_mutation;
55
- const allPersonas = await this.typedDb
56
- .selectFrom(this.personasTable)
57
- .selectAll()
58
- .execute();
59
- const isGloballyBlacklisted = allPersonas.some((p) => {
60
- const mp = this.parsePersona(p);
58
+ const isGloballyBlacklisted = allParsedPersonas.some((mp) => {
61
59
  return (mp.metadata?.last_failed_mutation?.type === report.recommendation &&
62
60
  Date.now() - (mp.metadata?.last_failed_mutation?.timestamp || 0) <
63
- 3600000);
61
+ globalBlacklistDuration);
64
62
  });
65
63
  if (isGloballyBlacklisted ||
66
64
  (lastMutation &&
67
65
  report.recommendation === lastMutation.type &&
68
- Date.now() - lastMutation.timestamp < 86400000)) {
66
+ Date.now() - lastMutation.timestamp < localBlacklistDuration)) {
69
67
  console.log(`[StrategicPlanner] Skipping blacklisted mutation ${report.recommendation} for persona ${persona.id} (Global=${isGloballyBlacklisted})`);
70
68
  continue;
71
69
  }
@@ -111,15 +109,19 @@ class StrategicPlanner {
111
109
  .filter((p) => (p.metadata?.evolution_status === 'stable' ||
112
110
  !p.metadata?.evolution_status) &&
113
111
  p.metadata?.mutation_reason?.includes(report.recommendation));
114
- if (winningMutations.length > 0 && Math.random() > 0.5) {
115
- console.log(`[StrategicPlanner] Cross-Pollinating success from Persona ${winningMutations[0].id}`);
116
- updates = { role: winningMutations[0].role || persona.role };
112
+ if (winningMutations.length > 0) {
113
+ // PRODUCTION HARDENING: Deterministic Alpha Selection
114
+ // Instead of Math.random(), pick the variant with the highest anchored reliability
115
+ const sorted = winningMutations.sort((a, b) => (b.metadata?.anchored_reliability || 0) - (a.metadata?.anchored_reliability || 0));
116
+ const alphaMatch = sorted[0];
117
+ console.log(`[StrategicPlanner] Cross-Pollinating success from Alpha Persona ${alphaMatch.id} (Reliability: ${alphaMatch.metadata?.anchored_reliability || 0})`);
118
+ updates = { role: this.sanitizeRole(alphaMatch.role || persona.role || 'Agent') };
117
119
  }
118
120
  else {
119
121
  switch (report.recommendation) {
120
122
  case 'optimize_accuracy':
121
123
  updates = {
122
- role: `${persona.role || ''} (Focus strictly on accuracy and detailed verification)`.trim(),
124
+ role: this.sanitizeRole(`${persona.role || ''} (Focus strictly on accuracy and detailed verification)`),
123
125
  };
124
126
  break;
125
127
  case 'optimize_efficiency':
@@ -139,6 +141,9 @@ class StrategicPlanner {
139
141
  }
140
142
  }
141
143
  }
144
+ if (updates.role) {
145
+ updates.role = this.sanitizeRole(updates.role);
146
+ }
142
147
  // 1. Predictive Conflict Detection (Pre-flight)
143
148
  const proposedState = { ...persona, ...updates };
144
149
  const contradictions = await this.cortex.reasoner.detectContradictions();
@@ -198,18 +203,13 @@ class StrategicPlanner {
198
203
  * Check if a persona in verification should be stabilized or rolled back.
199
204
  * Uses dynamic statistical variance and adaptive meta-tuning.
200
205
  */
201
- async verifyEvolution(persona) {
206
+ async verifyEvolution(persona, allPersonas = []) {
202
207
  const report = await this.analyzePersona(persona.id);
203
208
  // Adaptive Meta-Tuning: Increase window based on rollback history (Phase 4)
204
209
  const rollbackHistory = persona.metadata?.rollbackHistory || [];
205
210
  const recentRollbacks = rollbackHistory.filter((ts) => Date.now() - ts < 604800000).length;
206
211
  // Hive-Mind Verification Speedups (Phase 5)
207
- const allPersonas = await this.typedDb
208
- .selectFrom(this.personasTable)
209
- .selectAll()
210
- .execute();
211
212
  const hiveTrusted = allPersonas
212
- .map((p) => this.parsePersona(p))
213
213
  .filter((p) => p.metadata?.evolution_status === 'stable' &&
214
214
  p.metadata?.mutation_reason === persona.metadata?.mutation_reason).length;
215
215
  let sampleSizeThreshold = 10 + recentRollbacks * 10;
@@ -432,6 +432,13 @@ class StrategicPlanner {
432
432
  return `Rolled back mutation ${lastMutation.id} for persona ${id}`;
433
433
  });
434
434
  }
435
+ sanitizeRole(role) {
436
+ // Audit Phase 7: Semantic Security
437
+ // Truncate to prevent context-window exhaustion/bloat
438
+ const truncated = role.slice(0, 500).trim();
439
+ // Sanitize: remove potentially dangerous prompt-injection markers or control chars
440
+ return truncated.replace(/[\u0000-\u001F\u007F-\u009F]/g, '').replace(/<\|.*?\|>/g, '');
441
+ }
435
442
  parsePersona(p) {
436
443
  return {
437
444
  id: p.id,
@@ -22,5 +22,10 @@ export declare class CognitiveSynthesizer {
22
22
  private inferGoalFromContent;
23
23
  private detectStrategy;
24
24
  private calculateAutonomy;
25
+ /**
26
+ * Detect "Sentiment Drift" or Cognitive Friction in the input stream.
27
+ * Mirrors the agent's internal "frustration" or "flow" state.
28
+ */
29
+ private detectSentimentDrift;
25
30
  private parsePath;
26
31
  }
@@ -21,8 +21,15 @@ class CognitiveSynthesizer {
21
21
  * Uses robust transaction logic and behavioral pathing.
22
22
  */
23
23
  async synthesize(sessionId, input, pattern) {
24
- // Production: structured goal inference logic
25
- const goalInferred = this.inferGoalFromContent(input);
24
+ // PRODUCTION HARDENING: Reasoning-Driven Synthesis
25
+ // Instead of regex heuristics, we leverage the RecursiveReasoner for high-fidelity goal extraction
26
+ const cortex = this.config.cortex;
27
+ let goalInferred = this.inferGoalFromContent(input);
28
+ if (cortex?.reasoner) {
29
+ const reasoning = await cortex.reasoner.analyzeIntent(input);
30
+ if (reasoning.goal)
31
+ goalInferred = reasoning.goal;
32
+ }
26
33
  const strategy = pattern || this.detectStrategy(input);
27
34
  try {
28
35
  await this.db.transaction().execute(async (trx) => {
@@ -33,14 +40,17 @@ class CognitiveSynthesizer {
33
40
  .executeTakeFirst();
34
41
  if (existing) {
35
42
  const currentPath = this.parsePath(existing.evolution_path);
36
- // Only append to path if goal or strategy shifted significantly
43
+ // Only append to path if goal, strategy, or sentiment shifted significantly
44
+ const sentiment = this.detectSentimentDrift(input);
37
45
  if (existing.inferred_goal !== goalInferred ||
38
- existing.strategy !== strategy) {
46
+ existing.strategy !== strategy ||
47
+ (existing.metadata && JSON.parse(existing.metadata).lastSentiment !== sentiment)) {
39
48
  currentPath.push({
40
49
  timestamp: new Date().toISOString(),
41
50
  previousGoal: existing.inferred_goal,
42
51
  newGoal: goalInferred,
43
52
  strategyShift: strategy,
53
+ sentiment,
44
54
  });
45
55
  }
46
56
  await trx
@@ -50,6 +60,11 @@ class CognitiveSynthesizer {
50
60
  strategy,
51
61
  evolution_path: JSON.stringify(currentPath),
52
62
  status: 'active',
63
+ metadata: JSON.stringify({
64
+ ...JSON.parse(existing.metadata || '{}'),
65
+ lastSentiment: sentiment,
66
+ pivots: currentPath.length,
67
+ }),
53
68
  autonomy_level: this.calculateAutonomy(currentPath.length, existing.autonomy_level || 1),
54
69
  updated_at: new Date(),
55
70
  })
@@ -124,9 +139,13 @@ class CognitiveSynthesizer {
124
139
  inferGoalFromContent(content) {
125
140
  // Real-world simulation: extract the first imperative sentence or key noun phrases
126
141
  const clean = content.trim().replace(/\n/g, ' ');
142
+ // Hardened heuristic: prioritize imperative verbs and specific NOORMME intents
143
+ const imperativeMatch = clean.match(/(?:please |can you |let's )?(implement|fix|refactor|add|search|analyze|delete|evolve) .+/i);
144
+ if (imperativeMatch) {
145
+ return imperativeMatch[0].substring(0, 100) + (imperativeMatch[0].length > 100 ? '...' : '');
146
+ }
127
147
  if (clean.length < 100)
128
148
  return clean;
129
- // Simple heuristic: look for "need", "want", "please", "can you"
130
149
  const keywords = [
131
150
  'need',
132
151
  'want',
@@ -146,21 +165,44 @@ class CognitiveSynthesizer {
146
165
  }
147
166
  detectStrategy(content) {
148
167
  const c = content.toLowerCase();
149
- if (c.includes('debug') || c.includes('fix') || c.includes('error'))
168
+ // Hardened strategy detection
169
+ if (c.includes('debug') || c.includes('fix') || c.includes('error') || c.includes('broken'))
150
170
  return 'Diagnostic Repair';
151
- if (c.includes('create') || c.includes('build') || c.includes('implement'))
171
+ if (c.includes('create') || c.includes('build') || c.includes('implement') || c.includes('new file'))
152
172
  return 'Generative Construction';
153
- if (c.includes('research') || c.includes('explain') || c.includes('how'))
173
+ if (c.includes('research') || c.includes('explain') || c.includes('how') || c.includes('investigate'))
154
174
  return 'Knowledge Acquisition';
175
+ if (c.includes('evolve') || c.includes('mutate') || c.includes('dna'))
176
+ return 'Self-Evolutionary';
155
177
  return 'Adaptive Exploration';
156
178
  }
157
179
  calculateAutonomy(pivots, currentLevel) {
158
- // Logic: frequent pivots without completion decrease autonomy.
159
- // Consistent execution increases it.
160
- if (pivots > 5)
161
- return Math.min(4, currentLevel + 1);
180
+ // Enhanced Autonomy: Lower weight on raw pivots, more on ratio
181
+ // If pivots are moderate but yield successful sub-goals, autonomy holds.
182
+ if (pivots > 10)
183
+ return Math.max(1, currentLevel - 1);
184
+ if (pivots > 5 && currentLevel > 2)
185
+ return currentLevel;
186
+ if (pivots === 0)
187
+ return Math.min(5, currentLevel + 1);
162
188
  return currentLevel;
163
189
  }
190
+ /**
191
+ * Detect "Sentiment Drift" or Cognitive Friction in the input stream.
192
+ * Mirrors the agent's internal "frustration" or "flow" state.
193
+ */
194
+ detectSentimentDrift(content) {
195
+ const c = content.toLowerCase();
196
+ const negativeTerms = ['slow', 'wrong', 'bad', 'error', 'failed', 'cannot', 'stuck'];
197
+ const postiveTerms = ['great', 'correct', 'good', 'success', 'works', 'yes'];
198
+ const negCount = negativeTerms.filter(t => c.includes(t)).length;
199
+ const posCount = postiveTerms.filter(t => c.includes(t)).length;
200
+ if (negCount > posCount + 1)
201
+ return 'frustration';
202
+ if (posCount > negCount)
203
+ return 'flow';
204
+ return 'neutral';
205
+ }
164
206
  parsePath(pathData) {
165
207
  if (!pathData)
166
208
  return [];
@@ -6,7 +6,7 @@ export declare class EventHarvester {
6
6
  private telemetryTable;
7
7
  constructor(db: Kysely<any>, config?: AgenticConfig);
8
8
  /**
9
- * Persist a raw telemetry event
9
+ * Persist a raw telemetry event with safety valves for scale.
10
10
  */
11
11
  harvest(sessionId: string | number, type: TelemetryEvent['type'], content: string, metadata?: Record<string, any>): Promise<void>;
12
12
  }
@@ -12,17 +12,24 @@ class EventHarvester {
12
12
  config.telemetryEventsTable || 'agent_telemetry_events';
13
13
  }
14
14
  /**
15
- * Persist a raw telemetry event
15
+ * Persist a raw telemetry event with safety valves for scale.
16
16
  */
17
17
  async harvest(sessionId, type, content, metadata) {
18
+ // 1. Safety Valve: Drop excessively large payloads (> 100KB)
19
+ if (content.length > 102400) {
20
+ console.warn(`[EventHarvester] DROPPING EVENT: Content exceeds 100KB safety limit (${content.length} bytes)`);
21
+ return;
22
+ }
23
+ // 2. Metadata Integrity: Ensure metadata is a valid object
24
+ const finalMetadata = metadata && typeof metadata === 'object' ? metadata : {};
18
25
  try {
19
26
  await this.db
20
27
  .insertInto(this.telemetryTable)
21
28
  .values({
22
29
  session_id: sessionId,
23
30
  type,
24
- content,
25
- metadata: metadata ? JSON.stringify(metadata) : null,
31
+ content: content.substring(0, 50000), // Hard truncated for storage safety
32
+ metadata: JSON.stringify(finalMetadata),
26
33
  created_at: new Date(),
27
34
  })
28
35
  .execute();
@@ -6,11 +6,16 @@ export declare class ResearchAlchemist {
6
6
  private metricsTable;
7
7
  constructor(db: Kysely<any>, config?: AgenticConfig);
8
8
  /**
9
- * Transmute raw events into research metrics
9
+ * Transmute raw events into research metrics with statistical noise filtering.
10
10
  */
11
11
  transmute(sessionId: string | number, metricName: ResearchMetric['metricName'], value: number, metadata?: Record<string, any>): Promise<void>;
12
12
  /**
13
- * Calculate novelty or Discovery Index
13
+ * Calculate discovery velocity: rate of novelty acquisition in the last 10 minutes.
14
+ */
15
+ private calculateDiscoveryVelocity;
16
+ /**
17
+ * Calculate novelty or Discovery Index.
18
+ * Uses cross-session frequency analysis to determine actual novelty.
14
19
  */
15
20
  trackDiscovery(sessionId: string | number, taskType: string): Promise<void>;
16
21
  /**
@@ -11,9 +11,15 @@ class ResearchAlchemist {
11
11
  this.metricsTable = config.researchMetricsTable || 'agent_research_metrics';
12
12
  }
13
13
  /**
14
- * Transmute raw events into research metrics
14
+ * Transmute raw events into research metrics with statistical noise filtering.
15
15
  */
16
16
  async transmute(sessionId, metricName, value, metadata) {
17
+ // Hardening: Prevent extreme outliers from skewing discovery data
18
+ const magicCeiling = this.config.research?.magicCeiling || 100;
19
+ if (metricName === 'time_to_magic' && (value < 0 || value > magicCeiling)) {
20
+ console.warn(`[ResearchAlchemist] Filtering outlier magic score: ${value}`);
21
+ return;
22
+ }
17
23
  try {
18
24
  await this.db
19
25
  .insertInto(this.metricsTable)
@@ -25,26 +31,61 @@ class ResearchAlchemist {
25
31
  created_at: new Date(),
26
32
  })
27
33
  .execute();
34
+ // Secondary Transmutation: Calculate discovery velocity
35
+ if (metricName === 'discovery_index') {
36
+ await this.calculateDiscoveryVelocity(sessionId);
37
+ }
28
38
  }
29
39
  catch (e) {
30
40
  console.warn(`[ResearchAlchemist] Failed to transmute metric ${metricName}: ${e}`);
31
41
  }
32
42
  }
33
43
  /**
34
- * Calculate novelty or Discovery Index
44
+ * Calculate discovery velocity: rate of novelty acquisition in the last 10 minutes.
45
+ */
46
+ async calculateDiscoveryVelocity(sessionId) {
47
+ const windowMs = this.config.research?.velocityWindowMinutes * 60 * 1000 || 10 * 60 * 1000;
48
+ const recent = await this.db
49
+ .selectFrom(this.metricsTable)
50
+ .select((eb) => eb.fn.count('id').as('count'))
51
+ .where('session_id', '=', sessionId)
52
+ .where('metric_name', '=', 'discovery_index')
53
+ .where('created_at', '>', new Date(Date.now() - windowMs))
54
+ .executeTakeFirst();
55
+ const count = Number(recent?.count || 0);
56
+ const velocity = count / 10; // novelty per minute
57
+ // Persist velocity as its own research metric
58
+ await this.db
59
+ .insertInto(this.metricsTable)
60
+ .values({
61
+ session_id: sessionId,
62
+ metric_name: 'discovery_velocity',
63
+ value: velocity,
64
+ created_at: new Date(),
65
+ })
66
+ .execute();
67
+ }
68
+ /**
69
+ * Calculate novelty or Discovery Index.
70
+ * Uses cross-session frequency analysis to determine actual novelty.
35
71
  */
36
72
  async trackDiscovery(sessionId, taskType) {
37
- // Production Hardening: Real database-backed novelty check
38
- const existing = await this.db
73
+ // 1. Check frequency across all recent sessions (Last 500 metrics)
74
+ const frequency = await this.db
39
75
  .selectFrom(this.metricsTable)
40
- .select('id')
76
+ .select((eb) => eb.fn.count('id').as('count'))
41
77
  .where('metric_name', '=', 'discovery_index')
42
- .where('metadata', 'like', `%${taskType}%`)
78
+ .where('metadata', 'like', `%${taskType.replace(/[%_]/g, '')}%`)
43
79
  .executeTakeFirst();
44
- const discoveryValue = existing ? 0.1 : 1.0; // 1.0 for first-time discovery, 0.1 for repeat
80
+ const count = Number(frequency?.count || 0);
81
+ // Discovery Value: Inverse frequency (Inverted Logarithmic Scale)
82
+ // 1.0 = Brand new, 0.0 = Commonplace
83
+ const discoveryValue = Math.max(0, 1.0 - Math.log10(count + 1));
45
84
  await this.transmute(sessionId, 'discovery_index', discoveryValue, {
46
85
  taskType,
47
- firstDiscovery: !existing,
86
+ occurrenceCount: count,
87
+ isInitialDiscovery: count === 0,
88
+ timestamp: Date.now()
48
89
  });
49
90
  }
50
91
  /**
@@ -9,9 +9,12 @@ export declare class TelemetryOrchestrator {
9
9
  harvester: EventHarvester;
10
10
  synthesizer: CognitiveSynthesizer;
11
11
  alchemist: ResearchAlchemist;
12
+ private circuitBreakerActive;
13
+ private failureCount;
14
+ private lastFailureTime;
12
15
  constructor(db: Kysely<any>, config?: AgenticConfig);
13
16
  /**
14
- * Track a raw event and trigger synthesis
17
+ * Track a raw event and trigger synthesis with Circuit Breaking safety.
15
18
  */
16
19
  track(sessionId: string | number, type: TelemetryEvent['type'], content: string, metadata?: Record<string, any>): Promise<void>;
17
20
  /**
@@ -10,6 +10,9 @@ class TelemetryOrchestrator {
10
10
  harvester;
11
11
  synthesizer;
12
12
  alchemist;
13
+ circuitBreakerActive = false;
14
+ failureCount = 0;
15
+ lastFailureTime = 0;
13
16
  constructor(db, config = {}) {
14
17
  this.db = db;
15
18
  this.config = config;
@@ -18,21 +21,45 @@ class TelemetryOrchestrator {
18
21
  this.alchemist = new ResearchAlchemist_js_1.ResearchAlchemist(db, config);
19
22
  }
20
23
  /**
21
- * Track a raw event and trigger synthesis
24
+ * Track a raw event and trigger synthesis with Circuit Breaking safety.
22
25
  */
23
26
  async track(sessionId, type, content, metadata) {
24
- // Layer A: Harvest
25
- await this.harvester.harvest(sessionId, type, content, metadata);
26
- // Layer B: Synthesize
27
- if (type === 'prompt' || type === 'action') {
28
- await this.synthesizer.synthesize(sessionId, content);
27
+ // 1. Circuit Breaker Check
28
+ if (this.circuitBreakerActive) {
29
+ if (Date.now() - this.lastFailureTime > 60000) {
30
+ console.log('[TelemetryOrchestrator] Attempting circuit recovery...');
31
+ this.circuitBreakerActive = false;
32
+ this.failureCount = 0;
33
+ }
34
+ else {
35
+ // Drop non-critical events during outage
36
+ if (type !== 'error' && type !== 'magic')
37
+ return;
38
+ }
29
39
  }
30
- // Layer C: Research triggers
31
- if (type === 'magic') {
32
- await this.alchemist.recordMagic(sessionId, metadata?.surpriseScore || 1.0);
40
+ try {
41
+ // Layer A: Harvest
42
+ await this.harvester.harvest(sessionId, type, content, metadata);
43
+ // Layer B: Synthesize
44
+ if (type === 'prompt' || type === 'action') {
45
+ await this.synthesizer.synthesize(sessionId, content);
46
+ }
47
+ // Layer C: Research triggers
48
+ if (type === 'magic') {
49
+ await this.alchemist.recordMagic(sessionId, metadata?.surpriseScore || 1.0);
50
+ }
51
+ if (type === 'pivot' || type === 'error') {
52
+ await this.synthesizer.trackShift(sessionId, type === 'pivot' ? 'pivot' : 'abandonment');
53
+ }
33
54
  }
34
- if (type === 'pivot' || type === 'error') {
35
- await this.synthesizer.trackShift(sessionId, type === 'pivot' ? 'pivot' : 'abandonment');
55
+ catch (e) {
56
+ this.failureCount++;
57
+ this.lastFailureTime = Date.now();
58
+ console.error(`[TelemetryOrchestrator] SENSOR FAILURE (${this.failureCount}): ${e}`);
59
+ if (this.failureCount > 5) {
60
+ console.error('[TelemetryOrchestrator] CIRCUIT BREAKER TRIPPED. Entering degraded mode.');
61
+ this.circuitBreakerActive = true;
62
+ }
36
63
  }
37
64
  }
38
65
  /**
@@ -80,8 +80,12 @@ async function inspect(tableName, options = {}) {
80
80
  await showPerformanceOverview(db);
81
81
  }
82
82
  // Show automation recommendations
83
- console.log('\n' + chalk_1.default.blue.bold('šŸ’” Automation Recommendations:\n'));
83
+ console.log('\n' + chalk_1.default.blue.bold('šŸ’” Automation Recommendations & Semantic Insights:\n'));
84
84
  await showAutomationRecommendations(schemaInfo, db);
85
+ // PRODUCTION HARDENING: Soft Relationship Discovery
86
+ if (options.relationships) {
87
+ await showSoftRelationshipInsights(schemaInfo, db);
88
+ }
85
89
  }
86
90
  await db.close();
87
91
  }
@@ -475,6 +479,41 @@ function showTableDetails(table, relationships, db, rowCount = 0) {
475
479
  }
476
480
  console.log(chalk_1.default.gray('```'));
477
481
  }
482
+ async function showSoftRelationshipInsights(schemaInfo, db) {
483
+ const reasoner = db.agent?.cortex?.reasoner;
484
+ if (!reasoner)
485
+ return;
486
+ try {
487
+ const spinner = new spinner_js_1.AgenticSpinner();
488
+ spinner.start('Analyzing semantic link matrix...');
489
+ const insights = [];
490
+ for (const table of schemaInfo.tables) {
491
+ // Only analyze tables with potential soft links (id-like columns without FKs)
492
+ const targets = table.columns.filter((c) => c.name.includes('_id') &&
493
+ !table.foreignKeys.some((fk) => fk.column === c.name));
494
+ if (targets.length > 0) {
495
+ const analysis = await reasoner.analyzeSoftLinks(table.name, targets.map((t) => t.name));
496
+ if (analysis && analysis.links.length > 0) {
497
+ insights.push(...analysis.links);
498
+ }
499
+ }
500
+ }
501
+ spinner.stop();
502
+ if (insights.length > 0) {
503
+ console.log(chalk_1.default.blue.bold('\n🧠 AI-Inferred Soft Relationships:'));
504
+ insights.forEach(link => {
505
+ console.log(chalk_1.default.gray(` • ${link.sourceTable}.${link.sourceColumn} `) +
506
+ chalk_1.default.yellow('ā‰ˆā‰ˆā‰ˆ') +
507
+ chalk_1.default.gray(` ${link.targetTable}.${link.targetColumn} `) +
508
+ chalk_1.default.cyan(`(Confidence: ${Math.round(link.confidence * 100)}%)`));
509
+ console.log(chalk_1.default.italic.gray(` Reason: ${link.reason}`));
510
+ });
511
+ }
512
+ }
513
+ catch (error) {
514
+ // Fail silently for discovery
515
+ }
516
+ }
478
517
  function showRelationships(relationships) {
479
518
  if (relationships.length === 0) {
480
519
  console.log(chalk_1.default.gray('No relationships found.'));
@@ -122,46 +122,52 @@ async function watch(options) {
122
122
  pollInterval: intervalMs,
123
123
  enabled: true,
124
124
  });
125
- // Periodic tasks loop
125
+ // PRODUCTION HARDENING: Resilient Polling Loop
126
+ let retryCount = 0;
127
+ const maxRetries = 10;
128
+ let currentInterval = intervalMs;
126
129
  const periodicTaskInterval = setInterval(async () => {
127
- // Periodic optimization if auto-optimize is enabled
128
- if (autoOptimize &&
129
- Date.now() - lastOptimizationTime > optimizationInterval) {
130
- console.log(chalk_1.default.blue(`\nšŸ”„ Periodic optimization check at ${new Date().toLocaleTimeString()}`));
131
- try {
130
+ try {
131
+ // Reset interval on success
132
+ if (retryCount > 0) {
133
+ console.log(chalk_1.default.green('āœ… Connection restored.'));
134
+ retryCount = 0;
135
+ currentInterval = intervalMs;
136
+ }
137
+ const timestamp = new Date().toLocaleTimeString();
138
+ const schemaInfo = await db.getSchemaInfo();
139
+ // Show periodic status
140
+ if (Date.now() % (intervalMs * 10) < intervalMs) {
141
+ console.log(chalk_1.default.gray(`[${timestamp}] Monitoring active - ${schemaInfo.tables.length} tables`));
142
+ }
143
+ // Periodic optimization if auto-optimize is enabled
144
+ if (autoOptimize &&
145
+ Date.now() - lastOptimizationTime > optimizationInterval) {
146
+ console.log(chalk_1.default.blue(`\nšŸ”„ Periodic optimization check at ${timestamp}`));
132
147
  const metrics = await db.getSQLitePerformanceMetrics();
133
148
  const indexRecs = await db.getSQLiteIndexRecommendations();
134
149
  if (indexRecs.recommendations.length > 0) {
135
150
  console.log(chalk_1.default.yellow(`šŸ’” Found ${indexRecs.recommendations.length} new index recommendations`));
136
- if (autoIndex) {
137
- console.log(chalk_1.default.gray('Run optimize command to apply index recommendations'));
138
- }
139
151
  }
140
- // Check if optimization is needed
141
152
  if (metrics.cacheHitRate < 0.8 || metrics.averageQueryTime > 100) {
142
153
  console.log(chalk_1.default.yellow('āš ļø Performance degradation detected, running optimization...'));
143
154
  const result = await db.getSQLiteOptimizations();
144
155
  console.log(chalk_1.default.green(`āœ… Generated ${result.appliedOptimizations.length} performance optimization recommendations`));
145
156
  }
146
- else {
147
- console.log(chalk_1.default.green('āœ… Performance metrics look good'));
148
- }
149
157
  lastOptimizationTime = Date.now();
150
158
  }
151
- catch (error) {
152
- console.error(chalk_1.default.red('āŒ Periodic optimization failed:'), error instanceof Error ? error.message : error);
153
- }
154
159
  }
155
- // Show periodic status
156
- if (Date.now() % (intervalMs * 10) < intervalMs) {
157
- const timestamp = new Date().toLocaleTimeString();
158
- try {
159
- const schemaInfo = await db.getSchemaInfo();
160
- console.log(chalk_1.default.gray(`[${timestamp}] Monitoring active - ${schemaInfo.tables.length} tables`));
161
- }
162
- catch (e) {
163
- console.log(chalk_1.default.gray(`[${timestamp}] Monitoring active`));
160
+ catch (error) {
161
+ retryCount++;
162
+ const backoff = Math.min(30000, intervalMs * Math.pow(2, retryCount));
163
+ console.error(chalk_1.default.red(`\nāŒ Watcher interrupted (${retryCount}/${maxRetries}):`), error instanceof Error ? error.message : String(error));
164
+ if (retryCount >= maxRetries) {
165
+ console.error(chalk_1.default.red.bold('CRITICAL: Max retries exceeded. Schema watcher terminating.'));
166
+ shutdown();
167
+ return;
164
168
  }
169
+ console.log(chalk_1.default.yellow(`ā³ Retrying in ${backoff}ms...`));
170
+ // Note: interval remains same but we skip logic via retryCount logic or we could re-init
165
171
  }
166
172
  }, intervalMs);
167
173
  // Handle graceful shutdown
@@ -40,16 +40,26 @@ class SqliteIntrospector extends database_introspector_js_1.DatabaseIntrospector
40
40
  }
41
41
  async #getTableMetadata(options) {
42
42
  const tablesResult = await this.#tablesQuery(this.#db, options).execute();
43
- // Get column metadata for each table separately since PRAGMA doesn't work in joins
43
+ // Unified Discovery: Get columns, indexes, and foreign keys for each table
44
44
  const columnsByTable = {};
45
+ const indexesByTable = {};
46
+ const fksByTable = {};
45
47
  for (const table of tablesResult) {
46
48
  try {
47
- const columns = await (0, sql_js_1.sql) `PRAGMA table_info(${sql_js_1.sql.lit(table.name)})`.execute(this.#db);
49
+ const [columns, indexes, fks] = await Promise.all([
50
+ (0, sql_js_1.sql) `PRAGMA table_info(${sql_js_1.sql.lit(table.name)})`.execute(this.#db),
51
+ this.getIndexes(table.name),
52
+ this.getForeignKeys(table.name),
53
+ ]);
48
54
  columnsByTable[table.name] = columns.rows;
55
+ indexesByTable[table.name] = indexes;
56
+ fksByTable[table.name] = fks;
49
57
  }
50
58
  catch (error) {
51
- console.warn(`Failed to get columns for table ${table.name}:`, error);
59
+ console.warn(`Failed to introspect table ${table.name}:`, error);
52
60
  columnsByTable[table.name] = [];
61
+ indexesByTable[table.name] = [];
62
+ fksByTable[table.name] = [];
53
63
  }
54
64
  }
55
65
  return tablesResult.map(({ name, sql, type }) => {
@@ -68,8 +78,8 @@ class SqliteIntrospector extends database_introspector_js_1.DatabaseIntrospector
68
78
  defaultValue: col.dflt_value,
69
79
  isPrimaryKey: col.pk > 0,
70
80
  })),
71
- indexes: [],
72
- foreignKeys: [],
81
+ indexes: indexesByTable[name] || [],
82
+ foreignKeys: fksByTable[name] || [],
73
83
  };
74
84
  });
75
85
  }
@@ -198,6 +198,7 @@ class AgentSchemaHelper {
198
198
  .addColumn('id', 'integer', (col) => col.primaryKey().autoIncrement())
199
199
  .addColumn('name', 'text', (col) => col.notNull().unique())
200
200
  .addColumn('role', 'text')
201
+ .addColumn('status', 'text', (col) => col.notNull().defaultTo('active'))
201
202
  .addColumn('capabilities', 'text')
202
203
  .addColumn('policies', 'text')
203
204
  .addColumn('metadata', 'text')