@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.
- package/bin/conversational-agent-cli.js +30 -0
- package/cli/readme.md +181 -0
- package/dist/cjs/base-agent.d.ts +3 -1
- package/dist/cjs/conversational-agent.d.ts +14 -22
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +5 -3
- package/dist/cjs/langchain-agent.d.ts +6 -3
- package/dist/cjs/memory/SmartMemoryManager.d.ts +7 -1
- package/dist/cjs/memory/TokenCounter.d.ts +1 -1
- package/dist/cjs/plugins/hbar/AirdropToolWrapper.d.ts +43 -0
- package/dist/{types/plugins/hbar-transfer/HbarTransferPlugin.d.ts → cjs/plugins/hbar/HbarPlugin.d.ts} +2 -1
- package/dist/{types/plugins/hbar-transfer → cjs/plugins/hbar}/TransferHbarTool.d.ts +1 -1
- package/dist/cjs/plugins/hbar/index.d.ts +3 -0
- package/dist/cjs/plugins/index.d.ts +2 -1
- package/dist/cjs/services/EntityResolver.d.ts +26 -0
- package/dist/cjs/tools/EntityResolverTool.d.ts +104 -0
- package/dist/cjs/types/inscription.d.ts +37 -0
- package/dist/esm/index.js +8 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index12.js +1 -4
- package/dist/esm/index12.js.map +1 -1
- package/dist/esm/index13.js +0 -1
- package/dist/esm/index13.js.map +1 -1
- package/dist/esm/index14.js +2 -7
- package/dist/esm/index14.js.map +1 -1
- package/dist/esm/index15.js +31 -69
- package/dist/esm/index15.js.map +1 -1
- package/dist/esm/index16.js +126 -39
- package/dist/esm/index16.js.map +1 -1
- package/dist/esm/index17.js +148 -13
- package/dist/esm/index17.js.map +1 -1
- package/dist/esm/index18.js +44 -146
- package/dist/esm/index18.js.map +1 -1
- package/dist/esm/index19.js +100 -6
- package/dist/esm/index19.js.map +1 -1
- package/dist/esm/index20.js +20 -174
- package/dist/esm/index20.js.map +1 -1
- package/dist/esm/index21.js +7 -151
- package/dist/esm/index21.js.map +1 -1
- package/dist/esm/index22.js +154 -45
- package/dist/esm/index22.js.map +1 -1
- package/dist/esm/index23.js +149 -24
- package/dist/esm/index23.js.map +1 -1
- package/dist/esm/index24.js +56 -83
- package/dist/esm/index24.js.map +1 -1
- package/dist/esm/index25.js +24 -236
- package/dist/esm/index25.js.map +1 -1
- package/dist/esm/index26.js +95 -0
- package/dist/esm/index26.js.map +1 -0
- package/dist/esm/index27.js +242 -0
- package/dist/esm/index27.js.map +1 -0
- package/dist/esm/index5.js +32 -19
- package/dist/esm/index5.js.map +1 -1
- package/dist/esm/index6.js +156 -195
- package/dist/esm/index6.js.map +1 -1
- package/dist/esm/index7.js +2 -2
- package/dist/esm/index7.js.map +1 -1
- package/dist/esm/index8.js +80 -48
- package/dist/esm/index8.js.map +1 -1
- package/dist/types/base-agent.d.ts +3 -1
- package/dist/types/conversational-agent.d.ts +14 -22
- package/dist/types/index.d.ts +5 -3
- package/dist/types/langchain-agent.d.ts +6 -3
- package/dist/types/memory/SmartMemoryManager.d.ts +7 -1
- package/dist/types/memory/TokenCounter.d.ts +1 -1
- package/dist/types/plugins/hbar/AirdropToolWrapper.d.ts +43 -0
- package/dist/{cjs/plugins/hbar-transfer/HbarTransferPlugin.d.ts → types/plugins/hbar/HbarPlugin.d.ts} +2 -1
- package/dist/{cjs/plugins/hbar-transfer → types/plugins/hbar}/TransferHbarTool.d.ts +1 -1
- package/dist/types/plugins/hbar/index.d.ts +3 -0
- package/dist/types/plugins/index.d.ts +2 -1
- package/dist/types/services/EntityResolver.d.ts +26 -0
- package/dist/types/tools/EntityResolverTool.d.ts +104 -0
- package/dist/types/types/inscription.d.ts +37 -0
- package/package.json +13 -4
- package/src/base-agent.ts +14 -9
- package/src/config/system-message.ts +11 -2
- package/src/context/ReferenceContextManager.ts +1 -1
- package/src/conversational-agent.ts +221 -254
- package/src/index.ts +17 -3
- package/src/langchain-agent.ts +130 -78
- package/src/mcp/ContentProcessor.ts +0 -2
- package/src/mcp/adapters/langchain.ts +0 -1
- package/src/memory/ContentStorage.ts +0 -5
- package/src/memory/MemoryWindow.ts +0 -1
- package/src/memory/ReferenceIdGenerator.ts +4 -4
- package/src/memory/SmartMemoryManager.ts +53 -92
- package/src/memory/TokenCounter.ts +4 -7
- package/src/plugins/hbar/AirdropToolWrapper.ts +157 -0
- package/src/plugins/hbar/HbarPlugin.ts +86 -0
- package/src/plugins/{hbar-transfer → hbar}/TransferHbarTool.ts +3 -3
- package/src/plugins/hbar/index.ts +3 -0
- package/src/plugins/index.ts +2 -1
- package/src/services/EntityResolver.ts +135 -0
- package/src/tools/EntityResolverTool.ts +170 -0
- package/src/types/inscription.ts +40 -0
- package/dist/cjs/plugins/hbar-transfer/index.d.ts +0 -1
- package/dist/types/plugins/hbar-transfer/index.d.ts +0 -1
- package/src/plugins/hbar-transfer/HbarTransferPlugin.ts +0 -66
- package/src/plugins/hbar-transfer/index.ts +0 -1
- /package/dist/cjs/plugins/{hbar-transfer → hbar}/AccountBuilder.d.ts +0 -0
- /package/dist/cjs/plugins/{hbar-transfer → hbar}/types.d.ts +0 -0
- /package/dist/types/plugins/{hbar-transfer → hbar}/AccountBuilder.d.ts +0 -0
- /package/dist/types/plugins/{hbar-transfer → hbar}/types.d.ts +0 -0
- /package/src/plugins/{hbar-transfer → hbar}/AccountBuilder.ts +0 -0
- /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 {
|
|
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
|
|
96
|
+
public hbarPlugin: HbarPlugin;
|
|
90
97
|
public stateManager: IStateManager;
|
|
91
98
|
private options: ConversationalAgentOptions;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
private
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
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.
|
|
344
|
+
this.hbarPlugin,
|
|
285
345
|
];
|
|
286
|
-
|
|
287
|
-
const corePlugins
|
|
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:
|
|
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 && {
|
|
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
|
-
(
|
|
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
|
|
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
|
|
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
|
-
|
|
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 (
|
|
538
|
-
this.logger.
|
|
539
|
-
|
|
597
|
+
if (entities.length === 0) {
|
|
598
|
+
this.logger.info('No entities in memory, skipping resolution');
|
|
599
|
+
return content;
|
|
540
600
|
}
|
|
541
601
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
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
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
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(
|
|
614
|
-
|
|
615
|
-
|
|
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.
|
|
621
|
-
|
|
626
|
+
this.logger.error('Entity resolution failed:', error);
|
|
627
|
+
throw error;
|
|
622
628
|
}
|
|
623
629
|
}
|
|
624
630
|
|
|
625
631
|
/**
|
|
626
|
-
* Extract and store
|
|
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(
|
|
631
|
-
|
|
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
|
|
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 =
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
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
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
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.
|
|
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:
|
|
696
|
+
private extractTransactionId(response: unknown): string | undefined {
|
|
694
697
|
try {
|
|
695
|
-
if (
|
|
696
|
-
|
|
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(
|
|
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
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
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
|
-
|
|
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
|
-
|
|
803
|
-
|
|
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
|
|
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
|
}
|