@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.
- package/dist/browser/index.browser.js +120 -120
- package/dist/browser/index.browser.js.map +5 -21
- package/dist/browser/index.d.ts +3 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +1 -5
- package/dist/node/index.d.ts +3 -1
- package/package.json +10 -4
- package/src/__tests__/action-chaining-simple.test.ts +203 -0
- package/src/__tests__/actions.test.ts +218 -0
- package/src/__tests__/buffer.test.ts +337 -0
- package/src/__tests__/character-validation.test.ts +309 -0
- package/src/__tests__/database.test.ts +750 -0
- package/src/__tests__/entities.test.ts +727 -0
- package/src/__tests__/env.test.ts +23 -0
- package/src/__tests__/environment.test.ts +285 -0
- package/src/__tests__/logger-browser-node.test.ts +716 -0
- package/src/__tests__/logger.test.ts +403 -0
- package/src/__tests__/messages.test.ts +196 -0
- package/src/__tests__/mockCharacter.ts +544 -0
- package/src/__tests__/parsing.test.ts +58 -0
- package/src/__tests__/prompts.test.ts +159 -0
- package/src/__tests__/roles.test.ts +331 -0
- package/src/__tests__/runtime-embedding.test.ts +343 -0
- package/src/__tests__/runtime.test.ts +978 -0
- package/src/__tests__/search.test.ts +15 -0
- package/src/__tests__/services-by-type.test.ts +204 -0
- package/src/__tests__/services.test.ts +136 -0
- package/src/__tests__/settings.test.ts +810 -0
- package/src/__tests__/utils.test.ts +1105 -0
- package/src/__tests__/uuid.test.ts +94 -0
- package/src/actions.ts +122 -0
- package/src/database.ts +579 -0
- package/src/entities.ts +406 -0
- package/src/index.browser.ts +48 -0
- package/src/index.node.ts +39 -0
- package/src/index.ts +50 -0
- package/src/logger.ts +527 -0
- package/src/prompts.ts +243 -0
- package/src/roles.ts +85 -0
- package/src/runtime.ts +2514 -0
- package/src/schemas/character.ts +149 -0
- package/src/search.ts +1543 -0
- package/src/sentry/instrument.browser.ts +65 -0
- package/src/sentry/instrument.node.ts +57 -0
- package/src/sentry/instrument.ts +82 -0
- package/src/services.ts +105 -0
- package/src/settings.ts +409 -0
- package/src/test_resources/constants.ts +12 -0
- package/src/test_resources/testSetup.ts +21 -0
- package/src/test_resources/types.ts +22 -0
- package/src/types/agent.ts +112 -0
- package/src/types/browser.ts +145 -0
- package/src/types/components.ts +184 -0
- package/src/types/database.ts +348 -0
- package/src/types/email.ts +162 -0
- package/src/types/environment.ts +129 -0
- package/src/types/events.ts +249 -0
- package/src/types/index.ts +29 -0
- package/src/types/knowledge.ts +65 -0
- package/src/types/lp.ts +124 -0
- package/src/types/memory.ts +228 -0
- package/src/types/message.ts +233 -0
- package/src/types/messaging.ts +57 -0
- package/src/types/model.ts +359 -0
- package/src/types/pdf.ts +77 -0
- package/src/types/plugin.ts +78 -0
- package/src/types/post.ts +271 -0
- package/src/types/primitives.ts +97 -0
- package/src/types/runtime.ts +190 -0
- package/src/types/service.ts +198 -0
- package/src/types/settings.ts +30 -0
- package/src/types/state.ts +60 -0
- package/src/types/task.ts +72 -0
- package/src/types/tee.ts +107 -0
- package/src/types/testing.ts +30 -0
- package/src/types/token.ts +96 -0
- package/src/types/transcription.ts +133 -0
- package/src/types/video.ts +108 -0
- package/src/types/wallet.ts +56 -0
- package/src/types/web-search.ts +146 -0
- package/src/utils/__tests__/buffer.test.ts +80 -0
- package/src/utils/__tests__/environment.test.ts +58 -0
- package/src/utils/__tests__/stringToUuid.test.ts +88 -0
- package/src/utils/buffer.ts +312 -0
- package/src/utils/environment.ts +316 -0
- package/src/utils/server-health.ts +117 -0
- package/src/utils.ts +1076 -0
- package/dist/tsconfig.build.tsbuildinfo +0 -1
package/dist/browser/index.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Main entry point for @elizaos/core
|
|
3
|
-
* Automatically selects the correct build based on the environment
|
|
4
|
-
*/
|
|
5
|
-
|
|
1
|
+
// Main entry point for @elizaos/core
|
|
6
2
|
// This file is not used directly - package.json conditional exports handle the routing
|
|
7
3
|
// See package.json "exports" field for the actual entry points
|
|
8
4
|
export * from './node/index.node.js';
|
package/dist/node/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elizaos/core",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,14 +12,19 @@
|
|
|
12
12
|
".": {
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"browser": {
|
|
15
|
+
"types": "./dist/browser/index.d.ts",
|
|
15
16
|
"import": "./dist/browser/index.browser.js",
|
|
16
17
|
"default": "./dist/browser/index.browser.js"
|
|
17
18
|
},
|
|
18
19
|
"node": {
|
|
20
|
+
"types": "./dist/node/index.d.ts",
|
|
19
21
|
"import": "./dist/node/index.node.js",
|
|
20
22
|
"default": "./dist/node/index.node.js"
|
|
21
23
|
},
|
|
22
|
-
"bun":
|
|
24
|
+
"bun": {
|
|
25
|
+
"types": "./dist/node/index.d.ts",
|
|
26
|
+
"default": "./dist/node/index.node.js"
|
|
27
|
+
},
|
|
23
28
|
"default": "./dist/node/index.node.js"
|
|
24
29
|
},
|
|
25
30
|
"./node": {
|
|
@@ -34,7 +39,8 @@
|
|
|
34
39
|
}
|
|
35
40
|
},
|
|
36
41
|
"files": [
|
|
37
|
-
"dist"
|
|
42
|
+
"dist",
|
|
43
|
+
"src"
|
|
38
44
|
],
|
|
39
45
|
"scripts": {
|
|
40
46
|
"build": "bun run build.ts",
|
|
@@ -75,5 +81,5 @@
|
|
|
75
81
|
"publishConfig": {
|
|
76
82
|
"access": "public"
|
|
77
83
|
},
|
|
78
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "78ec4978065a95e4102d270417ac2b3f4dd96e9f"
|
|
79
85
|
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { describe, expect, it, beforeEach, mock } from 'bun:test';
|
|
2
|
+
import { AgentRuntime } from '../runtime';
|
|
3
|
+
import { createActionResult } from '../types/components';
|
|
4
|
+
import type { ActionResult } from '../types';
|
|
5
|
+
|
|
6
|
+
describe('Action Chaining Fixes', () => {
|
|
7
|
+
describe('createActionResult helper', () => {
|
|
8
|
+
it('should create ActionResult with default success=true', () => {
|
|
9
|
+
const result = createActionResult();
|
|
10
|
+
expect(result.success).toBe(true);
|
|
11
|
+
expect(result.text).toBeUndefined();
|
|
12
|
+
expect(result.error).toBeUndefined();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should allow overriding success field', () => {
|
|
16
|
+
const result = createActionResult({ success: false, error: 'Test error' });
|
|
17
|
+
expect(result.success).toBe(false);
|
|
18
|
+
expect(result.error).toBe('Test error');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should preserve all provided fields', () => {
|
|
22
|
+
const result = createActionResult({
|
|
23
|
+
text: 'Test text',
|
|
24
|
+
values: { key: 'value' },
|
|
25
|
+
data: { foo: 'bar' },
|
|
26
|
+
});
|
|
27
|
+
expect(result.success).toBe(true);
|
|
28
|
+
expect(result.text).toBe('Test text');
|
|
29
|
+
expect(result.values).toEqual({ key: 'value' });
|
|
30
|
+
expect(result.data).toEqual({ foo: 'bar' });
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('Runtime immutable helpers', () => {
|
|
35
|
+
let runtime: any;
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
// Access private methods through prototype
|
|
39
|
+
runtime = AgentRuntime.prototype;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should update action plan immutably', () => {
|
|
43
|
+
const originalPlan = {
|
|
44
|
+
currentStep: 1,
|
|
45
|
+
totalSteps: 3,
|
|
46
|
+
steps: [{ action: 'step1' }, { action: 'step2' }, { action: 'step3' }],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const updatedPlan = runtime.updateActionPlan(originalPlan, { currentStep: 2 });
|
|
50
|
+
|
|
51
|
+
// Original should be unchanged
|
|
52
|
+
expect(originalPlan.currentStep).toBe(1);
|
|
53
|
+
|
|
54
|
+
// Updated should have new value
|
|
55
|
+
expect(updatedPlan.currentStep).toBe(2);
|
|
56
|
+
expect(updatedPlan.totalSteps).toBe(3);
|
|
57
|
+
expect(updatedPlan.steps).toEqual(originalPlan.steps);
|
|
58
|
+
|
|
59
|
+
// Should be different objects
|
|
60
|
+
expect(updatedPlan).not.toBe(originalPlan);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should update action step immutably', () => {
|
|
64
|
+
const originalPlan = {
|
|
65
|
+
currentStep: 1,
|
|
66
|
+
steps: [
|
|
67
|
+
{ action: 'step1', status: 'pending' },
|
|
68
|
+
{ action: 'step2', status: 'pending' },
|
|
69
|
+
{ action: 'step3', status: 'pending' },
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const updatedPlan = runtime.updateActionStep(originalPlan, 1, {
|
|
74
|
+
status: 'completed',
|
|
75
|
+
result: { success: true },
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Original should be unchanged
|
|
79
|
+
expect(originalPlan.steps[1].status).toBe('pending');
|
|
80
|
+
expect(originalPlan.steps[1].result).toBeUndefined();
|
|
81
|
+
|
|
82
|
+
// Updated should have new values
|
|
83
|
+
expect(updatedPlan.steps[1].status).toBe('completed');
|
|
84
|
+
expect(updatedPlan.steps[1].result).toEqual({ success: true });
|
|
85
|
+
|
|
86
|
+
// Other steps should be unchanged
|
|
87
|
+
expect(updatedPlan.steps[0]).toEqual(originalPlan.steps[0]);
|
|
88
|
+
expect(updatedPlan.steps[2]).toEqual(originalPlan.steps[2]);
|
|
89
|
+
|
|
90
|
+
// Should be different objects
|
|
91
|
+
expect(updatedPlan).not.toBe(originalPlan);
|
|
92
|
+
expect(updatedPlan.steps).not.toBe(originalPlan.steps);
|
|
93
|
+
expect(updatedPlan.steps[1]).not.toBe(originalPlan.steps[1]);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('Working Memory Cleanup', () => {
|
|
98
|
+
it('should enforce MAX_WORKING_MEMORY_ENTRIES limit', () => {
|
|
99
|
+
// This is more of a documentation test showing the expected behavior
|
|
100
|
+
const MAX_WORKING_MEMORY_ENTRIES = 50;
|
|
101
|
+
const workingMemory: Record<string, any> = {};
|
|
102
|
+
|
|
103
|
+
// Add 60 entries
|
|
104
|
+
for (let i = 0; i < 60; i++) {
|
|
105
|
+
workingMemory[`action_${i}`] = {
|
|
106
|
+
actionName: `Action${i}`,
|
|
107
|
+
timestamp: Date.now() + i, // Incrementing timestamps
|
|
108
|
+
result: { success: true },
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Simulate cleanup
|
|
113
|
+
const entries = Object.entries(workingMemory);
|
|
114
|
+
expect(entries.length).toBe(60);
|
|
115
|
+
|
|
116
|
+
// Sort by timestamp (newest first) with proper type safety
|
|
117
|
+
const sorted = entries.sort((a, b) => {
|
|
118
|
+
const entryA = a[1] as { timestamp?: number } | null;
|
|
119
|
+
const entryB = b[1] as { timestamp?: number } | null;
|
|
120
|
+
const timestampA = entryA?.timestamp ?? 0;
|
|
121
|
+
const timestampB = entryB?.timestamp ?? 0;
|
|
122
|
+
return timestampB - timestampA;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Keep only the most recent MAX_WORKING_MEMORY_ENTRIES
|
|
126
|
+
const cleaned = Object.fromEntries(sorted.slice(0, MAX_WORKING_MEMORY_ENTRIES));
|
|
127
|
+
|
|
128
|
+
expect(Object.keys(cleaned).length).toBe(MAX_WORKING_MEMORY_ENTRIES);
|
|
129
|
+
|
|
130
|
+
// Verify we kept the newest entries
|
|
131
|
+
const cleanedKeys = Object.keys(cleaned);
|
|
132
|
+
expect(cleanedKeys).toContain('action_59');
|
|
133
|
+
expect(cleanedKeys).toContain('action_50');
|
|
134
|
+
expect(cleanedKeys).not.toContain('action_9'); // Old entry should be removed
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe('Bounds Checking', () => {
|
|
139
|
+
it('should handle updateActionStep with invalid indices', () => {
|
|
140
|
+
// Mock logger
|
|
141
|
+
const warnCalls: string[] = [];
|
|
142
|
+
const mockLogger = {
|
|
143
|
+
warn: (msg: string) => {
|
|
144
|
+
warnCalls.push(msg);
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// Helper function that mimics the runtime's updateActionStep
|
|
149
|
+
const updateActionStep = <T, S>(
|
|
150
|
+
plan: T & { steps: S[] },
|
|
151
|
+
index: number,
|
|
152
|
+
stepUpdates: Partial<S>,
|
|
153
|
+
logger: typeof mockLogger
|
|
154
|
+
): T & { steps: S[] } => {
|
|
155
|
+
if (!plan.steps || index < 0 || index >= plan.steps.length) {
|
|
156
|
+
logger.warn(
|
|
157
|
+
`Invalid step index: ${index} for plan with ${plan.steps?.length || 0} steps`
|
|
158
|
+
);
|
|
159
|
+
return plan;
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
...plan,
|
|
163
|
+
steps: plan.steps.map((step: S, i: number) =>
|
|
164
|
+
i === index ? { ...step, ...stepUpdates } : step
|
|
165
|
+
),
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Test data
|
|
170
|
+
const plan = {
|
|
171
|
+
name: 'test-plan',
|
|
172
|
+
steps: [
|
|
173
|
+
{ status: 'pending', action: 'step1' },
|
|
174
|
+
{ status: 'pending', action: 'step2' },
|
|
175
|
+
{ status: 'pending', action: 'step3' },
|
|
176
|
+
],
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// Test valid index
|
|
180
|
+
const updated1 = updateActionStep(plan, 1, { status: 'completed' }, mockLogger);
|
|
181
|
+
expect(updated1.steps[1].status).toBe('completed');
|
|
182
|
+
expect(warnCalls.length).toBe(0);
|
|
183
|
+
|
|
184
|
+
// Test negative index
|
|
185
|
+
const updated2 = updateActionStep(plan, -1, { status: 'failed' }, mockLogger);
|
|
186
|
+
expect(updated2).toBe(plan); // Should return original plan
|
|
187
|
+
expect(warnCalls[0]).toBe('Invalid step index: -1 for plan with 3 steps');
|
|
188
|
+
|
|
189
|
+
// Test index out of bounds
|
|
190
|
+
warnCalls.length = 0; // Clear warnings
|
|
191
|
+
const updated3 = updateActionStep(plan, 5, { status: 'failed' }, mockLogger);
|
|
192
|
+
expect(updated3).toBe(plan); // Should return original plan
|
|
193
|
+
expect(warnCalls[0]).toBe('Invalid step index: 5 for plan with 3 steps');
|
|
194
|
+
|
|
195
|
+
// Test with null steps
|
|
196
|
+
warnCalls.length = 0; // Clear warnings
|
|
197
|
+
const planWithNullSteps = { name: 'test', steps: null as any };
|
|
198
|
+
const updated4 = updateActionStep(planWithNullSteps, 0, { status: 'completed' }, mockLogger);
|
|
199
|
+
expect(updated4).toBe(planWithNullSteps);
|
|
200
|
+
expect(warnCalls[0]).toBe('Invalid step index: 0 for plan with 0 steps');
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
});
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
import { composeActionExamples, formatActionNames, formatActions } from '../actions';
|
|
3
|
+
import type { Action } from '../types';
|
|
4
|
+
|
|
5
|
+
describe('Actions', () => {
|
|
6
|
+
const mockActions: Action[] = [
|
|
7
|
+
{
|
|
8
|
+
name: 'greet',
|
|
9
|
+
description: 'Greet someone',
|
|
10
|
+
examples: [
|
|
11
|
+
[
|
|
12
|
+
{ name: 'name1', content: { text: 'Hello {{name2}}!' } },
|
|
13
|
+
{
|
|
14
|
+
name: 'name2',
|
|
15
|
+
content: { text: 'Hi {{name1}}!', action: 'wave' },
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
[
|
|
19
|
+
{
|
|
20
|
+
name: 'name1',
|
|
21
|
+
content: { text: 'Hey {{name2}}, how are you?' },
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'name2',
|
|
25
|
+
content: { text: "I'm good {{name1}}, thanks!" },
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
],
|
|
29
|
+
similes: ['say hi', 'welcome'],
|
|
30
|
+
handler: async () => {
|
|
31
|
+
throw new Error('Not implemented');
|
|
32
|
+
},
|
|
33
|
+
validate: async () => {
|
|
34
|
+
throw new Error('Not implemented');
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'farewell',
|
|
39
|
+
description: 'Say goodbye',
|
|
40
|
+
examples: [
|
|
41
|
+
[
|
|
42
|
+
{ name: 'name1', content: { text: 'Goodbye {{name2}}!' } },
|
|
43
|
+
{ name: 'name2', content: { text: 'Bye {{name1}}!' } },
|
|
44
|
+
],
|
|
45
|
+
],
|
|
46
|
+
similes: ['say bye', 'leave'],
|
|
47
|
+
handler: async () => {
|
|
48
|
+
throw new Error('Not implemented');
|
|
49
|
+
},
|
|
50
|
+
validate: async () => {
|
|
51
|
+
throw new Error('Not implemented');
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'help',
|
|
56
|
+
description: 'Get assistance',
|
|
57
|
+
examples: [
|
|
58
|
+
[
|
|
59
|
+
{
|
|
60
|
+
name: 'name1',
|
|
61
|
+
content: { text: 'Can you help me {{name2}}?' },
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'name2',
|
|
65
|
+
content: {
|
|
66
|
+
text: 'Of course {{name1}}, what do you need?',
|
|
67
|
+
action: 'assist',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
],
|
|
72
|
+
similes: ['assist', 'support'],
|
|
73
|
+
handler: async () => {
|
|
74
|
+
throw new Error('Not implemented');
|
|
75
|
+
},
|
|
76
|
+
validate: async () => {
|
|
77
|
+
throw new Error('Not implemented');
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
describe('composeActionExamples', () => {
|
|
83
|
+
it('should generate examples with correct format', () => {
|
|
84
|
+
const examples = composeActionExamples(mockActions, 1);
|
|
85
|
+
const lines = examples.trim().split('\n');
|
|
86
|
+
expect(lines.length).toBeGreaterThan(0);
|
|
87
|
+
expect(lines[0]).toMatch(/^name\d: .+/);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should replace name placeholders with generated names', () => {
|
|
91
|
+
const examples = composeActionExamples(mockActions, 1);
|
|
92
|
+
expect(examples).not.toContain('{{name1}}');
|
|
93
|
+
expect(examples).not.toContain('{{name2}}');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should handle empty actions array', () => {
|
|
97
|
+
const examples = composeActionExamples([], 5);
|
|
98
|
+
expect(examples).toBe('');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should handle count larger than available examples', () => {
|
|
102
|
+
const examples = composeActionExamples(mockActions, 10);
|
|
103
|
+
expect(examples.length).toBeGreaterThan(0);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should handle actions without examples', () => {
|
|
107
|
+
const actionsWithoutExamples: Action[] = [
|
|
108
|
+
{
|
|
109
|
+
name: 'test',
|
|
110
|
+
description: 'Test action without examples',
|
|
111
|
+
examples: [], // Empty examples array
|
|
112
|
+
similes: [],
|
|
113
|
+
handler: async () => {
|
|
114
|
+
throw new Error('Not implemented');
|
|
115
|
+
},
|
|
116
|
+
validate: async () => {
|
|
117
|
+
throw new Error('Not implemented');
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'test2',
|
|
122
|
+
description: 'Test action with no examples property',
|
|
123
|
+
// examples property not defined
|
|
124
|
+
similes: [],
|
|
125
|
+
handler: async () => {
|
|
126
|
+
throw new Error('Not implemented');
|
|
127
|
+
},
|
|
128
|
+
validate: async () => {
|
|
129
|
+
throw new Error('Not implemented');
|
|
130
|
+
},
|
|
131
|
+
} as Action,
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
const examples = composeActionExamples(actionsWithoutExamples, 5);
|
|
135
|
+
expect(examples).toBe('');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should handle count of zero', () => {
|
|
139
|
+
const examples = composeActionExamples(mockActions, 0);
|
|
140
|
+
expect(examples).toBe('');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should handle negative count', () => {
|
|
144
|
+
const examples = composeActionExamples(mockActions, -5);
|
|
145
|
+
expect(examples).toBe('');
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('formatActionNames', () => {
|
|
150
|
+
it('should format action names correctly', () => {
|
|
151
|
+
const formatted = formatActionNames([mockActions[0], mockActions[1]]);
|
|
152
|
+
expect(formatted).toMatch(/^(greet|farewell)(, (greet|farewell))?$/);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should handle single action', () => {
|
|
156
|
+
const formatted = formatActionNames([mockActions[0]]);
|
|
157
|
+
expect(formatted).toBe('greet');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should handle empty actions array', () => {
|
|
161
|
+
const formatted = formatActionNames([]);
|
|
162
|
+
expect(formatted).toBe('');
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('formatActions', () => {
|
|
167
|
+
it('should format actions with descriptions', () => {
|
|
168
|
+
const formatted = formatActions([mockActions[0]]);
|
|
169
|
+
expect(formatted).toBe('- **greet**: Greet someone');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should include commas and newlines between multiple actions', () => {
|
|
173
|
+
const formatted = formatActions([mockActions[0], mockActions[1]]);
|
|
174
|
+
const parts = formatted.split('\n');
|
|
175
|
+
expect(parts.length).toBe(2);
|
|
176
|
+
expect(parts[0]).toMatch(/^- \*\*(greet|farewell)\*\*: /);
|
|
177
|
+
expect(parts[1]).toMatch(/^- \*\*(greet|farewell)\*\*: /);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should handle empty actions array', () => {
|
|
181
|
+
const formatted = formatActions([]);
|
|
182
|
+
expect(formatted).toBe('');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('Action Structure', () => {
|
|
187
|
+
it('should validate action structure', () => {
|
|
188
|
+
for (const action of mockActions) {
|
|
189
|
+
expect(action).toHaveProperty('name');
|
|
190
|
+
expect(action).toHaveProperty('description');
|
|
191
|
+
expect(action).toHaveProperty('examples');
|
|
192
|
+
expect(action).toHaveProperty('similes');
|
|
193
|
+
expect(action).toHaveProperty('handler');
|
|
194
|
+
expect(action).toHaveProperty('validate');
|
|
195
|
+
expect(Array.isArray(action.examples)).toBe(true);
|
|
196
|
+
expect(Array.isArray(action.similes)).toBe(true);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should validate example structure', () => {
|
|
201
|
+
for (const action of mockActions) {
|
|
202
|
+
for (const example of action.examples ?? []) {
|
|
203
|
+
for (const message of example) {
|
|
204
|
+
expect(message).toHaveProperty('name');
|
|
205
|
+
expect(message).toHaveProperty('content');
|
|
206
|
+
expect(message.content).toHaveProperty('text');
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('should have unique action names', () => {
|
|
213
|
+
const names = mockActions.map((action) => action.name);
|
|
214
|
+
const uniqueNames = new Set(names);
|
|
215
|
+
expect(names.length).toBe(uniqueNames.size);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
});
|