@hashgraphonline/conversational-agent 0.1.207 → 0.1.209

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 (70) hide show
  1. package/dist/cjs/conversational-agent.d.ts +67 -8
  2. package/dist/cjs/index.cjs +1 -1
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/cjs/index.d.ts +1 -0
  5. package/dist/cjs/langchain/ContentAwareAgentExecutor.d.ts +4 -6
  6. package/dist/cjs/langchain-agent.d.ts +8 -0
  7. package/dist/cjs/memory/SmartMemoryManager.d.ts +58 -21
  8. package/dist/cjs/memory/index.d.ts +1 -1
  9. package/dist/esm/index.js +8 -0
  10. package/dist/esm/index.js.map +1 -1
  11. package/dist/esm/index12.js +124 -46
  12. package/dist/esm/index12.js.map +1 -1
  13. package/dist/esm/index13.js +178 -13
  14. package/dist/esm/index13.js.map +1 -1
  15. package/dist/esm/index14.js +604 -100
  16. package/dist/esm/index14.js.map +1 -1
  17. package/dist/esm/index15.js +453 -59
  18. package/dist/esm/index15.js.map +1 -1
  19. package/dist/esm/index16.js +44 -172
  20. package/dist/esm/index16.js.map +1 -1
  21. package/dist/esm/index17.js +11 -156
  22. package/dist/esm/index17.js.map +1 -1
  23. package/dist/esm/index18.js +106 -191
  24. package/dist/esm/index18.js.map +1 -1
  25. package/dist/esm/index19.js +7 -90
  26. package/dist/esm/index19.js.map +1 -1
  27. package/dist/esm/index2.js +22 -13
  28. package/dist/esm/index2.js.map +1 -1
  29. package/dist/esm/index20.js +130 -616
  30. package/dist/esm/index20.js.map +1 -1
  31. package/dist/esm/index21.js +138 -215
  32. package/dist/esm/index21.js.map +1 -1
  33. package/dist/esm/index22.js +45 -159
  34. package/dist/esm/index22.js.map +1 -1
  35. package/dist/esm/index23.js +25 -121
  36. package/dist/esm/index23.js.map +1 -1
  37. package/dist/esm/index24.js +83 -56
  38. package/dist/esm/index24.js.map +1 -1
  39. package/dist/esm/index25.js +236 -32
  40. package/dist/esm/index25.js.map +1 -1
  41. package/dist/esm/index5.js +1 -1
  42. package/dist/esm/index6.js +295 -17
  43. package/dist/esm/index6.js.map +1 -1
  44. package/dist/esm/index8.js +82 -8
  45. package/dist/esm/index8.js.map +1 -1
  46. package/dist/types/conversational-agent.d.ts +67 -8
  47. package/dist/types/index.d.ts +1 -0
  48. package/dist/types/langchain/ContentAwareAgentExecutor.d.ts +4 -6
  49. package/dist/types/langchain-agent.d.ts +8 -0
  50. package/dist/types/memory/SmartMemoryManager.d.ts +58 -21
  51. package/dist/types/memory/index.d.ts +1 -1
  52. package/package.json +3 -3
  53. package/src/context/ReferenceContextManager.ts +9 -4
  54. package/src/context/ReferenceResponseProcessor.ts +3 -4
  55. package/src/conversational-agent.ts +379 -31
  56. package/src/index.ts +2 -0
  57. package/src/langchain/ContentAwareAgentExecutor.ts +4 -97
  58. package/src/langchain-agent.ts +94 -11
  59. package/src/mcp/ContentProcessor.ts +13 -3
  60. package/src/mcp/adapters/langchain.ts +1 -9
  61. package/src/memory/ContentStorage.ts +3 -51
  62. package/src/memory/MemoryWindow.ts +4 -16
  63. package/src/memory/ReferenceIdGenerator.ts +0 -4
  64. package/src/memory/SmartMemoryManager.ts +400 -33
  65. package/src/memory/TokenCounter.ts +12 -16
  66. package/src/memory/index.ts +1 -1
  67. package/src/plugins/hcs-10/HCS10Plugin.ts +44 -14
  68. package/src/services/ContentStoreManager.ts +0 -3
  69. package/src/types/content-reference.ts +8 -8
  70. package/src/types/index.ts +0 -1
@@ -22,8 +22,23 @@ import { OpenConvaiState } from '@hashgraphonline/standards-agent-kit';
22
22
  import type { IStateManager } from '@hashgraphonline/standards-agent-kit';
