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
@@ -22,62 +22,69 @@ export class HiveLink {
22
22
  * Promote high-confidence local knowledge to global "Hive" knowledge.
23
23
  * This creates a new, session-agnostic entry or updates an existing global one.
24
24
  */
25
- async broadcastKnowledge(minConfidence = 0.9) {
26
- console.log(`[HiveLink] Broadcasting knowledge with confidence >= ${minConfidence}`);
25
+ async broadcastKnowledge(options = {}) {
26
+ const minConfidence = options.minConfidence ?? 0.9;
27
+ const limit = options.limit ?? 100;
28
+ const offset = options.offset ?? 0;
29
+ console.log(`[HiveLink] Broadcasting knowledge (limit=${limit}, offset=${offset}) with confidence >= ${minConfidence}`);
27
30
  // Find high-confidence items that are "local" (have a source_session_id)
28
31
  const items = (await this.typedDb
29
32
  .selectFrom(this.knowledgeTable)
30
33
  .selectAll()
31
34
  .where('confidence', '>=', minConfidence)
32
35
  .where('source_session_id', 'is not', null) // Only local items
36
+ .limit(limit)
37
+ .offset(offset)
33
38
  .execute());
34
39
  let promotedCount = 0;
35
40
  for (const item of items) {
36
- // Check if a global version already exists
37
- const existingGlobal = await this.typedDb
38
- .selectFrom(this.knowledgeTable)
39
- .selectAll()
40
- .where('entity', '=', item.entity)
41
- .where('fact', '=', item.fact)
42
- .where('source_session_id', 'is', null)
43
- .executeTakeFirst();
44
- if (existingGlobal) {
45
- // Reinforce existing global knowledge
46
- // Calculate new confidence: average of existing and new, heavily weighted towards max
47
- const newConfidence = Math.min(0.99, Math.max(existingGlobal.confidence, item.confidence) + 0.01);
48
- await this.db
49
- .updateTable(this.knowledgeTable)
50
- .set({
51
- confidence: newConfidence,
52
- updated_at: new Date(),
53
- })
54
- .where('id', '=', existingGlobal.id)
55
- .execute();
56
- }
57
- else {
58
- // Create new global knowledge
59
- const tags = item.tags ? [...item.tags] : [];
60
- if (!tags.includes('hive_mind'))
61
- tags.push('hive_mind');
62
- await this.db
63
- .insertInto(this.knowledgeTable)
64
- .values({
65
- entity: item.entity,
66
- fact: item.fact,
67
- confidence: item.confidence, // Carry over confidence
68
- source_session_id: null, // Global
69
- tags: JSON.stringify(tags),
70
- metadata: JSON.stringify({
71
- ...item.metadata,
72
- promoted_from: item.id,
73
- promoted_at: new Date(),
74
- }),
75
- created_at: new Date(),
76
- updated_at: new Date(),
77
- })
78
- .execute();
79
- promotedCount++;
80
- }
41
+ await this.db.transaction().execute(async (trx) => {
42
+ // Check if a global version already exists
43
+ const existingGlobal = await trx
44
+ .selectFrom(this.knowledgeTable)
45
+ .selectAll()
46
+ .where('entity', '=', item.entity)
47
+ .where('fact', '=', item.fact)
48
+ .where('source_session_id', 'is', null)
49
+ .forUpdate() // Audit Phase 15: prevent concurrent promotion duplication
50
+ .executeTakeFirst();
51
+ if (existingGlobal) {
52
+ // Reinforce existing global knowledge
53
+ const newConfidence = Math.min(0.99, Math.max(existingGlobal.confidence, item.confidence) + 0.01);
54
+ await trx
55
+ .updateTable(this.knowledgeTable)
56
+ .set({
57
+ confidence: newConfidence,
58
+ updated_at: new Date(),
59
+ })
60
+ .where('id', '=', existingGlobal.id)
61
+ .execute();
62
+ }
63
+ else {
64
+ // Create new global knowledge
65
+ const tags = item.tags ? [...item.tags] : [];
66
+ if (!tags.includes('hive_mind'))
67
+ tags.push('hive_mind');
68
+ await trx
69
+ .insertInto(this.knowledgeTable)
70
+ .values({
71
+ entity: item.entity,
72
+ fact: item.fact,
73
+ confidence: item.confidence,
74
+ source_session_id: null,
75
+ tags: JSON.stringify(tags),
76
+ metadata: JSON.stringify({
77
+ ...item.metadata,
78
+ promoted_from: item.id,
79
+ promoted_at: new Date(),
80
+ }),
81
+ created_at: new Date(),
82
+ updated_at: new Date(),
83
+ })
84
+ .execute();
85
+ promotedCount++;
86
+ }
87
+ });
81
88
  }
82
89
  return promotedCount;
83
90
  }
@@ -102,8 +109,8 @@ export class HiveLink {
102
109
  return Number(result[0]?.numUpdatedRows ?? 1);
103
110
  }
104
111
  /**
105
- * Propagate high-performing capabilities globally and block known-bad ones.
106
- * High-Throughput Refactor: Batch updates and optimized set-based checks.
112
+ * Propagate high-performing capabilities globally using the "Sovereign Draft" protocol.
113
+ * Uses Bayesian Convergence and Shadow Promotion to avoid deadlocks.
107
114
  */
108
115
  async broadcastSkills() {
109
116
  if (!this.config.evolution?.enableHiveLink &&
@@ -111,81 +118,96 @@ export class HiveLink {
111
118
  console.log('[HiveLink] Skill broadcasting disabled by config.');
112
119
  return 0;
113
120
  }
114
- console.log(`[HiveLink] Broadcasting emergent skills across the Hive (Performance-Aware)...`);
121
+ console.log(`[HiveLink] Executing Sovereign Draft for emergent skills...`);
115
122
  let broadcastCount = 0;
116
123
  const capTable = this.config.capabilitiesTable || 'agent_capabilities';
117
- await this.db.transaction().execute(async (trx) => {
118
- // 1. Resolve Verified Skills with "Survival of the Fittest" logic
119
- const verifiedSkills = await this.cortex.capabilities.getCapabilities('verified');
120
- for (const skill of verifiedSkills) {
121
- const meta = typeof skill.metadata === 'string'
122
- ? JSON.parse(skill.metadata)
123
- : skill.metadata || {};
124
- if (meta.broadcasted)
125
- continue;
126
- // Check for competing global versions
127
- const baseName = meta.mutatedFrom || skill.name;
128
- const competitor = await trx
124
+ // 1. Resolve Verified Skills with Bayesian "Alpha" selection
125
+ const verifiedSkills = await this.cortex.capabilities.getCapabilities('verified');
126
+ // Group verified skills by lineage (base tool name)
127
+ const lineageGroups = new Map();
128
+ for (const skill of verifiedSkills) {
129
+ const meta = typeof skill.metadata === 'string' ? JSON.parse(skill.metadata) : (skill.metadata || {});
130
+ const lineage = meta.lineage || skill.name;
131
+ if (!lineageGroups.has(lineage))
132
+ lineageGroups.set(lineage, []);
133
+ lineageGroups.get(lineage).push({ skill, meta });
134
+ }
135
+ for (const [lineage, variants] of lineageGroups.entries()) {
136
+ // Bayesian Winner Selection
137
+ // Score = (anchored_reliability * totalCount + K * prior) / (totalCount + K)
138
+ // For simplicity, we use anchored_reliability which already incorporates this weighting
139
+ const alphaCandidate = variants.reduce((prev, curr) => {
140
+ const pAnchored = prev.meta.anchored_reliability ?? 0;
141
+ const cAnchored = curr.meta.anchored_reliability ?? 0;
142
+ return cAnchored > pAnchored ? curr : prev;
143
+ });
144
+ // Non-Blocking Set Update: Flag Alpha and Shadow versions
145
+ await this.db.transaction().execute(async (trx) => {
146
+ const currentMeta = alphaCandidate.meta || {};
147
+ const updatedMeta = {
148
+ ...currentMeta,
149
+ is_alpha: true,
150
+ broadcasted: true,
151
+ broadcasted_at: new Date()
152
+ };
153
+ // Flag the winner as Alpha
154
+ // Audit Phase 15: Lock candidate before promotion
155
+ const winner = await trx
129
156
  .selectFrom(capTable)
130
- .selectAll()
131
- .where('name', 'like', `%${baseName}%`)
132
- .where('status', '=', 'verified')
133
- .where('id', '!=', skill.id)
157
+ .select('id')
158
+ .where('id', '=', alphaCandidate.skill.id)
159
+ .forUpdate()
134
160
  .executeTakeFirst();
135
- let shouldBroadcast = true;
136
- if (competitor) {
137
- const comp = competitor;
138
- const compRel = comp.reliability || 0;
139
- // Performance-Based Conflict Resolution: Only broadcast if reliability is strictly better
140
- // or if it's a direct version upgrade with equal/better reliability
141
- const isNewer = this.compareVersions(skill.version, comp.version) > 0;
142
- if (compRel > skill.reliability) {
143
- shouldBroadcast = false;
144
- }
145
- else if (compRel === skill.reliability && !isNewer) {
146
- shouldBroadcast = false;
147
- }
148
- }
149
- if (shouldBroadcast) {
161
+ if (winner) {
150
162
  await trx
151
163
  .updateTable(capTable)
152
164
  .set({
153
- metadata: JSON.stringify({
154
- ...meta,
155
- broadcasted: true,
156
- hive_verified: true,
157
- broadcasted_at: new Date(),
158
- conflict_resolved: !!competitor,
159
- }),
165
+ metadata: JSON.stringify(updatedMeta),
160
166
  })
161
- .where('id', '=', skill.id)
167
+ .where('id', '=', winner.id)
162
168
  .execute();
163
- broadcastCount++;
164
169
  }
165
- }
166
- // 2. Broadcast Blacklisted Skills (Immediate Immune Propagations)
167
- const blacklisted = await this.cortex.capabilities.getCapabilities('blacklisted');
168
- for (const skill of blacklisted) {
169
- const meta = typeof skill.metadata === 'string'
170
- ? JSON.parse(skill.metadata)
171
- : skill.metadata || {};
172
- if (!meta.broadcasted) {
173
- await trx
174
- .updateTable(capTable)
175
- .set({
176
- metadata: JSON.stringify({
177
- ...meta,
178
- broadcasted: true,
179
- hive_blacklisted: true,
180
- blocked_at: new Date(),
181
- }),
182
- })
183
- .where('id', '=', skill.id)
184
- .execute();
185
- broadcastCount++;
170
+ // Flag others in the same lineage as Shadow (Dialect-safe approach)
171
+ const shadowIds = variants
172
+ .filter(v => v.skill.id !== alphaCandidate.skill.id)
173
+ .map(v => v.skill.id);
174
+ if (shadowIds.length > 0) {
175
+ // We fetch and update individually or use a bulk update if the dialect supports complex JSON manipulation.
176
+ // For maximum compatibility (Postgres/SQLite), we do it in a loop for the shadows if the count is small.
177
+ for (const sid of shadowIds) {
178
+ const sMatch = variants.find(v => v.skill.id === sid);
179
+ const sMeta = sMatch?.meta || {};
180
+ await trx.updateTable(capTable)
181
+ .set({
182
+ metadata: JSON.stringify({ ...sMeta, is_alpha: false, is_shadow: true }),
183
+ status: 'experimental'
184
+ })
185
+ .where('id', '=', sid)
186
+ .execute();
187
+ }
186
188
  }
187
- }
188
- });
189
+ });
190
+ broadcastCount += variants.length;
191
+ }
192
+ // 2. Broadcast Blacklisted Skills (Immune Prophet)
193
+ const blacklisted = await this.cortex.capabilities.getCapabilities('blacklisted');
194
+ const blackIDs = blacklisted
195
+ .filter(s => {
196
+ const meta = typeof s.metadata === 'string' ? JSON.parse(s.metadata) : (s.metadata || {});
197
+ return !meta.broadcasted;
198
+ })
199
+ .map(s => s.id);
200
+ if (blackIDs.length > 0) {
201
+ await this.db
202
+ .updateTable(capTable)
203
+ .set({
204
+ metadata: sql `json_set(metadata, '$.broadcasted', true, '$.hive_blacklisted', true)`,
205
+ updated_at: new Date()
206
+ })
207
+ .where('id', 'in', blackIDs)
208
+ .execute();
209
+ broadcastCount += blackIDs.length;
210
+ }
189
211
  return broadcastCount;
190
212
  }
191
213
  /**
@@ -101,6 +101,7 @@ export class KnowledgeDistiller {
101
101
  return this.parseKnowledge(updated);
102
102
  }
103
103
  // Conflict Detection: Check if a similar entity has a conflicting fact
104
+ // Audit Phase 11: Explicit transaction propagation
104
105
  await this.challengeKnowledge(entity, fact, confidence, trx);
105
106
  // Create new
106
107
  const initialMeta = {
@@ -195,35 +196,38 @@ export class KnowledgeDistiller {
195
196
  * Record a retrieval hit for a knowledge item.
196
197
  */
197
198
  async recordHit(id) {
198
- const existing = await this.typedDb
199
- .selectFrom(this.knowledgeTable)
200
- .selectAll()
201
- .where('id', '=', id)
202
- .executeTakeFirst();
203
- if (!existing)
204
- return;
205
- const metadata = typeof existing.metadata === 'string'
206
- ? JSON.parse(existing.metadata)
207
- : existing.metadata || {};
208
- metadata.hit_count = (metadata.hit_count || 0) + 1;
209
- metadata.last_retrieved_at = new Date().toISOString();
210
- await this.db
211
- .updateTable(this.knowledgeTable)
212
- .set({
213
- metadata: JSON.stringify(metadata),
214
- updated_at: new Date(),
215
- })
216
- .where('id', '=', id)
217
- .execute();
218
- // Production Hardening: Emit a metric event for this hit to enable efficient hotspot detection
219
- await this.db
220
- .insertInto(this.config.metricsTable || 'agent_metrics')
221
- .values({
222
- metric_name: `entity_hit_${existing.entity}`,
223
- metric_value: 1,
224
- created_at: new Date(),
225
- })
226
- .execute();
199
+ await this.db.transaction().execute(async (trx) => {
200
+ const existing = await trx
201
+ .selectFrom(this.knowledgeTable)
202
+ .selectAll()
203
+ .where('id', '=', id)
204
+ .forUpdate() // Audit Phase 11: Atomic hit record
205
+ .executeTakeFirst();
206
+ if (!existing)
207
+ return;
208
+ const metadata = typeof existing.metadata === 'string'
209
+ ? JSON.parse(existing.metadata)
210
+ : existing.metadata || {};
211
+ metadata.hit_count = (metadata.hit_count || 0) + 1;
212
+ metadata.last_retrieved_at = new Date().toISOString();
213
+ await trx
214
+ .updateTable(this.knowledgeTable)
215
+ .set({
216
+ metadata: JSON.stringify(metadata),
217
+ updated_at: new Date(),
218
+ })
219
+ .where('id', '=', id)
220
+ .execute();
221
+ // Production Hardening: Emit a metric event for this hit to enable efficient hotspot detection
222
+ await trx
223
+ .insertInto(this.config.metricsTable || 'agent_metrics')
224
+ .values({
225
+ metric_name: `entity_hit_${existing.entity}`,
226
+ metric_value: 1,
227
+ created_at: new Date(),
228
+ })
229
+ .execute();
230
+ });
227
231
  }
228
232
  /**
229
233
  * Calculate the "Fitness" of a memory item.
@@ -246,6 +250,8 @@ export class KnowledgeDistiller {
246
250
  * we degrade the confidence of the old facts.
247
251
  */
248
252
  async challengeKnowledge(entity, competingFact, confidence, trxOrDb = this.db) {
253
+ // Audit Phase 11: Semantic sanitization of competing fact
254
+ const safeFact = competingFact.slice(0, 500).replace(/[\u0000-\u001F\u007F-\u009F]/g, '').replace(/<\|.*?\|>/g, '');
249
255
  const query = trxOrDb
250
256
  .selectFrom(this.knowledgeTable)
251
257
  .selectAll()
@@ -267,7 +273,7 @@ export class KnowledgeDistiller {
267
273
  newStatus = 'disputed';
268
274
  newMeta = {
269
275
  ...newMeta,
270
- status_reason: `Contradicted by: ${competingFact}`,
276
+ status_reason: `Contradicted by: ${safeFact}`,
271
277
  };
272
278
  penalty = 0.1;
273
279
  }
@@ -275,7 +281,7 @@ export class KnowledgeDistiller {
275
281
  newStatus = 'deprecated';
276
282
  newMeta = {
277
283
  ...newMeta,
278
- status_reason: `Superseded by: ${competingFact}`,
284
+ status_reason: `Superseded by: ${safeFact}`,
279
285
  };
280
286
  penalty = 0.4;
281
287
  }
@@ -416,22 +422,24 @@ export class KnowledgeDistiller {
416
422
  */
417
423
  async consolidateKnowledge() {
418
424
  let totalMerged = 0;
419
- // Find entities with multiple facts
425
+ // Find entities with multiple facts (Paginated to handle scale)
420
426
  const candidates = await this.db
421
427
  .selectFrom(this.knowledgeTable)
422
428
  .select('entity')
423
429
  .groupBy('entity')
424
430
  .having((eb) => eb.fn.count('id'), '>', 1)
431
+ .limit(500) // Audit Phase 11: Chunked search
425
432
  .execute();
426
433
  for (const cand of candidates) {
427
434
  const entity = cand.entity;
428
435
  const items = await this.getKnowledgeByEntity(entity);
429
- // Iterative merging inside the entity bucket
436
+ // Iterative merging inside the entity bucket (Paginated check)
430
437
  const mergedIds = new Set();
431
- for (let i = 0; i < items.length; i++) {
438
+ const iterLimit = Math.min(items.length, 100);
439
+ for (let i = 0; i < iterLimit; i++) {
432
440
  if (mergedIds.has(items[i].id))
433
441
  continue;
434
- for (let j = i + 1; j < items.length; j++) {
442
+ for (let j = i + 1; j < iterLimit; j++) {
435
443
  if (mergedIds.has(items[j].id))
436
444
  continue;
437
445
  const sim = calculateSimilarity(items[i].fact, items[j].fact);
@@ -0,0 +1,41 @@
1
+ import type { Kysely } from '../../kysely.js';
2
+ import type { AgenticConfig } from '../../types/index.js';
3
+ import type { Cortex } from '../Cortex.js';
4
+ /**
5
+ * QuotaManager enforces resource limits across personas and swarms.
6
+ */
7
+ export declare class QuotaManager {
8
+ private db;
9
+ private cortex;
10
+ private config;
11
+ private resourcesTable;
12
+ private metricsTable;
13
+ private rateCache;
14
+ private readonly CACHE_TTL;
15
+ constructor(db: Kysely<any>, cortex: Cortex, config?: AgenticConfig);
16
+ /**
17
+ * Check if a quota is violated for a given target.
18
+ */
19
+ checkQuota(targetType: 'persona' | 'swarm' | 'global', targetId?: string | null): Promise<{
20
+ allowed: boolean;
21
+ reason?: string;
22
+ }>;
23
+ /**
24
+ * Fetches active quotas for a given target.
25
+ */
26
+ private getActiveQuotas;
27
+ /**
28
+ * Calculates current usage for a specific quota window.
29
+ */
30
+ private getCurrentUsage;
31
+ /**
32
+ * Resolves exchange rate via persistent metric store or live update.
33
+ * Implements a true Oracle pattern for resource normalization.
34
+ */
35
+ private getExchangeRate;
36
+ /**
37
+ * Manually sync exchange rates from an external provider (Oracle pulse).
38
+ */
39
+ syncExchangeRates(rates: Record<string, number>): Promise<void>;
40
+ private getPeriodInMs;
41
+ }
@@ -0,0 +1,182 @@
1
+ /// <reference types="./QuotaManager.d.ts" />
2
+ import { sql } from '../../raw-builder/sql.js';
3
+ /**
4
+ * QuotaManager enforces resource limits across personas and swarms.
5
+ */
6
+ export class QuotaManager {
7
+ db;
8
+ cortex;
9
+ config;
10
+ resourcesTable;
11
+ metricsTable;
12
+ rateCache = new Map();
13
+ CACHE_TTL = 1000 * 60 * 60; // 1 hour cache
14
+ constructor(db, cortex, config = {}) {
15
+ this.db = db;
16
+ this.cortex = cortex;
17
+ this.config = config;
18
+ this.resourcesTable = config.resourcesTable || 'agent_resource_usage';
19
+ this.metricsTable = config.metricsTable || 'agent_metrics';
20
+ }
21
+ /**
22
+ * Check if a quota is violated for a given target.
23
+ */
24
+ async checkQuota(targetType, targetId = null) {
25
+ const quotas = await this.getActiveQuotas(targetType, targetId);
26
+ for (const quota of quotas) {
27
+ const usage = await this.getCurrentUsage(quota);
28
+ // Currency Conversion Logic: Convert usage to target currency if specified
29
+ let normalizedUsage = usage;
30
+ if (quota.metric === 'cost' && quota.metadata?.currency && quota.metadata.currency !== 'USD') {
31
+ const rate = await this.getExchangeRate(quota.metadata.currency);
32
+ normalizedUsage = usage * rate;
33
+ }
34
+ if (normalizedUsage >= quota.limit) {
35
+ const limitStr = quota.metric === 'cost'
36
+ ? `${quota.metadata?.currency || '$'}${quota.limit}`
37
+ : `${quota.limit}`;
38
+ return {
39
+ allowed: false,
40
+ reason: `Quota exceeded: ${quota.metric} limit is ${limitStr}, current is ${normalizedUsage.toFixed(4)} (${quota.period})`
41
+ };
42
+ }
43
+ }
44
+ return { allowed: true };
45
+ }
46
+ /**
47
+ * Fetches active quotas for a given target.
48
+ */
49
+ async getActiveQuotas(targetType, targetId) {
50
+ const quotas = [];
51
+ // 1. Fetch from PolicyEnforcer (Global & Type-specific)
52
+ const policies = await this.cortex.policies.getActivePolicies();
53
+ for (const policy of policies) {
54
+ if (policy.type === 'budget' &&
55
+ (policy.definition.targetType === targetType ||
56
+ (!policy.definition.targetType && targetType === 'global'))) {
57
+ quotas.push({
58
+ id: policy.id,
59
+ targetType: targetType,
60
+ targetId: targetId,
61
+ metric: policy.definition.metric || 'cost',
62
+ limit: policy.definition.limit || 0,
63
+ period: policy.definition.period || 'hourly',
64
+ currentUsage: 0,
65
+ createdAt: policy.createdAt,
66
+ updatedAt: policy.updatedAt,
67
+ metadata: policy.metadata
68
+ });
69
+ }
70
+ }
71
+ // 2. Fetch from Persona metadata (Specific override)
72
+ if (targetType === 'persona' && targetId) {
73
+ const persona = await this.db
74
+ .selectFrom(this.config.personasTable || 'agent_personas')
75
+ .select('metadata')
76
+ .where('id', '=', targetId)
77
+ .executeTakeFirst();
78
+ if (persona) {
79
+ const meta = typeof persona.metadata === 'string'
80
+ ? JSON.parse(persona.metadata)
81
+ : persona.metadata || {};
82
+ if (meta.quotas) {
83
+ quotas.push(...meta.quotas);
84
+ }
85
+ }
86
+ }
87
+ return quotas;
88
+ }
89
+ /**
90
+ * Calculates current usage for a specific quota window.
91
+ */
92
+ async getCurrentUsage(quota) {
93
+ const windowMs = this.getPeriodInMs(quota.period);
94
+ const startTime = new Date(Date.now() - windowMs);
95
+ let query = this.db
96
+ .selectFrom(this.resourcesTable)
97
+ .where('created_at', '>', startTime);
98
+ if (quota.targetType === 'persona' && quota.targetId) {
99
+ query = query.where('agent_id', '=', quota.targetId);
100
+ }
101
+ else if (quota.targetType === 'swarm' && quota.targetId) {
102
+ // PRODUCTION HARDENING: Efficient JSON filtering
103
+ query = query.where((eb) => eb.or([
104
+ eb(sql `json_extract(metadata, '$.swarm_id')`, '=', quota.targetId),
105
+ eb(sql `metadata->>'swarm_id'`, '=', String(quota.targetId))
106
+ ]));
107
+ }
108
+ const metricField = quota.metric === 'cost' ? 'cost' :
109
+ quota.metric === 'tokens_input' ? 'input_tokens' :
110
+ quota.metric === 'tokens_output' ? 'output_tokens' :
111
+ sql `input_tokens + output_tokens`;
112
+ const result = await query
113
+ .select((eb) => eb.fn.sum(metricField).as('total'))
114
+ .executeTakeFirst();
115
+ const usage = Number(result?.total || 0);
116
+ // Audit Phase 7: Floating-point drift protection
117
+ const epsilon = 1e-10;
118
+ return usage < epsilon ? 0 : usage;
119
+ }
120
+ /**
121
+ * Resolves exchange rate via persistent metric store or live update.
122
+ * Implements a true Oracle pattern for resource normalization.
123
+ */
124
+ async getExchangeRate(currency) {
125
+ // 1. Check in-memory cache
126
+ const cached = this.rateCache.get(currency);
127
+ if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
128
+ return cached.rate;
129
+ }
130
+ // 2. Check persistent metric store
131
+ const record = await this.db
132
+ .selectFrom(this.metricsTable)
133
+ .select(['metric_value', 'created_at'])
134
+ .where('metric_name', '=', `exchange_rate_${currency}`)
135
+ .orderBy('created_at', 'desc')
136
+ .executeTakeFirst();
137
+ if (record && Date.now() - new Date(record.created_at).getTime() < this.CACHE_TTL * 24) {
138
+ const rate = Number(record.metric_value);
139
+ this.rateCache.set(currency, { rate, timestamp: Date.now() });
140
+ return rate;
141
+ }
142
+ // 3. Fallback to base rates if unreachable (Statically hardened)
143
+ const baseRates = {
144
+ 'ETH': 0.00032,
145
+ 'BTC': 0.000015,
146
+ 'EUR': 0.92,
147
+ 'GBP': 0.79
148
+ };
149
+ const fallback = baseRates[currency] || 1.0;
150
+ // Log the need for sync
151
+ console.warn(`[QuotaManager] Exchange rate for ${currency} is stale or missing. Using hardened fallback: ${fallback}`);
152
+ return fallback;
153
+ }
154
+ /**
155
+ * Manually sync exchange rates from an external provider (Oracle pulse).
156
+ */
157
+ async syncExchangeRates(rates) {
158
+ await this.db.transaction().execute(async (trx) => {
159
+ for (const [currency, rate] of Object.entries(rates)) {
160
+ await trx
161
+ .insertInto(this.metricsTable)
162
+ .values({
163
+ metric_name: `exchange_rate_${currency}`,
164
+ metric_value: rate,
165
+ created_at: new Date()
166
+ })
167
+ .execute();
168
+ this.rateCache.set(currency, { rate, timestamp: Date.now() });
169
+ }
170
+ });
171
+ console.log(`[QuotaManager] Synchronized ${Object.keys(rates).length} exchange rates.`);
172
+ }
173
+ getPeriodInMs(period) {
174
+ switch (period) {
175
+ case 'hourly': return 3600000;
176
+ case 'daily': return 86400000;
177
+ case 'monthly': return 86400000 * 30;
178
+ case 'infinite': return Date.now();
179
+ default: return 3600000;
180
+ }
181
+ }
182
+ }