@elizaos/core 1.5.0 → 1.5.2

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 (90) hide show
  1. package/dist/browser/index.browser.js +102 -102
  2. package/dist/browser/index.browser.js.map +5 -5
  3. package/dist/browser/index.d.ts +3 -1
  4. package/dist/index.d.ts +2 -3
  5. package/dist/index.js +1 -5
  6. package/dist/node/index.d.ts +3 -1
  7. package/dist/node/index.node.js +91 -12
  8. package/dist/node/index.node.js.map +10 -10
  9. package/package.json +10 -4
  10. package/src/__tests__/action-chaining-simple.test.ts +203 -0
  11. package/src/__tests__/actions.test.ts +218 -0
  12. package/src/__tests__/buffer.test.ts +337 -0
  13. package/src/__tests__/character-validation.test.ts +309 -0
  14. package/src/__tests__/database.test.ts +750 -0
  15. package/src/__tests__/entities.test.ts +727 -0
  16. package/src/__tests__/env.test.ts +23 -0
  17. package/src/__tests__/environment.test.ts +285 -0
  18. package/src/__tests__/logger-browser-node.test.ts +716 -0
  19. package/src/__tests__/logger.test.ts +403 -0
  20. package/src/__tests__/messages.test.ts +196 -0
  21. package/src/__tests__/mockCharacter.ts +544 -0
  22. package/src/__tests__/parsing.test.ts +58 -0
  23. package/src/__tests__/prompts.test.ts +159 -0
  24. package/src/__tests__/roles.test.ts +331 -0
  25. package/src/__tests__/runtime-embedding.test.ts +343 -0
  26. package/src/__tests__/runtime.test.ts +978 -0
  27. package/src/__tests__/search.test.ts +15 -0
  28. package/src/__tests__/services-by-type.test.ts +204 -0
  29. package/src/__tests__/services.test.ts +136 -0
  30. package/src/__tests__/settings.test.ts +810 -0
  31. package/src/__tests__/utils.test.ts +1105 -0
  32. package/src/__tests__/uuid.test.ts +94 -0
  33. package/src/actions.ts +122 -0
  34. package/src/database.ts +579 -0
  35. package/src/entities.ts +406 -0
  36. package/src/index.browser.ts +48 -0
  37. package/src/index.node.ts +39 -0
  38. package/src/index.ts +50 -0
  39. package/src/logger.ts +527 -0
  40. package/src/prompts.ts +243 -0
  41. package/src/roles.ts +85 -0
  42. package/src/runtime.ts +2514 -0
  43. package/src/schemas/character.ts +149 -0
  44. package/src/search.ts +1543 -0
  45. package/src/sentry/instrument.browser.ts +65 -0
  46. package/src/sentry/instrument.node.ts +57 -0
  47. package/src/sentry/instrument.ts +82 -0
  48. package/src/services.ts +105 -0
  49. package/src/settings.ts +409 -0
  50. package/src/test_resources/constants.ts +12 -0
  51. package/src/test_resources/testSetup.ts +21 -0
  52. package/src/test_resources/types.ts +22 -0
  53. package/src/types/agent.ts +112 -0
  54. package/src/types/browser.ts +145 -0
  55. package/src/types/components.ts +184 -0
  56. package/src/types/database.ts +348 -0
  57. package/src/types/email.ts +162 -0
  58. package/src/types/environment.ts +129 -0
  59. package/src/types/events.ts +249 -0
  60. package/src/types/index.ts +29 -0
  61. package/src/types/knowledge.ts +65 -0
  62. package/src/types/lp.ts +124 -0
  63. package/src/types/memory.ts +228 -0
  64. package/src/types/message.ts +233 -0
  65. package/src/types/messaging.ts +57 -0
  66. package/src/types/model.ts +359 -0
  67. package/src/types/pdf.ts +77 -0
  68. package/src/types/plugin.ts +78 -0
  69. package/src/types/post.ts +271 -0
  70. package/src/types/primitives.ts +97 -0
  71. package/src/types/runtime.ts +190 -0
  72. package/src/types/service.ts +198 -0
  73. package/src/types/settings.ts +30 -0
  74. package/src/types/state.ts +60 -0
  75. package/src/types/task.ts +72 -0
  76. package/src/types/tee.ts +107 -0
  77. package/src/types/testing.ts +30 -0
  78. package/src/types/token.ts +96 -0
  79. package/src/types/transcription.ts +133 -0
  80. package/src/types/video.ts +108 -0
  81. package/src/types/wallet.ts +56 -0
  82. package/src/types/web-search.ts +146 -0
  83. package/src/utils/__tests__/buffer.test.ts +80 -0
  84. package/src/utils/__tests__/environment.test.ts +58 -0
  85. package/src/utils/__tests__/stringToUuid.test.ts +88 -0
  86. package/src/utils/buffer.ts +312 -0
  87. package/src/utils/environment.ts +316 -0
  88. package/src/utils/server-health.ts +117 -0
  89. package/src/utils.ts +1076 -0
  90. package/dist/tsconfig.build.tsbuildinfo +0 -1
