@hashgraphonline/conversational-agent 0.1.209 → 0.1.210

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 (106) hide show
  1. package/bin/conversational-agent-cli.js +30 -0
  2. package/cli/readme.md +181 -0
  3. package/dist/cjs/base-agent.d.ts +3 -1
  4. package/dist/cjs/conversational-agent.d.ts +14 -22
  5. package/dist/cjs/index.cjs +1 -1
  6. package/dist/cjs/index.cjs.map +1 -1
  7. package/dist/cjs/index.d.ts +5 -3
  8. package/dist/cjs/langchain-agent.d.ts +6 -3
  9. package/dist/cjs/memory/SmartMemoryManager.d.ts +7 -1
  10. package/dist/cjs/memory/TokenCounter.d.ts +1 -1
  11. package/dist/cjs/plugins/hbar/AirdropToolWrapper.d.ts +43 -0
  12. package/dist/{types/plugins/hbar-transfer/HbarTransferPlugin.d.ts → cjs/plugins/hbar/HbarPlugin.d.ts} +2 -1
  13. package/dist/{types/plugins/hbar-transfer → cjs/plugins/hbar}/TransferHbarTool.d.ts +1 -1
  14. package/dist/cjs/plugins/hbar/index.d.ts +3 -0
  15. package/dist/cjs/plugins/index.d.ts +2 -1
  16. package/dist/cjs/services/EntityResolver.d.ts +26 -0
  17. package/dist/cjs/tools/EntityResolverTool.d.ts +104 -0
  18. package/dist/cjs/types/inscription.d.ts +37 -0
  19. package/dist/esm/index.js +8 -2
  20. package/dist/esm/index.js.map +1 -1
  21. package/dist/esm/index12.js +1 -4
  22. package/dist/esm/index12.js.map +1 -1
  23. package/dist/esm/index13.js +0 -1
  24. package/dist/esm/index13.js.map +1 -1
  25. package/dist/esm/index14.js +2 -7
  26. package/dist/esm/index14.js.map +1 -1
  27. package/dist/esm/index15.js +31 -69
  28. package/dist/esm/index15.js.map +1 -1
  29. package/dist/esm/index16.js +126 -39
  30. package/dist/esm/index16.js.map +1 -1
  31. package/dist/esm/index17.js +148 -13
  32. package/dist/esm/index17.js.map +1 -1
  33. package/dist/esm/index18.js +44 -146
  34. package/dist/esm/index18.js.map +1 -1
  35. package/dist/esm/index19.js +100 -6
  36. package/dist/esm/index19.js.map +1 -1
  37. package/dist/esm/index20.js +20 -174
  38. package/dist/esm/index20.js.map +1 -1
  39. package/dist/esm/index21.js +7 -151
  40. package/dist/esm/index21.js.map +1 -1
  41. package/dist/esm/index22.js +154 -45
  42. package/dist/esm/index22.js.map +1 -1
  43. package/dist/esm/index23.js +149 -24
  44. package/dist/esm/index23.js.map +1 -1
  45. package/dist/esm/index24.js +56 -83
  46. package/dist/esm/index24.js.map +1 -1
  47. package/dist/esm/index25.js +24 -236
  48. package/dist/esm/index25.js.map +1 -1
  49. package/dist/esm/index26.js +95 -0
  50. package/dist/esm/index26.js.map +1 -0
  51. package/dist/esm/index27.js +242 -0
  52. package/dist/esm/index27.js.map +1 -0
  53. package/dist/esm/index5.js +32 -19
  54. package/dist/esm/index5.js.map +1 -1
  55. package/dist/esm/index6.js +156 -195
  56. package/dist/esm/index6.js.map +1 -1
  57. package/dist/esm/index7.js +2 -2
  58. package/dist/esm/index7.js.map +1 -1
  59. package/dist/esm/index8.js +80 -48
  60. package/dist/esm/index8.js.map +1 -1
  61. package/dist/types/base-agent.d.ts +3 -1
  62. package/dist/types/conversational-agent.d.ts +14 -22
  63. package/dist/types/index.d.ts +5 -3
  64. package/dist/types/langchain-agent.d.ts +6 -3
  65. package/dist/types/memory/SmartMemoryManager.d.ts +7 -1
  66. package/dist/types/memory/TokenCounter.d.ts +1 -1
  67. package/dist/types/plugins/hbar/AirdropToolWrapper.d.ts +43 -0
  68. package/dist/{cjs/plugins/hbar-transfer/HbarTransferPlugin.d.ts → types/plugins/hbar/HbarPlugin.d.ts} +2 -1
  69. package/dist/{cjs/plugins/hbar-transfer → types/plugins/hbar}/TransferHbarTool.d.ts +1 -1
  70. package/dist/types/plugins/hbar/index.d.ts +3 -0
  71. package/dist/types/plugins/index.d.ts +2 -1
  72. package/dist/types/services/EntityResolver.d.ts +26 -0
  73. package/dist/types/tools/EntityResolverTool.d.ts +104 -0
  74. package/dist/types/types/inscription.d.ts +37 -0
  75. package/package.json +13 -4
  76. package/src/base-agent.ts +14 -9
  77. package/src/config/system-message.ts +11 -2
  78. package/src/context/ReferenceContextManager.ts +1 -1
  79. package/src/conversational-agent.ts +221 -254
  80. package/src/index.ts +17 -3
  81. package/src/langchain-agent.ts +130 -78
  82. package/src/mcp/ContentProcessor.ts +0 -2
  83. package/src/mcp/adapters/langchain.ts +0 -1
  84. package/src/memory/ContentStorage.ts +0 -5
  85. package/src/memory/MemoryWindow.ts +0 -1
  86. package/src/memory/ReferenceIdGenerator.ts +4 -4
  87. package/src/memory/SmartMemoryManager.ts +53 -92
  88. package/src/memory/TokenCounter.ts +4 -7
  89. package/src/plugins/hbar/AirdropToolWrapper.ts +157 -0
  90. package/src/plugins/hbar/HbarPlugin.ts +86 -0
  91. package/src/plugins/{hbar-transfer → hbar}/TransferHbarTool.ts +3 -3
  92. package/src/plugins/hbar/index.ts +3 -0
  93. package/src/plugins/index.ts +2 -1
  94. package/src/services/EntityResolver.ts +135 -0
  95. package/src/tools/EntityResolverTool.ts +170 -0
  96. package/src/types/inscription.ts +40 -0
  97. package/dist/cjs/plugins/hbar-transfer/index.d.ts +0 -1
  98. package/dist/types/plugins/hbar-transfer/index.d.ts +0 -1
  99. package/src/plugins/hbar-transfer/HbarTransferPlugin.ts +0 -66
  100. package/src/plugins/hbar-transfer/index.ts +0 -1
  101. /package/dist/cjs/plugins/{hbar-transfer → hbar}/AccountBuilder.d.ts +0 -0
  102. /package/dist/cjs/plugins/{hbar-transfer → hbar}/types.d.ts +0 -0
  103. /package/dist/types/plugins/{hbar-transfer → hbar}/AccountBuilder.d.ts +0 -0
  104. /package/dist/types/plugins/{hbar-transfer → hbar}/types.d.ts +0 -0
  105. /package/src/plugins/{hbar-transfer → hbar}/AccountBuilder.ts +0 -0
  106. /package/src/plugins/{hbar-transfer → hbar}/types.ts +0 -0
