@elizaos/core 1.5.1 → 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 (88) hide show
  1. package/dist/browser/index.browser.js +120 -120
  2. package/dist/browser/index.browser.js.map +5 -21
  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/package.json +10 -4
  8. package/src/__tests__/action-chaining-simple.test.ts +203 -0
  9. package/src/__tests__/actions.test.ts +218 -0
  10. package/src/__tests__/buffer.test.ts +337 -0
  11. package/src/__tests__/character-validation.test.ts +309 -0
  12. package/src/__tests__/database.test.ts +750 -0
  13. package/src/__tests__/entities.test.ts +727 -0
  14. package/src/__tests__/env.test.ts +23 -0
  15. package/src/__tests__/environment.test.ts +285 -0
  16. package/src/__tests__/logger-browser-node.test.ts +716 -0
  17. package/src/__tests__/logger.test.ts +403 -0
  18. package/src/__tests__/messages.test.ts +196 -0
  19. package/src/__tests__/mockCharacter.ts +544 -0
  20. package/src/__tests__/parsing.test.ts +58 -0
  21. package/src/__tests__/prompts.test.ts +159 -0
  22. package/src/__tests__/roles.test.ts +331 -0
  23. package/src/__tests__/runtime-embedding.test.ts +343 -0
  24. package/src/__tests__/runtime.test.ts +978 -0
  25. package/src/__tests__/search.test.ts +15 -0
  26. package/src/__tests__/services-by-type.test.ts +204 -0
  27. package/src/__tests__/services.test.ts +136 -0
  28. package/src/__tests__/settings.test.ts +810 -0
  29. package/src/__tests__/utils.test.ts +1105 -0
  30. package/src/__tests__/uuid.test.ts +94 -0
  31. package/src/actions.ts +122 -0
  32. package/src/database.ts +579 -0
  33. package/src/entities.ts +406 -0
  34. package/src/index.browser.ts +48 -0
  35. package/src/index.node.ts +39 -0
  36. package/src/index.ts +50 -0
  37. package/src/logger.ts +527 -0
  38. package/src/prompts.ts +243 -0
  39. package/src/roles.ts +85 -0
  40. package/src/runtime.ts +2514 -0
  41. package/src/schemas/character.ts +149 -0
  42. package/src/search.ts +1543 -0
  43. package/src/sentry/instrument.browser.ts +65 -0
  44. package/src/sentry/instrument.node.ts +57 -0
  45. package/src/sentry/instrument.ts +82 -0
  46. package/src/services.ts +105 -0
  47. package/src/settings.ts +409 -0
  48. package/src/test_resources/constants.ts +12 -0
  49. package/src/test_resources/testSetup.ts +21 -0
  50. package/src/test_resources/types.ts +22 -0
  51. package/src/types/agent.ts +112 -0
  52. package/src/types/browser.ts +145 -0
  53. package/src/types/components.ts +184 -0
  54. package/src/types/database.ts +348 -0
  55. package/src/types/email.ts +162 -0
  56. package/src/types/environment.ts +129 -0
  57. package/src/types/events.ts +249 -0
  58. package/src/types/index.ts +29 -0
  59. package/src/types/knowledge.ts +65 -0
  60. package/src/types/lp.ts +124 -0
  61. package/src/types/memory.ts +228 -0
  62. package/src/types/message.ts +233 -0
  63. package/src/types/messaging.ts +57 -0
  64. package/src/types/model.ts +359 -0
  65. package/src/types/pdf.ts +77 -0
  66. package/src/types/plugin.ts +78 -0
  67. package/src/types/post.ts +271 -0
  68. package/src/types/primitives.ts +97 -0
  69. package/src/types/runtime.ts +190 -0
  70. package/src/types/service.ts +198 -0
  71. package/src/types/settings.ts +30 -0
  72. package/src/types/state.ts +60 -0
  73. package/src/types/task.ts +72 -0
  74. package/src/types/tee.ts +107 -0
  75. package/src/types/testing.ts +30 -0
  76. package/src/types/token.ts +96 -0
  77. package/src/types/transcription.ts +133 -0
  78. package/src/types/video.ts +108 -0
  79. package/src/types/wallet.ts +56 -0
  80. package/src/types/web-search.ts +146 -0
  81. package/src/utils/__tests__/buffer.test.ts +80 -0
  82. package/src/utils/__tests__/environment.test.ts +58 -0
  83. package/src/utils/__tests__/stringToUuid.test.ts +88 -0
  84. package/src/utils/buffer.ts +312 -0
  85. package/src/utils/environment.ts +316 -0
  86. package/src/utils/server-health.ts +117 -0
  87. package/src/utils.ts +1076 -0
  88. package/dist/tsconfig.build.tsbuildinfo +0 -1
