@almadar/agent 1.1.4 → 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.
package/dist/index.js CHANGED
@@ -18,6 +18,7 @@ import { MemorySaver } from '@langchain/langgraph';
18
18
  export { Command } from '@langchain/langgraph';
19
19
  import { v4 } from 'uuid';
20
20
  import { BaseCheckpointSaver, BaseStore } from '@langchain/langgraph-checkpoint';
21
+ import { EventEmitter } from 'events';
21
22
 
22
23
  var __defProp = Object.defineProperty;
23
24
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -4431,9 +4432,13 @@ var SessionManager = class {
4431
4432
  constructor(options = {}) {
4432
4433
  this.firestoreCheckpointer = null;
4433
4434
  this.firestoreSessionStore = null;
4435
+ this.memoryManager = null;
4436
+ this.compactionConfig = null;
4434
4437
  this.mode = options.mode ?? "memory";
4435
4438
  this.memoryBackend = new MemorySessionBackend();
4436
4439
  this.memoryCheckpointers = /* @__PURE__ */ new Map();
4440
+ this.memoryManager = options.memoryManager ?? null;
4441
+ this.compactionConfig = options.compactionConfig ?? null;
4437
4442
  if (this.mode === "firestore" && options.firestoreDb) {
4438
4443
  this.firestoreCheckpointer = new FirestoreCheckpointer({ db: options.firestoreDb });
4439
4444
  this.firestoreSessionStore = new FirestoreSessionStore({ db: options.firestoreDb });
@@ -4533,6 +4538,260 @@ var SessionManager = class {
4533
4538
  }
4534
4539
  return this.memoryBackend.list();
4535
4540
  }
4541
+ // ============================================================================
4542
+ // Session → Memory Sync (GAP-002D)
4543
+ // ============================================================================
4544
+ /**
4545
+ * Sync a completed session to orbital memory.
4546
+ * This enables the agent to learn from past sessions.
4547
+ *
4548
+ * @param threadId - The session thread ID
4549
+ * @param userId - The user ID for memory association
4550
+ * @param sessionData - Additional session data to record
4551
+ * @returns Promise that resolves when sync is complete
4552
+ */
4553
+ async syncSessionToMemory(threadId, userId, sessionData) {
4554
+ if (!this.memoryManager) {
4555
+ console.warn("[SessionManager] No memory manager configured, skipping session sync");
4556
+ return;
4557
+ }
4558
+ const metadata = this.get(threadId);
4559
+ if (!metadata) {
4560
+ console.warn(`[SessionManager] Session ${threadId} not found, skipping sync`);
4561
+ return;
4562
+ }
4563
+ try {
4564
+ await this.memoryManager.recordGeneration(userId, {
4565
+ threadId,
4566
+ prompt: sessionData.inputDescription,
4567
+ skill: metadata.skill,
4568
+ generatedSchema: sessionData.generatedOrbital ? { name: sessionData.generatedOrbital } : void 0,
4569
+ patterns: sessionData.patternsUsed ?? [],
4570
+ entities: sessionData.entities ?? [],
4571
+ success: sessionData.success,
4572
+ completedAt: /* @__PURE__ */ new Date()
4573
+ });
4574
+ if (sessionData.patternsUsed && sessionData.patternsUsed.length > 0) {
4575
+ await this.memoryManager.updateUserPreferences(userId, {
4576
+ preferredPatterns: sessionData.patternsUsed,
4577
+ commonEntities: sessionData.entities
4578
+ });
4579
+ }
4580
+ if (sessionData.entities && sessionData.entities.length > 0) {
4581
+ await this.memoryManager.updateProjectContext(sessionData.appId, {
4582
+ userId,
4583
+ existingEntities: sessionData.entities
4584
+ });
4585
+ }
4586
+ console.log(`[SessionManager] Session ${threadId} synced to memory for user ${userId}`);
4587
+ } catch (error) {
4588
+ console.error("[SessionManager] Failed to sync session to memory:", error);
4589
+ }
4590
+ }
4591
+ // ============================================================================
4592
+ // Interrupt → Memory Sync (GAP-003: Interrupt Memory)
4593
+ // ============================================================================
4594
+ /**
4595
+ * Record an interrupt decision to memory.
4596
+ * This enables learning from HITL (Human-in-the-Loop) decisions.
4597
+ *
4598
+ * @param sessionId - The session thread ID
4599
+ * @param userId - The user who made the decision
4600
+ * @param interruptData - The interrupt decision data
4601
+ * @returns Promise that resolves when sync is complete
4602
+ */
4603
+ async recordInterruptDecision(sessionId, userId, interruptData) {
4604
+ if (!this.memoryManager) {
4605
+ console.warn("[SessionManager] No memory manager configured, skipping interrupt sync");
4606
+ return;
4607
+ }
4608
+ try {
4609
+ await this.memoryManager.recordInterruptDecision(sessionId, userId, interruptData);
4610
+ console.log(`[SessionManager] Interrupt recorded for user ${userId}: ${interruptData.toolName} ${interruptData.decision}`);
4611
+ } catch (error) {
4612
+ console.error("[SessionManager] Failed to record interrupt:", error);
4613
+ }
4614
+ }
4615
+ /**
4616
+ * Get interrupt history for a session.
4617
+ */
4618
+ async getSessionInterrupts(sessionId) {
4619
+ if (!this.memoryManager) {
4620
+ return [];
4621
+ }
4622
+ return this.memoryManager.getSessionInterrupts(sessionId);
4623
+ }
4624
+ /**
4625
+ * Check if a tool should be auto-approved for a user.
4626
+ */
4627
+ async shouldAutoApproveTool(userId, toolName) {
4628
+ if (!this.memoryManager) {
4629
+ return false;
4630
+ }
4631
+ return this.memoryManager.shouldAutoApproveTool(userId, toolName);
4632
+ }
4633
+ // ============================================================================
4634
+ // Checkpoint Management (GAP-004: Checkpoint → Memory)
4635
+ // ============================================================================
4636
+ /**
4637
+ * Record a checkpoint to memory for learning.
4638
+ *
4639
+ * @param userId - The user who owns this checkpoint
4640
+ * @param checkpointData - Checkpoint information
4641
+ * @returns Promise that resolves when checkpoint is recorded
4642
+ */
4643
+ async recordCheckpoint(userId, checkpointData) {
4644
+ if (!this.memoryManager) {
4645
+ console.warn("[SessionManager] No memory manager configured, skipping checkpoint record");
4646
+ return;
4647
+ }
4648
+ try {
4649
+ await this.memoryManager.recordCheckpoint(userId, checkpointData);
4650
+ console.log(`[SessionManager] Checkpoint ${checkpointData.checkpointId} recorded for user ${userId}`);
4651
+ } catch (error) {
4652
+ console.error("[SessionManager] Failed to record checkpoint:", error);
4653
+ }
4654
+ }
4655
+ /**
4656
+ * Record a rollback to a checkpoint.
4657
+ *
4658
+ * @param userId - The user who performed the rollback
4659
+ * @param checkpointId - The checkpoint rolled back to
4660
+ * @param reason - Optional reason for rollback
4661
+ * @returns Promise that resolves when rollback is recorded
4662
+ */
4663
+ async recordRollback(userId, checkpointId, reason) {
4664
+ if (!this.memoryManager) {
4665
+ console.warn("[SessionManager] No memory manager configured, skipping rollback record");
4666
+ return;
4667
+ }
4668
+ try {
4669
+ await this.memoryManager.recordRollback(userId, checkpointId, reason);
4670
+ console.log(`[SessionManager] Rollback to ${checkpointId} recorded for user ${userId}`);
4671
+ } catch (error) {
4672
+ console.error("[SessionManager] Failed to record rollback:", error);
4673
+ }
4674
+ }
4675
+ /**
4676
+ * Mark a checkpoint as successful (terminal state).
4677
+ *
4678
+ * @param userId - The user who owns this checkpoint
4679
+ * @param checkpointId - The checkpoint that was successful
4680
+ * @returns Promise that resolves when success is recorded
4681
+ */
4682
+ async markCheckpointSuccessful(userId, checkpointId) {
4683
+ if (!this.memoryManager) {
4684
+ console.warn("[SessionManager] No memory manager configured, skipping success mark");
4685
+ return;
4686
+ }
4687
+ try {
4688
+ await this.memoryManager.markCheckpointSuccessful(userId, checkpointId);
4689
+ console.log(`[SessionManager] Checkpoint ${checkpointId} marked as successful for user ${userId}`);
4690
+ } catch (error) {
4691
+ console.error("[SessionManager] Failed to mark checkpoint as successful:", error);
4692
+ }
4693
+ }
4694
+ /**
4695
+ * Get checkpoint history for a thread.
4696
+ *
4697
+ * @param threadId - The thread to get checkpoints for
4698
+ * @returns Array of checkpoint records
4699
+ */
4700
+ async getThreadCheckpoints(threadId) {
4701
+ if (!this.memoryManager) {
4702
+ return [];
4703
+ }
4704
+ return this.memoryManager.getThreadCheckpoints(threadId);
4705
+ }
4706
+ /**
4707
+ * Get frequently rolled-back checkpoints (problem areas).
4708
+ *
4709
+ * @param userId - The user to get problem checkpoints for
4710
+ * @param minRollbackCount - Minimum rollback count (default: 2)
4711
+ * @returns Array of checkpoint records with rollback issues
4712
+ */
4713
+ async getProblemCheckpoints(userId, minRollbackCount = 2) {
4714
+ if (!this.memoryManager) {
4715
+ return [];
4716
+ }
4717
+ return this.memoryManager.getProblemCheckpoints(userId, minRollbackCount);
4718
+ }
4719
+ // ============================================================================
4720
+ // Context Compaction (GAP-005)
4721
+ // ============================================================================
4722
+ /**
4723
+ * Get the context compaction configuration.
4724
+ * @returns The compaction configuration or null if not configured.
4725
+ */
4726
+ getCompactionConfig() {
4727
+ return this.compactionConfig;
4728
+ }
4729
+ /**
4730
+ * Check if a session's messages need compaction based on token count.
4731
+ * Uses character-based estimation for quick checks.
4732
+ *
4733
+ * @param messages - Array of messages to check
4734
+ * @returns True if compaction is recommended
4735
+ */
4736
+ shouldCompactMessages(messages) {
4737
+ if (!this.compactionConfig) {
4738
+ return false;
4739
+ }
4740
+ const totalChars = messages.reduce((sum, msg) => {
4741
+ const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
4742
+ return sum + content.length;
4743
+ }, 0);
4744
+ const estimatedTokens = totalChars / 4;
4745
+ const threshold = this.compactionConfig.maxTokens ?? 15e4;
4746
+ return estimatedTokens > threshold * 0.8;
4747
+ }
4748
+ /**
4749
+ * Record a compaction event for a session.
4750
+ * This helps track when and why compaction occurs.
4751
+ *
4752
+ * @param threadId - The session thread ID
4753
+ * @param originalMessageCount - Number of messages before compaction
4754
+ * @param compactedMessageCount - Number of messages after compaction
4755
+ * @param reason - Reason for compaction
4756
+ */
4757
+ async recordCompaction(threadId, originalMessageCount, compactedMessageCount, reason) {
4758
+ if (!this.memoryManager) {
4759
+ console.warn("[SessionManager] No memory manager configured, skipping compaction record");
4760
+ return;
4761
+ }
4762
+ try {
4763
+ const metadata = this.get(threadId);
4764
+ if (metadata) {
4765
+ const compactionInfo = {
4766
+ timestamp: Date.now(),
4767
+ originalMessageCount,
4768
+ compactedMessageCount,
4769
+ reason: reason ?? "token_limit"
4770
+ };
4771
+ const meta = metadata;
4772
+ const existingCompactions = meta.compactions ?? [];
4773
+ meta.compactions = [...existingCompactions, compactionInfo];
4774
+ this.store(threadId, metadata);
4775
+ }
4776
+ console.log(`[SessionManager] Compaction recorded for ${threadId}: ${originalMessageCount} \u2192 ${compactedMessageCount} messages`);
4777
+ } catch (error) {
4778
+ console.error("[SessionManager] Failed to record compaction:", error);
4779
+ }
4780
+ }
4781
+ /**
4782
+ * Get compaction history for a session.
4783
+ *
4784
+ * @param threadId - The session thread ID
4785
+ * @returns Array of compaction events
4786
+ */
4787
+ getCompactionHistory(threadId) {
4788
+ const metadata = this.get(threadId);
4789
+ if (!metadata) {
4790
+ return [];
4791
+ }
4792
+ const meta = metadata;
4793
+ return meta.compactions ?? [];
4794
+ }
4536
4795
  };
4537
4796
 
4538
4797
  // src/agent/interrupt-config.ts
@@ -5458,6 +5717,9 @@ var MemoryManager = class {
5458
5717
  this.projectsCollection = options.projectsCollection ?? "agent_memory_projects";
5459
5718
  this.patternsCollection = options.patternsCollection ?? "agent_memory_patterns";
5460
5719
  this.feedbackCollection = options.feedbackCollection ?? "agent_memory_feedback";
5720
+ this.interruptsCollection = options.interruptsCollection ?? "agent_memory_interrupts";
5721
+ this.toolPreferencesCollection = options.toolPreferencesCollection ?? "agent_memory_tool_preferences";
5722
+ this.checkpointsCollection = options.checkpointsCollection ?? "agent_memory_checkpoints";
5461
5723
  }
5462
5724
  // ============================================================================
5463
5725
  // User Preferences
@@ -5742,6 +6004,178 @@ var MemoryManager = class {
5742
6004
  serializeContext(context) {
5743
6005
  return { ...context };
5744
6006
  }
6007
+ // ============================================================================
6008
+ // Interrupt Tracking (GAP-003: Interrupt Memory)
6009
+ // ============================================================================
6010
+ /**
6011
+ * Record an interrupt decision for learning
6012
+ */
6013
+ async recordInterruptDecision(sessionId, userId, interruptData) {
6014
+ const interruptId = `int_${Date.now()}_${Math.random().toString(36).slice(2)}`;
6015
+ const record = {
6016
+ interruptId,
6017
+ sessionId,
6018
+ userId,
6019
+ toolName: interruptData.toolName,
6020
+ toolArgs: interruptData.toolArgs,
6021
+ decision: interruptData.decision,
6022
+ modifiedArgs: interruptData.modifiedArgs,
6023
+ reason: interruptData.reason,
6024
+ timestamp: /* @__PURE__ */ new Date()
6025
+ };
6026
+ await this.db.collection(this.interruptsCollection).doc(interruptId).set(record);
6027
+ await this.updateToolApprovalPreference(userId, interruptData.toolName, interruptData.decision);
6028
+ }
6029
+ /**
6030
+ * Get interrupt history for a session
6031
+ */
6032
+ async getSessionInterrupts(sessionId) {
6033
+ const snapshot = await this.db.collection(this.interruptsCollection).where("sessionId", "==", sessionId).orderBy("timestamp", "desc").get();
6034
+ return snapshot.docs.map((doc) => doc.data());
6035
+ }
6036
+ /**
6037
+ * Get interrupt history for a user
6038
+ */
6039
+ async getUserInterrupts(userId, limit = 50) {
6040
+ const snapshot = await this.db.collection(this.interruptsCollection).where("userId", "==", userId).orderBy("timestamp", "desc").limit(limit).get();
6041
+ return snapshot.docs.map((doc) => doc.data());
6042
+ }
6043
+ /**
6044
+ * Get tool approval preference for a user
6045
+ */
6046
+ async getToolApprovalPreference(userId, toolName) {
6047
+ const prefId = `${userId}_${toolName}`;
6048
+ const doc = await this.db.collection(this.toolPreferencesCollection).doc(prefId).get();
6049
+ if (!doc.exists) return null;
6050
+ return doc.data();
6051
+ }
6052
+ /**
6053
+ * Update tool approval preference based on interrupt decisions
6054
+ */
6055
+ async updateToolApprovalPreference(userId, toolName, decision) {
6056
+ const prefId = `${userId}_${toolName}`;
6057
+ const existing = await this.db.collection(this.toolPreferencesCollection).doc(prefId).get();
6058
+ if (!existing.exists) {
6059
+ const pref = {
6060
+ userId,
6061
+ toolName,
6062
+ autoApprove: decision === "approved",
6063
+ confidence: decision === "approved" ? 0.5 : 0,
6064
+ approvedCount: decision === "approved" ? 1 : 0,
6065
+ rejectedCount: decision === "rejected" ? 1 : 0,
6066
+ lastDecisionAt: /* @__PURE__ */ new Date()
6067
+ };
6068
+ await this.db.collection(this.toolPreferencesCollection).doc(prefId).set(pref);
6069
+ } else {
6070
+ const data = existing.data();
6071
+ const approvedCount = data.approvedCount + (decision === "approved" ? 1 : 0);
6072
+ const rejectedCount = data.rejectedCount + (decision === "rejected" ? 1 : 0);
6073
+ const total = approvedCount + rejectedCount;
6074
+ const approvalRate = approvedCount / total;
6075
+ const pref = {
6076
+ ...data,
6077
+ approvedCount,
6078
+ rejectedCount,
6079
+ // Auto-approve if approval rate > 80% and at least 5 decisions
6080
+ autoApprove: total >= 5 && approvalRate > 0.8,
6081
+ confidence: Math.min(0.95, total * 0.1),
6082
+ lastDecisionAt: /* @__PURE__ */ new Date()
6083
+ };
6084
+ await this.db.collection(this.toolPreferencesCollection).doc(prefId).set(pref);
6085
+ }
6086
+ }
6087
+ /**
6088
+ * Get all tool approval preferences for a user
6089
+ */
6090
+ async getUserToolPreferences(userId) {
6091
+ const snapshot = await this.db.collection(this.toolPreferencesCollection).where("userId", "==", userId).get();
6092
+ return snapshot.docs.map((doc) => doc.data());
6093
+ }
6094
+ /**
6095
+ * Check if a tool should be auto-approved for a user
6096
+ */
6097
+ async shouldAutoApproveTool(userId, toolName) {
6098
+ const pref = await this.getToolApprovalPreference(userId, toolName);
6099
+ return pref?.autoApprove ?? false;
6100
+ }
6101
+ // ============================================================================
6102
+ // Checkpoint Tracking (GAP-004: Checkpoint → Memory)
6103
+ // ============================================================================
6104
+ /**
6105
+ * Record a checkpoint for learning
6106
+ */
6107
+ async recordCheckpoint(userId, checkpointData) {
6108
+ const record = {
6109
+ checkpointId: checkpointData.checkpointId,
6110
+ threadId: checkpointData.threadId,
6111
+ userId,
6112
+ parentCheckpointId: checkpointData.parentCheckpointId,
6113
+ metadata: checkpointData.metadata ?? {},
6114
+ createdAt: /* @__PURE__ */ new Date(),
6115
+ rollbackCount: 0,
6116
+ wasSuccessful: false
6117
+ };
6118
+ const docId = `${userId}_${checkpointData.checkpointId}`;
6119
+ await this.db.collection(this.checkpointsCollection).doc(docId).set(record);
6120
+ }
6121
+ /**
6122
+ * Record a rollback to a checkpoint
6123
+ */
6124
+ async recordRollback(userId, checkpointId, reason) {
6125
+ const docId = `${userId}_${checkpointId}`;
6126
+ const doc = await this.db.collection(this.checkpointsCollection).doc(docId).get();
6127
+ if (doc.exists) {
6128
+ const data = doc.data();
6129
+ await this.db.collection(this.checkpointsCollection).doc(docId).set({
6130
+ ...data,
6131
+ rollbackCount: data.rollbackCount + 1,
6132
+ lastRollbackReason: reason,
6133
+ lastRollbackAt: /* @__PURE__ */ new Date()
6134
+ });
6135
+ }
6136
+ }
6137
+ /**
6138
+ * Mark a checkpoint as successful (terminal state)
6139
+ */
6140
+ async markCheckpointSuccessful(userId, checkpointId) {
6141
+ const docId = `${userId}_${checkpointId}`;
6142
+ const doc = await this.db.collection(this.checkpointsCollection).doc(docId).get();
6143
+ if (doc.exists) {
6144
+ const data = doc.data();
6145
+ await this.db.collection(this.checkpointsCollection).doc(docId).set({
6146
+ ...data,
6147
+ wasSuccessful: true
6148
+ });
6149
+ }
6150
+ }
6151
+ /**
6152
+ * Get checkpoint history for a user
6153
+ */
6154
+ async getUserCheckpoints(userId, limit = 50) {
6155
+ const snapshot = await this.db.collection(this.checkpointsCollection).where("userId", "==", userId).orderBy("createdAt", "desc").limit(limit).get();
6156
+ return snapshot.docs.map((doc) => doc.data());
6157
+ }
6158
+ /**
6159
+ * Get checkpoints for a thread
6160
+ */
6161
+ async getThreadCheckpoints(threadId) {
6162
+ const snapshot = await this.db.collection(this.checkpointsCollection).where("threadId", "==", threadId).orderBy("createdAt", "desc").get();
6163
+ return snapshot.docs.map((doc) => doc.data());
6164
+ }
6165
+ /**
6166
+ * Get frequently rolled-back checkpoints (problem areas)
6167
+ */
6168
+ async getProblemCheckpoints(userId, minRollbackCount = 2) {
6169
+ const snapshot = await this.db.collection(this.checkpointsCollection).where("userId", "==", userId).where("rollbackCount", ">=", minRollbackCount).orderBy("rollbackCount", "desc").get();
6170
+ return snapshot.docs.map((doc) => doc.data());
6171
+ }
6172
+ /**
6173
+ * Get successful checkpoint patterns for learning
6174
+ */
6175
+ async getSuccessfulCheckpoints(userId, limit = 20) {
6176
+ const snapshot = await this.db.collection(this.checkpointsCollection).where("userId", "==", userId).where("wasSuccessful", "==", true).orderBy("createdAt", "desc").limit(limit).get();
6177
+ return snapshot.docs.map((doc) => doc.data());
6178
+ }
5745
6179
  };
5746
6180
  var PreferenceLearner = class {
5747
6181
  constructor(options) {
@@ -5966,11 +6400,987 @@ Respond in JSON format:
5966
6400
  function createPreferenceLearner(options) {
5967
6401
  return new PreferenceLearner(options);
5968
6402
  }
6403
+
6404
+ // src/memory/agentic-search.ts
6405
+ var AgenticSearchEngine = class {
6406
+ constructor(memoryManager) {
6407
+ this.memoryManager = memoryManager;
6408
+ }
6409
+ /**
6410
+ * Perform agentic search through memory
6411
+ */
6412
+ async search(params) {
6413
+ const startTime = Date.now();
6414
+ const strategy = params.strategy ?? "hybrid";
6415
+ const depth = params.depth ?? 3;
6416
+ const limit = params.limit ?? 10;
6417
+ let results = [];
6418
+ switch (strategy) {
6419
+ case "temporal":
6420
+ results = await this.temporalSearch(params, depth, limit);
6421
+ break;
6422
+ case "semantic":
6423
+ results = await this.semanticSearch(params, depth, limit);
6424
+ break;
6425
+ case "pattern":
6426
+ results = await this.patternSearch(params, depth, limit);
6427
+ break;
6428
+ case "hybrid":
6429
+ default:
6430
+ results = await this.hybridSearch(params, depth, limit);
6431
+ break;
6432
+ }
6433
+ results.sort((a, b) => b.relevance - a.relevance);
6434
+ const insights = this.generateInsights(results, params.query);
6435
+ const duration = Date.now() - startTime;
6436
+ return {
6437
+ results: results.slice(0, limit),
6438
+ insights,
6439
+ metadata: {
6440
+ strategy,
6441
+ depth,
6442
+ duration,
6443
+ totalResults: results.length
6444
+ }
6445
+ };
6446
+ }
6447
+ // ============================================================================
6448
+ // Search Strategies
6449
+ // ============================================================================
6450
+ /**
6451
+ * Temporal search - "What did I do last week?"
6452
+ * Navigates memory by time relationships
6453
+ */
6454
+ async temporalSearch(params, _depth, limit) {
6455
+ const results = [];
6456
+ const isRecentQuery = /recent|last|latest|newest/i.test(params.query);
6457
+ /week|month|day|ago/i.test(params.query);
6458
+ const sessions = await this.memoryManager.getUserGenerationHistory(params.userId, limit * 2);
6459
+ for (const session of sessions) {
6460
+ let relevance = 0.5;
6461
+ let reasoning = "Recent generation session";
6462
+ if (isRecentQuery) {
6463
+ const daysAgo = (Date.now() - session.createdAt.getTime()) / (1e3 * 60 * 60 * 24);
6464
+ relevance = Math.max(0.1, 1 - daysAgo / 30);
6465
+ reasoning = `Created ${Math.round(daysAgo)} days ago`;
6466
+ }
6467
+ const sessionText = `${session.prompt} ${session.entities.join(" ")} ${session.patterns.join(" ")}`.toLowerCase();
6468
+ const queryTerms = params.query.toLowerCase().split(/\s+/);
6469
+ const termMatches = queryTerms.filter((term) => sessionText.includes(term)).length;
6470
+ relevance += termMatches * 0.1;
6471
+ if (relevance > 0.3) {
6472
+ results.push({
6473
+ type: "session",
6474
+ data: session,
6475
+ relevance: Math.min(1, relevance),
6476
+ reasoning,
6477
+ source: "generation_history",
6478
+ timestamp: session.createdAt
6479
+ });
6480
+ }
6481
+ }
6482
+ return results;
6483
+ }
6484
+ /**
6485
+ * Semantic search - "How did I handle user roles?"
6486
+ * Reasoning-based understanding of structure
6487
+ */
6488
+ async semanticSearch(params, _depth, limit) {
6489
+ const results = [];
6490
+ const concepts = this.extractConcepts(params.query);
6491
+ const prefs = await this.memoryManager.getUserPreferences(params.userId);
6492
+ if (prefs) {
6493
+ let relevance = 0.3;
6494
+ const matchedConcepts = [];
6495
+ if (concepts.naming && prefs.namingConvention) {
6496
+ relevance += 0.2;
6497
+ matchedConcepts.push(`uses ${prefs.namingConvention}`);
6498
+ }
6499
+ if (concepts.patterns && prefs.preferredPatterns.length > 0) {
6500
+ const matched = prefs.preferredPatterns.filter(
6501
+ (p) => concepts.patterns?.some((cp) => p.toLowerCase().includes(cp.toLowerCase()))
6502
+ );
6503
+ relevance += matched.length * 0.1;
6504
+ matchedConcepts.push(`patterns: ${matched.join(", ")}`);
6505
+ }
6506
+ if (concepts.entities && prefs.commonEntities.length > 0) {
6507
+ const matched = prefs.commonEntities.filter(
6508
+ (e) => concepts.entities?.some((ce) => e.toLowerCase().includes(ce.toLowerCase()))
6509
+ );
6510
+ relevance += matched.length * 0.1;
6511
+ matchedConcepts.push(`entities: ${matched.join(", ")}`);
6512
+ }
6513
+ if (relevance > 0.4) {
6514
+ results.push({
6515
+ type: "preference",
6516
+ data: prefs,
6517
+ relevance: Math.min(1, relevance),
6518
+ reasoning: `User preferences match query concepts: ${matchedConcepts.join("; ")}`,
6519
+ source: "user_preferences",
6520
+ timestamp: prefs.learnedAt
6521
+ });
6522
+ }
6523
+ }
6524
+ if (params.appId) {
6525
+ const project = await this.memoryManager.getProjectContext(params.appId);
6526
+ if (project) {
6527
+ let relevance = 0.3;
6528
+ const projectText = `${project.projectName ?? ""} ${project.description ?? ""} ${project.existingEntities.join(" ")}`.toLowerCase();
6529
+ const queryTerms = params.query.toLowerCase().split(/\s+/);
6530
+ const termMatches = queryTerms.filter((term) => projectText.includes(term)).length;
6531
+ relevance += termMatches * 0.15;
6532
+ if (relevance > 0.4) {
6533
+ results.push({
6534
+ type: "project",
6535
+ data: project,
6536
+ relevance: Math.min(1, relevance),
6537
+ reasoning: `Project context contains ${termMatches} matching terms`,
6538
+ source: "project_context",
6539
+ timestamp: project.lastUpdatedAt
6540
+ });
6541
+ }
6542
+ }
6543
+ }
6544
+ const sessions = await this.memoryManager.getUserGenerationHistory(params.userId, limit);
6545
+ for (const session of sessions) {
6546
+ const sessionText = `${session.prompt} ${session.entities.join(" ")}`.toLowerCase();
6547
+ let relevance = 0.3;
6548
+ if (concepts.entities) {
6549
+ const entityMatches = session.entities.filter(
6550
+ (e) => concepts.entities?.some((ce) => e.toLowerCase().includes(ce.toLowerCase()))
6551
+ );
6552
+ relevance += entityMatches.length * 0.15;
6553
+ }
6554
+ if (concepts.patterns) {
6555
+ const patternMatches = session.patterns.filter(
6556
+ (p) => concepts.patterns?.some((cp) => p.toLowerCase().includes(cp.toLowerCase()))
6557
+ );
6558
+ relevance += patternMatches.length * 0.1;
6559
+ }
6560
+ const queryTerms = params.query.toLowerCase().split(/\s+/);
6561
+ const termMatches = queryTerms.filter((term) => sessionText.includes(term)).length;
6562
+ relevance += termMatches * 0.05;
6563
+ if (relevance > 0.4) {
6564
+ results.push({
6565
+ type: "session",
6566
+ data: session,
6567
+ relevance: Math.min(1, relevance),
6568
+ reasoning: `Session contains relevant entities, patterns, or keywords`,
6569
+ source: "generation_history",
6570
+ timestamp: session.createdAt
6571
+ });
6572
+ }
6573
+ }
6574
+ return results;
6575
+ }
6576
+ /**
6577
+ * Pattern search - "Show me all list views I've built"
6578
+ * Searches for specific patterns and effects
6579
+ */
6580
+ async patternSearch(params, _depth, limit) {
6581
+ const results = [];
6582
+ const patternTerms = ["list", "form", "detail", "card", "table", "chart", "map", "calendar"];
6583
+ const matchedTerms = patternTerms.filter(
6584
+ (term) => params.query.toLowerCase().includes(term)
6585
+ );
6586
+ const patterns = await this.memoryManager.getUserPatterns(params.userId);
6587
+ for (const pattern of patterns) {
6588
+ let relevance = 0.3;
6589
+ let reasoning = `Pattern usage: ${pattern.usageCount} times`;
6590
+ if (matchedTerms.some((term) => pattern.patternId.toLowerCase().includes(term))) {
6591
+ relevance += 0.3;
6592
+ reasoning += ", matches query pattern type";
6593
+ }
6594
+ const successRate = pattern.usageCount > 0 ? pattern.successCount / pattern.usageCount : 0;
6595
+ relevance += successRate * 0.2;
6596
+ if (relevance > 0.4) {
6597
+ results.push({
6598
+ type: "pattern",
6599
+ data: pattern,
6600
+ relevance: Math.min(1, relevance),
6601
+ reasoning: `${reasoning}, ${Math.round(successRate * 100)}% success rate`,
6602
+ source: "pattern_affinity",
6603
+ timestamp: pattern.lastUsedAt
6604
+ });
6605
+ }
6606
+ }
6607
+ const sessions = await this.memoryManager.getUserGenerationHistory(params.userId, limit);
6608
+ for (const session of sessions) {
6609
+ const matchingPatterns = session.patterns.filter(
6610
+ (p) => matchedTerms.some((term) => p.toLowerCase().includes(term))
6611
+ );
6612
+ if (matchingPatterns.length > 0) {
6613
+ results.push({
6614
+ type: "session",
6615
+ data: session,
6616
+ relevance: 0.5 + matchingPatterns.length * 0.1,
6617
+ reasoning: `Session uses patterns: ${matchingPatterns.join(", ")}`,
6618
+ source: "generation_history",
6619
+ timestamp: session.createdAt
6620
+ });
6621
+ }
6622
+ }
6623
+ return results;
6624
+ }
6625
+ /**
6626
+ * Hybrid search - combines all strategies
6627
+ */
6628
+ async hybridSearch(params, depth, limit) {
6629
+ const [temporal, semantic, pattern] = await Promise.all([
6630
+ this.temporalSearch(params, depth, Math.ceil(limit / 2)),
6631
+ this.semanticSearch(params, depth, Math.ceil(limit / 2)),
6632
+ this.patternSearch(params, depth, Math.ceil(limit / 2))
6633
+ ]);
6634
+ const seen = /* @__PURE__ */ new Set();
6635
+ const combined = [];
6636
+ for (const result of [...temporal, ...semantic, ...pattern]) {
6637
+ const key = `${result.type}-${JSON.stringify(result.data)}`;
6638
+ if (!seen.has(key)) {
6639
+ seen.add(key);
6640
+ combined.push(result);
6641
+ }
6642
+ }
6643
+ return combined;
6644
+ }
6645
+ // ============================================================================
6646
+ // Helpers
6647
+ // ============================================================================
6648
+ /**
6649
+ * Extract semantic concepts from query
6650
+ */
6651
+ extractConcepts(query) {
6652
+ const lower = query.toLowerCase();
6653
+ return {
6654
+ naming: /naming|case|pascal|camel|snake/i.test(lower),
6655
+ validation: /validat|schema|required|optional/i.test(lower),
6656
+ patterns: ["entity", "list", "form", "detail", "card"].filter((p) => lower.includes(p)),
6657
+ entities: this.extractEntityNames(lower),
6658
+ actions: ["create", "update", "delete", "list", "view"].filter((a) => lower.includes(a))
6659
+ };
6660
+ }
6661
+ /**
6662
+ * Extract potential entity names from query
6663
+ */
6664
+ extractEntityNames(query) {
6665
+ const words = query.split(/\s+/);
6666
+ const entities = [];
6667
+ for (const word of words) {
6668
+ const clean = word.replace(/[^a-zA-Z]/g, "");
6669
+ if (clean.length > 2 && clean[0] === clean[0].toUpperCase()) {
6670
+ entities.push(clean);
6671
+ }
6672
+ }
6673
+ return entities;
6674
+ }
6675
+ /**
6676
+ * Generate insights from search results
6677
+ */
6678
+ generateInsights(results, query) {
6679
+ const summary = `Found ${results.length} relevant memory items for "${query}"`;
6680
+ const patternResults = results.filter((r) => r.type === "pattern");
6681
+ const patterns = patternResults.length > 0 ? patternResults.slice(0, 3).map((r) => r.data.patternId) : ["No dominant patterns identified"];
6682
+ const sessions = results.filter((r) => r.type === "session");
6683
+ const trends = [];
6684
+ if (sessions.length > 0) {
6685
+ const timestamps = sessions.filter((s) => s.timestamp).map((s) => s.timestamp.getTime()).sort((a, b) => b - a);
6686
+ if (timestamps.length >= 2) {
6687
+ const avgGap = (timestamps[0] - timestamps[timestamps.length - 1]) / (timestamps.length - 1);
6688
+ const daysGap = avgGap / (1e3 * 60 * 60 * 24);
6689
+ if (daysGap < 7) {
6690
+ trends.push("High activity - multiple sessions per week");
6691
+ } else if (daysGap > 30) {
6692
+ trends.push("Sporadic usage - sessions spread out over time");
6693
+ }
6694
+ }
6695
+ }
6696
+ const suggestions = [];
6697
+ if (patterns.length > 0 && !patterns[0].includes("No dominant")) {
6698
+ suggestions.push(`Consider reusing pattern: ${patterns[0]}`);
6699
+ }
6700
+ const projectResults = results.filter((r) => r.type === "project");
6701
+ if (projectResults.length > 0) {
6702
+ suggestions.push("Review existing project conventions for consistency");
6703
+ }
6704
+ const interruptResults = results.filter((r) => r.type === "interrupt");
6705
+ if (interruptResults.length > 3) {
6706
+ suggestions.push("High interrupt frequency - consider adjusting auto-approval settings");
6707
+ }
6708
+ if (suggestions.length === 0) {
6709
+ suggestions.push("No specific suggestions based on current memory");
6710
+ }
6711
+ return { summary, patterns, trends, suggestions };
6712
+ }
6713
+ };
6714
+ function createAgenticSearchEngine(memoryManager) {
6715
+ return new AgenticSearchEngine(memoryManager);
6716
+ }
6717
+
6718
+ // src/observability.ts
6719
+ var ObservabilityCollector = class {
6720
+ constructor(options = {}) {
6721
+ this.events = [];
6722
+ this.sessions = /* @__PURE__ */ new Map();
6723
+ this.maxEvents = options.maxEvents ?? 1e4;
6724
+ }
6725
+ /**
6726
+ * Record an observable event
6727
+ */
6728
+ recordEvent(event) {
6729
+ const fullEvent = {
6730
+ ...event,
6731
+ timestamp: Date.now()
6732
+ };
6733
+ this.events.push(fullEvent);
6734
+ if (this.events.length > this.maxEvents) {
6735
+ this.events = this.events.slice(-this.maxEvents);
6736
+ }
6737
+ this.updateSessionTelemetry(fullEvent);
6738
+ }
6739
+ /**
6740
+ * Start session tracking
6741
+ */
6742
+ startSession(sessionId, userId) {
6743
+ this.sessions.set(sessionId, {
6744
+ sessionId,
6745
+ userId,
6746
+ startedAt: Date.now(),
6747
+ toolCallCount: 0,
6748
+ llmCallCount: 0,
6749
+ interruptCount: 0,
6750
+ checkpointCount: 0,
6751
+ totalTokens: 0,
6752
+ errors: [],
6753
+ status: "running"
6754
+ });
6755
+ this.recordEvent({
6756
+ type: "session_start",
6757
+ sessionId,
6758
+ userId,
6759
+ payload: { startedAt: Date.now() }
6760
+ });
6761
+ }
6762
+ /**
6763
+ * End session tracking
6764
+ */
6765
+ endSession(sessionId, status = "completed") {
6766
+ const session = this.sessions.get(sessionId);
6767
+ if (session) {
6768
+ session.endedAt = Date.now();
6769
+ session.status = status;
6770
+ this.recordEvent({
6771
+ type: "session_end",
6772
+ sessionId,
6773
+ userId: session.userId,
6774
+ payload: {
6775
+ status,
6776
+ duration: session.endedAt - session.startedAt,
6777
+ toolCalls: session.toolCallCount,
6778
+ llmCalls: session.llmCallCount
6779
+ },
6780
+ duration: session.endedAt - session.startedAt
6781
+ });
6782
+ }
6783
+ }
6784
+ /**
6785
+ * Record tool call
6786
+ */
6787
+ recordToolCall(sessionId, toolName, args, duration) {
6788
+ this.recordEvent({
6789
+ type: "tool_call",
6790
+ sessionId,
6791
+ payload: { tool: toolName, args },
6792
+ duration
6793
+ });
6794
+ const session = this.sessions.get(sessionId);
6795
+ if (session) {
6796
+ session.toolCallCount++;
6797
+ }
6798
+ }
6799
+ /**
6800
+ * Record LLM call
6801
+ */
6802
+ recordLLMCall(sessionId, model, tokens, duration) {
6803
+ this.recordEvent({
6804
+ type: "llm_call",
6805
+ sessionId,
6806
+ payload: { model, tokens },
6807
+ duration
6808
+ });
6809
+ const session = this.sessions.get(sessionId);
6810
+ if (session) {
6811
+ session.llmCallCount++;
6812
+ session.totalTokens += tokens.input + tokens.output;
6813
+ }
6814
+ }
6815
+ /**
6816
+ * Record error
6817
+ */
6818
+ recordError(sessionId, error, context) {
6819
+ this.recordEvent({
6820
+ type: "error",
6821
+ sessionId,
6822
+ payload: { ...context, message: error.message },
6823
+ error: {
6824
+ message: error.message,
6825
+ code: error.code,
6826
+ stack: error.stack
6827
+ }
6828
+ });
6829
+ const session = this.sessions.get(sessionId);
6830
+ if (session) {
6831
+ session.errors.push({
6832
+ timestamp: Date.now(),
6833
+ message: error.message,
6834
+ type: error.constructor.name
6835
+ });
6836
+ }
6837
+ }
6838
+ /**
6839
+ * Get events by type
6840
+ */
6841
+ getEvents(type, sessionId) {
6842
+ let filtered = this.events;
6843
+ if (type) {
6844
+ filtered = filtered.filter((e) => e.type === type);
6845
+ }
6846
+ if (sessionId) {
6847
+ filtered = filtered.filter((e) => e.sessionId === sessionId);
6848
+ }
6849
+ return filtered;
6850
+ }
6851
+ /**
6852
+ * Get session telemetry
6853
+ */
6854
+ getSessionTelemetry(sessionId) {
6855
+ return this.sessions.get(sessionId);
6856
+ }
6857
+ /**
6858
+ * Get all active sessions
6859
+ */
6860
+ getActiveSessions() {
6861
+ return Array.from(this.sessions.values()).filter((s) => s.status === "running");
6862
+ }
6863
+ /**
6864
+ * Get performance snapshot
6865
+ */
6866
+ getPerformanceSnapshot() {
6867
+ const now = Date.now();
6868
+ const sessions = Array.from(this.sessions.values());
6869
+ const activeSessions = sessions.filter((s) => s.status === "running");
6870
+ const last24h = sessions.filter((s) => s.startedAt > now - 24 * 60 * 60 * 1e3);
6871
+ const completed24h = last24h.filter((s) => s.status === "completed");
6872
+ const failed24h = last24h.filter((s) => s.status === "failed");
6873
+ const successRate24h = last24h.length > 0 ? completed24h.length / last24h.length * 100 : 0;
6874
+ const errorRate24h = last24h.length > 0 ? failed24h.length / last24h.length * 100 : 0;
6875
+ const completedSessions = sessions.filter((s) => s.endedAt);
6876
+ const avgSessionDuration = completedSessions.length > 0 ? completedSessions.reduce((sum, s) => sum + ((s.endedAt || now) - s.startedAt), 0) / completedSessions.length : 0;
6877
+ const sessionsWithTokens = sessions.filter((s) => s.totalTokens > 0);
6878
+ const avgTokensPerSession = sessionsWithTokens.length > 0 ? sessionsWithTokens.reduce((sum, s) => sum + s.totalTokens, 0) / sessionsWithTokens.length : 0;
6879
+ return {
6880
+ timestamp: now,
6881
+ activeSessions: activeSessions.length,
6882
+ totalSessions: sessions.length,
6883
+ avgSessionDuration,
6884
+ successRate24h,
6885
+ errorRate24h,
6886
+ avgTokensPerSession
6887
+ };
6888
+ }
6889
+ /**
6890
+ * Perform health check
6891
+ */
6892
+ async healthCheck() {
6893
+ const checks = [];
6894
+ const now = Date.now();
6895
+ checks.push({
6896
+ component: "event_buffer",
6897
+ status: this.events.length < this.maxEvents * 0.9 ? "healthy" : "degraded",
6898
+ responseTime: 0,
6899
+ checkedAt: now
6900
+ });
6901
+ const activeSessions = this.getActiveSessions();
6902
+ const staleSessions = activeSessions.filter(
6903
+ (s) => now - s.startedAt > 30 * 60 * 1e3
6904
+ // 30 minutes
6905
+ );
6906
+ checks.push({
6907
+ component: "sessions",
6908
+ status: staleSessions.length < 10 ? "healthy" : "degraded",
6909
+ responseTime: 0,
6910
+ checkedAt: now,
6911
+ error: staleSessions.length > 0 ? `${staleSessions.length} stale sessions` : void 0
6912
+ });
6913
+ return checks;
6914
+ }
6915
+ /**
6916
+ * Export metrics for external systems
6917
+ */
6918
+ exportMetrics() {
6919
+ return {
6920
+ events: this.events.slice(-1e3),
6921
+ // Last 1000 events
6922
+ sessions: Array.from(this.sessions.values()),
6923
+ snapshot: this.getPerformanceSnapshot(),
6924
+ health: []
6925
+ // Populated by healthCheck
6926
+ };
6927
+ }
6928
+ /**
6929
+ * Clear all data
6930
+ */
6931
+ clear() {
6932
+ this.events = [];
6933
+ this.sessions.clear();
6934
+ }
6935
+ // ============================================================================
6936
+ // Private Helpers
6937
+ // ============================================================================
6938
+ updateSessionTelemetry(event) {
6939
+ const session = this.sessions.get(event.sessionId);
6940
+ if (!session) return;
6941
+ switch (event.type) {
6942
+ case "interrupt":
6943
+ session.interruptCount++;
6944
+ break;
6945
+ case "checkpoint_save":
6946
+ session.checkpointCount++;
6947
+ break;
6948
+ }
6949
+ }
6950
+ };
6951
+ var globalCollector = null;
6952
+ function getObservabilityCollector() {
6953
+ if (!globalCollector) {
6954
+ globalCollector = new ObservabilityCollector();
6955
+ }
6956
+ return globalCollector;
6957
+ }
6958
+ function resetObservabilityCollector() {
6959
+ globalCollector = null;
6960
+ }
6961
+ function recordEvent(event) {
6962
+ getObservabilityCollector().recordEvent(event);
6963
+ }
6964
+ function startObservabilitySession(sessionId, userId) {
6965
+ getObservabilityCollector().startSession(sessionId, userId);
6966
+ }
6967
+ function endObservabilitySession(sessionId, status) {
6968
+ getObservabilityCollector().endSession(sessionId, status);
6969
+ }
6970
+ function getPerformanceSnapshot() {
6971
+ return getObservabilityCollector().getPerformanceSnapshot();
6972
+ }
6973
+
6974
+ // src/multi-user.ts
6975
+ var MultiUserManager = class {
6976
+ constructor() {
6977
+ this.sessionOwnership = /* @__PURE__ */ new Map();
6978
+ // threadId -> userId
6979
+ this.userSessions = /* @__PURE__ */ new Map();
6980
+ }
6981
+ // userId -> Set<threadId>
6982
+ /**
6983
+ * Check if a user owns a session
6984
+ */
6985
+ isSessionOwner(threadId, userId) {
6986
+ const owner = this.sessionOwnership.get(threadId);
6987
+ return owner === userId;
6988
+ }
6989
+ /**
6990
+ * Check if a user can access a session
6991
+ */
6992
+ canAccessSession(threadId, userContext) {
6993
+ const owner = this.sessionOwnership.get(threadId);
6994
+ if (!owner) {
6995
+ return { allowed: true };
6996
+ }
6997
+ if (owner === userContext.userId) {
6998
+ return { allowed: true };
6999
+ }
7000
+ if (userContext.roles?.includes("admin")) {
7001
+ return { allowed: true };
7002
+ }
7003
+ if (userContext.sessionScope?.includes(threadId)) {
7004
+ return { allowed: true };
7005
+ }
7006
+ return {
7007
+ allowed: false,
7008
+ reason: "Session does not belong to user",
7009
+ requiredRole: "owner or admin"
7010
+ };
7011
+ }
7012
+ /**
7013
+ * Assign session ownership
7014
+ */
7015
+ assignSessionOwnership(threadId, userId) {
7016
+ const previousOwner = this.sessionOwnership.get(threadId);
7017
+ if (previousOwner) {
7018
+ const previousSessions = this.userSessions.get(previousOwner);
7019
+ if (previousSessions) {
7020
+ previousSessions.delete(threadId);
7021
+ }
7022
+ }
7023
+ this.sessionOwnership.set(threadId, userId);
7024
+ if (!this.userSessions.has(userId)) {
7025
+ this.userSessions.set(userId, /* @__PURE__ */ new Set());
7026
+ }
7027
+ this.userSessions.get(userId).add(threadId);
7028
+ }
7029
+ /**
7030
+ * Get all sessions for a user
7031
+ */
7032
+ getUserSessions(userId) {
7033
+ const sessions = this.userSessions.get(userId);
7034
+ return sessions ? Array.from(sessions) : [];
7035
+ }
7036
+ /**
7037
+ * Get session owner
7038
+ */
7039
+ getSessionOwner(threadId) {
7040
+ return this.sessionOwnership.get(threadId);
7041
+ }
7042
+ /**
7043
+ * Remove session ownership
7044
+ */
7045
+ removeSession(threadId) {
7046
+ const owner = this.sessionOwnership.get(threadId);
7047
+ if (owner) {
7048
+ const sessions = this.userSessions.get(owner);
7049
+ if (sessions) {
7050
+ sessions.delete(threadId);
7051
+ }
7052
+ }
7053
+ this.sessionOwnership.delete(threadId);
7054
+ }
7055
+ /**
7056
+ * Check if user has any sessions
7057
+ */
7058
+ hasSessions(userId) {
7059
+ const sessions = this.userSessions.get(userId);
7060
+ return sessions ? sessions.size > 0 : false;
7061
+ }
7062
+ /**
7063
+ * Get user session count
7064
+ */
7065
+ getSessionCount(userId) {
7066
+ const sessions = this.userSessions.get(userId);
7067
+ return sessions ? sessions.size : 0;
7068
+ }
7069
+ /**
7070
+ * Transfer session ownership
7071
+ */
7072
+ transferOwnership(threadId, fromUserId, toUserId) {
7073
+ const owner = this.sessionOwnership.get(threadId);
7074
+ if (owner !== fromUserId) {
7075
+ return {
7076
+ allowed: false,
7077
+ reason: "Only the owner can transfer session ownership"
7078
+ };
7079
+ }
7080
+ this.assignSessionOwnership(threadId, toUserId);
7081
+ return { allowed: true };
7082
+ }
7083
+ /**
7084
+ * Share session with another user
7085
+ */
7086
+ shareSession(threadId, ownerId, targetUserId, permission = "read") {
7087
+ const owner = this.sessionOwnership.get(threadId);
7088
+ if (owner !== ownerId) {
7089
+ return {
7090
+ allowed: false,
7091
+ reason: "Only the owner can share a session"
7092
+ };
7093
+ }
7094
+ return { allowed: true };
7095
+ }
7096
+ /**
7097
+ * Get all user IDs with sessions
7098
+ */
7099
+ getAllUsers() {
7100
+ return Array.from(this.userSessions.keys());
7101
+ }
7102
+ /**
7103
+ * Clear all data (for testing)
7104
+ */
7105
+ clear() {
7106
+ this.sessionOwnership.clear();
7107
+ this.userSessions.clear();
7108
+ }
7109
+ /**
7110
+ * Create scoped session metadata
7111
+ */
7112
+ createScopedMetadata(metadata, userContext) {
7113
+ return {
7114
+ ...metadata,
7115
+ userId: userContext.userId,
7116
+ orgId: userContext.orgId,
7117
+ createdBy: userContext.userId,
7118
+ lastAccessedBy: userContext.userId,
7119
+ acl: {
7120
+ readers: [userContext.userId],
7121
+ writers: [userContext.userId],
7122
+ isPublic: false
7123
+ }
7124
+ };
7125
+ }
7126
+ /**
7127
+ * Validate user context
7128
+ */
7129
+ validateUserContext(userContext) {
7130
+ if (!userContext || typeof userContext !== "object") {
7131
+ return false;
7132
+ }
7133
+ const ctx = userContext;
7134
+ if (!ctx.userId || typeof ctx.userId !== "string") {
7135
+ return false;
7136
+ }
7137
+ if (ctx.orgId !== void 0 && typeof ctx.orgId !== "string") {
7138
+ return false;
7139
+ }
7140
+ if (ctx.roles !== void 0 && !Array.isArray(ctx.roles)) {
7141
+ return false;
7142
+ }
7143
+ return true;
7144
+ }
7145
+ };
7146
+ var globalMultiUserManager = null;
7147
+ function getMultiUserManager() {
7148
+ if (!globalMultiUserManager) {
7149
+ globalMultiUserManager = new MultiUserManager();
7150
+ }
7151
+ return globalMultiUserManager;
7152
+ }
7153
+ function resetMultiUserManager() {
7154
+ globalMultiUserManager = null;
7155
+ }
7156
+ function createUserContext(userId, options = {}) {
7157
+ return {
7158
+ userId,
7159
+ orgId: options.orgId,
7160
+ roles: options.roles ?? ["user"]
7161
+ };
7162
+ }
7163
+ function isAdmin(userContext) {
7164
+ return userContext.roles?.includes("admin") ?? false;
7165
+ }
7166
+ function requireOwnership(threadId, userContext, manager = getMultiUserManager()) {
7167
+ const check = manager.canAccessSession(threadId, userContext);
7168
+ if (!check.allowed) {
7169
+ throw new Error(`Access denied: ${check.reason}`);
7170
+ }
7171
+ }
7172
+ var StateSyncManager = class extends EventEmitter {
7173
+ constructor(config = {}) {
7174
+ super();
7175
+ this.sequenceNumber = 0;
7176
+ this.pendingChanges = [];
7177
+ this.throttleTimer = null;
7178
+ this.config = {
7179
+ enabled: config.enabled ?? true,
7180
+ conflictStrategy: config.conflictStrategy ?? "last_write_wins",
7181
+ throttleInterval: config.throttleInterval ?? 100,
7182
+ maxRetries: config.maxRetries ?? 3,
7183
+ clientId: config.clientId ?? this.generateClientId()
7184
+ };
7185
+ }
7186
+ /**
7187
+ * Notify that state has changed (called by agent internals)
7188
+ */
7189
+ notifyStateChange(type, threadId, payload, userId) {
7190
+ if (!this.config.enabled) return;
7191
+ const event = {
7192
+ type,
7193
+ threadId,
7194
+ userId,
7195
+ timestamp: Date.now(),
7196
+ payload,
7197
+ version: this.createVersionVector(),
7198
+ sourceClientId: this.config.clientId
7199
+ };
7200
+ this.pendingChanges.push(event);
7201
+ this.emit("stateChange", event);
7202
+ this.scheduleSync();
7203
+ }
7204
+ /**
7205
+ * Receive state change from server (called by server transport)
7206
+ */
7207
+ receiveRemoteChange(event) {
7208
+ if (event.sourceClientId === this.config.clientId) return;
7209
+ const conflicts = this.findConflicts(event);
7210
+ if (conflicts.length > 0) {
7211
+ const resolution = this.resolveConflicts(event, conflicts);
7212
+ if (resolution.resolved) {
7213
+ this.emit("stateReconciled", resolution.winningState, event);
7214
+ } else {
7215
+ this.emit("conflictDetected", conflicts, event);
7216
+ }
7217
+ } else {
7218
+ this.emit("remoteChange", event);
7219
+ }
7220
+ }
7221
+ /**
7222
+ * Create sync snapshot for current state
7223
+ */
7224
+ createSnapshot(threadId, state) {
7225
+ return {
7226
+ threadId,
7227
+ checkpoint: state.checkpoint,
7228
+ sessionMetadata: state.sessionMetadata,
7229
+ memoryState: state.memoryState,
7230
+ version: this.createVersionVector(),
7231
+ lastUpdated: Date.now()
7232
+ };
7233
+ }
7234
+ /**
7235
+ * Compare two version vectors
7236
+ * Returns: -1 if a < b, 0 if concurrent/equal, 1 if a > b
7237
+ */
7238
+ compareVersions(a, b) {
7239
+ if (a.timestamp < b.timestamp) return -1;
7240
+ if (a.timestamp > b.timestamp) return 1;
7241
+ if (a.sequence < b.sequence) return -1;
7242
+ if (a.sequence > b.sequence) return 1;
7243
+ return 0;
7244
+ }
7245
+ /**
7246
+ * Check if there are pending changes to sync
7247
+ */
7248
+ hasPendingChanges() {
7249
+ return this.pendingChanges.length > 0;
7250
+ }
7251
+ /**
7252
+ * Get and clear pending changes
7253
+ */
7254
+ flushPendingChanges() {
7255
+ const changes = [...this.pendingChanges];
7256
+ this.pendingChanges = [];
7257
+ return changes;
7258
+ }
7259
+ /**
7260
+ * Get sync configuration
7261
+ */
7262
+ getConfig() {
7263
+ return { ...this.config };
7264
+ }
7265
+ /**
7266
+ * Update sync configuration
7267
+ */
7268
+ updateConfig(config) {
7269
+ this.config = { ...this.config, ...config };
7270
+ this.emit("configUpdated", this.config);
7271
+ }
7272
+ /**
7273
+ * Dispose resources
7274
+ */
7275
+ dispose() {
7276
+ if (this.throttleTimer) {
7277
+ clearTimeout(this.throttleTimer);
7278
+ this.throttleTimer = null;
7279
+ }
7280
+ this.removeAllListeners();
7281
+ this.pendingChanges = [];
7282
+ }
7283
+ // ============================================================================
7284
+ // Private Helpers
7285
+ // ============================================================================
7286
+ generateClientId() {
7287
+ return `client_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
7288
+ }
7289
+ createVersionVector() {
7290
+ this.sequenceNumber++;
7291
+ return {
7292
+ timestamp: Date.now(),
7293
+ sequence: this.sequenceNumber,
7294
+ nodeId: this.config.clientId
7295
+ };
7296
+ }
7297
+ scheduleSync() {
7298
+ if (this.throttleTimer) return;
7299
+ this.throttleTimer = setTimeout(() => {
7300
+ this.throttleTimer = null;
7301
+ if (this.pendingChanges.length > 0) {
7302
+ this.emit("syncRequired", this.flushPendingChanges());
7303
+ }
7304
+ }, this.config.throttleInterval);
7305
+ }
7306
+ findConflicts(incoming) {
7307
+ return this.pendingChanges.filter(
7308
+ (local) => local.threadId === incoming.threadId && local.type === incoming.type && this.compareVersions(local.version, incoming.version) !== 0
7309
+ );
7310
+ }
7311
+ resolveConflicts(incoming, conflicts) {
7312
+ switch (this.config.conflictStrategy) {
7313
+ case "last_write_wins":
7314
+ let winningEvent = incoming;
7315
+ for (const conflict of conflicts) {
7316
+ if (this.compareVersions(conflict.version, winningEvent.version) > 0) {
7317
+ winningEvent = conflict;
7318
+ }
7319
+ }
7320
+ return {
7321
+ resolved: true,
7322
+ strategy: "last_write_wins"
7323
+ };
7324
+ case "manual":
7325
+ return {
7326
+ resolved: false,
7327
+ strategy: "manual",
7328
+ conflicts: conflicts.map((c) => ({ clientA: c, clientB: incoming }))
7329
+ };
7330
+ case "merge":
7331
+ default:
7332
+ return {
7333
+ resolved: conflicts.length === 0,
7334
+ strategy: conflicts.length === 0 ? "merge" : "manual",
7335
+ conflicts: conflicts.length > 0 ? conflicts.map((c) => ({ clientA: c, clientB: incoming })) : void 0
7336
+ };
7337
+ }
7338
+ }
7339
+ };
7340
+ var globalStateSyncManager = null;
7341
+ function getStateSyncManager(config) {
7342
+ if (!globalStateSyncManager) {
7343
+ globalStateSyncManager = new StateSyncManager(config);
7344
+ }
7345
+ return globalStateSyncManager;
7346
+ }
7347
+ function resetStateSyncManager() {
7348
+ globalStateSyncManager?.dispose();
7349
+ globalStateSyncManager = null;
7350
+ }
7351
+ function withSync(fn, syncManager, options) {
7352
+ return ((...args) => {
7353
+ const result = fn(...args);
7354
+ syncManager.notifyStateChange(
7355
+ options.type,
7356
+ options.threadId,
7357
+ options.getPayload(...args)
7358
+ );
7359
+ return result;
7360
+ });
7361
+ }
7362
+ function debounceSync(syncManager, delay = 100) {
7363
+ let timeout = null;
7364
+ let pending = null;
7365
+ return (type, threadId, payload) => {
7366
+ pending = { type, threadId, payload };
7367
+ if (timeout) {
7368
+ clearTimeout(timeout);
7369
+ }
7370
+ timeout = setTimeout(() => {
7371
+ if (pending) {
7372
+ syncManager.notifyStateChange(pending.type, pending.threadId, pending.payload);
7373
+ pending = null;
7374
+ }
7375
+ timeout = null;
7376
+ }, delay);
7377
+ };
7378
+ }
5969
7379
  var export_applySectionUpdate = domain_language_exports.applySectionUpdate;
5970
7380
  var export_convertDomainToSchema = domain_language_exports.convertDomainToSchema;
5971
7381
  var export_convertSchemaToDomain = domain_language_exports.convertSchemaToDomain;
5972
7382
  var export_deleteSection = domain_language_exports.deleteSection;
5973
7383
 
5974
- export { ContinueRequestSchema, DEFAULT_COMPACTION_CONFIG, EVENT_BUDGETS, ExtractedRequirementsSchema, FirestoreCheckpointer, FirestoreSessionStore, FirestoreStore, GenerateRequestSchema, MemoryManager, MemoryOrbitalSchema, MemorySessionBackend, MetricsCollector, PreferenceLearner, ResumeRequestSchema, SessionManager, analyzeFailures, export_applySectionUpdate as applySectionUpdate, combineOrbitals, combineOrbitalsToSchema, export_convertDomainToSchema as convertDomainToSchema, export_convertSchemaToDomain as convertSchemaToDomain, createAgentTools, createApplyChunkTool, createCombineSchemasTool, createCompactSystemPrompt, createConstructCombinedDomainTool, createDomainOrbitalTools, createErrorFixerSubagent, createExecuteTool, createExtractChunkTool, createFinishTaskTool, createGenerateOrbitalDomainTool, createGenerateSchemaTool, createOrbitalSubagentTool, createPreferenceLearner, createQuerySchemaStructureTool, createSSEEvent, createSchemaChunkingTools, createSchemaGeneratorSubagent, createSkillAgent, createSubagentConfigs, createSubagentEventWrapper, createSubagents, createSummaryPrompt, createSystemPrompt, createTestAnalyzerSubagent, createTraitEventWrapper, createTraitSubagentTool, createValidateSchemaTool, export_deleteSection as deleteSection, estimateCacheSavings, estimateCombineComplexity, estimateTokens, extractFileOperation, extractInterruptData, formatSSEEvent, formatSummary, generateFullOrbital, getBudgetWarningMessage, getEventBudget, getInterruptConfig, hasInterrupt, isCompleteEvent, isErrorEvent, isExecutionEvent, isFileOperation, isSSECompleteEvent, isSSEErrorEvent, isSSEGenerationLogEvent, isSSEInterruptEvent, isSSEMessageEvent, isSSEStartEvent, isSSESubagentEvent, isSSETodoDetailEvent, isSSETodoUpdateEvent, isSSEToolCallEvent, isSchemaEvent, isStartEvent, isTodoUpdate, needsCompaction, parseDeepAgentEvent, parseSSEEvent, resumeSkillAgent, transformAgentEvent, transformAgentEventMulti, validateCommandPaths };
7384
+ export { AgenticSearchEngine, ContinueRequestSchema, DEFAULT_COMPACTION_CONFIG, EVENT_BUDGETS, ExtractedRequirementsSchema, FirestoreCheckpointer, FirestoreSessionStore, FirestoreStore, GenerateRequestSchema, MemoryManager, MemoryOrbitalSchema, MemorySessionBackend, MetricsCollector, MultiUserManager, ObservabilityCollector, PreferenceLearner, ResumeRequestSchema, SessionManager, StateSyncManager, analyzeFailures, export_applySectionUpdate as applySectionUpdate, combineOrbitals, combineOrbitalsToSchema, export_convertDomainToSchema as convertDomainToSchema, export_convertSchemaToDomain as convertSchemaToDomain, createAgentTools, createAgenticSearchEngine, createApplyChunkTool, createCombineSchemasTool, createCompactSystemPrompt, createConstructCombinedDomainTool, createDomainOrbitalTools, createErrorFixerSubagent, createExecuteTool, createExtractChunkTool, createFinishTaskTool, createGenerateOrbitalDomainTool, createGenerateSchemaTool, createOrbitalSubagentTool, createPreferenceLearner, createQuerySchemaStructureTool, createSSEEvent, createSchemaChunkingTools, createSchemaGeneratorSubagent, createSkillAgent, createSubagentConfigs, createSubagentEventWrapper, createSubagents, createSummaryPrompt, createSystemPrompt, createTestAnalyzerSubagent, createTraitEventWrapper, createTraitSubagentTool, createUserContext, createValidateSchemaTool, debounceSync, export_deleteSection as deleteSection, endObservabilitySession, estimateCacheSavings, estimateCombineComplexity, estimateTokens, extractFileOperation, extractInterruptData, formatSSEEvent, formatSummary, generateFullOrbital, getBudgetWarningMessage, getEventBudget, getInterruptConfig, getMultiUserManager, getObservabilityCollector, getPerformanceSnapshot, getStateSyncManager, hasInterrupt, isAdmin, isCompleteEvent, isErrorEvent, isExecutionEvent, isFileOperation, isSSECompleteEvent, isSSEErrorEvent, isSSEGenerationLogEvent, isSSEInterruptEvent, isSSEMessageEvent, isSSEStartEvent, isSSESubagentEvent, isSSETodoDetailEvent, isSSETodoUpdateEvent, isSSEToolCallEvent, isSchemaEvent, isStartEvent, isTodoUpdate, needsCompaction, parseDeepAgentEvent, parseSSEEvent, recordEvent, requireOwnership, resetMultiUserManager, resetObservabilityCollector, resetStateSyncManager, resumeSkillAgent, startObservabilitySession, transformAgentEvent, transformAgentEventMulti, validateCommandPaths, withSync };
5975
7385
  //# sourceMappingURL=index.js.map
5976
7386
  //# sourceMappingURL=index.js.map