@@ -0,0 +1,403 @@
1
+ import { describe, expect, it, beforeEach, afterEach } from 'bun:test';
2
+ import { mock } from 'bun:test';
3
+ import { createLogger, logger, elizaLogger } from '../logger';
4
+
5
+ // Mock environment variables
6
+ const mockEnv = {
7
+ LOG_LEVEL: '',
8
+ DEFAULT_LOG_LEVEL: '',
9
+ LOG_JSON_FORMAT: '',
10
+ SENTRY_LOGGING: 'false',
11
+ LOG_DIAGNOSTIC: '',
12
+ };
13
+
14
+ // No external logger transport to mock; Adze is used internally
15
+
16
+ describe('Logger', () => {
17
+ let originalEnv: NodeJS.ProcessEnv;
18
+
19
+ beforeEach(() => {
20
+ // Save original environment
21
+ originalEnv = { ...process.env };
22
+ // Reset environment variables
23
+ Object.keys(mockEnv).forEach((key) => {
24
+ process.env[key] = mockEnv[key];
25
+ });
26
+ mock.restore();
27
+ });
28
+
29
+ afterEach(() => {
30
+ // Restore original environment
31
+ process.env = originalEnv;
32
+ });
33
+
34
+ describe('Logger Creation', () => {
35
+ it('should export logger instance', () => {
36
+ expect(logger).toBeDefined();
37
+ expect(typeof logger.info).toBe('function');
38
+ expect(typeof logger.error).toBe('function');
39
+ // Note: warn and debug methods exist on the pino logger instance
40
+ // but may not be enumerable. Test their functionality instead.
41
+ expect(logger.warn).toBeDefined();
42
+ expect(logger.debug).toBeDefined();
43
+ expect(typeof logger.warn).toBe('function');
44
+ expect(typeof logger.debug).toBe('function');
45
+ });
46
+
47
+ it('should export elizaLogger as alias for backward compatibility', () => {
48
+ expect(elizaLogger).toBeDefined();
49
+ expect(elizaLogger).toBe(logger);
50
+ });
51
+
52
+ it('should have custom log levels', () => {
53
+ const testLogger = createLogger({ agentName: 'test' });
54
+ expect(typeof testLogger.fatal).toBe('function');
55
+ expect(typeof testLogger.error).toBe('function');
56
+ expect(typeof testLogger.warn).toBe('function');
57
+ expect(typeof testLogger.info).toBe('function');
58
+ expect(typeof testLogger.debug).toBe('function');
59
+ expect(typeof testLogger.trace).toBe('function');
60
+ });
61
+ });
62
+
63
+ describe('createLogger Function', () => {
64
+ it('should create logger with bindings', () => {
65
+ const bindings = { agentName: 'TestAgent', agentId: '123' };
66
+ const customLogger = createLogger(bindings);
67
+
68
+ expect(customLogger).toBeDefined();
69
+ expect(typeof customLogger.info).toBe('function');
70
+ });
71
+
72
+ it('should create logger without bindings', () => {
73
+ const customLogger = createLogger();
74
+
75
+ expect(customLogger).toBeDefined();
76
+ expect(typeof customLogger.info).toBe('function');
77
+ });
78
+
79
+ it('should handle boolean bindings parameter', () => {
80
+ const customLogger = createLogger(false);
81
+
82
+ expect(customLogger).toBeDefined();
83
+ expect(typeof customLogger.info).toBe('function');
84
+ });
85
+ });
86
+
87
+ describe('Log Level Configuration', () => {
88
+ it('should use debug level when LOG_LEVEL is debug', () => {
89
+ process.env.LOG_LEVEL = 'debug';
90
+ const customLogger = createLogger();
91
+
92
+ // Logger should be created with debug level
93
+ expect(customLogger.level).toBeDefined();
94
+ });
95
+
96
+ it('should use DEFAULT_LOG_LEVEL when LOG_LEVEL is not debug', () => {
97
+ process.env.LOG_LEVEL = '';
98
+ process.env.DEFAULT_LOG_LEVEL = 'warn';
99
+ const customLogger = createLogger();
100
+
101
+ expect(customLogger.level).toBeDefined();
102
+ });
103
+
104
+ it('should default to info level when no log level is specified', () => {
105
+ process.env.LOG_LEVEL = '';
106
+ process.env.DEFAULT_LOG_LEVEL = '';
107
+ const customLogger = createLogger();
108
+
109
+ expect(customLogger.level).toBeDefined();
110
+ });
111
+ });
112
+
113
+ describe('JSON Format Configuration', () => {
114
+ it('should use JSON format when LOG_JSON_FORMAT is true', () => {
115
+ process.env.LOG_JSON_FORMAT = 'true';
116
+ const customLogger = createLogger();
117
+
118
+ expect(customLogger).toBeDefined();
119
+ });
120
+
121
+ it('should use pretty format when LOG_JSON_FORMAT is false', () => {
122
+ process.env.LOG_JSON_FORMAT = 'false';
123
+ const customLogger = createLogger();
124
+
125
+ expect(customLogger).toBeDefined();
126
+ });
127
+ });
128
+
129
+ describe('Log Filtering', () => {
130
+ it('should filter service registration logs in non-debug mode', () => {
131
+ process.env.LOG_LEVEL = 'info';
132
+ const customLogger = createLogger();
133
+
134
+ // These logs should be filtered in non-debug mode
135
+ const filteredMessages = [
136
+ 'registered successfully',
137
+ 'Registering',
138
+ 'Success:',
139
+ 'linked to',
140
+ 'Started',
141
+ ];
142
+
143
+ // Logger is created and can handle these messages
144
+ filteredMessages.forEach((msg) => {
145
+ expect(() => customLogger.info({ agentName: 'test', agentId: '123' }, msg)).not.toThrow();
146
+ });
147
+ });
148
+
149
+ it('should not filter service registration logs in debug mode', () => {
150
+ process.env.LOG_LEVEL = 'debug';
151
+ const customLogger = createLogger();
152
+
153
+ // In debug mode, all logs should pass through
154
+ expect(customLogger.level).toBeDefined();
155
+ });
156
+ });
157
+
158
+ describe('Error Handling', () => {
159
+ it('should handle Error objects in log messages', () => {
160
+ const customLogger = createLogger();
161
+ const testError = new Error('Test error');
162
+
163
+ expect(() => customLogger.error(testError)).not.toThrow();
164
+ expect(() => customLogger.error('Message', testError)).not.toThrow();
165
+ expect(() =>
166
+ customLogger.error({ context: 'test' }, 'Error occurred', testError)
167
+ ).not.toThrow();
168
+ });
169
+
170
+ it('should format error messages properly', () => {
171
+ const customLogger = createLogger();
172
+ const testError = new Error('Test error');
173
+ testError.name = 'TestError';
174
+
175
+ // Should handle error formatting without throwing
176
+ expect(() => customLogger.error(testError)).not.toThrow();
177
+ });
178
+ });
179
+
180
+ describe('Clear Method', () => {
181
+ it('should have clear method when not using raw JSON format', () => {
182
+ process.env.LOG_JSON_FORMAT = 'false';
183
+ // Since the logger is created asynchronously with pretty printing,
184
+ // we just verify the logger is created successfully
185
+ expect(logger).toBeDefined();
186
+ });
187
+ });
188
+
189
+ describe('Hook Methods', () => {
190
+ it('should handle various log input formats', () => {
191
+ const customLogger = createLogger();
192
+
193
+ // Test various input formats
194
+ expect(() => customLogger.info('Simple string')).not.toThrow();
195
+ expect(() => customLogger.info({ key: 'value' }, 'With object')).not.toThrow();
196
+ expect(() => customLogger.info('Multiple', 'string', 'parts')).not.toThrow();
197
+ expect(() => customLogger.error(new Error('Test'), 'With error')).not.toThrow();
198
+ });
199
+
200
+ it('should handle mixed arguments with errors', () => {
201
+ const customLogger = createLogger();
202
+ const error = new Error('Test error');
203
+
204
+ expect(() => customLogger.error('Message', error, { extra: 'data' })).not.toThrow();
205
+ });
206
+ });
207
+
208
+ describe('Diagnostic Mode', () => {
209
+ it('should add diagnostic flag when LOG_DIAGNOSTIC is enabled', () => {
210
+ process.env.LOG_DIAGNOSTIC = 'true';
211
+ const customLogger = createLogger();
212
+
213
+ // Logger should handle diagnostic mode
214
+ expect(customLogger).toBeDefined();
215
+ });
216
+ });
217
+
218
+ describe('Custom Prettifiers', () => {
219
+ it('should format log levels correctly', () => {
220
+ const customLogger = createLogger();
221
+
222
+ // Test that various log levels work
223
+ expect(() => customLogger.trace('Trace message')).not.toThrow();
224
+ expect(() => customLogger.debug('Debug message')).not.toThrow();
225
+ expect(() => customLogger.info('Info message')).not.toThrow();
226
+ expect(() => customLogger.warn('Warn message')).not.toThrow();
227
+ expect(() => customLogger.error('Error message')).not.toThrow();
228
+ expect(() => customLogger.fatal('Fatal message')).not.toThrow();
229
+ });
230
+ });
231
+
232
+ describe('Comprehensive Hook Method Coverage', () => {
233
+ it('should handle error as first argument with formatting', () => {
234
+ const customLogger = createLogger();
235
+ const error = new Error('Test error message');
236
+ error.name = 'CustomError';
237
+ error.stack = 'Error: Test error message\n at Object.<anonymous> (test.js:1:1)';
238
+
239
+ // This triggers the formatError path in hooks.logMethod
240
+ expect(() => customLogger.error(error)).not.toThrow();
241
+ });
242
+
243
+ it('should handle object with multiple string arguments', () => {
244
+ const customLogger = createLogger();
245
+
246
+ // This triggers the object + rest args path
247
+ expect(() => customLogger.info({ userId: '123' }, 'User', 'logged', 'in')).not.toThrow();
248
+ });
249
+
250
+ it('should handle string with error in rest arguments', () => {
251
+ const customLogger = createLogger();
252
+ const error1 = new Error('First error');
253
+ const error2 = new Error('Second error');
254
+
255
+ // This triggers error handling in rest args
256
+ expect(() => customLogger.error('Multiple errors:', error1, error2)).not.toThrow();
257
+ });
258
+
259
+ it('should handle mixed object and string arguments', () => {
260
+ const customLogger = createLogger();
261
+
262
+ // This triggers the context building path
263
+ expect(() => customLogger.info('Status:', { active: true }, 'for user')).not.toThrow();
264
+ });
265
+
266
+ it('should handle non-string, non-error objects in arguments', () => {
267
+ const customLogger = createLogger();
268
+
269
+ // This triggers JSON.stringify for non-string args
270
+ expect(() =>
271
+ customLogger.info('Data:', { complex: { nested: true } }, ['array', 'data'])
272
+ ).not.toThrow();
273
+ });
274
+
275
+ it('should handle Sentry exception capture for errors', () => {
276
+ const originalSentryLogging = process.env.SENTRY_LOGGING;
277
+ process.env.SENTRY_LOGGING = ''; // Not 'false', so Sentry logging is enabled
278
+
279
+ const customLogger = createLogger();
280
+ const error = new Error('Sentry test');
281
+
282
+ // This should trigger Sentry.captureException
283
+ expect(() => customLogger.error(error)).not.toThrow();
284
+ expect(() => customLogger.error('Message with error:', error)).not.toThrow();
285
+
286
+ process.env.SENTRY_LOGGING = originalSentryLogging;
287
+ });
288
+
289
+ it('should handle all argument being non-string objects', () => {
290
+ const customLogger = createLogger();
291
+
292
+ // Logger expects string message after object, so we need to provide valid signatures
293
+ expect(() => customLogger.info({ a: 1, b: 2, c: 3 }, 'Combined object log')).not.toThrow();
294
+ expect(() => customLogger.info('Objects:', { a: 1 }, { b: 2 })).not.toThrow();
295
+ });
296
+
297
+ it('should handle logger clear method when destination exists', () => {
298
+ // Access the clear method if it exists
299
+ if (typeof (logger as any).clear === 'function') {
300
+ expect(() => (logger as any).clear()).not.toThrow();
301
+ }
302
+
303
+ // Also test on a newly created logger
304
+ const customLogger = createLogger();
305
+ if (typeof (customLogger as any).clear === 'function') {
306
+ expect(() => (customLogger as any).clear()).not.toThrow();
307
+ }
308
+ });
309
+ });
310
+
311
+ describe('InMemoryDestination Coverage', () => {
312
+ it('should handle non-JSON string data in write method', () => {
313
+ const customLogger = createLogger();
314
+
315
+ // This could trigger the non-JSON path in InMemoryDestination.write
316
+ // when the transport receives malformed data
317
+ expect(() => customLogger.info('Simple text that might not be JSON')).not.toThrow();
318
+ });
319
+
320
+ it('should handle diagnostic mode with filtered logs', () => {
321
+ process.env.LOG_DIAGNOSTIC = 'true';
322
+ process.env.LOG_LEVEL = 'info'; // Not debug
323
+
324
+ const customLogger = createLogger({ agentName: 'test', agentId: '123' });
325
+
326
+ // These should be filtered but diagnostic mode might log them
327
+ expect(() => customLogger.info('registered successfully')).not.toThrow();
328
+ expect(() => customLogger.info('Registering service')).not.toThrow();
329
+
330
+ process.env.LOG_DIAGNOSTIC = '';
331
+ });
332
+ });
333
+
334
+ describe('Async Stream Creation', () => {
335
+ it('should handle async stream creation when require fails', async () => {
336
+ // This test simulates the async fallback path
337
+ // We can't easily mock require failure in test environments, so we test the async path exists
338
+ const originalEnv = process.env.LOG_JSON_FORMAT;
339
+ process.env.LOG_JSON_FORMAT = 'false';
340
+
341
+ // Force a new logger creation which might use async path
342
+ // Note: bun:test doesn't have resetModules equivalent
343
+ const { createLogger: asyncLogger } = await import('../logger');
344
+
345
+ const logger = asyncLogger();
346
+ expect(logger).toBeDefined();
347
+
348
+ // Wait a bit for async initialization
349
+ await new Promise((resolve) => setTimeout(resolve, 100));
350
+
351
+ expect(() => logger.info('Async logger test')).not.toThrow();
352
+
353
+ process.env.LOG_JSON_FORMAT = originalEnv;
354
+ });
355
+
356
+ it('should handle pino-pretty module not having default export', async () => {
357
+ // Mock pino-pretty without default export
358
+ // Note: bun:test has different module mocking behavior
359
+ const { createLogger: testLogger } = await import('../logger');
360
+
361
+ const logger = testLogger();
362
+ expect(logger).toBeDefined();
363
+ });
364
+ });
365
+
366
+ describe('Additional Custom Level Tests', () => {
367
+ it('should use custom log levels', () => {
368
+ const customLogger = createLogger();
369
+
370
+ // Test custom levels exist and work
371
+ expect(typeof (customLogger as any).log).toBe('function');
372
+ expect(typeof (customLogger as any).progress).toBe('function');
373
+ expect(typeof (customLogger as any).success).toBe('function');
374
+
375
+ expect(() => (customLogger as any).log('Custom log message')).not.toThrow();
376
+ expect(() => (customLogger as any).progress('Progress update')).not.toThrow();
377
+ expect(() => (customLogger as any).success('Operation successful')).not.toThrow();
378
+ });
379
+ });
380
+
381
+ describe('Custom Prettifier Edge Cases', () => {
382
+ it('should handle undefined level in prettifier', () => {
383
+ const customLogger = createLogger();
384
+
385
+ // This might trigger the undefined level path in prettifier
386
+ expect(() => customLogger.info('Test with potential undefined level')).not.toThrow();
387
+ });
388
+
389
+ it('should handle null level in prettifier', () => {
390
+ const customLogger = createLogger();
391
+
392
+ // Force a log that might have null level
393
+ expect(() => (customLogger as any).child({ level: null }).info('Test')).not.toThrow();
394
+ });
395
+
396
+ it('should handle object level data in prettifier', () => {
397
+ const customLogger = createLogger();
398
+
399
+ // Test object input to level prettifier
400
+ expect(() => customLogger.child({ level: 30 }).info('Test with numeric level')).not.toThrow();
401
+ });
402
+ });
403
+ });
@@ -0,0 +1,196 @@
1
+ import { beforeAll, describe, expect, test, it } from 'bun:test';
2
+ import { formatEntities } from '../entities';
3
+ import { formatMessages, formatTimestamp } from '../utils';
4
+ import type { Content, Entity, Memory, UUID } from '../types';
5
+
6
+ describe('Messages Library', () => {
7
+ let entities: Entity[];
8
+ let entityId: UUID;
9
+
10
+ beforeAll(() => {
11
+ // Mock user data with proper UUID format
12
+ entityId = '123e4567-e89b-12d3-a456-426614174000' as UUID;
13
+ entities = [
14
+ {
15
+ id: entityId,
16
+ names: ['Test User'],
17
+ agentId: '123e4567-e89b-12d3-a456-426614174001' as UUID,
18
+ },
19
+ ];
20
+ });
21
+
22
+ test('formatEntities should format entities into a readable string', () => {
23
+ const formattedEntities = formatEntities({ entities });
24
+
25
+ expect(formattedEntities).toContain('Test User');
26
+ });
27
+
28
+ test('formatMessages should format messages into a readable string', () => {
29
+ const messages: Memory[] = [
30
+ {
31
+ content: { text: 'Hello, world!' } as Content,
32
+ entityId: entityId,
33
+ roomId: '123e4567-e89b-12d3-a456-426614174002' as UUID,
34
+ createdAt: new Date().getTime(),
35
+ agentId: '' as UUID, // assuming agentId is an empty string here
36
+ },
37
+ ];
38
+
39
+ const formattedMessages = formatMessages({ messages, entities });
40
+
41
+ // Assertions
42
+ expect(formattedMessages).toContain('Hello, world!');
43
+ expect(formattedMessages).toContain('Test User');
44
+ });
45
+
46
+ test('formatTimestamp should return correct time string', () => {
47
+ const timestamp = new Date().getTime() - 60000; // 1 minute ago
48
+ const result = formatTimestamp(timestamp);
49
+
50
+ // Assertions
51
+ expect(result).toBe('1 minute ago');
52
+ });
53
+
54
+ test('formatMessages should include attachments if present', () => {
55
+ const messages: Memory[] = [
56
+ {
57
+ content: {
58
+ text: 'Check this attachment',
59
+ attachments: [
60
+ {
61
+ id: '123e4567-e89b-12d3-a456-426614174003' as UUID,
62
+ title: 'Image',
63
+ url: 'http://example.com/image.jpg',
64
+ },
65
+ ],
66
+ } as Content,
67
+ entityId: entityId,
68
+ roomId: '123e4567-e89b-12d3-a456-426614174004' as UUID,
69
+ createdAt: new Date().getTime(),
70
+ agentId: '' as UUID, // assuming agentId is an empty string here
71
+ },
72
+ ];
73
+
74
+ const formattedMessages = formatMessages({ messages, entities });
75
+
76
+ // Assertions
77
+ expect(formattedMessages).toContain('Check this attachment');
78
+ expect(formattedMessages).toContain('Attachments: [');
79
+ });
80
+
81
+ test('formatMessages should handle empty attachments gracefully', () => {
82
+ const messages: Memory[] = [
83
+ {
84
+ content: {
85
+ text: 'No attachments here',
86
+ } as Content,
87
+ entityId: entityId,
88
+ roomId: '123e4567-e89b-12d3-a456-426614174005' as UUID,
89
+ createdAt: new Date().getTime(),
90
+ agentId: '' as UUID, // assuming agentId is an empty string here
91
+ },
92
+ ];
93
+
94
+ const formattedMessages = formatMessages({ messages, entities });
95
+
96
+ // Assertions
97
+ expect(formattedMessages).toContain('No attachments here');
98
+ expect(formattedMessages).not.toContain('Attachments');
99
+ });
100
+ });
101
+
102
+ describe('Messages', () => {
103
+ const mockEntities: Entity[] = [
104
+ {
105
+ id: '123e4567-e89b-12d3-a456-426614174006' as UUID,
106
+ names: ['Alice'],
107
+ agentId: '123e4567-e89b-12d3-a456-426614174001' as UUID,
108
+ },
109
+ {
110
+ id: '123e4567-e89b-12d3-a456-426614174007' as UUID,
111
+ names: ['Bob'],
112
+ agentId: '123e4567-e89b-12d3-a456-426614174002' as UUID,
113
+ },
114
+ ];
115
+
116
+ describe('formatEntities', () => {
117
+ it('should format entities with complete details', () => {
118
+ const formatted = formatEntities({ entities: mockEntities });
119
+ expect(formatted).toContain('"Alice"\nID:');
120
+ expect(formatted).toContain('"Bob"\nID:');
121
+ });
122
+
123
+ it('should handle entities without details', () => {
124
+ const actorsWithoutDetails: Entity[] = [
125
+ {
126
+ id: '123e4567-e89b-12d3-a456-426614174013' as UUID,
127
+ names: ['Charlie'],
128
+ agentId: '123e4567-e89b-12d3-a456-426614174003' as UUID,
129
+ },
130
+ ];
131
+ const formatted = formatEntities({ entities: actorsWithoutDetails });
132
+ expect(formatted).toContain('"Charlie"\nID:');
133
+ });
134
+
135
+ it('should handle empty entities array', () => {
136
+ const formatted = formatEntities({ entities: [] });
137
+ expect(formatted).toBe('');
138
+ });
139
+ });
140
+
141
+ describe('formatMessages', () => {
142
+ it('should handle messages from unknown users', () => {
143
+ const messagesWithUnknownUser: Memory[] = [
144
+ {
145
+ id: '123e4567-e89b-12d3-a456-426614174014' as UUID,
146
+ roomId: '123e4567-e89b-12d3-a456-426614174009' as UUID,
147
+ entityId: '123e4567-e89b-12d3-a456-426614174015' as UUID,
148
+ createdAt: Date.now(),
149
+ content: { text: 'Test message' } as Content,
150
+ agentId: '123e4567-e89b-12d3-a456-426614174001',
151
+ },
152
+ ];
153
+
154
+ const formatted = formatMessages({
155
+ messages: messagesWithUnknownUser,
156
+ entities: mockEntities,
157
+ });
158
+ expect(formatted).toContain('Unknown User: Test message');
159
+ });
160
+
161
+ it('should handle messages with no action', () => {
162
+ const messagesWithoutAction: Memory[] = [
163
+ {
164
+ id: '123e4567-e89b-12d3-a456-426614174016' as UUID,
165
+ roomId: '123e4567-e89b-12d3-a456-426614174009' as UUID,
166
+ entityId: mockEntities[0].id as UUID,
167
+ createdAt: Date.now(),
168
+ content: { text: 'Simple message' } as Content,
169
+ agentId: '123e4567-e89b-12d3-a456-426614174001',
170
+ },
171
+ ];
172
+
173
+ const formatted = formatMessages({
174
+ messages: messagesWithoutAction,
175
+ entities: mockEntities,
176
+ });
177
+ expect(formatted).not.toContain('()');
178
+ expect(formatted).toContain('Simple message');
179
+ });
180
+
181
+ it('should handle empty messages array', () => {
182
+ const formatted = formatMessages({
183
+ messages: [],
184
+ entities: mockEntities,
185
+ });
186
+ expect(formatted).toBe('');
187
+ });
188
+ });
189
+
190
+ describe('formatTimestamp', () => {
191
+ it('should handle exact time boundaries', () => {
192
+ const now = Date.now();
193
+ expect(formatTimestamp(now)).toContain('just now');
194
+ });
195
+ });
196
+ });