@@ -12,12 +12,13 @@ import { createAgent } from './agent-factory';
12
12
  import { LangChainProvider } from './providers';
13
13
  import type { ChatResponse, ConversationContext } from './base-agent';
14
14
  import { ChatOpenAI } from '@langchain/openai';
15
+ import { ChatAnthropic } from '@langchain/anthropic';
15
16
  import { HumanMessage, AIMessage } from '@langchain/core/messages';
16
17
  import type { AgentOperationalMode, MirrorNodeConfig } from 'hedera-agent-kit';
17
18
  import { HCS10Plugin } from './plugins/hcs-10/HCS10Plugin';
18
19
  import { HCS2Plugin } from './plugins/hcs-2/HCS2Plugin';
19
20
  import { InscribePlugin } from './plugins/inscribe/InscribePlugin';
20
- import { HbarTransferPlugin } from './plugins/hbar-transfer/HbarTransferPlugin';
21
+ import { HbarPlugin } from './plugins/hbar/HbarPlugin';
21
22
  import { OpenConvaiState } from '@hashgraphonline/standards-agent-kit';
22
23
  import type { IStateManager } from '@hashgraphonline/standards-agent-kit';
23
24
  import { PrivateKey } from '@hashgraph/sdk';
@@ -25,6 +26,11 @@ import { getSystemMessage } from './config/system-message';
25
26
  import type { MCPServerConfig, MCPConnectionStatus } from './mcp/types';
