noormme 1.2.4 → 1.2.6

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 (45) hide show
  1. package/dist/cjs/agentic/CapabilityManager.js +4 -8
  2. package/dist/cjs/agentic/EpisodicMemory.js +4 -3
  3. package/dist/cjs/agentic/PersonaManager.js +4 -8
  4. package/dist/cjs/agentic/PolicyEnforcer.js +4 -7
  5. package/dist/cjs/agentic/ResourceMonitor.js +2 -1
  6. package/dist/cjs/agentic/SessionManager.js +7 -6
  7. package/dist/cjs/agentic/improvement/AblationEngine.d.ts +0 -4
  8. package/dist/cjs/agentic/improvement/AblationEngine.js +4 -14
  9. package/dist/cjs/agentic/improvement/ActionRefiner.js +3 -7
  10. package/dist/cjs/agentic/improvement/ConflictResolver.js +4 -3
  11. package/dist/cjs/agentic/improvement/GoalArchitect.js +10 -9
  12. package/dist/cjs/agentic/improvement/KnowledgeDistiller.js +4 -3
  13. package/dist/cjs/agentic/improvement/SelfEvolution.d.ts +3 -2
  14. package/dist/cjs/agentic/improvement/SelfEvolution.js +11 -6
  15. package/dist/cjs/agentic/improvement/SelfTestRegistry.js +3 -7
  16. package/dist/cjs/agentic/improvement/governance/PersonaAuditor.js +4 -8
  17. package/dist/cjs/agentic/improvement/hive/KnowledgePromoter.js +4 -3
  18. package/dist/cjs/agentic/improvement/hive/SkillPropagator.js +1 -1
  19. package/dist/cjs/agentic/util/db-utils.d.ts +4 -0
  20. package/dist/cjs/agentic/util/db-utils.js +27 -0
  21. package/dist/cjs/helpers/agent-schema.js +1 -0
  22. package/dist/cjs/testing/test-utils.js +2 -0
  23. package/dist/esm/agentic/CapabilityManager.js +4 -8
  24. package/dist/esm/agentic/EpisodicMemory.js +4 -3
  25. package/dist/esm/agentic/PersonaManager.js +4 -8
  26. package/dist/esm/agentic/PolicyEnforcer.js +4 -7
  27. package/dist/esm/agentic/ResourceMonitor.js +2 -1
  28. package/dist/esm/agentic/SessionManager.js +7 -6
  29. package/dist/esm/agentic/improvement/AblationEngine.d.ts +0 -4
  30. package/dist/esm/agentic/improvement/AblationEngine.js +4 -14
  31. package/dist/esm/agentic/improvement/ActionRefiner.js +3 -7
  32. package/dist/esm/agentic/improvement/ConflictResolver.js +4 -3
  33. package/dist/esm/agentic/improvement/GoalArchitect.js +10 -9
  34. package/dist/esm/agentic/improvement/KnowledgeDistiller.js +4 -3
  35. package/dist/esm/agentic/improvement/SelfEvolution.d.ts +3 -2
  36. package/dist/esm/agentic/improvement/SelfEvolution.js +11 -6
  37. package/dist/esm/agentic/improvement/SelfTestRegistry.js +3 -7
  38. package/dist/esm/agentic/improvement/governance/PersonaAuditor.js +4 -8
  39. package/dist/esm/agentic/improvement/hive/KnowledgePromoter.js +4 -3
  40. package/dist/esm/agentic/improvement/hive/SkillPropagator.js +1 -1
  41. package/dist/esm/agentic/util/db-utils.d.ts +4 -0
  42. package/dist/esm/agentic/util/db-utils.js +25 -0
  43. package/dist/esm/helpers/agent-schema.js +1 -0
  44. package/dist/esm/testing/test-utils.js +2 -0
  45. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CapabilityManager = void 0;
4
+ const db_utils_js_1 = require("./util/db-utils.js");
4
5
  /**
5
6
  * CapabilityManager tracks the skills (tools) available to an agent
6
7
  * and their historical reliability.
@@ -88,18 +89,13 @@ class CapabilityManager {
88
89
  */
