@hashgraphonline/conversational-agent 0.1.208 → 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 (117) 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 +64 -13
  5. package/dist/cjs/index.cjs +1 -1
  6. package/dist/cjs/index.cjs.map +1 -1
  7. package/dist/cjs/index.d.ts +6 -3
  8. package/dist/cjs/langchain-agent.d.ts +11 -0
  9. package/dist/cjs/memory/SmartMemoryManager.d.ts +65 -22
  10. package/dist/cjs/memory/TokenCounter.d.ts +1 -1
  11. package/dist/cjs/memory/index.d.ts +1 -1
  12. package/dist/cjs/plugins/hbar/AirdropToolWrapper.d.ts +43 -0
  13. package/dist/{types/plugins/hbar-transfer/HbarTransferPlugin.d.ts → cjs/plugins/hbar/HbarPlugin.d.ts} +2 -1
  14. package/dist/{types/plugins/hbar-transfer → cjs/plugins/hbar}/TransferHbarTool.d.ts +1 -1
  15. package/dist/cjs/plugins/hbar/index.d.ts +3 -0
  16. package/dist/cjs/plugins/index.d.ts +2 -1
  17. package/dist/cjs/services/EntityResolver.d.ts +26 -0
  18. package/dist/cjs/tools/EntityResolverTool.d.ts +104 -0
  19. package/dist/cjs/types/inscription.d.ts +37 -0
  20. package/dist/esm/index.js +16 -2
  21. package/dist/esm/index.js.map +1 -1
  22. package/dist/esm/index12.js +121 -46
  23. package/dist/esm/index12.js.map +1 -1
  24. package/dist/esm/index13.js +177 -13
  25. package/dist/esm/index13.js.map +1 -1
  26. package/dist/esm/index14.js +599 -100
  27. package/dist/esm/index14.js.map +1 -1
  28. package/dist/esm/index15.js +426 -9
  29. package/dist/esm/index15.js.map +1 -1
  30. package/dist/esm/index16.js +119 -160
  31. package/dist/esm/index16.js.map +1 -1
  32. package/dist/esm/index17.js +140 -150
  33. package/dist/esm/index17.js.map +1 -1
  34. package/dist/esm/index18.js +44 -231
  35. package/dist/esm/index18.js.map +1 -1
  36. package/dist/esm/index19.js +86 -643
  37. package/dist/esm/index19.js.map +1 -1
  38. package/dist/esm/index2.js +22 -13
  39. package/dist/esm/index2.js.map +1 -1
  40. package/dist/esm/index20.js +20 -230
  41. package/dist/esm/index20.js.map +1 -1
  42. package/dist/esm/index21.js +9 -179
  43. package/dist/esm/index21.js.map +1 -1
  44. package/dist/esm/index22.js +140 -89
  45. package/dist/esm/index22.js.map +1 -1
  46. package/dist/esm/index23.js +141 -81
  47. package/dist/esm/index23.js.map +1 -1
  48. package/dist/esm/index24.js +4 -4
  49. package/dist/esm/index24.js.map +1 -1
  50. package/dist/esm/index25.js +0 -8
  51. package/dist/esm/index25.js.map +1 -1
  52. package/dist/esm/index26.js +95 -0
  53. package/dist/esm/index26.js.map +1 -0
  54. package/dist/esm/index27.js +242 -0
  55. package/dist/esm/index27.js.map +1 -0
  56. package/dist/esm/index5.js +32 -19
  57. package/dist/esm/index5.js.map +1 -1
  58. package/dist/esm/index6.js +276 -37
  59. package/dist/esm/index6.js.map +1 -1
  60. package/dist/esm/index7.js +2 -2
  61. package/dist/esm/index7.js.map +1 -1
  62. package/dist/esm/index8.js +124 -18
  63. package/dist/esm/index8.js.map +1 -1
  64. package/dist/types/base-agent.d.ts +3 -1
  65. package/dist/types/conversational-agent.d.ts +64 -13
  66. package/dist/types/index.d.ts +6 -3
  67. package/dist/types/langchain-agent.d.ts +11 -0
  68. package/dist/types/memory/SmartMemoryManager.d.ts +65 -22
  69. package/dist/types/memory/TokenCounter.d.ts +1 -1
  70. package/dist/types/memory/index.d.ts +1 -1
  71. package/dist/types/plugins/hbar/AirdropToolWrapper.d.ts +43 -0
  72. package/dist/{cjs/plugins/hbar-transfer/HbarTransferPlugin.d.ts → types/plugins/hbar/HbarPlugin.d.ts} +2 -1
  73. package/dist/{cjs/plugins/hbar-transfer → types/plugins/hbar}/TransferHbarTool.d.ts +1 -1
  74. package/dist/types/plugins/hbar/index.d.ts +3 -0
  75. package/dist/types/plugins/index.d.ts +2 -1
  76. package/dist/types/services/EntityResolver.d.ts +26 -0
  77. package/dist/types/tools/EntityResolverTool.d.ts +104 -0
  78. package/dist/types/types/inscription.d.ts +37 -0
  79. package/package.json +13 -4
  80. package/src/base-agent.ts +14 -9
  81. package/src/config/system-message.ts +11 -2
  82. package/src/context/ReferenceContextManager.ts +10 -5
  83. package/src/context/ReferenceResponseProcessor.ts +3 -4
  84. package/src/conversational-agent.ts +372 -57
  85. package/src/index.ts +19 -3
  86. package/src/langchain/ContentAwareAgentExecutor.ts +0 -1
  87. package/src/langchain-agent.ts +168 -33
  88. package/src/mcp/ContentProcessor.ts +11 -3
  89. package/src/mcp/adapters/langchain.ts +1 -10
  90. package/src/memory/ContentStorage.ts +2 -55
  91. package/src/memory/MemoryWindow.ts +4 -17
  92. package/src/memory/ReferenceIdGenerator.ts +4 -8
  93. package/src/memory/SmartMemoryManager.ts +375 -47
  94. package/src/memory/TokenCounter.ts +15 -22
  95. package/src/memory/index.ts +1 -1
  96. package/src/plugins/hbar/AirdropToolWrapper.ts +157 -0
  97. package/src/plugins/hbar/HbarPlugin.ts +86 -0
  98. package/src/plugins/{hbar-transfer → hbar}/TransferHbarTool.ts +3 -3
  99. package/src/plugins/hbar/index.ts +3 -0
  100. package/src/plugins/hcs-10/HCS10Plugin.ts +44 -14
  101. package/src/plugins/index.ts +2 -1
  102. package/src/services/ContentStoreManager.ts +0 -3
  103. package/src/services/EntityResolver.ts +135 -0
  104. package/src/tools/EntityResolverTool.ts +170 -0
  105. package/src/types/content-reference.ts +8 -8
  106. package/src/types/index.ts +0 -1
  107. package/src/types/inscription.ts +40 -0
  108. package/dist/cjs/plugins/hbar-transfer/index.d.ts +0 -1
  109. package/dist/types/plugins/hbar-transfer/index.d.ts +0 -1
  110. package/src/plugins/hbar-transfer/HbarTransferPlugin.ts +0 -66
  111. package/src/plugins/hbar-transfer/index.ts +0 -1
  112. /package/dist/cjs/plugins/{hbar-transfer → hbar}/AccountBuilder.d.ts +0 -0
  113. /package/dist/cjs/plugins/{hbar-transfer → hbar}/types.d.ts +0 -0
  114. /package/dist/types/plugins/{hbar-transfer → hbar}/AccountBuilder.d.ts +0 -0
  115. /package/dist/types/plugins/{hbar-transfer → hbar}/types.d.ts +0 -0
  116. /package/src/plugins/{hbar-transfer → hbar}/AccountBuilder.ts +0 -0
  117. /package/src/plugins/{hbar-transfer → hbar}/types.ts +0 -0