23
23
  import { PrivateKey } from '@hashgraph/sdk';
24
24
  import { getSystemMessage } from './config/system-message';
25
- import type { MCPServerConfig } from './mcp/types';
25
+ import type { MCPServerConfig, MCPConnectionStatus } from './mcp/types';
26
26
  import { ContentStoreManager } from './services/ContentStoreManager';
27
+ import { SmartMemoryManager, type SmartMemoryConfig } from './memory';
28
+
29
+ export type ToolDescriptor = {
30
+ name: string;
31
+ namespace?: string;
32
+ };
33
+
34
+ export type ChatHistoryItem = {
35
+ type: 'human' | 'ai';
36
+ content: string;
37
+ };
38
+
39
+ export type AgentInstance = ReturnType<typeof createAgent>;
40
+
41
+ export type MirrorNetwork = 'testnet' | 'mainnet' | 'previewnet';
27
42
 
28
43
  const DEFAULT_MODEL_NAME = 'gpt-4o';
29
44
  const DEFAULT_TEMPERATURE = 0.1;
@@ -49,6 +64,12 @@ export interface ConversationalAgentOptions {
49
64
  enabledPlugins?: string[];
50
65
  toolFilter?: (tool: { name: string; namespace?: string }) => boolean;
51
66
  mcpServers?: MCPServerConfig[];
67
+
68
+ /** Enable automatic entity memory functionality (default: true) */
69
+ entityMemoryEnabled?: boolean;
70
+
71
+ /** Configuration for entity memory system */
72
+ entityMemoryConfig?: SmartMemoryConfig;
52
73
  }
53
74
 
54
75
  /**
@@ -61,15 +82,17 @@ export interface ConversationalAgentOptions {
61
82
  * @returns A new instance of the ConversationalAgent class.
62
83
  */
63
84
  export class ConversationalAgent {
64
- private agent?: ReturnType<typeof createAgent>;
85
+ protected agent?: AgentInstance;
65
86
  public hcs10Plugin: HCS10Plugin;
66
87
  public hcs2Plugin: HCS2Plugin;
67
88
  public inscribePlugin: InscribePlugin;
68
89
  public hbarTransferPlugin: HbarTransferPlugin;
69
90
  public stateManager: IStateManager;
70
91
  private options: ConversationalAgentOptions;
71
- private logger: Logger;
92
+ protected logger: Logger;
72
93
  private contentStoreManager?: ContentStoreManager;
94
+ private memoryManager?: SmartMemoryManager | undefined;
95
+ private mcpConnectionStatus: Map<string, MCPConnectionStatus> = new Map();
73
96
 
74
97
  constructor(options: ConversationalAgentOptions) {
75
98
  this.options = options;
@@ -82,6 +105,11 @@ export class ConversationalAgent {
82
105
  module: 'ConversationalAgent',
83
106
  silent: options.disableLogging || false,
84
107
  });
108
+
109
+ if (this.options.entityMemoryEnabled !== false) {
110
+ this.memoryManager = new SmartMemoryManager(this.options.entityMemoryConfig);
111
+ this.logger.info('Entity memory initialized');
112
+ }
85
113
  }
86
114
 
87
115
  /**
@@ -110,7 +138,7 @@ export class ConversationalAgent {
110
138
  const serverSigner = new ServerSigner(
111
139
  accountId!,
112
140
  privateKeyInstance,
113
- network as 'testnet' | 'mainnet' | 'previewnet'
141
+ network as MirrorNetwork
114
142
  );
115
143
 
116
144
  const allPlugins = this.preparePlugins();
@@ -126,7 +154,6 @@ export class ConversationalAgent {
126
154
 
127
155
  this.configureHCS10Plugin(allPlugins);
128
156
 
129
- // Initialize ContentStoreManager if MCP servers are configured
130
157
  if (this.options.mcpServers && this.options.mcpServers.length > 0) {
131
158
  this.contentStoreManager = new ContentStoreManager();
132
159
  await this.contentStoreManager.initialize();
@@ -134,6 +161,11 @@ export class ConversationalAgent {
134
161
  }
135
162
 
136
163
  await this.agent.boot();
164
+
165
+ // Start MCP connections asynchronously after agent is booted
166
+ if (this.options.mcpServers && this.options.mcpServers.length > 0) {
167
+ this.connectMCP();
168
+ }
137
169
  } catch (error) {
138
170
  this.logger.error('Failed to initialize ConversationalAgent:', error);
139
171
  throw error;
@@ -186,28 +218,42 @@ export class ConversationalAgent {
186
218
  */
