@hashgraphonline/conversational-agent 0.2.0 → 0.2.101

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 (63) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/conversational-agent.d.ts +11 -1
  3. package/dist/cjs/index.cjs +1 -1
  4. package/dist/cjs/index.cjs.map +1 -1
  5. package/dist/cjs/services/attachment-processor.d.ts +41 -0
  6. package/dist/cjs/services/index.d.ts +2 -0
  7. package/dist/cjs/services/parameter-service.d.ts +43 -0
  8. package/dist/cjs/tools/entity-resolver-tool.d.ts +5 -3
  9. package/dist/esm/index.js +9 -5
  10. package/dist/esm/index.js.map +1 -1
  11. package/dist/esm/index10.js +2 -2
  12. package/dist/esm/index21.js +1 -1
  13. package/dist/esm/index23.js +3 -3
  14. package/dist/esm/index24.js +20 -4
  15. package/dist/esm/index24.js.map +1 -1
  16. package/dist/esm/index29.js +248 -903
  17. package/dist/esm/index29.js.map +1 -1
  18. package/dist/esm/index30.js +98 -219
  19. package/dist/esm/index30.js.map +1 -1
  20. package/dist/esm/index31.js +834 -1085
  21. package/dist/esm/index31.js.map +1 -1
  22. package/dist/esm/index32.js +228 -115
  23. package/dist/esm/index32.js.map +1 -1
  24. package/dist/esm/index33.js +1185 -79
  25. package/dist/esm/index33.js.map +1 -1
  26. package/dist/esm/index34.js +119 -39
  27. package/dist/esm/index34.js.map +1 -1
  28. package/dist/esm/index35.js +103 -96
  29. package/dist/esm/index35.js.map +1 -1
  30. package/dist/esm/index36.js +46 -21
  31. package/dist/esm/index36.js.map +1 -1
  32. package/dist/esm/index37.js +104 -24
  33. package/dist/esm/index37.js.map +1 -1
  34. package/dist/esm/index38.js +21 -12
  35. package/dist/esm/index38.js.map +1 -1
  36. package/dist/esm/index39.js +4 -6
  37. package/dist/esm/index39.js.map +1 -1
  38. package/dist/esm/index40.js +11 -4
  39. package/dist/esm/index40.js.map +1 -1
  40. package/dist/esm/index41.js +1 -1
  41. package/dist/esm/index43.js +24 -89
  42. package/dist/esm/index43.js.map +1 -1
  43. package/dist/esm/index44.js +10 -0
  44. package/dist/esm/index44.js.map +1 -0
  45. package/dist/esm/index45.js +95 -0
  46. package/dist/esm/index45.js.map +1 -0
  47. package/dist/esm/index5.js +2 -2
  48. package/dist/esm/index6.js +76 -6
  49. package/dist/esm/index6.js.map +1 -1
  50. package/dist/esm/index8.js +1 -1
  51. package/dist/types/conversational-agent.d.ts +11 -1
  52. package/dist/types/services/attachment-processor.d.ts +41 -0
  53. package/dist/types/services/index.d.ts +2 -0
  54. package/dist/types/services/parameter-service.d.ts +43 -0
  55. package/dist/types/tools/entity-resolver-tool.d.ts +5 -3
  56. package/package.json +3 -2
  57. package/src/conversational-agent.ts +97 -5
  58. package/src/langchain/langchain-agent.ts +9 -1
  59. package/src/services/attachment-processor.ts +163 -0
  60. package/src/services/content-store-manager.ts +32 -4
  61. package/src/services/index.ts +2 -0
  62. package/src/services/parameter-service.ts +430 -0
  63. package/src/tools/entity-resolver-tool.ts +12 -18