26
27
  import { ContentStoreManager } from './services/ContentStoreManager';
27
28
  import { SmartMemoryManager, type SmartMemoryConfig } from './memory';
29
+ import {
30
+ createEntityTools,
31
+ ResolveEntitiesTool,
32
+ ExtractEntitiesTool,
33
+ } from './tools/EntityResolverTool';
28
34
 
29
35
  export type ToolDescriptor = {
30
36
  name: string;
@@ -51,6 +57,7 @@ export interface ConversationalAgentOptions {
51
57
  network?: NetworkType;
52
58
  openAIApiKey: string;
53
59
  openAIModelName?: string;
60
+ llmProvider?: 'openai' | 'anthropic';
54
61
  verbose?: boolean;
55
62
  operationalMode?: AgentOperationalMode;
56
63
  userAccountId?: string;
@@ -64,10 +71,10 @@ export interface ConversationalAgentOptions {
64
71
  enabledPlugins?: string[];
65
72
  toolFilter?: (tool: { name: string; namespace?: string }) => boolean;
66
73
  mcpServers?: MCPServerConfig[];
67
-
74
+
68
75
  /** Enable automatic entity memory functionality (default: true) */
69
76
  entityMemoryEnabled?: boolean;
70
-
77
+
71
78
  /** Configuration for entity memory system */
72
79
  entityMemoryConfig?: SmartMemoryConfig;
73
80
  }
@@ -86,13 +93,16 @@ export class ConversationalAgent {
86
93
  public hcs10Plugin: HCS10Plugin;
87
94
  public hcs2Plugin: HCS2Plugin;
88
95
  public inscribePlugin: InscribePlugin;
89
- public hbarTransferPlugin: HbarTransferPlugin;
96
+ public hbarPlugin: HbarPlugin;
90
97
  public stateManager: IStateManager;
91
98
  private options: ConversationalAgentOptions;
92
- protected logger: Logger;
93
- private contentStoreManager?: ContentStoreManager;
94
- private memoryManager?: SmartMemoryManager | undefined;
95
- private mcpConnectionStatus: Map<string, MCPConnectionStatus> = new Map();
99
+ public logger: Logger;
100
+ protected contentStoreManager?: ContentStoreManager;
101
+ public memoryManager?: SmartMemoryManager | undefined;
102
+ private entityTools?: {
103
+ resolveEntities: ResolveEntitiesTool;
104
+ extractEntities: ExtractEntitiesTool;
105
+ };
96
106
 
97
107
  constructor(options: ConversationalAgentOptions) {
98
108
  this.options = options;
@@ -100,20 +110,31 @@ export class ConversationalAgent {
100
110
  this.hcs10Plugin = new HCS10Plugin();
101
111
  this.hcs2Plugin = new HCS2Plugin();
102
112
  this.inscribePlugin = new InscribePlugin();
103
- this.hbarTransferPlugin = new HbarTransferPlugin();
113
+ this.hbarPlugin = new HbarPlugin();
104
114
  this.logger = new Logger({
105
115
  module: 'ConversationalAgent',
106
116
  silent: options.disableLogging || false,
107
117
  });
108
-
118
+
109
119
  if (this.options.entityMemoryEnabled !== false) {
110
- this.memoryManager = new SmartMemoryManager(this.options.entityMemoryConfig);
120
+ if (!options.openAIApiKey) {
121
+ throw new Error(
122
+ 'OpenAI API key is required when entity memory is enabled'
123
+ );
124
+ }
125
+
126
+ this.memoryManager = new SmartMemoryManager(
127
+ this.options.entityMemoryConfig
128
+ );
111
129
  this.logger.info('Entity memory initialized');
130
+
131
+ this.entityTools = createEntityTools(options.openAIApiKey, 'gpt-4o-mini');
132
+ this.logger.info('LLM-based entity resolver tools initialized');
112
133
  }
113
134
  }
114
135
 
115
136
  /**
116
- * Initialize the conversational agent with Hedera network connection and AI configuration
137
+ * Initialize the conversational agent with Hedera Hashgraph connection and AI configuration
117
138
  * @throws {Error} If account ID or private key is missing
118
139
  * @throws {Error} If initialization fails
119
140
  */
@@ -124,6 +145,7 @@ export class ConversationalAgent {
124
145
  network = DEFAULT_NETWORK,
125
146
  openAIApiKey,
126
147
  openAIModelName = DEFAULT_MODEL_NAME,
148
+ llmProvider = 'openai',
127
149
  } = this.options;
128
150
 
129
151
  this.validateOptions(accountId, privateKey);
@@ -141,28 +163,66 @@ export class ConversationalAgent {
141
163
  network as MirrorNetwork
142
164
  );
143
165
 
144
- const allPlugins = this.preparePlugins();
145
-
146
- const llm = new ChatOpenAI({
147
- apiKey: openAIApiKey,
148
- modelName: openAIModelName,
149
- temperature: DEFAULT_TEMPERATURE,
150
- });
166
+ let llm: ChatOpenAI | ChatAnthropic;
167
+ if (llmProvider === 'anthropic') {
168
+ llm = new ChatAnthropic({
169
+ apiKey: openAIApiKey,
170
+ modelName: openAIModelName || 'claude-3-5-sonnet-20241022',
171
+ temperature: DEFAULT_TEMPERATURE,
172
+ });
173
+ } else {
174
+ const modelName = openAIModelName || 'gpt-4o-mini';
175
+ const isGPT5Model =
176
+ modelName.toLowerCase().includes('gpt-5') ||
177
+ modelName.toLowerCase().includes('gpt5');
178
+ llm = new ChatOpenAI({
179
+ apiKey: openAIApiKey,
180
+ modelName: openAIModelName,
181
+ ...(isGPT5Model
182
+ ? { temperature: 1 }
183
+ : { temperature: DEFAULT_TEMPERATURE }),
184
+ });
185
+ }
151
186
 
187
+ const allPlugins = this.preparePlugins();
152
188
  const agentConfig = this.createAgentConfig(serverSigner, llm, allPlugins);
189
+
153
190
  this.agent = createAgent(agentConfig);
154
191
 
155
192
  this.configureHCS10Plugin(allPlugins);
156
193
 
157
- if (this.options.mcpServers && this.options.mcpServers.length > 0) {
158
- this.contentStoreManager = new ContentStoreManager();
159
- await this.contentStoreManager.initialize();
160
- this.logger.info('ContentStoreManager initialized for MCP content reference support');
161
- }
194
+ this.contentStoreManager = new ContentStoreManager();
195
+ await this.contentStoreManager.initialize();
196
+ this.logger.info(
197
+ 'ContentStoreManager initialized for content reference support'
198
+ );
162
199
 
163
200
  await this.agent.boot();
164
201
 
165
- // Start MCP connections asynchronously after agent is booted
202
+ if (this.agent) {
203
+ const cfg = agentConfig;
204
+ cfg.filtering = cfg.filtering || {};
205
+ const originalPredicate = cfg.filtering.toolPredicate as
206
+ | ((t: ToolDescriptor) => boolean)
207
+ | undefined;
208
+ const userPredicate = this.options.toolFilter;
209
+ cfg.filtering.toolPredicate = (tool: ToolDescriptor): boolean => {
210
+ if (tool && tool.name === 'hedera-account-transfer-hbar') {
211
+ return false;
212
+ }
213
+ if (tool && tool.name === 'hedera-hts-airdrop-token') {
214
+ return false;
215
+ }
216
+ if (originalPredicate && !originalPredicate(tool)) {
217
+ return false;
218
+ }
219
+ if (userPredicate && !userPredicate(tool)) {
220
+ return false;
221
+ }
222
+ return true;
223
+ };
224
+ }
225
+
166
226
  if (this.options.mcpServers && this.options.mcpServers.length > 0) {
167
227
  this.connectMCP();
168
228
  }
@@ -225,7 +285,7 @@ export class ConversationalAgent {
225
285
  }
226
286
 
227
287
  try {
228
- const resolvedMessage = this.memoryManager
288
+ const resolvedMessage = this.memoryManager
229
289
  ? await this.resolveEntitiesInMessage(message)
230
290
  : message;
231
291
 
@@ -242,13 +302,13 @@ export class ConversationalAgent {
242
302
  };
243
303
 
244
304
  const response = await this.agent.chat(resolvedMessage, context);
245
-
305
+
246
306
  if (this.memoryManager) {
247
307
  await this.extractAndStoreEntities(response, message);
248
308
  }
249
-
309
+
250
310
  this.logger.info('Message processed successfully');
251
-
311
+
252
312
  return response;
253
313
  } catch (error) {
254
314
  this.logger.error('Error processing message:', error);
@@ -258,7 +318,7 @@ export class ConversationalAgent {
258
318
 
259
319
  /**
260
320
  * Validates initialization options and throws if required fields are missing.
261
- *
321
+ *
262
322
  * @param accountId - The Hedera account ID
263
323
  * @param privateKey - The private key for the account
264
324
  * @throws {Error} If required fields are missing
@@ -271,21 +331,21 @@ export class ConversationalAgent {
271
331
 
272
332
  /**
273
333
  * Prepares the list of plugins to use based on configuration.
274
- *
334
+ *
275
335
  * @returns Array of plugins to initialize with the agent
276
336
  */
277
337
  private preparePlugins(): BasePlugin[] {
278
338
  const { additionalPlugins = [], enabledPlugins } = this.options;
279
-
339
+
280
340
  const standardPlugins = [
281
341
  this.hcs10Plugin,
282
342
  this.hcs2Plugin,
283
343
  this.inscribePlugin,
284
- this.hbarTransferPlugin,
344
+ this.hbarPlugin,
285
345
  ];
286
-
287
- const corePlugins: BasePlugin[] = getAllHederaCorePlugins();
288
-
346
+
347
+ const corePlugins = getAllHederaCorePlugins();
348
+
289
349
  if (enabledPlugins) {
290
350
  const enabledSet = new Set(enabledPlugins);
291
351
  const filteredPlugins = [...standardPlugins, ...corePlugins].filter(
@@ -293,13 +353,13 @@ export class ConversationalAgent {
293
353
  );
294
354
  return [...filteredPlugins, ...additionalPlugins];
295
355
  }
296
-
356
+
297
357
  return [...standardPlugins, ...corePlugins, ...additionalPlugins];
298
358
  }
299
359
 
300
360
  /**
301
361
  * Creates the agent configuration object.
302
- *
362
+ *
303
363
  * @param serverSigner - The server signer instance
304
364
  * @param llm - The language model instance
305
365
  * @param allPlugins - Array of plugins to use
@@ -307,7 +367,7 @@ export class ConversationalAgent {
307
367
  */
308
368
  private createAgentConfig(
309
369
  serverSigner: ServerSigner,
310
- llm: ChatOpenAI,
370
+ llm: ChatOpenAI | ChatAnthropic,
311
371
  allPlugins: BasePlugin[]
312
372
  ): Parameters<typeof createAgent>[0] {
313
373
  const {
@@ -330,7 +390,8 @@ export class ConversationalAgent {
330
390
  operationalMode: operationalMode,
331
391
  ...(userAccountId && { userAccountId }),
332
392
  ...(scheduleUserTransactionsInBytesMode !== undefined && {
333
- scheduleUserTransactionsInBytesMode: scheduleUserTransactionsInBytesMode,
393
+ scheduleUserTransactionsInBytesMode:
394
+ scheduleUserTransactionsInBytesMode,
334
395
  scheduleUserTransactions: scheduleUserTransactionsInBytesMode,
335
396
  }),
336
397
  },
@@ -350,7 +411,9 @@ export class ConversationalAgent {
350
411
  messaging: {
351
412
  systemPreamble:
352
413
  customSystemMessagePreamble || getSystemMessage(accountId),
353
- ...(customSystemMessagePostamble && { systemPostamble: customSystemMessagePostamble }),
414
+ ...(customSystemMessagePostamble && {
415
+ systemPostamble: customSystemMessagePostamble,
416
+ }),
354
417
  conciseMode: true,
355
418
  },
356
419
  extensions: {
@@ -374,13 +437,15 @@ export class ConversationalAgent {
374
437
 
375
438
  /**
376
439
  * Configures the HCS-10 plugin with the state manager.
377
- *
440
+ *
378
441
  * @param allPlugins - Array of all plugins
379
442
  */
380
443
  private configureHCS10Plugin(allPlugins: BasePlugin[]): void {
381
444
  const hcs10 = allPlugins.find((p) => p.id === 'hcs-10');
382
445
  if (hcs10) {
383
- (hcs10 as BasePlugin & { appConfig?: Record<string, unknown> }).appConfig = {
446
+ (
447
+ hcs10 as BasePlugin & { appConfig?: Record<string, unknown> }
448
+ ).appConfig = {
384
449
  stateManager: this.stateManager,
385
450
  };
386
451
  }
@@ -496,7 +561,7 @@ export class ConversationalAgent {
496
561
  * Detect the private key type by querying the account info from mirror node
497
562
  * @param {string} accountId - The Hedera account ID
498
563
  * @param {string} privateKey - The private key string
499
- * @param {NetworkType} network - The Hedera network
564
+ * @param {NetworkType} network - The Hedera Hashgraph
500
565
  * @returns {Promise<PrivateKey>} The appropriate PrivateKey instance
501
566
  */
502
567
  private async detectPrivateKeyType(
@@ -517,171 +582,109 @@ export class ConversationalAgent {
517
582
  }
518
583
 
519
584
  /**
520
- * Resolve entity references in the message content
585
+ * Resolve entity references using LLM-based resolver
521
586
  * @param content - Message content to resolve
522
587
  * @returns Resolved message content with entity IDs replaced
523
588
  */
524
589
  private async resolveEntitiesInMessage(content: string): Promise<string> {
525
- if (!this.memoryManager) {
590
+ if (!this.memoryManager || !this.entityTools) {
526
591
  return content;
527
592
  }
528
593
 
529
594
  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
- }
595
+ const entities = this.memoryManager.getEntityAssociations();
536
596
 
537
- if (content.length > 5000) {
538
- this.logger.warn('Content too long for entity resolution, truncating');
539
- content = content.substring(0, 5000);
597
+ if (entities.length === 0) {
598
+ this.logger.info('No entities in memory, skipping resolution');
599
+ return content;
540
600
  }
541
601
 
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
- ];
602
+ this.logger.info(
603
+ `Starting LLM-based entity resolution for: "${content.substring(
604
+ 0,
605
+ 100
606
+ )}..."`
607
+ );
550
608
 
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
- }
609
+ const resolvedContent = await this.entityTools.resolveEntities.call({
610
+ message: content,
611
+ entities: entities.map((e) => ({
612
+ entityId: e.entityId,
613
+ entityName: e.entityName,
614
+ entityType: e.entityType,
615
+ })),
616
+ });
611
617
 
612
618
  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');
619
+ this.logger.info(
620
+ `Entity resolution completed. Original: "${content}" -> Resolved: "${resolvedContent}"`
621
+ );
616
622
  }
617
-
623
+
618
624
  return resolvedContent;
619
625
  } catch (error) {
620
- this.logger.warn('Entity resolution failed, using original message:', error);
621
- return content;
626
+ this.logger.error('Entity resolution failed:', error);
627
+ throw error;
622
628
  }
623
629
  }
624
630
 
625
631
  /**
626
- * Extract and store entity associations from transaction responses
632
+ * Extract and store entities from agent responses
627
633
  * @param response - Agent response containing potential entity information
628
634
  * @param originalMessage - Original user message for context
629
635
  */
630
- private async extractAndStoreEntities(response: any, originalMessage: string): Promise<void> {
631
- if (!this.memoryManager) {
636
+ private async extractAndStoreEntities(
637
+ response: unknown,
638
+ originalMessage: string
639
+ ): Promise<void> {
640
+ if (!this.memoryManager || !this.entityTools) {
632
641
  return;
633
642
  }
634
643
 
635
644
  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
- };
645
+ this.logger.info('Starting LLM-based entity extraction');
644
646
 
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
-
647
+ const responseText = this.extractResponseText(response);
648
+
649
+ const entitiesJson = await this.entityTools.extractEntities.call({
650
+ response: responseText,
651
+ userMessage: originalMessage,
652
+ });
653
+
654
+ try {
655
+ const entities = JSON.parse(entitiesJson);
656
+
657
+ for (const entity of entities) {
658
+ this.logger.info(
659
+ `Storing entity: ${entity.name} (${entity.type}) -> ${entity.id}`
660
+ );
661
+
662
+ const transactionId = this.extractTransactionId(response);
671
663
  this.memoryManager.storeEntityAssociation(
672
- entityId,
673
- entityName,
674
- entityType,
675
- this.extractTransactionId(response)
664
+ entity.id,
665
+ entity.name,
666
+ entity.type,
667
+ transactionId
676
668
  );
677
-
678
- this.logger.info(`Stored entity association: ${entityName} (${entityId})`);
679
669
  }
670
+
671
+ if (entities.length > 0) {
672
+ this.logger.info(
673
+ `Stored ${entities.length} entities via LLM extraction`
674
+ );
675
+ } else {
676
+ this.logger.info('No entities found in response via LLM extraction');
677
+ }
678
+ } catch (parseError) {
679
+ this.logger.error(
680
+ 'Failed to parse extracted entities JSON:',
681
+ parseError
682
+ );
683
+ throw parseError;
680
684
  }
681
-
682
- this.logger.info('Entity extraction completed');
683
685
  } catch (error) {
684
- this.logger.warn('Entity extraction failed:', error);
686
+ this.logger.error('Entity extraction failed:', error);
687
+ throw error;
685
688
  }
686
689
  }
687
690
 
@@ -690,13 +693,19 @@ export class ConversationalAgent {
690
693
  * @param response - Transaction response
691
694
  * @returns Transaction ID or undefined
692
695
  */
693
- private extractTransactionId(response: any): string | undefined {
696
+ private extractTransactionId(response: unknown): string | undefined {
694
697
  try {
695
- if (typeof response === 'object' && response?.transactionId) {
696
- return response.transactionId;
698
+ if (
699
+ typeof response === 'object' &&
700
+ response &&
701
+ 'transactionId' in response
702
+ ) {
703
+ return (response as { transactionId?: string }).transactionId;
697
704
  }
698
705
  if (typeof response === 'string') {
699
- const match = response.match(/transaction[\s\w]*ID[\s:"]*([0-9a-fA-F@\.\-]+)/i);
706
+ const match = response.match(
707
+ /transaction[\s\w]*ID[\s:"]*([0-9a-fA-F@\.\-]+)/i
708
+ );
700
709
  return match ? match[1] : undefined;
701
710
  }
702
711
  return undefined;
@@ -714,75 +723,14 @@ export class ConversationalAgent {
714
723
  return;
715
724
  }
716
725
 
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);
726
+ this.agent
727
+ .connectMCPServers()
728
+ .catch((e) => {
729
+ this.logger.error('Failed to connect MCP servers:', e);
730
+ })
731
+ .then(() => {
732
+ this.logger.info('MCP servers connected successfully');
730
733
  });
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
734
  }
787
735
 
788
736
  /**
@@ -790,7 +738,10 @@ export class ConversationalAgent {
790
738
  * @returns {Map<string, MCPConnectionStatus>} Connection status map
791
739
  */
792
740
  getMCPConnectionStatus(): Map<string, MCPConnectionStatus> {
793
- return new Map(this.mcpConnectionStatus);
741
+ if (this.agent) {
742
+ return this.agent.getMCPConnectionStatus();
743
+ }
744
+ return new Map();
794
745
  }
795
746
 
796
747
  /**
@@ -799,8 +750,12 @@ export class ConversationalAgent {
799
750
  * @returns {boolean} True if connected, false otherwise
800
751
  */
801
752
  isMCPServerConnected(serverName: string): boolean {
802
- const status = this.mcpConnectionStatus.get(serverName);
803
- return status?.connected ?? false;
753
+ if (this.agent) {
754
+ const statusMap = this.agent.getMCPConnectionStatus();
755
+ const status = statusMap.get(serverName);
756
+ return status?.connected ?? false;
757
+ }
758
+ return false;
804
759
  }
805
760
 
806
761
  /**
@@ -809,7 +764,7 @@ export class ConversationalAgent {
809
764
  async cleanup(): Promise<void> {
810
765
  try {
811
766
  this.logger.info('Cleaning up ConversationalAgent...');
812
-
767
+
813
768
  if (this.memoryManager) {
814
769
  try {
815
770
  this.memoryManager.dispose();
@@ -817,17 +772,29 @@ export class ConversationalAgent {
817
772
  } catch (error) {
818
773
  this.logger.warn('Error cleaning up memory manager:', error);
819
774
  }
820
- this.memoryManager = undefined as any;
775
+ this.memoryManager = undefined;
821
776
  }
822
-
777
+
823
778
  if (this.contentStoreManager) {
824
779
  await this.contentStoreManager.dispose();
825
780
  this.logger.info('ContentStoreManager cleaned up');
826
781
  }
827
-
782
+
828
783
  this.logger.info('ConversationalAgent cleanup completed');
829
784
  } catch (error) {
830
785
  this.logger.error('Error during cleanup:', error);
831
786
  }
832
787
  }
788
+
789
+ private extractResponseText(response: unknown): string {
790
+ if (typeof response === 'string') {
791
+ return response;
792
+ }
793
+
794
+ if (response && typeof response === 'object' && 'output' in response) {
795
+ return String(response.output);
796
+ }
797
+
798
+ return JSON.stringify(response);
799
+ }
833
800
  }