@@ -24,12 +24,14 @@ import {
24
24
  import { MCPClientManager } from './mcp/MCPClientManager';
25
25
  import { convertMCPToolToLangChain } from './mcp/adapters/langchain';
26
26
  import { SmartMemoryManager } from './memory/SmartMemoryManager';
27
+ import type { MCPConnectionStatus } from './mcp/types';
27
28
 
28
29
  export class LangChainAgent extends BaseAgent {
29
30
  private executor: ContentAwareAgentExecutor | undefined;
30
31
  private systemMessage = '';
31
32
  private mcpManager?: MCPClientManager;
32
33
  private smartMemory: SmartMemoryManager | undefined;
34
+ private mcpConnectionStatus: Map<string, MCPConnectionStatus> = new Map();
33
35
 
34
36
  async boot(): Promise<void> {
35
37
  if (this.initialized) {
@@ -51,26 +53,32 @@ export class LangChainAgent extends BaseAgent {
51
53
  this.tools = this.filterTools(allTools);
52
54
 
53
55
  if (this.config.mcp?.servers && this.config.mcp.servers.length > 0) {
54
- await this.initializeMCP();
56
+ if (this.config.mcp.autoConnect !== false) {
57
+ await this.initializeMCP();
58
+ } else {
59
+ this.logger.info(
60
+ 'MCP servers configured but autoConnect=false, skipping synchronous connection'
61
+ );
62
+ this.mcpManager = new MCPClientManager(this.logger);
63
+ }
55
64
  }
56
65
 
57
66
  this.smartMemory = new SmartMemoryManager({
58
67
  modelName,
59
68
  maxTokens: 90000,
60
69
  reserveTokens: 10000,
61
- storageLimit: 1000
70
+ storageLimit: 1000,
62
71
  });
63
-
72
+
64
73
  this.logger.info('SmartMemoryManager initialized:', {
65
74
  modelName,
66
75
  toolsCount: this.tools.length,
67
76
  maxTokens: 90000,
68
- reserveTokens: 10000
77
+ reserveTokens: 10000,
69
78
  });
70
79
 
71
80
  this.systemMessage = this.buildSystemPrompt();
72
-
73
- // Set the system prompt in smart memory
81
+
74
82
  this.smartMemory.setSystemPrompt(this.systemMessage);
75
83
 
76
84
  await this.createExecutor();
@@ -92,31 +100,31 @@ export class LangChainAgent extends BaseAgent {
92
100
  }
93
101
 
94
102
  try {
95
- this.logger.info('LangChainAgent.chat called with:', { message, contextLength: context?.messages?.length || 0 });
96
-
97
- // If context is provided, populate smart memory with previous messages
103
+ this.logger.info('LangChainAgent.chat called with:', {
104
+ message,
105
+ contextLength: context?.messages?.length || 0,
106
+ });
107
+
98
108
  if (context?.messages && context.messages.length > 0) {
99
- // Clear existing memory and add messages from context
100
109
  this.smartMemory.clear();
101
-
110
+
102
111
  for (const msg of context.messages) {
103
112
  this.smartMemory.addMessage(msg);
104
113
  }
105
114
  }
106
-
107
- // Add the current user message to memory
115
+
108
116
  const { HumanMessage } = await import('@langchain/core/messages');
109
117
  this.smartMemory.addMessage(new HumanMessage(message));
110
-
118
+
111
119
  const memoryStats = this.smartMemory.getMemoryStats();
112
120
  this.logger.info('Memory stats before execution:', {
113
121
  totalMessages: memoryStats.totalActiveMessages,
114
122
  currentTokens: memoryStats.currentTokenCount,
115
123
  maxTokens: memoryStats.maxTokens,
116
124
  usagePercentage: memoryStats.usagePercentage,
117
- toolsCount: this.tools.length
125
+ toolsCount: this.tools.length,
118
126
  });
119
-
127
+
120
128
  const result = await this.executor.invoke({
121
129
  input: message,
122
130
  chat_history: this.smartMemory.getMessages(),
@@ -131,15 +139,19 @@ export class LangChainAgent extends BaseAgent {
131
139
  intermediateSteps: result.intermediateSteps,
132
140
  };
133
141
 
134
- // Extract tool calls from intermediate steps
135
142
  if (result.intermediateSteps && Array.isArray(result.intermediateSteps)) {
136
- const toolCalls = result.intermediateSteps.map((step: any, index: number) => ({
137
- id: `call_${index}`,
138
- name: step.action?.tool || 'unknown',
139
- args: step.action?.toolInput || {},
140
- output: typeof step.observation === 'string' ? step.observation : JSON.stringify(step.observation)
141
- }));
142
-
143
+ const toolCalls = result.intermediateSteps.map(
144
+ (step: any, index: number) => ({
145
+ id: `call_${index}`,
146
+ name: step.action?.tool || 'unknown',
147
+ args: step.action?.toolInput || {},
148
+ output:
149
+ typeof step.observation === 'string'
150
+ ? step.observation
151
+ : JSON.stringify(step.observation),
152
+ })
153
+ );
154
+
143
155
  if (toolCalls.length > 0) {
144
156
  response.tool_calls = toolCalls;
145
157
  }
@@ -163,7 +175,6 @@ export class LangChainAgent extends BaseAgent {
163
175
  response.output = 'Agent action complete.';
164
176
  }
165
177
 
166
- // Add the AI response to memory
167
178
  if (response.output) {
168
179
  const { AIMessage } = await import('@langchain/core/messages');
169
180
  this.smartMemory.addMessage(new AIMessage(response.output));
@@ -184,8 +195,8 @@ export class LangChainAgent extends BaseAgent {
184
195
  activeMessages: finalMemoryStats.totalActiveMessages,
185
196
  tokenUsage: finalMemoryStats.currentTokenCount,
186
197
  maxTokens: finalMemoryStats.maxTokens,
187
- usagePercentage: finalMemoryStats.usagePercentage
188
- }
198
+ usagePercentage: finalMemoryStats.usagePercentage,
199
+ },
189
200
  };
190
201
 
191
202
  this.logger.info('LangChainAgent.chat returning response:', response);
@@ -261,6 +272,9 @@ export class LangChainAgent extends BaseAgent {
261
272
  }
262
273
  }
263
274
 
275
+ getMCPConnectionStatus(): Map<string, MCPConnectionStatus> {
276
+ return new Map(this.mcpConnectionStatus);
277
+ }
264
278
 
265
279
  private async createAgentKit(): Promise<HederaAgentKit> {
266
280
  const corePlugins = getAllHederaCorePlugins();
@@ -276,7 +290,7 @@ export class LangChainAgent extends BaseAgent {
276
290
  { plugins },
277
291
  operationalMode,
278
292
  this.config.execution?.userAccountId,
279
- this.config.execution?.scheduleUserTransactionsInBytesMode ?? true,
293
+ this.config.execution?.scheduleUserTransactionsInBytesMode ?? false,
280
294
  undefined,
281
295
  modelName,
282
296
  this.config.extensions?.mirrorConfig,
@@ -296,11 +310,16 @@ export class LangChainAgent extends BaseAgent {
296
310
  throw new Error('OpenAI API key required');
297
311
  }
298
312
 
313
+ const modelName = this.config.ai?.modelName || 'gpt-4o-mini';
314
+ const isGPT5Model =
315
+ modelName.toLowerCase().includes('gpt-5') ||
316
+ modelName.toLowerCase().includes('gpt5');
317
+
299
318
  llm = new ChatOpenAI({
300
319
  apiKey,
301
- modelName: this.config.ai?.modelName || 'gpt-4o-mini',
302
- temperature: this.config.ai?.temperature ?? 0.1,
320
+ modelName,
303
321
  callbacks: this.tokenTracker ? [this.tokenTracker] : [],
322
+ ...(isGPT5Model ? { temperature: 1 } : {}),
304
323
  });
305
324
  }
306
325
 
@@ -319,7 +338,6 @@ export class LangChainAgent extends BaseAgent {
319
338
  prompt,
320
339
  });
321
340
 
322
- // Create executor without memory - we handle memory manually with SmartMemoryManager
323
341
  this.executor = new ContentAwareAgentExecutor({
324
342
  agent,
325
343
  tools: langchainTools,
@@ -343,9 +361,49 @@ export class LangChainAgent extends BaseAgent {
343
361
  }
344
362
  }
345
363
 
364
+ let userFriendlyMessage = errorMessage;
365
+ let userFriendlyOutput = errorMessage;
366
+
367
+ if (errorMessage.includes('429')) {
368
+ if (errorMessage.includes('quota')) {
369
+ userFriendlyMessage =
370
+ 'API quota exceeded. Please check your OpenAI billing and usage limits.';
371
+ userFriendlyOutput =
372
+ "I'm currently unable to respond because the API quota has been exceeded. Please check your OpenAI account billing and usage limits, then try again.";
373
+ } else {
374
+ userFriendlyMessage =
375
+ 'Too many requests. Please wait a moment and try again.';
376
+ userFriendlyOutput =
377
+ "I'm receiving too many requests right now. Please wait a moment and try again.";
378
+ }
379
+ } else if (
380
+ errorMessage.includes('401') ||
381
+ errorMessage.includes('unauthorized')
382
+ ) {
383
+ userFriendlyMessage =
384
+ 'API authentication failed. Please check your API key configuration.';
385
+ userFriendlyOutput =
386
+ "There's an issue with the API authentication. Please check your OpenAI API key configuration in settings.";
387
+ } else if (errorMessage.includes('timeout')) {
388
+ userFriendlyMessage = 'Request timed out. Please try again.';
389
+ userFriendlyOutput =
390
+ 'The request took too long to process. Please try again.';
391
+ } else if (
392
+ errorMessage.includes('network') ||
393
+ errorMessage.includes('fetch')
394
+ ) {
395
+ userFriendlyMessage =
396
+ 'Network error. Please check your internet connection and try again.';
397
+ userFriendlyOutput =
398
+ 'There was a network error. Please check your internet connection and try again.';
399
+ } else if (errorMessage.includes('400')) {
400
+ userFriendlyMessage = errorMessage;
401
+ userFriendlyOutput = errorMessage;
402
+ }
403
+
346
404
  const errorResponse: ChatResponse = {
347
- output: 'Sorry, I encountered an error processing your request.',
348
- message: 'Error processing request.',
405
+ output: userFriendlyOutput,
406
+ message: userFriendlyMessage,
349
407
  error: errorMessage,
350
408
  notes: [],
351
409
  };
@@ -395,6 +453,83 @@ export class LangChainAgent extends BaseAgent {
395
453
  }
396
454
  }
397
455
 
456
+ /**
457
+ * Connect to MCP servers asynchronously after agent boot with background timeout pattern
458
+ */
459
+ async connectMCPServers(): Promise<void> {
460
+ if (!this.config.mcp?.servers || this.config.mcp.servers.length === 0) {
461
+ return;
462
+ }
463
+
464
+ if (!this.mcpManager) {
465
+ this.mcpManager = new MCPClientManager(this.logger);
466
+ }
467
+
468
+ this.logger.info(
469
+ `Starting background MCP server connections for ${this.config.mcp.servers.length} servers...`
470
+ );
471
+
472
+ this.config.mcp.servers.forEach((serverConfig) => {
473
+ this.connectServerInBackground(serverConfig);
474
+ });
475
+
476
+ this.logger.info('MCP server connections initiated in background');
477
+ }
478
+
479
+ /**
480
+ * Connect to a single MCP server in background with timeout
481
+ */
482
+ private connectServerInBackground(serverConfig: any): void {
483
+ const serverName = serverConfig.name;
484
+
485
+ setTimeout(async () => {
486
+ try {
487
+ this.logger.info(`Background connecting to MCP server: ${serverName}`);
488
+
489
+ const status = await this.mcpManager!.connectServer(serverConfig);
490
+ this.mcpConnectionStatus.set(serverName, status);
491
+
492
+ if (status.connected) {
493
+ this.logger.info(
494
+ `Successfully connected to MCP server ${status.serverName} with ${status.tools.length} tools`
495
+ );
496
+
497
+ for (const mcpTool of status.tools) {
498
+ const langchainTool = convertMCPToolToLangChain(
499
+ mcpTool,
500
+ this.mcpManager!,
501
+ serverConfig
502
+ );
503
+ this.tools.push(langchainTool);
504
+ }
505
+
506
+ if (this.initialized && this.executor) {
507
+ this.logger.info(
508
+ `Recreating executor with ${this.tools.length} total tools`
509
+ );
510
+ await this.createExecutor();
511
+ }
512
+ } else {
513
+ this.logger.error(
514
+ `Failed to connect to MCP server ${status.serverName}: ${status.error}`
515
+ );
516
+ }
517
+ } catch (error) {
518
+ this.logger.error(
519
+ `Background connection failed for MCP server ${serverName}:`,
520
+ error
521
+ );
522
+
523
+ this.mcpConnectionStatus.set(serverName, {
524
+ connected: false,
525
+ serverName,
526
+ tools: [],
527
+ error: error instanceof Error ? error.message : 'Connection failed',
528
+ });
529
+ }
530
+ }, 1000);
531
+ }
532
+
398
533
  /**
399
534
  * Check if a string is valid JSON
400
535
  */
@@ -111,7 +111,7 @@ export class MCPContentProcessor {
111
111
  content: record.text,
112
112
  type: 'text',
113
113
  sizeBytes: Buffer.byteLength(record.text, 'utf8'),
114
- mimeType: 'text/plain'
114
+ mimeType: this.detectMimeType(record.text as string)
115
115
  });
116
116
  return;
117
117
  }
@@ -238,7 +238,7 @@ export class MCPContentProcessor {
238
238
  };
239
239
  }
240
240
 
241
- private replaceContentInResponse(obj: unknown, oldContent: unknown, newContent: unknown): void {
241
+ private replaceContentInResponse(obj: unknown, oldContent: unknown, newContent: any): void {
242
242
  if (obj === null || obj === undefined) {
243
243
  return;
244
244
  }
@@ -256,7 +256,15 @@ export class MCPContentProcessor {
256
256
 
257
257
  if (typeof obj === 'object') {
258
258
  const record = obj as Record<string, unknown>;
259
-
259
+ if (record.type === 'text' && record.text === oldContent) {
260
+ for (const key of Object.keys(record)) {
261
+ delete record[key];
262
+ }
263
+ for (const key of Object.keys(newContent)) {
264
+ record[key] = newContent[key];
265
+ }
266
+ return;
267
+ }
260
268
  for (const key in record) {
261
269
  if (record[key] === oldContent) {
262
270
  record[key] = newContent;
@@ -71,16 +71,12 @@ export function convertMCPToolToLangChain(
71
71
  responseText = JSON.stringify(result);
72
72
  }
73
73
 
74
- // Check if content should be stored as reference
75
74
  const responseBuffer = Buffer.from(responseText, 'utf8');
76
- console.log(`[MCP Adapter] Response size: ${responseBuffer.length} bytes, tool: ${tool.serverName}_${tool.name}`);
77
75
 
78
- // Use a lower threshold for MCP tools (10KB) to avoid token limit issues
79
- const MCP_REFERENCE_THRESHOLD = 10 * 1024; // 10KB
76
+ const MCP_REFERENCE_THRESHOLD = 10 * 1024;
80
77
  const shouldStoreMCPContent = responseBuffer.length > MCP_REFERENCE_THRESHOLD;
81
78
 
82
79
  if (shouldStoreMCPContent || shouldUseReference(responseBuffer)) {
83
- console.log(`[MCP Adapter] Content exceeds threshold (${responseBuffer.length} > ${MCP_REFERENCE_THRESHOLD}), storing as reference`);
84
80
  const contentStore = ContentStoreService.getInstance();
85
81
  if (contentStore) {
86
82
  try {
@@ -90,14 +86,9 @@ export function convertMCPToolToLangChain(
90
86
  mcpToolName: `${tool.serverName}_${tool.name}`,
91
87
  originalSize: responseBuffer.length
92
88
  });
93
- console.log(`[MCP Adapter] Stored content as reference: content-ref:${referenceId}`);
94
89
  return `content-ref:${referenceId}`;
95
90
  } catch (storeError) {
96
- // If storage fails, fall back to returning the content
97
- console.warn('Failed to store large MCP content as reference:', storeError);
98
91
  }
99
- } else {
100
- console.warn('[MCP Adapter] ContentStoreService not available');
101
92
  }
102
93
  }
103
94