89
90
  async reportOutcome(name, success, trxOrDb = this.db) {
90
91
  const runner = async (trx) => {
91
- let query = trx
92
+ const baseQuery = trx
92
93
  .selectFrom(this.capabilitiesTable)
93
94
  .selectAll()
94
95
  .where('name', '=', name)
95
96
  .orderBy('updated_at', 'desc');
96
- // PRODUCTION HARDENING: Lock row to prevent RMW race (Skip for SQLite)
97
- const executor = trx.getExecutor();
98
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
99
- if (!adapterName.toLowerCase().includes('sqlite')) {
100
- query = query.forUpdate();
101
- }
102
- const capability = await query.executeTakeFirst();
97
+ const capability = await (0, db_utils_js_1.withLock)(baseQuery, trx)
98
+ .executeTakeFirst();
103
99
  if (capability) {
104
100
  const cap = capability;
105
101
  const metadata = typeof cap.metadata === 'string'
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EpisodicMemory = void 0;
4
+ const db_utils_js_1 = require("./util/db-utils.js");
4
5
  /**
5
6
  * EpisodicMemory groups interactions into semantic chunks (episodes),
6
7
  * allowing agents to recall specific scenarios and their outcomes.
@@ -39,11 +40,11 @@ class EpisodicMemory {
39
40
  */
40
41
  async completeEpisode(episodeId, summary, metadata) {
41
42
  return await this.db.transaction().execute(async (trx) => {
42
- const existing = await trx
43
+ const query = trx
43
44
  .selectFrom(this.episodesTable)
44
45
  .selectAll()
45
- .where('id', '=', episodeId)
46
- .forUpdate() // Audit Phase 12: Atomic completion lock
46
+ .where('id', '=', episodeId);
47
+ const existing = await (0, db_utils_js_1.withLock)(query, trx) // Audit Phase 12: Atomic completion lock
47
48
  .executeTakeFirst();
48
49
  if (!existing)
49
50
  throw new Error(`Episode with ID ${episodeId} not found`);
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PersonaManager = void 0;
4
+ const db_utils_js_1 = require("./util/db-utils.js");
4
5
  /**
5
6
  * PersonaManager handles persistent agent identities that bridge multiple sessions.
6
7
  */
@@ -21,17 +22,12 @@ class PersonaManager {
21
22
  */
22
23
  async upsertPersona(name, options = {}, trxOrDb = this.db) {
23
24
  const runner = async (trx) => {
24
- let query = trx
25
+ const baseQuery = trx
25
26
  .selectFrom(this.personasTable)
26
27
  .selectAll()
27
28
  .where('name', '=', name);
28
- // Audit Phase 13: Atomic identity lock (Skip for SQLite)
29
- const executor = trx.getExecutor();
30
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
31
- if (!adapterName.toLowerCase().includes('sqlite')) {
32
- query = query.forUpdate();
33
- }
34
- const existing = await query.executeTakeFirst();
29
+ const existing = await (0, db_utils_js_1.withLock)(baseQuery, trx)
30
+ .executeTakeFirst();
35
31
  const values = {
36
32
  name,
37
33
  role: options.role || null,
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PolicyEnforcer = void 0;
4
+ const db_utils_js_1 = require("./util/db-utils.js");
4
5
  /**
5
6
  * PolicyEnforcer stores and validates agent autonomous guardrails,
6
7
  * such as budgets, safety constraints, and privacy rules.
@@ -25,16 +26,12 @@ class PolicyEnforcer {
25
26
  */
26
27
  async definePolicy(name, type, definition, isEnabled = true, trxOrDb = this.db) {
27
28
  const runner = async (trx) => {
28
- let query = trx
29
+ const query = trx
29
30
  .selectFrom(this.policiesTable)
30
31
  .select('id')
31
32
  .where('name', '=', name);
32
- const executor = trx.getExecutor();
33
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
34
- if (!adapterName.toLowerCase().includes('sqlite')) {
35
- query = query.forUpdate();
36
- }
37
- const existing = await query.executeTakeFirst();
33
+ const existing = await (0, db_utils_js_1.withLock)(query, trx)
34
+ .executeTakeFirst();
38
35
  if (existing) {
39
36
  const updated = await trx
40
37
  .updateTable(this.policiesTable)
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ResourceMonitor = void 0;
4
+ const sql_js_1 = require("../raw-builder/sql.js");
4
5
  /**
5
6
  * ResourceMonitor tracks token usage and costs across sessions.
6
7
  */
@@ -100,7 +101,7 @@ class ResourceMonitor {
100
101
  .select([
101
102
  'model_name',
102
103
  (eb) => eb.fn
103
- .sum(eb('input_tokens', '+', 'output_tokens'))
104
+ .sum((0, sql_js_1.sql) `input_tokens + output_tokens`)
104
105
  .as('totalTokens'),
105
106
  (eb) => eb.fn.sum('cost').as('totalCost'),
106
107
  ])
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SessionManager = void 0;
4
+ const db_utils_js_1 = require("./util/db-utils.js");
4
5
  /**
5
6
  * SessionManager handles the lifecycle of agentic sessions, including
6
7
  * message history, goal tracking, and memory persistence.
@@ -134,12 +135,12 @@ class SessionManager {
134
135
  async upsertGoal(sessionId, description, options = {}) {
135
136
  const { status = 'pending', priority = 0, parentId, metadata } = options;
136
137
  return await this.db.transaction().execute(async (trx) => {
137
- const existing = await trx
138
+ const query = trx
138
139
  .selectFrom(this.goalsTable)
139
140
  .selectAll()
140
141
  .where('session_id', '=', sessionId)
141
- .where('description', '=', description)
142
- .forUpdate() // Audit Phase 13: Atomic goal lock
142
+ .where('description', '=', description);
143
+ const existing = await (0, db_utils_js_1.withLock)(query, trx) // Audit Phase 13: Atomic goal lock
143
144
  .executeTakeFirst();
144
145
  if (existing) {
145
146
  const updated = await trx
@@ -210,11 +211,11 @@ class SessionManager {
210
211
  // We avoid the Read-Modify-Write race condition by letting the DB handle the merge
211
212
  // or by using a strict transaction if the DB doesn't support JSON patching natively.
212
213
  const updated = await this.db.transaction().execute(async (trx) => {
213
- const message = await trx
214
+ const query = trx
214
215
  .selectFrom(this.messagesTable)
215
216
  .select('metadata')
216
- .where('id', '=', messageId)
217
- .forUpdate() // Lock the row for the duration of the transaction
217
+ .where('id', '=', messageId);
218
+ const message = await (0, db_utils_js_1.withLock)(query, trx) // Lock the row for the duration of the transaction
218
219
  .executeTakeFirstOrThrow();
219
220
  const metadata = typeof message.metadata === 'string'
220
221
  ? JSON.parse(message.metadata)
@@ -14,10 +14,6 @@ export declare class AblationEngine {
14
14
  private linksTable;
15
15
  constructor(db: Kysely<any>, cortex: Cortex, config?: AgenticConfig);
16
16
  private get typedDb();
17
- /**
18
- * Helper to apply forUpdate only where supported (Skip for SQLite)
19
- */
20
- private withLock;
21
17
  /**
22
18
  * Identify "Zombies": Items that have never been retrieved/hit and are old.
23
19
  */
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AblationEngine = void 0;
4
+ const db_utils_js_1 = require("../util/db-utils.js");
4
5
  /**
5
6
  * AblationEngine identifies and removes unused or redundant data
6
7
  * to keep the agent's context window and database lean.
@@ -23,17 +24,6 @@ class AblationEngine {
23
24
  get typedDb() {
24
25
  return this.db;
25
26
  }
26
- /**
27
- * Helper to apply forUpdate only where supported (Skip for SQLite)
28
- */
29
- withLock(query, trx) {
30
- const executor = trx.getExecutor();
31
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
32
- if (adapterName.toLowerCase().includes('sqlite')) {
33
- return query;
34
- }
35
- return query.forUpdate();
36
- }
37
27
  /**
38
28
  * Identify "Zombies": Items that have never been retrieved/hit and are old.
39
29
  */
@@ -55,7 +45,7 @@ class AblationEngine {
55
45
  .where('id', 'not in', (eb) => eb.selectFrom(this.linksTable).select('source_id'))
56
46
  .where('id', 'not in', (eb) => eb.selectFrom(this.linksTable).select('target_id'))
57
47
  .limit(500); // Audit Phase 9: Batch limit
58
- const knowledgeToPrune = await this.withLock(query, trx).execute();
48
+ const knowledgeToPrune = await (0, db_utils_js_1.withLock)(query, trx).execute();
59
49
  if (knowledgeToPrune.length > 0) {
60
50
  const candidates = knowledgeToPrune.map((k) => this.cortex.knowledge['parseKnowledge'](k));
61
51
  const idsToDelete = [];
@@ -151,7 +141,7 @@ class AblationEngine {
151
141
  .selectFrom(this.knowledgeTable)
152
142
  .selectAll()
153
143
  .where('id', '=', id);
154
- const item = (await this.withLock(query, trx).executeTakeFirst());
144
+ const item = (await (0, db_utils_js_1.withLock)(query, trx).executeTakeFirst());
155
145
  if (!item)
156
146
  return false;
157
147
  const metadata = typeof item.metadata === 'string'
@@ -194,7 +184,7 @@ class AblationEngine {
194
184
  .selectFrom(this.knowledgeTable)
195
185
  .selectAll()
196
186
  .where('id', '=', id);
197
- const item = (await this.withLock(query, t).executeTakeFirst());
187
+ const item = (await (0, db_utils_js_1.withLock)(query, t).executeTakeFirst());
198
188
  if (!item)
199
189
  return false;
200
190
  const metadata = typeof item.metadata === 'string'
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ActionRefiner = void 0;
4
+ const db_utils_js_1 = require("../util/db-utils.js");
4
5
  /**
5
6
  * ActionRefiner analyzes the ActionJournal to find patterns in failures
6
7
  * and suggests new CognitiveRules to improve agent performance.
@@ -73,18 +74,13 @@ class ActionRefiner {
73
74
  // Audit Phase 19: Atomic rule proposal via transaction + existence check
74
75
  const runner = async (trx) => {
75
76
  const rulesTable = this.cortex.config.rulesTable || 'agent_rules';
76
- let query = trx
77
+ const query = trx
77
78
  .selectFrom(rulesTable)
78
79
  .select('id')
79
80
  .where('table_name', '=', 'agent_actions')
80
81
  .where('operation', '=', 'insert')
81
82
  .where('metadata', 'like', `%\"targetTool\":\"${toolName}\"%`);
82
- const executor = trx.getExecutor();
83
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
84
- if (!adapterName.toLowerCase().includes('sqlite')) {
85
- query = query.forUpdate();
86
- }
87
- const existing = await query.executeTakeFirst();
83
+ const existing = await (0, db_utils_js_1.withLock)(query, trx).executeTakeFirst();
88
84
  if (!existing) {
89
85
  console.log(`[ActionRefiner] Proposing reflection rule for tool: ${toolName}`);
90
86
  await this.cortex.rules.defineRule('agent_actions', 'insert', 'audit', {
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ConflictResolver = void 0;
4
4
  const similarity_js_1 = require("../../util/similarity.js");
5
+ const db_utils_js_1 = require("../util/db-utils.js");
5
6
  /**
6
7
  * ConflictResolver identifies and resolves logical inconsistencies
7
8
  * in the agent's cognitive rules and behavior policies.
@@ -85,14 +86,14 @@ class ConflictResolver {
85
86
  async resolveConflict(tableName, operation) {
86
87
  console.log(`[ConflictResolver] Resolving conflict for ${tableName}:${operation}`);
87
88
  return await this.db.transaction().execute(async (trx) => {
88
- const rules = (await trx
89
+ const query = trx
89
90
  .selectFrom(this.rulesTable)
90
91
  .selectAll()
91
92
  .where('table_name', '=', tableName)
92
93
  .where('operation', '=', operation)
93
94
  .where('is_enabled', '=', true)
94
- .orderBy('created_at', 'desc')
95
- .forUpdate() // Audit Phase 10: Atomic resolution lock
95
+ .orderBy('created_at', 'desc');
96
+ const rules = (await (0, db_utils_js_1.withLock)(query, trx) // Audit Phase 10: Atomic resolution lock
96
97
  .execute());
97
98
  if (rules.length <= 1)
98
99
  return;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GoalArchitect = void 0;
4
4
  const similarity_js_1 = require("../../util/similarity.js");
5
+ const db_utils_js_1 = require("../util/db-utils.js");
5
6
  /**
6
7
  * GoalArchitect enables agents to autonomously deconstruct complex
7
8
  * objectives into manageable sub-goals.
@@ -26,11 +27,11 @@ class GoalArchitect {
26
27
  return await this.db.transaction().execute(async (trx) => {
27
28
  // 1. Audit Phase 9: Circular Dependency Protection inside transaction
28
29
  await this.detectCircularDependency(goalId, new Set(), trx);
29
- const goal = (await trx
30
+ const query = trx
30
31
  .selectFrom(this.goalsTable)
31
32
  .selectAll()
32
- .where('id', '=', goalId)
33
- .forUpdate() // Audit Phase 9: Atomic acquisition
33
+ .where('id', '=', goalId);
34
+ const goal = (await (0, db_utils_js_1.withLock)(query, trx) // Audit Phase 9: Atomic acquisition
34
35
  .executeTakeFirst());
35
36
  if (!goal)
36
37
  throw new Error(`Goal ${goalId} not found`);
@@ -101,11 +102,11 @@ class GoalArchitect {
101
102
  const sortedIds = [...goalIds].sort((a, b) => String(a).localeCompare(String(b)));
102
103
  await this.db.transaction().execute(async (trx) => {
103
104
  // Pre-lock all rows in deterministic order
104
- await trx
105
+ const query = trx
105
106
  .selectFrom(this.goalsTable)
106
107
  .select('id')
107
- .where('id', 'in', sortedIds)
108
- .forUpdate()
108
+ .where('id', 'in', sortedIds);
109
+ await (0, db_utils_js_1.withLock)(query, trx)
109
110
  .execute();
110
111
  for (let i = 0; i < goalIds.length; i++) {
111
112
  await trx
@@ -121,11 +122,11 @@ class GoalArchitect {
121
122
  */
122
123
  async markGoalAs(goalId, status, outcome) {
123
124
  return await this.db.transaction().execute(async (trx) => {
124
- const goal = (await trx
125
+ const query = trx
125
126
  .selectFrom(this.goalsTable)
126
127
  .selectAll()
127
- .where('id', '=', goalId)
128
- .forUpdate() // Audit Phase 9: Atomic status/meta update
128
+ .where('id', '=', goalId);
129
+ const goal = (await (0, db_utils_js_1.withLock)(query, trx) // Audit Phase 9: Atomic status/meta update
129
130
  .executeTakeFirst());
130
131
  if (!goal)
131
132
  throw new Error(`Goal ${goalId} not found`);
@@ -5,6 +5,7 @@ const FactDistiller_js_1 = require("./distillation/FactDistiller.js");
5
5
  const ConflictChallenger_js_1 = require("./distillation/ConflictChallenger.js");
6
6
  const RelationshipArchitect_js_1 = require("./distillation/RelationshipArchitect.js");
7
7
  const KnowledgeConsolidator_js_1 = require("./distillation/KnowledgeConsolidator.js");
8
+ const db_utils_js_1 = require("../util/db-utils.js");
8
9
  /**
9
10
  * KnowledgeDistiller extracts structured "KnowledgeItems" from longtail history,
10
11
  * allowing agents to build a permanent, queryable knowledge base.
@@ -106,11 +107,11 @@ class KnowledgeDistiller {
106
107
  */
107
108
  async recordHit(id) {
108
109
  await this.db.transaction().execute(async (trx) => {
109
- const existing = await trx
110
+ const query = trx
110
111
  .selectFrom(this.knowledgeTable)
111
112
  .select(['id', 'entity', 'metadata'])
112
- .where('id', '=', id)
113
- .forUpdate()
113
+ .where('id', '=', id);
114
+ const existing = await (0, db_utils_js_1.withLock)(query, trx)
114
115
  .executeTakeFirst();
115
116
  if (!existing)
116
117
  return;
@@ -8,9 +8,10 @@ export declare class SelfEvolution {
8
8
  private db;
9
9
  private config;
10
10
  private evolution;
11
- private typeGenerator;
11
+ private typeGenerator?;
12
12
  private snapshotsTable;
13
13
  constructor(db: Kysely<any>, config: NOORMConfig);
14
+ private getTypeGenerator;
14
15
  /**
15
16
  * Ensure core agentic tables have telemetry columns like 'accessed_at'
16
17
  */
@@ -33,7 +34,7 @@ export declare class SelfEvolution {
33
34
  /**
34
35
  * Get the current "DNA" (structural overview) of the agent's database
35
36
  */
36
- getDNA(): Promise<string>;
37
+ getDNA(db?: Kysely<any>): Promise<string>;
37
38
  /**
38
39
  * Proactively suggest and apply optimizations based on usage patterns.
39
40
  */
@@ -53,10 +53,15 @@ class SelfEvolution {
53
53
  this.db = db;
54
54
  this.config = config;
55
55
  this.evolution = new schema_evolution_js_1.SchemaEvolutionHelper(db);
56
- this.typeGenerator = new type_generator_js_1.TypeGenerator(config.introspection);
57
56
  this.snapshotsTable =
58
57
  config.agentic?.metadata?.snapshotsTable || 'agent_snapshots';
59
58
  }
59
+ getTypeGenerator() {
60
+ if (!this.typeGenerator) {
61
+ this.typeGenerator = new type_generator_js_1.TypeGenerator(this.config.introspection);
62
+ }
63
+ return this.typeGenerator;
64
+ }
60
65
  /**
61
66
  * Ensure core agentic tables have telemetry columns like 'accessed_at'
62
67
  */
@@ -136,13 +141,13 @@ class SelfEvolution {
136
141
  console.log(`[SelfEvolution] Applying structural change: ${ddl}`);
137
142
  const runner = async (trx) => {
138
143
  // 1. Apply the DDL change
139
- await trx.execute(sql_js_1.sql.raw(ddl));
144
+ await sql_js_1.sql.raw(ddl).execute(trx);
140
145
  // 1b. Log for potential rollback
141
146
  await trx
142
147
  .insertInto(this.snapshotsTable)
143
148
  .values({
144
149
  name: options.name || `auto_evolution_${Date.now()}`,
145
- dna: await this.getDNA(),
150
+ dna: await this.getDNA(trx),
146
151
  metadata: JSON.stringify({
147
152
  ...options.metadata,
148
153
  ddl,
@@ -178,7 +183,7 @@ class SelfEvolution {
178
183
  })),
179
184
  relationships: [],
180
185
  };
181
- const generated = this.typeGenerator.generateTypes(schemaInfo);
186
+ const generated = this.getTypeGenerator().generateTypes(schemaInfo);
182
187
  if (this.config.agentic?.metadata?.typesOutputPath) {
183
188
  const outputPath = this.config.agentic.metadata.typesOutputPath;
184
189
  console.log(`[SelfEvolution] Writing regenerated types to ${outputPath}`);
@@ -189,8 +194,8 @@ class SelfEvolution {
189
194
  /**
190
195
  * Get the current "DNA" (structural overview) of the agent's database
191
196
  */
192
- async getDNA() {
193
- return this.evolution.getStructuralOverview();
197
+ async getDNA(db = this.db) {
198
+ return new schema_evolution_js_1.SchemaEvolutionHelper(db).getStructuralOverview();
194
199
  }
195
200
  /**
196
201
  * Proactively suggest and apply optimizations based on usage patterns.
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SelfTestRegistry = void 0;
4
+ const db_utils_js_1 = require("../util/db-utils.js");
4
5
  /**
5
6
  * SelfTestRegistry allows agents to self-register verification probes
6
7
  * that ensure autonomous changes don't violate core logic.
@@ -57,16 +58,11 @@ class SelfTestRegistry {
57
58
  results.push({ name: probe.name, success });
58
59
  const updateRunner = async (trx) => {
59
60
  // Audit Phase 13: Lock row before updating last_status
60
- let query = trx
61
+ const query = trx
61
62
  .selectFrom('agent_logic_probes')
62
63
  .select('id')
63
64
  .where('id', '=', probe.id);
64
- const executor = trx.getExecutor();
65
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
66
- if (!adapterName.toLowerCase().includes('sqlite')) {
67
- query = query.forUpdate();
68
- }
69
- await query.executeTakeFirst();
65
+ await (0, db_utils_js_1.withLock)(query, trx).executeTakeFirst();
70
66
  await trx
71
67
  .updateTable('agent_logic_probes')
72
68
  .set({
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PersonaAuditor = void 0;
4
+ const db_utils_js_1 = require("../../util/db-utils.js");
4
5
  class PersonaAuditor {
5
6
  async audit(ctx) {
6
7
  const issues = [];
@@ -43,17 +44,12 @@ class PersonaAuditor {
43
44
  console.warn(`[PersonaAuditor] QUARANTINING Persona ${id}: ${reason}`);
44
45
  // Use the provided transaction or start a new one to ensure atomicity
45
46
  const runner = async (trx) => {
46
- let query = trx
47
+ const query = trx
47
48
  .selectFrom(ctx.personasTable)
48
49
  .selectAll()
49
50
  .where('id', '=', id);
50
- // Audit Phase 16: Exclusive lock for containment (Skip for SQLite)
51
- const executor = trx.getExecutor();
52
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
53
- if (!adapterName.toLowerCase().includes('sqlite')) {
54
- query = query.forUpdate();
55
- }
56
- const persona = await query.executeTakeFirst();
51
+ const persona = await (0, db_utils_js_1.withLock)(query, trx)
52
+ .executeTakeFirst();
57
53
  if (persona) {
58
54
  const metadata = typeof persona.metadata === 'string'
59
55
  ? JSON.parse(persona.metadata)
@@ -1,17 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.KnowledgePromoter = void 0;
4
+ const db_utils_js_1 = require("../../util/db-utils.js");
4
5
  class KnowledgePromoter {
5
6
  async promote(db, cortex, config, knowledgeTable, item) {
6
7
  return await db.transaction().execute(async (trx) => {
7
8
  // Check if a global version already exists
8
- const existingGlobal = await trx
9
+ const query = trx
9
10
  .selectFrom(knowledgeTable)
10
11
  .selectAll()
11
12
  .where('entity', '=', item.entity)
12
13
  .where('fact', '=', item.fact)
13
- .where('source_session_id', 'is', null)
14
- .forUpdate() // Prevent concurrent promotion duplication
14
+ .where('source_session_id', 'is', null);
15
+ const existingGlobal = await (0, db_utils_js_1.withLock)(query, trx) // Prevent concurrent promotion duplication
15
16
  .executeTakeFirst();
16
17
  if (existingGlobal) {
17
18
  // Reinforce existing global knowledge
@@ -54,7 +54,7 @@ class SkillPropagator {
54
54
  .execute();
55
55
  }
56
56
  });
57
- broadcastCount += variants.length;
57
+ broadcastCount++;
58
58
  }
59
59
  // 2. Blacklisted Skill Propagation (Immune Prophet)
60
60
  const blacklisted = await cortex.capabilities.getCapabilities('blacklisted');
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Utility function to apply a "FOR UPDATE" lock only where supported (Not in SQLite)
3
+ */
4
+ export declare function withLock(query: any, trx: any): any;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withLock = withLock;
4
+ /**
5
+ * Utility function to apply a "FOR UPDATE" lock only where supported (Not in SQLite)
6
+ */
7
+ function withLock(query, trx) {
8
+ if (!trx || typeof trx.getExecutor !== 'function') {
9
+ // If we're using a mock or a version of Kysely without getExecutor
10
+ // we default to no lock to prevent failures in tests
11
+ return query;
12
+ }
13
+ try {
14
+ const executor = trx.getExecutor();
15
+ const adapterName = executor?.adapter?.constructor?.name ||
16
+ executor?.dialect?.constructor?.name ||
17
+ '';
18
+ if (adapterName.toLowerCase().includes('sqlite')) {
19
+ return query;
20
+ }
21
+ }
22
+ catch (error) {
23
+ // Fallback if execution fails for some reason
24
+ return query;
25
+ }
26
+ return query.forUpdate();
27
+ }
@@ -119,6 +119,7 @@ class AgentSchemaHelper {
119
119
  .addColumn('tool_name', 'text', (col) => col.notNull())
120
120
  .addColumn('arguments', 'text', (col) => col.notNull())
121
121
  .addColumn('outcome', 'text')
122
+ .addColumn('error', 'text')
122
123
  .addColumn('status', 'text', (col) => col.notNull().defaultTo('pending'))
123
124
  .addColumn('duration_ms', 'integer')
124
125
  .addColumn('metadata', 'text')
@@ -94,6 +94,8 @@ async function setupTestSchema(db) {
94
94
  .on('comments')
95
95
  .column('user_id')
96
96
  .execute();
97
+ // Initialize agent schema
98
+ await db.agent.schema.initializeSchema();
97
99
  // Initialize NOORMME to discover the schema
98
100
  // Temporarily enable warnings to see discovery errors
99
101
  const originalWarn = console.warn;
@@ -1,4 +1,5 @@
1
1
  /// <reference types="./CapabilityManager.d.ts" />
2
+ import { withLock } from './util/db-utils.js';
2
3
  /**
3
4
  * CapabilityManager tracks the skills (tools) available to an agent
4
5
  * and their historical reliability.
@@ -86,18 +87,13 @@ export class CapabilityManager {
86
87
  */
87
88
  async reportOutcome(name, success, trxOrDb = this.db) {
88
89
  const runner = async (trx) => {
89
- let query = trx
90
+ const baseQuery = trx
90
91
  .selectFrom(this.capabilitiesTable)
91
92
  .selectAll()
92
93
  .where('name', '=', name)
93
94
  .orderBy('updated_at', 'desc');
94
- // PRODUCTION HARDENING: Lock row to prevent RMW race (Skip for SQLite)
95
- const executor = trx.getExecutor();
96
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
97
- if (!adapterName.toLowerCase().includes('sqlite')) {
98
- query = query.forUpdate();
99
- }
100
- const capability = await query.executeTakeFirst();
95
+ const capability = await withLock(baseQuery, trx)
96
+ .executeTakeFirst();
101
97
  if (capability) {
102
98
  const cap = capability;
103
99
  const metadata = typeof cap.metadata === 'string'
@@ -1,4 +1,5 @@
1
1
  /// <reference types="./EpisodicMemory.d.ts" />
2
+ import { withLock } from './util/db-utils.js';
2
3
  /**
3
4
  * EpisodicMemory groups interactions into semantic chunks (episodes),
4
5
  * allowing agents to recall specific scenarios and their outcomes.
@@ -37,11 +38,11 @@ export class EpisodicMemory {
37
38
  */
38
39
  async completeEpisode(episodeId, summary, metadata) {
39
40
  return await this.db.transaction().execute(async (trx) => {
40
- const existing = await trx
41
+ const query = trx
41
42
  .selectFrom(this.episodesTable)
42
43
  .selectAll()
43
- .where('id', '=', episodeId)
44
- .forUpdate() // Audit Phase 12: Atomic completion lock
44
+ .where('id', '=', episodeId);
45
+ const existing = await withLock(query, trx) // Audit Phase 12: Atomic completion lock
45
46
  .executeTakeFirst();
46
47
  if (!existing)
47
48
  throw new Error(`Episode with ID ${episodeId} not found`);
@@ -1,4 +1,5 @@
1
1
  /// <reference types="./PersonaManager.d.ts" />
2
+ import { withLock } from './util/db-utils.js';
2
3
  /**
3
4
  * PersonaManager handles persistent agent identities that bridge multiple sessions.
4
5
  */
@@ -19,17 +20,12 @@ export class PersonaManager {
19
20
  */
20
21
  async upsertPersona(name, options = {}, trxOrDb = this.db) {
21
22
  const runner = async (trx) => {
22
- let query = trx
23
+ const baseQuery = trx
23
24
  .selectFrom(this.personasTable)
24
25
  .selectAll()
25
26
  .where('name', '=', name);
26
- // Audit Phase 13: Atomic identity lock (Skip for SQLite)
27
- const executor = trx.getExecutor();
28
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
29
- if (!adapterName.toLowerCase().includes('sqlite')) {
30
- query = query.forUpdate();
31
- }
32
- const existing = await query.executeTakeFirst();
27
+ const existing = await withLock(baseQuery, trx)
28
+ .executeTakeFirst();
33
29
  const values = {
34
30
  name,
35
31
  role: options.role || null,
@@ -1,4 +1,5 @@
1
1
  /// <reference types="./PolicyEnforcer.d.ts" />
2
+ import { withLock } from './util/db-utils.js';
2
3
  /**
3
4
  * PolicyEnforcer stores and validates agent autonomous guardrails,
4
5
  * such as budgets, safety constraints, and privacy rules.
@@ -23,16 +24,12 @@ export class PolicyEnforcer {
23
24
  */
24
25
  async definePolicy(name, type, definition, isEnabled = true, trxOrDb = this.db) {
25
26
  const runner = async (trx) => {
26
- let query = trx
27
+ const query = trx
27
28
  .selectFrom(this.policiesTable)
28
29
  .select('id')
29
30
  .where('name', '=', name);
30
- const executor = trx.getExecutor();
31
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
32
- if (!adapterName.toLowerCase().includes('sqlite')) {
33
- query = query.forUpdate();
34
- }
35
- const existing = await query.executeTakeFirst();
31
+ const existing = await withLock(query, trx)
32
+ .executeTakeFirst();
36
33
  if (existing) {
37
34
  const updated = await trx
38
35
  .updateTable(this.policiesTable)
@@ -1,4 +1,5 @@
1
1
  /// <reference types="./ResourceMonitor.d.ts" />
2
+ import { sql } from '../raw-builder/sql.js';
2
3
  /**
3
4
  * ResourceMonitor tracks token usage and costs across sessions.
4
5
  */
@@ -98,7 +99,7 @@ export class ResourceMonitor {
98
99
  .select([
99
100
  'model_name',
100
101
  (eb) => eb.fn
101
- .sum(eb('input_tokens', '+', 'output_tokens'))
102
+ .sum(sql `input_tokens + output_tokens`)
102
103
  .as('totalTokens'),
103
104
  (eb) => eb.fn.sum('cost').as('totalCost'),
104
105
  ])
@@ -1,4 +1,5 @@
1
1
  /// <reference types="./SessionManager.d.ts" />
2
+ import { withLock } from './util/db-utils.js';
2
3
  /**
3
4
  * SessionManager handles the lifecycle of agentic sessions, including
4
5
  * message history, goal tracking, and memory persistence.
@@ -132,12 +133,12 @@ export class SessionManager {
132
133
  async upsertGoal(sessionId, description, options = {}) {
133
134
  const { status = 'pending', priority = 0, parentId, metadata } = options;
134
135
  return await this.db.transaction().execute(async (trx) => {
135
- const existing = await trx
136
+ const query = trx
136
137
  .selectFrom(this.goalsTable)
137
138
  .selectAll()
138
139
  .where('session_id', '=', sessionId)
139
- .where('description', '=', description)
140
- .forUpdate() // Audit Phase 13: Atomic goal lock
140
+ .where('description', '=', description);
141
+ const existing = await withLock(query, trx) // Audit Phase 13: Atomic goal lock
141
142
  .executeTakeFirst();
142
143
  if (existing) {
143
144
  const updated = await trx
@@ -208,11 +209,11 @@ export class SessionManager {
208
209
  // We avoid the Read-Modify-Write race condition by letting the DB handle the merge
209
210
  // or by using a strict transaction if the DB doesn't support JSON patching natively.
210
211
  const updated = await this.db.transaction().execute(async (trx) => {
211
- const message = await trx
212
+ const query = trx
212
213
  .selectFrom(this.messagesTable)
213
214
  .select('metadata')
214
- .where('id', '=', messageId)
215
- .forUpdate() // Lock the row for the duration of the transaction
215
+ .where('id', '=', messageId);
216
+ const message = await withLock(query, trx) // Lock the row for the duration of the transaction
216
217
  .executeTakeFirstOrThrow();
217
218
  const metadata = typeof message.metadata === 'string'
218
219
  ? JSON.parse(message.metadata)
@@ -14,10 +14,6 @@ export declare class AblationEngine {
14
14
  private linksTable;
15
15
  constructor(db: Kysely<any>, cortex: Cortex, config?: AgenticConfig);
16
16
  private get typedDb();
17
- /**
18
- * Helper to apply forUpdate only where supported (Skip for SQLite)
19
- */
20
- private withLock;
21
17
  /**
22
18
  * Identify "Zombies": Items that have never been retrieved/hit and are old.
23
19
  */
@@ -1,4 +1,5 @@
1
1
  /// <reference types="./AblationEngine.d.ts" />
2
+ import { withLock } from '../util/db-utils.js';
2
3
  /**
3
4
  * AblationEngine identifies and removes unused or redundant data
4
5
  * to keep the agent's context window and database lean.
@@ -21,17 +22,6 @@ export class AblationEngine {
21
22
  get typedDb() {
22
23
  return this.db;
23
24
  }
24
- /**
25
- * Helper to apply forUpdate only where supported (Skip for SQLite)
26
- */
27
- withLock(query, trx) {
28
- const executor = trx.getExecutor();
29
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
30
- if (adapterName.toLowerCase().includes('sqlite')) {
31
- return query;
32
- }
33
- return query.forUpdate();
34
- }
35
25
  /**
36
26
  * Identify "Zombies": Items that have never been retrieved/hit and are old.
37
27
  */
@@ -53,7 +43,7 @@ export class AblationEngine {
53
43
  .where('id', 'not in', (eb) => eb.selectFrom(this.linksTable).select('source_id'))
54
44
  .where('id', 'not in', (eb) => eb.selectFrom(this.linksTable).select('target_id'))
55
45
  .limit(500); // Audit Phase 9: Batch limit
56
- const knowledgeToPrune = await this.withLock(query, trx).execute();
46
+ const knowledgeToPrune = await withLock(query, trx).execute();
57
47
  if (knowledgeToPrune.length > 0) {
58
48
  const candidates = knowledgeToPrune.map((k) => this.cortex.knowledge['parseKnowledge'](k));
59
49
  const idsToDelete = [];
@@ -149,7 +139,7 @@ export class AblationEngine {
149
139
  .selectFrom(this.knowledgeTable)
150
140
  .selectAll()
151
141
  .where('id', '=', id);
152
- const item = (await this.withLock(query, trx).executeTakeFirst());
142
+ const item = (await withLock(query, trx).executeTakeFirst());
153
143
  if (!item)
154
144
  return false;
155
145
  const metadata = typeof item.metadata === 'string'
@@ -192,7 +182,7 @@ export class AblationEngine {
192
182
  .selectFrom(this.knowledgeTable)
193
183
  .selectAll()
194
184
  .where('id', '=', id);
195
- const item = (await this.withLock(query, t).executeTakeFirst());
185
+ const item = (await withLock(query, t).executeTakeFirst());
196
186
  if (!item)
197
187
  return false;
198
188
  const metadata = typeof item.metadata === 'string'
@@ -1,4 +1,5 @@
1
1
  /// <reference types="./ActionRefiner.d.ts" />
2
+ import { withLock } from '../util/db-utils.js';
2
3
  /**
3
4
  * ActionRefiner analyzes the ActionJournal to find patterns in failures
4
5
  * and suggests new CognitiveRules to improve agent performance.
@@ -71,18 +72,13 @@ export class ActionRefiner {
71
72
  // Audit Phase 19: Atomic rule proposal via transaction + existence check
72
73
  const runner = async (trx) => {
73
74
  const rulesTable = this.cortex.config.rulesTable || 'agent_rules';
74
- let query = trx
75
+ const query = trx
75
76
  .selectFrom(rulesTable)
76
77
  .select('id')
77
78
  .where('table_name', '=', 'agent_actions')
78
79
  .where('operation', '=', 'insert')
79
80
  .where('metadata', 'like', `%\"targetTool\":\"${toolName}\"%`);
80
- const executor = trx.getExecutor();
81
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
82
- if (!adapterName.toLowerCase().includes('sqlite')) {
83
- query = query.forUpdate();
84
- }
85
- const existing = await query.executeTakeFirst();
81
+ const existing = await withLock(query, trx).executeTakeFirst();
86
82
  if (!existing) {
87
83
  console.log(`[ActionRefiner] Proposing reflection rule for tool: ${toolName}`);
88
84
  await this.cortex.rules.defineRule('agent_actions', 'insert', 'audit', {
@@ -1,5 +1,6 @@
1
1
  /// <reference types="./ConflictResolver.d.ts" />
2
2
  import { calculateSimilarity } from '../../util/similarity.js';
3
+ import { withLock } from '../util/db-utils.js';
3
4
  /**
4
5
  * ConflictResolver identifies and resolves logical inconsistencies
5
6
  * in the agent's cognitive rules and behavior policies.
@@ -83,14 +84,14 @@ export class ConflictResolver {
83
84
  async resolveConflict(tableName, operation) {
84
85
  console.log(`[ConflictResolver] Resolving conflict for ${tableName}:${operation}`);
85
86
  return await this.db.transaction().execute(async (trx) => {
86
- const rules = (await trx
87
+ const query = trx
87
88
  .selectFrom(this.rulesTable)
88
89
  .selectAll()
89
90
  .where('table_name', '=', tableName)
90
91
  .where('operation', '=', operation)
91
92
  .where('is_enabled', '=', true)
92
- .orderBy('created_at', 'desc')
93
- .forUpdate() // Audit Phase 10: Atomic resolution lock
93
+ .orderBy('created_at', 'desc');
94
+ const rules = (await withLock(query, trx) // Audit Phase 10: Atomic resolution lock
94
95
  .execute());
95
96
  if (rules.length <= 1)
96
97
  return;
@@ -1,5 +1,6 @@
1
1
  /// <reference types="./GoalArchitect.d.ts" />
2
2
  import { calculateSimilarity } from '../../util/similarity.js';
3
+ import { withLock } from '../util/db-utils.js';
3
4
  /**
4
5
  * GoalArchitect enables agents to autonomously deconstruct complex
5
6
  * objectives into manageable sub-goals.
@@ -24,11 +25,11 @@ export class GoalArchitect {
24
25
  return await this.db.transaction().execute(async (trx) => {
25
26
  // 1. Audit Phase 9: Circular Dependency Protection inside transaction
26
27
  await this.detectCircularDependency(goalId, new Set(), trx);
27
- const goal = (await trx
28
+ const query = trx
28
29
  .selectFrom(this.goalsTable)
29
30
  .selectAll()
30
- .where('id', '=', goalId)
31
- .forUpdate() // Audit Phase 9: Atomic acquisition
31
+ .where('id', '=', goalId);
32
+ const goal = (await withLock(query, trx) // Audit Phase 9: Atomic acquisition
32
33
  .executeTakeFirst());
33
34
  if (!goal)
34
35
  throw new Error(`Goal ${goalId} not found`);
@@ -99,11 +100,11 @@ export class GoalArchitect {
99
100
  const sortedIds = [...goalIds].sort((a, b) => String(a).localeCompare(String(b)));
100
101
  await this.db.transaction().execute(async (trx) => {
101
102
  // Pre-lock all rows in deterministic order
102
- await trx
103
+ const query = trx
103
104
  .selectFrom(this.goalsTable)
104
105
  .select('id')
105
- .where('id', 'in', sortedIds)
106
- .forUpdate()
106
+ .where('id', 'in', sortedIds);
107
+ await withLock(query, trx)
107
108
  .execute();
108
109
  for (let i = 0; i < goalIds.length; i++) {
109
110
  await trx
@@ -119,11 +120,11 @@ export class GoalArchitect {
119
120
  */
120
121
  async markGoalAs(goalId, status, outcome) {
121
122
  return await this.db.transaction().execute(async (trx) => {
122
- const goal = (await trx
123
+ const query = trx
123
124
  .selectFrom(this.goalsTable)
124
125
  .selectAll()
125
- .where('id', '=', goalId)
126
- .forUpdate() // Audit Phase 9: Atomic status/meta update
126
+ .where('id', '=', goalId);
127
+ const goal = (await withLock(query, trx) // Audit Phase 9: Atomic status/meta update
127
128
  .executeTakeFirst());
128
129
  if (!goal)
129
130
  throw new Error(`Goal ${goalId} not found`);
@@ -3,6 +3,7 @@ import { FactDistiller } from './distillation/FactDistiller.js';
3
3
  import { ConflictChallenger } from './distillation/ConflictChallenger.js';
4
4
  import { RelationshipArchitect } from './distillation/RelationshipArchitect.js';
5
5
  import { KnowledgeConsolidator } from './distillation/KnowledgeConsolidator.js';
6
+ import { withLock } from '../util/db-utils.js';
6
7
  /**
7
8
  * KnowledgeDistiller extracts structured "KnowledgeItems" from longtail history,
8
9
  * allowing agents to build a permanent, queryable knowledge base.
@@ -104,11 +105,11 @@ export class KnowledgeDistiller {
104
105
  */
105
106
  async recordHit(id) {
106
107
  await this.db.transaction().execute(async (trx) => {
107
- const existing = await trx
108
+ const query = trx
108
109
  .selectFrom(this.knowledgeTable)
109
110
  .select(['id', 'entity', 'metadata'])
110
- .where('id', '=', id)
111
- .forUpdate()
111
+ .where('id', '=', id);
112
+ const existing = await withLock(query, trx)
112
113
  .executeTakeFirst();
113
114
  if (!existing)
114
115
  return;
@@ -8,9 +8,10 @@ export declare class SelfEvolution {
8
8
  private db;
9
9
  private config;
10
10
  private evolution;
11
- private typeGenerator;
11
+ private typeGenerator?;
12
12
  private snapshotsTable;
13
13
  constructor(db: Kysely<any>, config: NOORMConfig);
14
+ private getTypeGenerator;
14
15
  /**
15
16
  * Ensure core agentic tables have telemetry columns like 'accessed_at'
16
17
  */
@@ -33,7 +34,7 @@ export declare class SelfEvolution {
33
34
  /**
34
35
  * Get the current "DNA" (structural overview) of the agent's database
35
36
  */
36
- getDNA(): Promise<string>;
37
+ getDNA(db?: Kysely<any>): Promise<string>;
37
38
  /**
38
39
  * Proactively suggest and apply optimizations based on usage patterns.
39
40
  */
@@ -18,10 +18,15 @@ export class SelfEvolution {
18
18
  this.db = db;
19
19
  this.config = config;
20
20
  this.evolution = new SchemaEvolutionHelper(db);
21
- this.typeGenerator = new TypeGenerator(config.introspection);
22
21
  this.snapshotsTable =
23
22
  config.agentic?.metadata?.snapshotsTable || 'agent_snapshots';
24
23
  }
24
+ getTypeGenerator() {
25
+ if (!this.typeGenerator) {
26
+ this.typeGenerator = new TypeGenerator(this.config.introspection);
27
+ }
28
+ return this.typeGenerator;
29
+ }
25
30
  /**
26
31
  * Ensure core agentic tables have telemetry columns like 'accessed_at'
27
32
  */
@@ -101,13 +106,13 @@ export class SelfEvolution {
101
106
  console.log(`[SelfEvolution] Applying structural change: ${ddl}`);
102
107
  const runner = async (trx) => {
103
108
  // 1. Apply the DDL change
104
- await trx.execute(sql.raw(ddl));
109
+ await sql.raw(ddl).execute(trx);
105
110
  // 1b. Log for potential rollback
106
111
  await trx
107
112
  .insertInto(this.snapshotsTable)
108
113
  .values({
109
114
  name: options.name || `auto_evolution_${Date.now()}`,
110
- dna: await this.getDNA(),
115
+ dna: await this.getDNA(trx),
111
116
  metadata: JSON.stringify({
112
117
  ...options.metadata,
113
118
  ddl,
@@ -143,7 +148,7 @@ export class SelfEvolution {
143
148
  })),
144
149
  relationships: [],
145
150
  };
146
- const generated = this.typeGenerator.generateTypes(schemaInfo);
151
+ const generated = this.getTypeGenerator().generateTypes(schemaInfo);
147
152
  if (this.config.agentic?.metadata?.typesOutputPath) {
148
153
  const outputPath = this.config.agentic.metadata.typesOutputPath;
149
154
  console.log(`[SelfEvolution] Writing regenerated types to ${outputPath}`);
@@ -154,8 +159,8 @@ export class SelfEvolution {
154
159
  /**
155
160
  * Get the current "DNA" (structural overview) of the agent's database
156
161
  */
157
- async getDNA() {
158
- return this.evolution.getStructuralOverview();
162
+ async getDNA(db = this.db) {
163
+ return new SchemaEvolutionHelper(db).getStructuralOverview();
159
164
  }
160
165
  /**
161
166
  * Proactively suggest and apply optimizations based on usage patterns.
@@ -1,4 +1,5 @@
1
1
  /// <reference types="./SelfTestRegistry.d.ts" />
2
+ import { withLock } from '../util/db-utils.js';
2
3
  /**
3
4
  * SelfTestRegistry allows agents to self-register verification probes
4
5
  * that ensure autonomous changes don't violate core logic.
@@ -55,16 +56,11 @@ export class SelfTestRegistry {
55
56
  results.push({ name: probe.name, success });
56
57
  const updateRunner = async (trx) => {
57
58
  // Audit Phase 13: Lock row before updating last_status
58
- let query = trx
59
+ const query = trx
59
60
  .selectFrom('agent_logic_probes')
60
61
  .select('id')
61
62
  .where('id', '=', probe.id);
62
- const executor = trx.getExecutor();
63
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
64
- if (!adapterName.toLowerCase().includes('sqlite')) {
65
- query = query.forUpdate();
66
- }
67
- await query.executeTakeFirst();
63
+ await withLock(query, trx).executeTakeFirst();
68
64
  await trx
69
65
  .updateTable('agent_logic_probes')
70
66
  .set({
@@ -1,4 +1,5 @@
1
1
  /// <reference types="./PersonaAuditor.d.ts" />
2
+ import { withLock } from '../../util/db-utils.js';
2
3
  export class PersonaAuditor {
3
4
  async audit(ctx) {
4
5
  const issues = [];
@@ -41,17 +42,12 @@ export class PersonaAuditor {
41
42
  console.warn(`[PersonaAuditor] QUARANTINING Persona ${id}: ${reason}`);
42
43
  // Use the provided transaction or start a new one to ensure atomicity
43
44
  const runner = async (trx) => {
44
- let query = trx
45
+ const query = trx
45
46
  .selectFrom(ctx.personasTable)
46
47
  .selectAll()
47
48
  .where('id', '=', id);
48
- // Audit Phase 16: Exclusive lock for containment (Skip for SQLite)
49
- const executor = trx.getExecutor();
50
- const adapterName = executor?.adapter?.constructor?.name || executor?.dialect?.constructor?.name || '';
51
- if (!adapterName.toLowerCase().includes('sqlite')) {
52
- query = query.forUpdate();
53
- }
54
- const persona = await query.executeTakeFirst();
49
+ const persona = await withLock(query, trx)
50
+ .executeTakeFirst();
55
51
  if (persona) {
56
52
  const metadata = typeof persona.metadata === 'string'
57
53
  ? JSON.parse(persona.metadata)
@@ -1,15 +1,16 @@
1
1
  /// <reference types="./KnowledgePromoter.d.ts" />
2
+ import { withLock } from '../../util/db-utils.js';
2
3
  export class KnowledgePromoter {
3
4
  async promote(db, cortex, config, knowledgeTable, item) {
4
5
  return await db.transaction().execute(async (trx) => {
5
6
  // Check if a global version already exists
6
- const existingGlobal = await trx
7
+ const query = trx
7
8
  .selectFrom(knowledgeTable)
8
9
  .selectAll()
9
10
  .where('entity', '=', item.entity)
10
11
  .where('fact', '=', item.fact)
11
- .where('source_session_id', 'is', null)
12
- .forUpdate() // Prevent concurrent promotion duplication
12
+ .where('source_session_id', 'is', null);
13
+ const existingGlobal = await withLock(query, trx) // Prevent concurrent promotion duplication
13
14
  .executeTakeFirst();
14
15
  if (existingGlobal) {
15
16
  // Reinforce existing global knowledge
@@ -52,7 +52,7 @@ export class SkillPropagator {
52
52
  .execute();
53
53
  }
54
54
  });
55
- broadcastCount += variants.length;
55
+ broadcastCount++;
56
56
  }
57
57
  // 2. Blacklisted Skill Propagation (Immune Prophet)
58
58
  const blacklisted = await cortex.capabilities.getCapabilities('blacklisted');
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Utility function to apply a "FOR UPDATE" lock only where supported (Not in SQLite)
3
+ */
4
+ export declare function withLock(query: any, trx: any): any;
@@ -0,0 +1,25 @@
1
+ /// <reference types="./db-utils.d.ts" />
2
+ /**
3
+ * Utility function to apply a "FOR UPDATE" lock only where supported (Not in SQLite)
4
+ */
5
+ export function withLock(query, trx) {
6
+ if (!trx || typeof trx.getExecutor !== 'function') {
7
+ // If we're using a mock or a version of Kysely without getExecutor
8
+ // we default to no lock to prevent failures in tests
9
+ return query;
10
+ }
11
+ try {
12
+ const executor = trx.getExecutor();
13
+ const adapterName = executor?.adapter?.constructor?.name ||
14
+ executor?.dialect?.constructor?.name ||
15
+ '';
16
+ if (adapterName.toLowerCase().includes('sqlite')) {
17
+ return query;
18
+ }
19
+ }
20
+ catch (error) {
21
+ // Fallback if execution fails for some reason
22
+ return query;
23
+ }
24
+ return query.forUpdate();
25
+ }
@@ -117,6 +117,7 @@ export class AgentSchemaHelper {
117
117
  .addColumn('tool_name', 'text', (col) => col.notNull())
118
118
  .addColumn('arguments', 'text', (col) => col.notNull())
119
119
  .addColumn('outcome', 'text')
120
+ .addColumn('error', 'text')
120
121
  .addColumn('status', 'text', (col) => col.notNull().defaultTo('pending'))
121
122
  .addColumn('duration_ms', 'integer')
122
123
  .addColumn('metadata', 'text')
@@ -89,6 +89,8 @@ export async function setupTestSchema(db) {
89
89
  .on('comments')
90
90
  .column('user_id')
91
91
  .execute();
92
+ // Initialize agent schema
93
+ await db.agent.schema.initializeSchema();
92
94
  // Initialize NOORMME to discover the schema
93
95
  // Temporarily enable warnings to see discovery errors
94
96
  const originalWarn = console.warn;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noormme",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "NOORMME - The Agentic Data Engine. High-fidelity persistence and cognitive governance for Autonomous AI Agents.",
5
5
  "repository": {
6
6
  "type": "git",