187
219
  async processMessage(
188
220
  message: string,
189
- chatHistory: {
190
- type: 'human' | 'ai';
191
- content: string;
192
- }[] = []
221
+ chatHistory: ChatHistoryItem[] = []
193
222
  ): Promise<ChatResponse> {
194
223
  if (!this.agent) {
195
224
  throw new Error('Agent not initialized. Call initialize() first.');
196
225
  }
197
226
 
198
- const messages = chatHistory.map((msg) => {
199
- if (msg.type === 'human') {
200
- return new HumanMessage(msg.content);
201
- } else {
202
- return new AIMessage(msg.content);
203
- }
204
- });
227
+ try {
228
+ const resolvedMessage = this.memoryManager
229
+ ? await this.resolveEntitiesInMessage(message)
230
+ : message;
231
+
232
+ const messages = chatHistory.map((msg) => {
233
+ if (msg.type === 'human') {
234
+ return new HumanMessage(msg.content);
235
+ } else {
236
+ return new AIMessage(msg.content);
237
+ }
238
+ });
205
239
 
206
- const context: ConversationContext = {
207
- messages,
208
- };
240
+ const context: ConversationContext = {
241
+ messages,
242
+ };
209
243
 
210
- return this.agent.chat(message, context);
244
+ const response = await this.agent.chat(resolvedMessage, context);
245
+
246
+ if (this.memoryManager) {
247
+ await this.extractAndStoreEntities(response, message);
248
+ }
249
+
250
+ this.logger.info('Message processed successfully');
251
+
252
+ return response;
253
+ } catch (error) {
254
+ this.logger.error('Error processing message:', error);
255
+ throw error;
256
+ }
211
257
  }
212
258
 