@@ -0,0 +1,337 @@
1
+ import { describe, expect, it, beforeEach, afterEach } from 'bun:test';
2
+ import {
3
+ BufferUtils,
4
+ fromHex,
5
+ fromString,
6
+ fromBytes,
7
+ toHex,
8
+ toString,
9
+ isBuffer,
10
+ alloc,
11
+ concat,
12
+ slice,
13
+ equals,
14
+ byteLength,
15
+ randomBytes,
16
+ } from '../utils/buffer';
17
+
18
+ describe('Buffer Abstraction', () => {
19
+ describe('fromHex and toHex', () => {
20
+ it('should convert hex string to buffer and back', () => {
21
+ const hex = '48656c6c6f20576f726c64';
22
+ const buffer = fromHex(hex);
23
+ const result = toHex(buffer);
24
+ expect(result).toBe(hex.toLowerCase());
25
+ });
26
+
27
+ it('should handle empty hex string', () => {
28
+ const buffer = fromHex('');
29
+ expect(buffer.length).toBe(0);
30
+ expect(toHex(buffer)).toBe('');
31
+ });
32
+
33
+ it('should handle hex with non-hex characters', () => {
34
+ const hex = '48-65-6c-6c-6f';
35
+ const buffer = fromHex(hex);
36
+ const cleanHex = '48656c6c6f';
37
+ expect(toHex(buffer)).toBe(cleanHex.toLowerCase());
38
+ });
39
+
40
+ it('should handle odd-length hex strings', () => {
41
+ const hex = '486';
42
+ const buffer = fromHex(hex);
43
+ expect(buffer.length).toBe(1);
44
+ expect(buffer[0]).toBe(0x48);
45
+ });
46
+ });
47
+
48
+ describe('fromString and toString', () => {
49
+ it('should convert UTF-8 string to buffer and back', () => {
50
+ const text = 'Hello World';
51
+ const buffer = fromString(text);
52
+ const result = toString(buffer);
53
+ expect(result).toBe(text);
54
+ });
55
+
56
+ it('should handle UTF-8 with special characters', () => {
57
+ const text = 'Hello 世界 🌍';
58
+ const buffer = fromString(text);
59
+ const result = toString(buffer);
60
+ expect(result).toBe(text);
61
+ });
62
+
63
+ it('should handle base64 encoding', () => {
64
+ const text = 'Hello World';
65
+ const buffer = fromString(text);
66
+ const base64 = toString(buffer, 'base64');
67
+ expect(base64).toBe('SGVsbG8gV29ybGQ=');
68
+
69
+ const decoded = fromString(base64, 'base64');
70
+ expect(toString(decoded)).toBe(text);
71
+ });
72
+
73
+ it('should handle hex encoding in toString', () => {
74
+ const text = 'Hello';
75
+ const buffer = fromString(text);
76
+ const hex = toString(buffer, 'hex');
77
+ expect(hex).toBe('48656c6c6f');
78
+ });
79
+
80
+ it('should handle empty string', () => {
81
+ const buffer = fromString('');
82
+ expect(buffer.length).toBe(0);
83
+ expect(toString(buffer)).toBe('');
84
+ });
85
+
86
+ it('should handle utf-8 and utf8 encoding aliases', () => {
87
+ const text = 'Test';
88
+ const buffer1 = fromString(text, 'utf8');
89
+ const buffer2 = fromString(text, 'utf-8');
90
+ expect(equals(buffer1, buffer2)).toBe(true);
91
+ });
92
+ });
93
+
94
+ describe('fromBytes', () => {
95
+ it('should create buffer from byte array', () => {
96
+ const bytes = [72, 101, 108, 108, 111]; // "Hello"
97
+ const buffer = fromBytes(bytes);
98
+ expect(toString(buffer)).toBe('Hello');
99
+ });
100
+
101
+ it('should create buffer from Uint8Array', () => {
102
+ const bytes = new Uint8Array([72, 101, 108, 108, 111]);
103
+ const buffer = fromBytes(bytes);
104
+ expect(toString(buffer)).toBe('Hello');
105
+ });
106
+
107
+ it('should handle empty array', () => {
108
+ const buffer = fromBytes([]);
109
+ expect(buffer.length).toBe(0);
110
+ });
111
+ });
112
+
113
+ describe('isBuffer', () => {
114
+ it('should identify buffer-like objects', () => {
115
+ const buffer = fromString('test');
116
+ expect(isBuffer(buffer)).toBe(true);
117
+ });
118
+
119
+ it('should identify Uint8Array', () => {
120
+ const arr = new Uint8Array([1, 2, 3]);
121
+ expect(isBuffer(arr)).toBe(true);
122
+ });
123
+
124
+ it('should identify ArrayBuffer', () => {
125
+ const buffer = new ArrayBuffer(8);
126
+ expect(isBuffer(buffer)).toBe(true);
127
+ });
128
+
129
+ it('should reject non-buffer objects', () => {
130
+ expect(isBuffer('string')).toBe(false);
131
+ expect(isBuffer(123)).toBe(false);
132
+ expect(isBuffer({})).toBe(false);
133
+ expect(isBuffer([])).toBe(false);
134
+ expect(isBuffer(null)).toBe(false);
135
+ expect(isBuffer(undefined)).toBe(false);
136
+ });
137
+ });
138
+
139
+ describe('alloc', () => {
140
+ it('should create zero-filled buffer of specified size', () => {
141
+ const buffer = alloc(10);
142
+ expect(buffer.length).toBe(10);
143
+
144
+ // Check all bytes are zero
145
+ for (let i = 0; i < buffer.length; i++) {
146
+ expect(buffer[i]).toBe(0);
147
+ }
148
+ });
149
+
150
+ it('should create empty buffer for size 0', () => {
151
+ const buffer = alloc(0);
152
+ expect(buffer.length).toBe(0);
153
+ });
154
+ });
155
+
156
+ describe('concat', () => {
157
+ it('should concatenate multiple buffers', () => {
158
+ const buf1 = fromString('Hello');
159
+ const buf2 = fromString(' ');
160
+ const buf3 = fromString('World');
161
+ const result = concat([buf1, buf2, buf3]);
162
+ expect(toString(result)).toBe('Hello World');
163
+ });
164
+
165
+ it('should handle single buffer', () => {
166
+ const buffer = fromString('Hello');
167
+ const result = concat([buffer]);
168
+ expect(toString(result)).toBe('Hello');
169
+ });
170
+
171
+ it('should handle empty array', () => {
172
+ const result = concat([]);
173
+ expect(result.length).toBe(0);
174
+ });
175
+
176
+ it('should handle mix of buffer types', () => {
177
+ const buf1 = fromString('A');
178
+ const buf2 = new Uint8Array([66]); // 'B'
179
+ const result = concat([buf1, buf2]);
180
+ expect(toString(result)).toBe('AB');
181
+ });
182
+ });
183
+
184
+ describe('slice', () => {
185
+ it('should slice buffer from start to end', () => {
186
+ const buffer = fromString('Hello World');
187
+ const sliced = slice(buffer, 0, 5);
188
+ expect(toString(sliced)).toBe('Hello');
189
+ });
190
+
191
+ it('should slice from start if no end provided', () => {
192
+ const buffer = fromString('Hello World');
193
+ const sliced = slice(buffer, 6);
194
+ expect(toString(sliced)).toBe('World');
195
+ });
196
+
197
+ it('should handle negative indices', () => {
198
+ const buffer = fromString('Hello World');
199
+ const sliced = slice(buffer, -5);
200
+ expect(toString(sliced)).toBe('World');
201
+ });
202
+
203
+ it('should return empty buffer for invalid range', () => {
204
+ const buffer = fromString('Hello');
205
+ const sliced = slice(buffer, 10, 15);
206
+ expect(sliced.length).toBe(0);
207
+ });
208
+ });
209
+
210
+ describe('equals', () => {
211
+ it('should return true for equal buffers', () => {
212
+ const buf1 = fromString('Hello');
213
+ const buf2 = fromString('Hello');
214
+ expect(equals(buf1, buf2)).toBe(true);
215
+ });
216
+
217
+ it('should return false for different buffers', () => {
218
+ const buf1 = fromString('Hello');
219
+ const buf2 = fromString('World');
220
+ expect(equals(buf1, buf2)).toBe(false);
221
+ });
222
+
223
+ it('should return false for different lengths', () => {
224
+ const buf1 = fromString('Hi');
225
+ const buf2 = fromString('Hello');
226
+ expect(equals(buf1, buf2)).toBe(false);
227
+ });
228
+
229
+ it('should handle empty buffers', () => {
230
+ const buf1 = alloc(0);
231
+ const buf2 = alloc(0);
232
+ expect(equals(buf1, buf2)).toBe(true);
233
+ });
234
+ });
235
+
236
+ describe('byteLength', () => {
237
+ it('should return correct byte length', () => {
238
+ const buffer = fromString('Hello');
239
+ expect(byteLength(buffer)).toBe(5);
240
+ });
241
+
242
+ it('should handle UTF-8 multi-byte characters', () => {
243
+ const buffer = fromString('世界');
244
+ expect(byteLength(buffer)).toBe(6); // Each character is 3 bytes
245
+ });
246
+
247
+ it('should return 0 for empty buffer', () => {
248
+ const buffer = alloc(0);
249
+ expect(byteLength(buffer)).toBe(0);
250
+ });
251
+ });
252
+
253
+ describe('randomBytes', () => {
254
+ it('should generate random bytes of specified length', () => {
255
+ const buffer = randomBytes(16);
256
+ expect(buffer.length).toBe(16);
257
+ });
258
+
259
+ it('should generate different values on each call', () => {
260
+ const buf1 = randomBytes(16);
261
+ const buf2 = randomBytes(16);
262
+
263
+ // It's extremely unlikely these will be equal
264
+ expect(equals(buf1, buf2)).toBe(false);
265
+ });
266
+
267
+ it('should handle zero length', () => {
268
+ const buffer = randomBytes(0);
269
+ expect(buffer.length).toBe(0);
270
+ });
271
+
272
+ it('should generate bytes in valid range', () => {
273
+ const buffer = randomBytes(100);
274
+ for (let i = 0; i < buffer.length; i++) {
275
+ expect(buffer[i]).toBeGreaterThanOrEqual(0);
276
+ expect(buffer[i]).toBeLessThanOrEqual(255);
277
+ }
278
+ });
279
+ });
280
+
281
+ describe('BufferUtils namespace', () => {
282
+ it('should expose all functions through namespace', () => {
283
+ expect(BufferUtils.fromHex).toBe(fromHex);
284
+ expect(BufferUtils.fromString).toBe(fromString);
285
+ expect(BufferUtils.fromBytes).toBe(fromBytes);
286
+ expect(BufferUtils.toHex).toBe(toHex);
287
+ expect(BufferUtils.toString).toBe(toString);
288
+ expect(BufferUtils.isBuffer).toBe(isBuffer);
289
+ expect(BufferUtils.alloc).toBe(alloc);
290
+ expect(BufferUtils.concat).toBe(concat);
291
+ expect(BufferUtils.slice).toBe(slice);
292
+ expect(BufferUtils.equals).toBe(equals);
293
+ expect(BufferUtils.byteLength).toBe(byteLength);
294
+ expect(BufferUtils.randomBytes).toBe(randomBytes);
295
+ });
296
+ });
297
+
298
+ describe('Cross-environment compatibility', () => {
299
+ let originalBuffer: any;
300
+ let originalCrypto: any;
301
+
302
+ beforeEach(() => {
303
+ // Store original globals
304
+ originalBuffer = (global as any).Buffer;
305
+ originalCrypto = (global as any).crypto;
306
+ });
307
+
308
+ afterEach(() => {
309
+ // Restore original globals
310
+ if (originalBuffer !== undefined) {
311
+ (global as any).Buffer = originalBuffer;
312
+ } else {
313
+ delete (global as any).Buffer;
314
+ }
315
+
316
+ if (originalCrypto !== undefined) {
317
+ (global as any).crypto = originalCrypto;
318
+ }
319
+ });
320
+
321
+ it('should work without native Buffer', () => {
322
+ // Temporarily remove Buffer
323
+ delete (global as any).Buffer;
324
+
325
+ // Force module re-evaluation would be needed here
326
+ // For now, just test that functions work
327
+ const buffer = fromString('Test without Buffer');
328
+ const hex = toHex(buffer);
329
+ const decoded = fromHex(hex);
330
+ expect(toString(decoded)).toBe('Test without Buffer');
331
+ });
332
+
333
+ it.skip('should use crypto.getRandomValues when available', () => {
334
+ // Skip: Node.js environment uses crypto.randomBytes, not getRandomValues
335
+ });
336
+ });
337
+ });
@@ -0,0 +1,309 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import {
3
+ validateCharacter,
4
+ parseAndValidateCharacter,
5
+ isValidCharacter,
6
+ } from '../schemas/character';
7
+ import type { Character } from '../types/agent';
8
+
9
+ describe('Character Schema Validation', () => {
10
+ const validCharacter: Character = {
11
+ name: 'Test Character',
12
+ bio: 'A test character for validation',
13
+ messageExamples: [],
14
+ postExamples: [],
15
+ topics: ['AI', 'Testing'],
16
+ adjectives: ['helpful', 'reliable'],
17
+ knowledge: [],
18
+ plugins: [],
19
+ settings: {},
20
+ style: {},
21
+ };
22
+
23
+ const minimalValidCharacter: Character = {
24
+ name: 'Minimal Character',
25
+ bio: 'Just the basics',
26
+ };
27
+
28
+ describe('validateCharacter', () => {
29
+ test('should validate a complete valid character', () => {
30
+ const result = validateCharacter(validCharacter);
31
+ expect(result.success).toBe(true);
32
+ expect(result.data).toEqual(validCharacter);
33
+ expect(result.error).toBeUndefined();
34
+ });
35
+
36
+ test('should validate a minimal valid character', () => {
37
+ const result = validateCharacter(minimalValidCharacter);
38
+ expect(result.success).toBe(true);
39
+ expect(result.data).toEqual(minimalValidCharacter);
40
+ });
41
+
42
+ test('should reject character without name', () => {
43
+ const invalidCharacter = { bio: 'No name character' };
44
+ const result = validateCharacter(invalidCharacter);
45
+ expect(result.success).toBe(false);
46
+ expect(result.error?.message).toContain('Character validation failed');
47
+ expect(result.error?.issues).toBeDefined();
48
+ });
49
+
50
+ test('should reject character with empty name', () => {
51
+ const invalidCharacter = { name: '', bio: 'Empty name' };
52
+ const result = validateCharacter(invalidCharacter);
53
+ expect(result.success).toBe(false);
54
+ expect(result.error?.message).toContain('Character validation failed');
55
+ });
56
+
57
+ test('should reject character without bio', () => {
58
+ const invalidCharacter = { name: 'No Bio Character' };
59
+ const result = validateCharacter(invalidCharacter);
60
+ expect(result.success).toBe(false);
61
+ expect(result.error?.message).toContain('Character validation failed');
62
+ });
63
+
64
+ test('should accept bio as string array', () => {
65
+ const characterWithArrayBio = {
66
+ name: 'Array Bio Character',
67
+ bio: ['First line', 'Second line', 'Third line'],
68
+ };
69
+ const result = validateCharacter(characterWithArrayBio);
70
+ expect(result.success).toBe(true);
71
+ });
72
+
73
+ test('should reject unknown properties in strict mode', () => {
74
+ const characterWithExtra = {
75
+ ...validCharacter,
76
+ unknownProperty: 'should be rejected',
77
+ anotherUnknown: 123,
78
+ };
79
+ const result = validateCharacter(characterWithExtra);
80
+ expect(result.success).toBe(false);
81
+ expect(result.error?.message).toContain('Unrecognized key');
82
+ });
83
+
84
+ test('should validate optional fields correctly', () => {
85
+ const characterWithOptionals = {
86
+ name: 'Optional Fields Character',
87
+ bio: 'Testing optional fields',
88
+ username: 'test_user',
89
+ system: 'Test system prompt',
90
+ messageExamples: [
91
+ [
92
+ {
93
+ name: 'user',
94
+ content: { text: 'Hello' },
95
+ },
96
+ {
97
+ name: 'assistant',
98
+ content: { text: 'Hi there!' },
99
+ },
100
+ ],
101
+ ],
102
+ postExamples: ['Example post 1', 'Example post 2'],
103
+ topics: ['AI', 'Testing', 'Validation'],
104
+ adjectives: ['helpful', 'reliable', 'intelligent'],
105
+ knowledge: [
106
+ 'knowledge/file1.txt',
107
+ { path: 'knowledge/file2.txt', shared: true },
108
+ { directory: 'knowledge/shared', shared: true },
109
+ ],
110
+ plugins: ['plugin1', 'plugin2'],
111
+ settings: {
112
+ temperature: 0.7,
113
+ maxTokens: 1000,
114
+ debug: true,
115
+ },
116
+ secrets: {
117
+ apiKey: 'secret-key',
118
+ enabled: true,
119
+ },
120
+ style: {
121
+ all: ['casual', 'friendly'],
122
+ chat: ['responsive', 'helpful'],
123
+ post: ['engaging', 'informative'],
124
+ },
125
+ };
126
+ const result = validateCharacter(characterWithOptionals);
127
+ expect(result.success).toBe(true);
128
+ });
129
+
130
+ test('should validate UUID format for id field', () => {
131
+ const characterWithValidUuid = {
132
+ ...validCharacter,
133
+ id: '123e4567-e89b-12d3-a456-426614174000',
134
+ };
135
+ const result = validateCharacter(characterWithValidUuid);
136
+ expect(result.success).toBe(true);
137
+ });
138
+
139
+ test('should reject invalid UUID format for id field', () => {
140
+ const characterWithInvalidUuid = {
141
+ ...validCharacter,
142
+ id: 'invalid-uuid-format',
143
+ };
144
+ const result = validateCharacter(characterWithInvalidUuid);
145
+ expect(result.success).toBe(false);
146
+ expect(result.error?.message).toContain('Invalid UUID format');
147
+ });
148
+ });
149
+
150
+ describe('parseAndValidateCharacter', () => {
151
+ test('should parse and validate valid JSON character', () => {
152
+ const jsonString = JSON.stringify(validCharacter);
153
+ const result = parseAndValidateCharacter(jsonString);
154
+ expect(result.success).toBe(true);
155
+ expect(result.data).toEqual(validCharacter);
156
+ });
157
+
158
+ test('should handle malformed JSON', () => {
159
+ const malformedJson = '{ "name": "Test", "bio": "Test" '; // Missing closing brace
160
+ const result = parseAndValidateCharacter(malformedJson);
161
+ expect(result.success).toBe(false);
162
+ expect(result.error?.message).toContain('Invalid JSON');
163
+ });
164
+
165
+ test('should handle JSON with invalid character data', () => {
166
+ const invalidCharacterJson = JSON.stringify({ name: '', bio: 'Invalid' });
167
+ const result = parseAndValidateCharacter(invalidCharacterJson);
168
+ expect(result.success).toBe(false);
169
+ expect(result.error?.message).toContain('Character validation failed');
170
+ });
171
+
172
+ test('should handle empty JSON object', () => {
173
+ const emptyJson = '{}';
174
+ const result = parseAndValidateCharacter(emptyJson);
175
+ expect(result.success).toBe(false);
176
+ expect(result.error?.message).toContain('Character validation failed');
177
+ });
178
+ });
179
+
180
+ describe('isValidCharacter', () => {
181
+ test('should return true for valid character', () => {
182
+ expect(isValidCharacter(validCharacter)).toBe(true);
183
+ });
184
+
185
+ test('should return false for invalid character', () => {
186
+ const invalidCharacter = { name: '', bio: 'Invalid' };
187
+ expect(isValidCharacter(invalidCharacter)).toBe(false);
188
+ });
189
+
190
+ test('should return false for non-object input', () => {
191
+ expect(isValidCharacter('string')).toBe(false);
192
+ expect(isValidCharacter(null)).toBe(false);
193
+ expect(isValidCharacter(undefined)).toBe(false);
194
+ expect(isValidCharacter(123)).toBe(false);
195
+ });
196
+ });
197
+
198
+ describe('Complex validation scenarios', () => {
199
+ test('should validate character with complex knowledge array', () => {
200
+ const characterWithComplexKnowledge = {
201
+ name: 'Knowledge Character',
202
+ bio: 'Testing knowledge validation',
203
+ knowledge: [
204
+ 'simple/path.txt',
205
+ { path: 'path/with/config.txt', shared: false },
206
+ { path: 'shared/path.txt', shared: true },
207
+ { directory: 'knowledge/dir' },
208
+ { directory: 'shared/dir', shared: true },
209
+ ],
210
+ };
211
+ const result = validateCharacter(characterWithComplexKnowledge);
212
+ expect(result.success).toBe(true);
213
+ });
214
+
215
+ test('should validate character with complex message examples', () => {
216
+ const characterWithComplexMessages = {
217
+ name: 'Message Character',
218
+ bio: 'Testing message validation',
219
+ messageExamples: [
220
+ [
221
+ {
222
+ name: 'user',
223
+ content: {
224
+ text: 'Hello, how are you?',
225
+ source: 'user',
226
+ },
227
+ },
228
+ {
229
+ name: 'assistant',
230
+ content: {
231
+ text: 'I am doing well, thank you!',
232
+ source: 'assistant',
233
+ attachments: [{ type: 'text', data: 'additional info' }],
234
+ },
235
+ },
236
+ ],
237
+ [
238
+ {
239
+ name: 'user',
240
+ content: { text: 'What is the weather like?' },
241
+ },
242
+ {
243
+ name: 'assistant',
244
+ content: {
245
+ text: 'I would need to check a weather service for current conditions.',
246
+ url: 'https://weather.example.com',
247
+ },
248
+ },
249
+ ],
250
+ ],
251
+ };
252
+ const result = validateCharacter(characterWithComplexMessages);
253
+ expect(result.success).toBe(true);
254
+ });
255
+
256
+ test('should validate character with flexible settings', () => {
257
+ const characterWithFlexibleSettings = {
258
+ name: 'Settings Character',
259
+ bio: 'Testing settings validation',
260
+ settings: {
261
+ temperature: 0.8,
262
+ maxTokens: 2000,
263
+ enableDebug: true,
264
+ model: 'gpt-4',
265
+ customConfig: {
266
+ nested: {
267
+ deeply: {
268
+ value: 'test',
269
+ },
270
+ },
271
+ },
272
+ arrayValue: [1, 2, 3],
273
+ },
274
+ secrets: {
275
+ apiKey: 'sk-test123',
276
+ secretNumber: 42,
277
+ isEnabled: true,
278
+ },
279
+ };
280
+ const result = validateCharacter(characterWithFlexibleSettings);
281
+ expect(result.success).toBe(true);
282
+ });
283
+ });
284
+
285
+ describe('Edge cases and error handling', () => {
286
+ test('should handle null and undefined inputs', () => {
287
+ expect(validateCharacter(null).success).toBe(false);
288
+ expect(validateCharacter(undefined).success).toBe(false);
289
+ });
290
+
291
+ test('should handle non-object inputs', () => {
292
+ expect(validateCharacter('string').success).toBe(false);
293
+ expect(validateCharacter(123).success).toBe(false);
294
+ expect(validateCharacter([]).success).toBe(false);
295
+ });
296
+
297
+ test('should provide detailed error information', () => {
298
+ const invalidCharacter = {
299
+ name: '', // Invalid: empty string
300
+ bio: 123, // Invalid: should be string or string[]
301
+ messageExamples: 'invalid', // Invalid: should be array
302
+ };
303
+ const result = validateCharacter(invalidCharacter);
304
+ expect(result.success).toBe(false);
305
+ expect(result.error?.issues).toBeDefined();
306
+ expect(result.error?.issues?.length).toBeGreaterThan(0);
307
+ });
308
+ });
309
+ });