@@ -0,0 +1,163 @@
1
+ import { Logger } from '@hashgraphonline/standards-sdk';
2
+ import type { ContentStoreManager as PackageContentStoreManager } from './content-store-manager';
3
+
4
+ export interface AttachmentData {
5
+ name: string;
6
+ data: string;
7
+ type: string;
8
+ size: number;
9
+ }
10
+
11
+ type ContentStoreManager = PackageContentStoreManager;
12
+
13
+ /**
14
+ * Utility for processing file attachments and content references
15
+ */
16
+ export class AttachmentProcessor {
17
+ private logger: Logger;
18
+
19
+ constructor() {
20
+ this.logger = new Logger({ module: 'AttachmentProcessor' });
21
+ }
22
+
23
+ /**
24
+ * Process attachments and create content references
25
+ */
26
+ async processAttachments(
27
+ content: string,
28
+ attachments: AttachmentData[],
29
+ contentStoreManager?: ContentStoreManager
30
+ ): Promise<string> {
31
+ if (attachments.length === 0) {
32
+ return content;
33
+ }
34
+
35
+ this.logger.info('Processing attachments with content reference system:', {
36
+ attachmentCount: attachments.length,
37
+ totalSize: attachments.reduce((sum, att) => sum + att.size, 0),
38
+ });
39
+
40
+ if (contentStoreManager && contentStoreManager.isInitialized()) {
41
+ return this.processWithContentStore(content, attachments, contentStoreManager);
42
+ } else {
43
+ this.logger.warn('Content storage not available, creating simple file references');
44
+ return this.processWithSimpleReferences(content, attachments);
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Process attachments using content store manager
50
+ */
51
+ private async processWithContentStore(
52
+ content: string,
53
+ attachments: AttachmentData[],
54
+ contentStoreManager: ContentStoreManager
55
+ ): Promise<string> {
56
+ const contentReferences: string[] = [];
57
+
58
+ for (const attachment of attachments) {
59
+ try {
60
+ const base64Data = attachment.data.includes('base64,')
61
+ ? attachment.data.split('base64,')[1]
62
+ : attachment.data;
63
+ const buffer = Buffer.from(base64Data, 'base64');
64
+
65
+ const contentRef = await contentStoreManager.storeContentIfLarge(
66
+ buffer,
67
+ {
68
+ mimeType: attachment.type,
69
+ source: 'user_upload',
70
+ fileName: attachment.name,
71
+ tags: ['attachment', 'user_file'],
72
+ }
73
+ );
74
+
75
+ if (contentRef) {
76
+ if (attachment.type.startsWith('image/')) {
77
+ contentReferences.push(
78
+ `[Image File: ${attachment.name}] (content-ref:${contentRef.referenceId})`
79
+ );
80
+ } else {
81
+ contentReferences.push(
82
+ `[File: ${attachment.name}] (content-ref:${contentRef.referenceId})`
83
+ );
84
+ }
85
+ } else {
86
+ contentReferences.push(
87
+ this.createInlineReference(attachment, base64Data)
88
+ );
89
+ }
90
+ } catch (error) {
91
+ this.logger.error('Failed to process attachment:', {
92
+ fileName: attachment.name,
93
+ error: error instanceof Error ? error.message : 'Unknown error',
94
+ });
95
+ contentReferences.push(
96
+ `[File: ${attachment.name} - Error processing file: ${
97
+ error instanceof Error ? error.message : 'Unknown error'
98
+ }]`
99
+ );
100
+ }
101
+ }
102
+
103
+ const fileList = this.createFileList(attachments);
104
+ return content
105
+ ? `${content}\n\nAttached files:\n${fileList}\n\n${contentReferences.join('\n')}`
106
+ : `Attached files:\n${fileList}\n\n${contentReferences.join('\n')}`;
107
+ }
108
+
109
+ /**
110
+ * Process attachments with simple file references
111
+ */
112
+ private processWithSimpleReferences(content: string, attachments: AttachmentData[]): string {
113
+ const fileReferences = attachments.map((attachment) => {
114
+ const sizeStr = this.formatFileSize(attachment.size);
115
+
116
+ if (attachment.type.startsWith('image/')) {
117
+ return `📎 Image: ${attachment.name} (${sizeStr}, ${attachment.type})`;
118
+ } else {
119
+ return `📎 File: ${attachment.name} (${sizeStr}, ${attachment.type})`;
120
+ }
121
+ });
122
+
123
+ return content
124
+ ? `${content}\n\nAttached files:\n${fileReferences.join('\n')}`
125
+ : `Attached files:\n${fileReferences.join('\n')}`;
126
+ }
127
+
128
+ /**
129
+ * Create inline reference for small files
130
+ */
131
+ private createInlineReference(attachment: AttachmentData, base64Data: string): string {
132
+ if (attachment.size < 50000) {
133
+ if (attachment.type.startsWith('image/')) {
134
+ return `![${attachment.name}](data:${attachment.type};base64,${base64Data})`;
135
+ } else {
136
+ return `[File: ${attachment.name} (${this.formatFileSize(attachment.size)})]\nContent: ${base64Data}`;
137
+ }
138
+ } else {
139
+ return `[File: ${attachment.name} (${this.formatFileSize(attachment.size)}) - Content too large to include inline]`;
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Create formatted file list
145
+ */
146
+ private createFileList(attachments: AttachmentData[]): string {
147
+ return attachments
148
+ .map((file) => {
149
+ const sizeStr = this.formatFileSize(file.size);
150
+ return `📎 ${file.name} (${sizeStr})`;
151
+ })
152
+ .join('\n');
153
+ }
154
+
155
+ /**
156
+ * Format file size for display
157
+ */
158
+ private formatFileSize(size: number): string {
159
+ return size >= 1024 * 1024
160
+ ? `${(size / (1024 * 1024)).toFixed(1)}MB`
161
+ : `${(size / 1024).toFixed(1)}KB`;
162
+ }
163
+ }
@@ -165,8 +165,26 @@ export class ContentStoreManager {
165
165
  }
166
166
 
167
167
  try {
168
- await ContentStoreService.setInstance(this.adapter);
169
- ContentResolverRegistry.register(this.resolver);
168
+ if (
169
+ ContentStoreService &&
170
+ typeof (ContentStoreService as unknown as { setInstance?: Function }).setInstance === 'function'
171
+ ) {
172
+ await (ContentStoreService as unknown as { setInstance: (adapter: unknown) => Promise<void> }).setInstance(
173
+ this.adapter
174
+ );
175
+ } else {
176
+ this.logger.warn('ContentStoreService.setInstance is unavailable; skipping registration');
177
+ }
178
+ if (
179
+ ContentResolverRegistry &&
180
+ typeof (ContentResolverRegistry as unknown as { register?: Function }).register === 'function'
181
+ ) {
182
+ (ContentResolverRegistry as unknown as { register: (resolver: unknown) => void }).register(
183
+ this.resolver
184
+ );
185
+ } else {
186
+ this.logger.warn('ContentResolverRegistry.register is unavailable; skipping registration');
187
+ }
170
188
  this.isRegistered = true;
171
189
  this.logger.info(
172
190
  'ContentStoreManager initialized and registered for cross-package access'
@@ -236,8 +254,18 @@ export class ContentStoreManager {
236
254
  async dispose(): Promise<void> {
237
255
  if (this.isRegistered) {
238
256
  this.contentStorage.dispose();
239
- ContentStoreService.dispose();
240
- ContentResolverRegistry.unregister();
257
+ if (
258
+ ContentStoreService &&
259
+ typeof (ContentStoreService as unknown as { dispose?: Function }).dispose === 'function'
260
+ ) {
261
+ (ContentStoreService as unknown as { dispose: () => void }).dispose();
262
+ }
263
+ if (
264
+ ContentResolverRegistry &&
265
+ typeof (ContentResolverRegistry as unknown as { unregister?: Function }).unregister === 'function'
266
+ ) {
267
+ (ContentResolverRegistry as unknown as { unregister: () => void }).unregister();
268
+ }
241
269
  this.isRegistered = false;
242
270
  this.logger.info('ContentStoreManager disposed and unregistered');
243
271
  }
@@ -1,3 +1,5 @@
1
1
  export * from './entity-resolver';
2
2
  export * from './content-store-manager';
3
3
  export * from './formatters';
4
+ export * from './parameter-service';
5
+ export * from './attachment-processor';
@@ -0,0 +1,430 @@
1
+ import { Logger, type NetworkType } from '@hashgraphonline/standards-sdk';
2
+ import { EntityFormat, FormatConverterRegistry } from './formatters';
3
+ import type { EntityAssociation } from '../memory/smart-memory-manager';
4
+
5
+ /**
6
+ * Service for processing tool parameters and applying entity format conversions
7
+ */
8
+ export class ParameterService {
9
+ private logger: Logger;
10
+ private formatConverterRegistry: FormatConverterRegistry;
11
+ private networkType: NetworkType;
12
+
13
+ constructor(
14
+ formatConverterRegistry: FormatConverterRegistry,
15
+ networkType: NetworkType
16
+ ) {
17
+ this.logger = new Logger({ module: 'ParameterService' });
18
+ this.formatConverterRegistry = formatConverterRegistry;
19
+ this.networkType = networkType;
20
+ }
21
+
22
+ /**
23
+ * Unified preprocessing entrypoint (DRY):
24
+ * - Optional AI-driven resolution via provided entityResolver
25
+ * - Deterministic post-pass for safe format enforcement
26
+ */
27
+ async preprocessParameters(
28
+ toolName: string,
29
+ parameters: Record<string, unknown>,
30
+ entities: EntityAssociation[] = [],
31
+ options?: {
32
+ entityResolver?: {
33
+ resolveReferences: (
34
+ message: string,
35
+ entities: EntityAssociation[]
36
+ ) => Promise<string>;
37
+ };
38
+ sessionId?: string;
39
+ preferences?: Record<string, string>;
40
+ }
41
+ ): Promise<Record<string, unknown>> {
42
+ const sessionId = options?.sessionId;
43
+ const entityResolver = options?.entityResolver;
44
+ const preferences = options?.preferences;
45
+
46
+ let working: Record<string, unknown> = { ...parameters };
47
+
48
+ if (entityResolver && entities.length > 0) {
49
+ try {
50
+ this.logger.info('AI-driven preprocessing phase', {
51
+ toolName,
52
+ entityCount: entities.length,
53
+ sessionId,
54
+ });
55
+
56
+ const aiProcessed: Record<string, unknown> = { ...working };
57
+ for (const [paramName, paramValue] of Object.entries(working)) {
58
+ if (typeof paramValue === 'string') {
59
+ const resolved = await entityResolver.resolveReferences(
60
+ paramValue,
61
+ entities
62
+ );
63
+ const converted = await this.convertParameterEntities(
64
+ resolved,
65
+ entities,
66
+ preferences
67
+ );
68
+ aiProcessed[paramName] = converted;
69
+ } else if (Array.isArray(paramValue)) {
70
+ const out: unknown[] = [];
71
+ for (const item of paramValue) {
72
+ if (typeof item === 'string') {
73
+ const resolved = await entityResolver.resolveReferences(
74
+ item,
75
+ entities
76
+ );
77
+ const converted = await this.convertParameterEntities(
78
+ resolved,
79
+ entities,
80
+ preferences
81
+ );
82
+ out.push(converted);
83
+ } else {
84
+ out.push(item);
85
+ }
86
+ }
87
+ aiProcessed[paramName] = out;
88
+ }
89
+ }
90
+ working = aiProcessed;
91
+ } catch (error) {
92
+ const message = error instanceof Error ? error.message : 'unknown';
93
+ this.logger.warn(
94
+ 'AI phase failed; continuing with deterministic pass',
95
+ {
96
+ toolName,
97
+ error: message,
98
+ }
99
+ );
100
+ }
101
+ }
102
+
103
+ try {
104
+ const processed: Record<string, unknown> = { ...working };
105
+ for (const [paramName, paramValue] of Object.entries(working)) {
106
+ if (typeof paramValue === 'string') {
107
+ const converted = await this.convertParameterEntities(
108
+ paramValue,
109
+ entities,
110
+ preferences
111
+ );
112
+ processed[paramName] = converted;
113
+ } else if (Array.isArray(paramValue)) {
114
+ const out: unknown[] = [];
115
+ for (const item of paramValue) {
116
+ if (typeof item === 'string') {
117
+ const converted = await this.convertParameterEntities(
118
+ item,
119
+ entities,
120
+ preferences
121
+ );
122
+ out.push(converted);
123
+ } else {
124
+ out.push(item);
125
+ }
126
+ }
127
+ processed[paramName] = out;
128
+ }
129
+ }
130
+ working = processed;
131
+ } catch (e) {
132
+ this.logger.warn('Deterministic post-pass failed', {
133
+ toolName,
134
+ error: e instanceof Error ? e.message : 'unknown',
135
+ });
136
+ }
137
+
138
+ return working;
139
+ }
140
+
141
+ /**
142
+ * Attach unified preprocessing callback directly to the agent.
143
+ */
144
+ attachToAgent(
145
+ agent: unknown,
146
+ deps?: {
147
+ getSessionId?: () => string | null;
148
+ getEntities?: (sessionId: string | null) => Promise<EntityAssociation[]>;
149
+ entityResolver?: {
150
+ resolveReferences: (
151
+ message: string,
152
+ entities: EntityAssociation[]
153
+ ) => Promise<string>;
154
+ };
155
+ }
156
+ ): void {
157
+ const getSessionId = deps?.getSessionId ?? (() => null);
158
+ const getEntities =
159
+ deps?.getEntities ?? (async () => [] as EntityAssociation[]);
160
+ const entityResolver = deps?.entityResolver;
161
+
162
+ const maybe = agent as {
163
+ setParameterPreprocessingCallback?: (
164
+ callback: (
165
+ toolName: string,
166
+ parameters: Record<string, unknown>,
167
+ toolContext?: {
168
+ entityResolutionPreferences?: Record<string, string>;
169
+ }
170
+ ) => Promise<Record<string, unknown>>
171
+ ) => void;
172
+ getAgent?: () => unknown;
173
+ };
174
+
175
+ const attach = (target: unknown): boolean => {
176
+ const t = target as {
177
+ setParameterPreprocessingCallback?: (
178
+ callback: (
179
+ toolName: string,
180
+ parameters: Record<string, unknown>,
181
+ toolContext?: {
182
+ entityResolutionPreferences?: Record<string, string>;
183
+ }
184
+ ) => Promise<Record<string, unknown>>
185
+ ) => void;
186
+ };
187
+ if (typeof t.setParameterPreprocessingCallback === 'function') {
188
+ t.setParameterPreprocessingCallback(
189
+ async (
190
+ toolName: string,
191
+ parameters: Record<string, unknown>
192
+ ): Promise<Record<string, unknown>> => {
193
+ const sessionId = getSessionId();
194
+ const entities = await getEntities(sessionId);
195
+ const opts: {
196
+ entityResolver?: {
197
+ resolveReferences: (
198
+ message: string,
199
+ entities: EntityAssociation[]
200
+ ) => Promise<string>;
201
+ };
202
+ sessionId?: string;
203
+ preferences?: Record<string, string>;
204
+ } = {};
205
+ if (entityResolver) {
206
+ opts.entityResolver = entityResolver;
207
+ }
208
+ if (sessionId) {
209
+ opts.sessionId = sessionId;
210
+ }
211
+ return this.preprocessParameters(toolName, parameters, entities, opts);
212
+ }
213
+ );
214
+ this.logger.info('Parameter preprocessing callback attached');
215
+ return true;
216
+ }
217
+ return false;
218
+ };
219
+
220
+ if (!attach(agent) && typeof maybe.getAgent === 'function') {
221
+ const underlying = maybe.getAgent();
222
+ if (underlying) {
223
+ void attach(underlying);
224
+ }
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Preprocess tool parameters by applying format conversions based on tool's entity resolution preferences
230
+ */
231
+ async preprocessToolParameters(
232
+ toolName: string,
233
+ parameters: Record<string, unknown>,
234
+ entities?: EntityAssociation[],
235
+ sessionId?: string
236
+ ): Promise<Record<string, unknown>> {
237
+ try {
238
+ if (!entities || entities.length === 0) {
239
+ this.logger.info(
240
+ 'Tool parameter preprocessing skipped - no entities provided:',
241
+ {
242
+ toolName,
243
+ originalParams: Object.keys(parameters),
244
+ }
245
+ );
246
+ return parameters;
247
+ }
248
+
249
+ const processedParameters = { ...parameters };
250
+ const preferences: Record<string, string> | undefined = undefined;
251
+ let hasChanges = false;
252
+
253
+ for (const [paramName, paramValue] of Object.entries(parameters)) {
254
+ if (typeof paramValue === 'string') {
255
+ const convertedValue = await this.convertParameterEntities(
256
+ paramValue,
257
+ entities,
258
+ preferences
259
+ );
260
+
261
+ if (convertedValue !== paramValue) {
262
+ processedParameters[paramName] = convertedValue;
263
+ hasChanges = true;
264
+
265
+ this.logger.info('Parameter entity conversion applied:', {
266
+ toolName,
267
+ paramName,
268
+ original: paramValue,
269
+ converted: convertedValue,
270
+ });
271
+ }
272
+ } else if (Array.isArray(paramValue)) {
273
+ const originalArray = paramValue as unknown[];
274
+ const convertedArray: unknown[] = [];
275
+ let arrayChanged = false;
276
+
277
+ for (const item of originalArray) {
278
+ if (typeof item === 'string') {
279
+ const convertedItem = await this.convertParameterEntities(
280
+ item,
281
+ entities,
282
+ preferences
283
+ );
284
+
285
+ convertedArray.push(convertedItem);
286
+
287
+ if (convertedItem !== item) {
288
+ arrayChanged = true;
289
+ this.logger.info('Parameter array item conversion applied:', {
290
+ toolName,
291
+ paramName,
292
+ original: item,
293
+ converted: convertedItem,
294
+ });
295
+ }
296
+ } else {
297
+ convertedArray.push(item);
298
+ }
299
+ }
300
+
301
+ if (arrayChanged) {
302
+ processedParameters[paramName] = convertedArray;
303
+ hasChanges = true;
304
+ }
305
+ }
306
+ }
307
+
308
+ this.logger.info('Tool parameter preprocessing completed:', {
309
+ toolName,
310
+ originalParams: Object.keys(parameters),
311
+ hasChanges,
312
+ sessionId,
313
+ });
314
+
315
+ return processedParameters;
316
+ } catch (error) {
317
+ this.logger.warn('Tool parameter preprocessing failed:', {
318
+ toolName,
319
+ error: error instanceof Error ? error.message : 'Unknown error',
320
+ });
321
+ return parameters;
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Convert entity references in a parameter value based on tool preferences
327
+ */
328
+ async convertParameterEntities(
329
+ parameterValue: string,
330
+ entities: EntityAssociation[],
331
+ preferences?: Record<string, string>
332
+ ): Promise<string> {
333
+ let convertedValue = parameterValue;
334
+
335
+ for (const entity of entities) {
336
+ const containsEntityId = convertedValue.includes(entity.entityId);
337
+ const containsEntityName = convertedValue.includes(entity.entityName);
338
+
339
+ if (!containsEntityId && !containsEntityName) {
340
+ continue;
341
+ }
342
+
343
+ let targetFormat: EntityFormat | null = null;
344
+
345
+ if (entity.entityType === EntityFormat.TOPIC_ID) {
346
+ if (
347
+ preferences?.inscription === 'hrl' ||
348
+ preferences?.topic === 'hrl'
349
+ ) {
350
+ targetFormat = EntityFormat.HRL;
351
+ } else if (
352
+ preferences?.inscription === 'topicId' ||
353
+ preferences?.topic === 'topicId'
354
+ ) {
355
+ targetFormat = EntityFormat.TOPIC_ID;
356
+ }
357
+ } else if (entity.entityType === EntityFormat.TOKEN_ID) {
358
+ if (preferences?.token === 'tokenId') {
359
+ targetFormat = EntityFormat.TOKEN_ID;
360
+ } else if (preferences?.token === 'symbol') {
361
+ targetFormat = EntityFormat.SYMBOL;
362
+ }
363
+ } else if (entity.entityType === EntityFormat.ACCOUNT_ID) {
364
+ if (
365
+ preferences?.account === 'accountId' ||
366
+ preferences?.supplyKey === 'accountId' ||
367
+ preferences?.adminKey === 'accountId'
368
+ ) {
369
+ targetFormat = EntityFormat.ACCOUNT_ID;
370
+ } else if (preferences?.account === 'alias') {
371
+ targetFormat = EntityFormat.ALIAS;
372
+ }
373
+ }
374
+
375
+ if (targetFormat) {
376
+ try {
377
+ const context: {
378
+ networkType?: string | NetworkType;
379
+ sessionId?: string;
380
+ toolPreferences?: Record<string, string>;
381
+ } = {
382
+ networkType: this.networkType,
383
+ sessionId: 'unknown',
384
+ };
385
+ if (preferences) {
386
+ context.toolPreferences = preferences;
387
+ }
388
+ const convertedEntityValue = await this.formatConverterRegistry.convertEntity(
389
+ entity.entityId,
390
+ targetFormat,
391
+ context as never
392
+ );
393
+
394
+ if (containsEntityId) {
395
+ convertedValue = convertedValue.replace(
396
+ new RegExp(`\\b${entity.entityId.replace(/\./g, '\\.')}\\b`, 'g'),
397
+ convertedEntityValue
398
+ );
399
+ }
400
+
401
+ if (containsEntityName) {
402
+ convertedValue = convertedValue.replace(
403
+ new RegExp(
404
+ `\\b${entity.entityName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`,
405
+ 'g'
406
+ ),
407
+ convertedEntityValue
408
+ );
409
+ }
410
+
411
+ this.logger.info('Applied format conversion to parameter:', {
412
+ entityId: entity.entityId,
413
+ entityType: entity.entityType,
414
+ targetFormat,
415
+ convertedValue: convertedEntityValue,
416
+ parameterValue: convertedValue,
417
+ });
418
+ } catch (error) {
419
+ this.logger.warn('Format conversion failed for parameter:', {
420
+ entityId: entity.entityId,
421
+ targetFormat,
422
+ error: error instanceof Error ? error.message : 'Unknown error',
423
+ });
424
+ }
425
+ }
426
+ }
427
+
428
+ return convertedValue;
429
+ }
430
+ }