213
259
  /**
@@ -238,7 +284,7 @@ export class ConversationalAgent {
238
284
  this.hbarTransferPlugin,
239
285
  ];
240
286
 
241
- const corePlugins = getAllHederaCorePlugins();
287
+ const corePlugins: BasePlugin[] = getAllHederaCorePlugins();
242
288
 
243
289
  if (enabledPlugins) {
244
290
  const enabledSet = new Set(enabledPlugins);
@@ -284,6 +330,7 @@ export class ConversationalAgent {
284
330
  operationalMode: operationalMode,
285
331
  ...(userAccountId && { userAccountId }),
286
332
  ...(scheduleUserTransactionsInBytesMode !== undefined && {
333
+ scheduleUserTransactionsInBytesMode: scheduleUserTransactionsInBytesMode,
287
334
  scheduleUserTransactions: scheduleUserTransactionsInBytesMode,
288
335
  }),
289
336
  },
@@ -292,7 +339,7 @@ export class ConversationalAgent {
292
339
  temperature: DEFAULT_TEMPERATURE,
293
340
  },
294
341
  filtering: {
295
- toolPredicate: (tool) => {
342
+ toolPredicate: (tool: ToolDescriptor): boolean => {
296
343
  if (tool.name === 'hedera-account-transfer-hbar') return false;
297
344
  if (this.options.toolFilter && !this.options.toolFilter(tool)) {
298
345
  return false;
@@ -315,7 +362,7 @@ export class ConversationalAgent {
315
362
  ...(this.options.mcpServers && {
316
363
  mcp: {
317
364
  servers: this.options.mcpServers,
318
- autoConnect: true,
365
+ autoConnect: false,
319
366
  },
320
367
  }),
321
368
  debug: {
@@ -333,7 +380,7 @@ export class ConversationalAgent {
333
380
  private configureHCS10Plugin(allPlugins: BasePlugin[]): void {
334
381
  const hcs10 = allPlugins.find((p) => p.id === 'hcs-10');
335
382
  if (hcs10) {
336
- (hcs10 as { appConfig?: Record<string, unknown> }).appConfig = {
383
+ (hcs10 as BasePlugin & { appConfig?: Record<string, unknown> }).appConfig = {
337
384
  stateManager: this.stateManager,
338
385
  };
339
386
  }
@@ -469,17 +516,318 @@ export class ConversationalAgent {
469
516
  }
470
517
  }
471
518
 
519
+ /**
520
+ * Resolve entity references in the message content
521
+ * @param content - Message content to resolve
522
+ * @returns Resolved message content with entity IDs replaced
523
+ */
524
+ private async resolveEntitiesInMessage(content: string): Promise<string> {
525
+ if (!this.memoryManager) {
526
+ return content;
527
+ }
528
+
529
+ try {
530
+ this.logger.info(`Starting entity resolution for message: "${content.substring(0, 100)}..."`);
531
+
532
+ if (!content || typeof content !== 'string') {
533
+ this.logger.warn('Invalid content provided for entity resolution');
534
+ return content || '';
535
+ }
536
+
537
+ if (content.length > 5000) {
538
+ this.logger.warn('Content too long for entity resolution, truncating');
539
+ content = content.substring(0, 5000);
540
+ }
541
+
542
+ let resolvedContent = content;
543
+
544
+ const patterns = [
545
+ /\b(my|the|our)\s+(token|account|topic|schedule)\b/gi,
546
+ /'([^']+)'/g,
547
+ /"([^"]+)"/g,
548
+ /\b([A-Z][A-Za-z0-9_-]{2,})\b/g
549
+ ];
550
+
551
+ for (const pattern of patterns) {
552
+ try {
553
+ let match;
554
+ const matches: any[] = [];
555
+ while ((match = pattern.exec(resolvedContent)) !== null) {
556
+ matches.push(match);
557
+ if (!pattern.global) break;
558
+ }
559
+
560
+ for (const match of matches) {
561
+ try {
562
+ const originalRef = match[0];
563
+ const entityName = match[1] || match[0];
564
+
565
+ if (entityName.length > 50) {
566
+ this.logger.debug(`Skipping overly long entity name: ${entityName.substring(0, 20)}...`);
567
+ continue;
568
+ }
569
+
570
+ const commonWords = ['the', 'my', 'our', 'this', 'that', 'it', 'is', 'are', 'was', 'will'];
571
+ if (commonWords.includes(entityName.toLowerCase())) {
572
+ continue;
573
+ }
574
+
575
+ let entityAssociations: any[] = [];
576
+
577
+ if (match[1] && ['token', 'account', 'topic', 'schedule'].includes(match[1].toLowerCase())) {
578
+ const entityType = match[1].toLowerCase();
579
+ entityAssociations = this.memoryManager.resolveEntityReference(
580
+ entityName,
581
+ { entityType, limit: 1, fuzzyMatch: true }
582
+ );
583
+ } else {
584
+ entityAssociations = this.memoryManager.resolveEntityReference(
585
+ entityName,
586
+ { limit: 1, fuzzyMatch: false }
587
+ );
588
+ }
589
+
590
+ if (entityAssociations.length > 0) {
591
+ const entity = entityAssociations[0];
592
+ if (entity.entityId && entity.entityId.trim().length > 0) {
593
+ if (entityAssociations.length > 1) {
594
+ this.logger.info(`Multiple entities found for "${originalRef}", using most recent: ${entity.entityName}`);
595
+ }
596
+
597
+ resolvedContent = resolvedContent.replace(originalRef, entity.entityId);
598
+ this.logger.info(`Resolved entity reference: "${originalRef}" -> ${entity.entityId}`);
599
+ }
600
+ }
601
+ } catch (matchError) {
602
+ this.logger.debug('Error processing entity match:', matchError);
603
+ continue;
604
+ }
605
+ }
606
+ } catch (patternError) {
607
+ this.logger.debug('Error processing pattern:', patternError);
608
+ continue;
609
+ }
610
+ }
611
+
612
+ if (resolvedContent !== content) {
613
+ this.logger.info(`Entity resolution completed. Original: "${content}" -> Resolved: "${resolvedContent}"`);
614
+ } else {
615
+ this.logger.info('No entity references resolved in message');
616
+ }
617
+
618
+ return resolvedContent;
619
+ } catch (error) {
620
+ this.logger.warn('Entity resolution failed, using original message:', error);
621
+ return content;
622
+ }
623
+ }
624
+
625
+ /**
626
+ * Extract and store entity associations from transaction responses
627
+ * @param response - Agent response containing potential entity information
628
+ * @param originalMessage - Original user message for context
629
+ */
630
+ private async extractAndStoreEntities(response: any, originalMessage: string): Promise<void> {
631
+ if (!this.memoryManager) {
632
+ return;
633
+ }
634
+
635
+ try {
636
+ this.logger.info('Starting entity extraction from response');
637
+
638
+ const entityPatterns = {
639
+ token: /(?:token|Token)\s*(?:ID\s*[:"*\s]*)?([0-9]+\.[0-9]+\.[0-9]+)/g,
640
+ account: /(?:account|Account)\s*(?:ID\s*[:"*\s]*)?([0-9]+\.[0-9]+\.[0-9]+)/g,
641
+ topic: /(?:topic|Topic)\s*(?:ID\s*[:"*\s]*)?([0-9]+\.[0-9]+\.[0-9]+)/g,
642
+ schedule: /(?:schedule|Schedule)\s*(?:ID\s*[:"*\s]*)?([0-9]+\.[0-9]+\.[0-9]+)/g
643
+ };
644
+
645
+ const responseText = typeof response === 'string' ? response : JSON.stringify(response);
646
+ this.logger.info(`Searching response text: ${responseText.substring(0, 200)}...`);
647
+
648
+ for (const [entityType, pattern] of Object.entries(entityPatterns)) {
649
+ let match;
650
+ while ((match = pattern.exec(responseText)) !== null) {
651
+ const entityId = match[1];
652
+
653
+ let entityName = `${entityType}-${entityId}`;
654
+
655
+ const namePatterns = [
656
+ new RegExp(`(?:called|named)\\s+([\\w\\d_-]+)`, 'i'),
657
+ new RegExp(`(?:token|account|topic|schedule)\\s+([\\w\\d_-]+)`, 'i'),
658
+ new RegExp(`([\\w\\d_-]+)\\s+${entityType}`, 'i')
659
+ ];
660
+
661
+ for (const namePattern of namePatterns) {
662
+ const nameMatch = originalMessage.match(namePattern);
663
+ if (nameMatch && nameMatch[1]) {
664
+ entityName = nameMatch[1].trim();
665
+ break;
666
+ }
667
+ }
668
+
669
+ this.logger.info(`Extracting entity: ${entityName} (${entityType}) -> ${entityId}`);
670
+
671
+ this.memoryManager.storeEntityAssociation(
672
+ entityId,
673
+ entityName,
674
+ entityType,
675
+ this.extractTransactionId(response)
676
+ );
677
+
678
+ this.logger.info(`Stored entity association: ${entityName} (${entityId})`);
679
+ }
680
+ }
681
+
682
+ this.logger.info('Entity extraction completed');
683
+ } catch (error) {
684
+ this.logger.warn('Entity extraction failed:', error);
685
+ }
686
+ }
687
+
688
+ /**
689
+ * Extract transaction ID from response if available
690
+ * @param response - Transaction response
691
+ * @returns Transaction ID or undefined
692
+ */
693
+ private extractTransactionId(response: any): string | undefined {
694
+ try {
695
+ if (typeof response === 'object' && response?.transactionId) {
696
+ return response.transactionId;
697
+ }
698
+ if (typeof response === 'string') {
699
+ const match = response.match(/transaction[\s\w]*ID[\s:"]*([0-9a-fA-F@\.\-]+)/i);
700
+ return match ? match[1] : undefined;
701
+ }
702
+ return undefined;
703
+ } catch {
704
+ return undefined;
705
+ }
706
+ }
707
+
708
+ /**
709
+ * Connect to MCP servers asynchronously
710
+ * @private
711
+ */
712
+ private connectMCP(): void {
713
+ if (!this.agent || !this.options.mcpServers) {
714
+ return;
715
+ }
716
+
717
+ // Initialize connection status for all servers
718
+ this.options.mcpServers.forEach(server => {
719
+ this.mcpConnectionStatus.set(server.name, {
720
+ serverName: server.name,
721
+ connected: false,
722
+ tools: []
723
+ });
724
+ });
725
+
726
+ // Call the agent's MCP connection method if available
727
+ if (typeof (this.agent as any).connectMCPServers === 'function') {
728
+ (this.agent as any).connectMCPServers().catch((error: any) => {
729
+ this.logger.error('Failed to connect MCP servers:', error);
730
+ });
731
+ } else {
732
+ // Fallback for agents that don't support async MCP connections
733
+ this.startConnections();
734
+ }
735
+ }
736
+
737
+ /**
738
+ * Start MCP connections without blocking initialization
739
+ * @private
740
+ */
741
+ private async startConnections(): Promise<void> {
742
+ if (!this.agent || !this.options.mcpServers) {
743
+ return;
744
+ }
745
+
746
+ try {
747
+ this.logger.info('Starting MCP server connections asynchronously...');
748
+
749
+ for (const server of this.options.mcpServers) {
750
+ this.connectServer(server);
751
+ }
752
+ } catch (error) {
753
+ this.logger.error('Error starting MCP connections:', error);
754
+ }
755
+ }
756
+
757
+ /**
758
+ * Connect to a single MCP server
759
+ * @param {MCPServerConfig} server - Server configuration
760
+ * @private
761
+ */
762
+ private async connectServer(server: MCPServerConfig): Promise<void> {
763
+ try {
764
+ this.logger.info(`Connecting to MCP server: ${server.name}`);
765
+
766
+ // TODO: Implement actual MCP connection logic
767
+ // For now, we'll simulate the connection process
768
+ const status = this.mcpConnectionStatus.get(server.name);
769
+ if (status) {
770
+ // Simulate connection success after a delay
771
+ setTimeout(() => {
772
+ status.connected = true;
773
+ this.logger.info(`MCP server ${server.name} connected successfully`);
774
+ }, Math.random() * 2000 + 1000); // 1-3 second delay
775
+ }
776
+
777
+ } catch (error) {
778
+ this.logger.error(`Failed to connect to MCP server ${server.name}:`, error);
779
+
780
+ const status = this.mcpConnectionStatus.get(server.name);
781
+ if (status) {
782
+ status.connected = false;
783
+ status.error = error instanceof Error ? error.message : 'Unknown error';
784
+ }
785
+ }
786
+ }
787
+
788
+ /**
789
+ * Get MCP connection status for all servers
790
+ * @returns {Map<string, MCPConnectionStatus>} Connection status map
791
+ */
792
+ getMCPConnectionStatus(): Map<string, MCPConnectionStatus> {
793
+ return new Map(this.mcpConnectionStatus);
794
+ }
795
+
796
+ /**
797
+ * Check if a specific MCP server is connected
798
+ * @param {string} serverName - Name of the server to check
799
+ * @returns {boolean} True if connected, false otherwise
800
+ */
801
+ isMCPServerConnected(serverName: string): boolean {
802
+ const status = this.mcpConnectionStatus.get(serverName);
803
+ return status?.connected ?? false;
804
+ }
805
+
472
806
  /**
473
807
  * Clean up resources
474
808
  */
475
809
  async cleanup(): Promise<void> {
476
- if (this.contentStoreManager) {
477
- await this.contentStoreManager.dispose();
478
- this.logger.info('ContentStoreManager cleaned up');
479
- }
480
- // Agent cleanup if needed
481
- if (this.agent) {
482
- // Add agent cleanup if available
810
+ try {
811
+ this.logger.info('Cleaning up ConversationalAgent...');
812
+
813
+ if (this.memoryManager) {
814
+ try {
815
+ this.memoryManager.dispose();
816
+ this.logger.info('Memory manager cleaned up successfully');
817
+ } catch (error) {
818
+ this.logger.warn('Error cleaning up memory manager:', error);
819
+ }
820
+ this.memoryManager = undefined as any;
821
+ }
822
+
823
+ if (this.contentStoreManager) {
824
+ await this.contentStoreManager.dispose();
825
+ this.logger.info('ContentStoreManager cleaned up');
826
+ }
827
+
828
+ this.logger.info('ConversationalAgent cleanup completed');
829
+ } catch (error) {
830
+ this.logger.error('Error during cleanup:', error);
483
831
  }
484
832
  }
485
833
  }
package/src/index.ts CHANGED
@@ -31,3 +31,5 @@ export type { IStateManager } from '@hashgraphonline/standards-agent-kit';
31
31
 
32
32
  export type { MCPServerConfig, MCPConnectionStatus, MCPToolInfo } from './mcp/types';
33
33
  export { MCPServers, createMCPConfig, validateServerConfig } from './mcp/helpers';
34
+
35
+ export * from './memory';
@@ -1,112 +1,19 @@
1
1
  import { AgentExecutor } from 'langchain/agents';
2
- import type { AgentAction, AgentFinish, AgentStep } from '@langchain/core/agents';
3
- import type { ChainValues } from '@langchain/core/utils/types';
4
- import type { CallbackManagerForChainRun } from '@langchain/core/callbacks/manager';
5
- import type { RunnableConfig } from '@langchain/core/runnables';
6
- import type { ToolInterface } from '@langchain/core/tools';
7
- import { ContentStoreService, shouldUseReference } from '@hashgraphonline/standards-sdk';
8
2
  import { Logger } from '@hashgraphonline/standards-sdk';
9
3
 
10
4
  /**
11
5
  * Custom AgentExecutor that intercepts large tool outputs and converts them to content references
12
6
  * before they are sent to the LLM to avoid token limit issues.
7
+ *
8
+ * Note: The content reference conversion is already handled in the MCP adapter,
9
+ * so this class currently just extends AgentExecutor without modifications.
10
+ * We keep it as a placeholder for future enhancements.
13
11
  */
14
12
  export class ContentAwareAgentExecutor extends AgentExecutor {
15
13
  private logger: Logger;
16
- private readonly MCP_REFERENCE_THRESHOLD = 10 * 1024; // 10KB for MCP tools
17
14
 
18
15
  constructor(config: any) {
19
16
  super(config);
20
17
  this.logger = new Logger({ module: 'ContentAwareAgentExecutor' });
21
18
  }
22
-
23
- /**
24
- * Override the method that processes tool outputs to intercept large content
25
- */
26
- override async _call(inputs: ChainValues): Promise<ChainValues> {
27
- try {
28
- // Store the original _takeNextStep method
29
- const originalTakeNextStep = this._takeNextStep.bind(this);
30
-
31
- // Override _takeNextStep to intercept tool outputs
32
- this._takeNextStep = async (
33
- nameToolMap: Record<string, ToolInterface>,
34
- inputs: ChainValues,
35
- intermediateSteps: AgentStep[],
36
- runManager?: CallbackManagerForChainRun,
37
- config?: RunnableConfig
38
- ): Promise<AgentFinish | AgentStep[]> => {
39
- // Call the original method
40
- const result = await originalTakeNextStep(nameToolMap, inputs, intermediateSteps, runManager, config);
41
-
42
- // If result is an array of intermediate steps, process tool outputs
43
- if (Array.isArray(result)) {
44
- const processedSteps = await Promise.all(
45
- result.map(async (step) => {
46
- const { action, observation } = step;
47
-
48
- // Check if observation is large and should be stored as reference
49
- if (typeof observation === 'string') {
50
- const observationBuffer = Buffer.from(observation, 'utf8');
51
- const shouldStore = observationBuffer.length > this.MCP_REFERENCE_THRESHOLD ||
52
- shouldUseReference(observationBuffer);
53
-
54
- if (shouldStore) {
55
- this.logger.info(
56
- `[ContentAwareAgentExecutor] Large tool output detected: ${observationBuffer.length} bytes from ${action.tool}`
57
- );
58
-
59
- const contentStore = ContentStoreService.getInstance();
60
- if (contentStore) {
61
- try {
62
- const referenceId = await contentStore.storeContent(observationBuffer, {
63
- contentType: 'text',
64
- source: 'tool',
65
- toolName: action.tool,
66
- originalSize: observationBuffer.length
67
- });
68
-
69
- const referenceMessage = `content-ref:${referenceId}`;
70
- this.logger.info(
71
- `[ContentAwareAgentExecutor] Stored large output as reference: ${referenceMessage}`
72
- );
73
-
74
- // Return the step with the reference instead of the full content
75
- return { action, observation: referenceMessage };
76
- } catch (error) {
77
- this.logger.warn(
78
- '[ContentAwareAgentExecutor] Failed to store content as reference:',
79
- error
80
- );
81
- }
82
- } else {
83
- this.logger.warn('[ContentAwareAgentExecutor] ContentStoreService not available');
84
- }
85
- }
86
- }
87
-
88
- // Return unchanged if not large or storage failed
89
- return step;
90
- })
91
- );
92
-
93
- return processedSteps;
94
- }
95
-
96
- // Return as-is if not an array (AgentFinish)
97
- return result;
98
- };
99
-
100
- // Call the parent _call method with our overridden _takeNextStep
101
- const result = await super._call(inputs);
102
-
103
- // Restore the original method
104
- this._takeNextStep = originalTakeNextStep;
105
-
106
- return result;
107
- } catch (error) {
108
- this.logger.error('[ContentAwareAgentExecutor] Error in _call:', error);
109
- throw error;
110
- }
111
- }
112
19
  }