@elizaos/cli 1.3.0 → 1.3.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/README.md +1 -1
- package/dist/{chunk-2CUIHNPL.js → chunk-5GUS4CFO.js} +7 -2
- package/dist/{chunk-2ALAPQLV.js → chunk-E6XYTE3A.js} +296 -311
- package/dist/chunk-GXWWPFBO.js +39 -0
- package/dist/{chunk-I77ZRNYO.js → chunk-T2QDIXGU.js} +2 -2
- package/dist/commands/agent/actions/index.d.ts +5 -0
- package/dist/commands/agent/actions/index.js +2 -2
- package/dist/commands/agent/index.d.ts +2 -2
- package/dist/commands/agent/index.js +2 -2
- package/dist/commands/create/actions/index.js +3 -3
- package/dist/commands/create/index.js +4 -4
- package/dist/commands/shared/index.d.ts +11 -28
- package/dist/commands/shared/index.js +7 -3
- package/dist/index.js +541 -450
- package/dist/{registry-N626N4VG.js → registry-433S5F3Y.js} +2 -2
- package/dist/templates/plugin-quick-starter/.gitignore +66 -0
- package/dist/templates/plugin-quick-starter/.npmignore +5 -0
- package/dist/templates/plugin-quick-starter/package.json +11 -3
- package/dist/templates/plugin-quick-starter/src/__tests__/plugin.test.ts +499 -146
- package/dist/templates/plugin-quick-starter/src/__tests__/test-utils.ts +316 -115
- package/dist/templates/plugin-quick-starter/src/plugin.ts +7 -13
- package/dist/templates/plugin-starter/.gitignore +66 -0
- package/dist/templates/plugin-starter/.npmignore +5 -0
- package/dist/templates/plugin-starter/README.md +1 -1
- package/dist/templates/plugin-starter/package.json +11 -3
- package/dist/templates/plugin-starter/src/__tests__/integration.test.ts +13 -13
- package/dist/templates/plugin-starter/src/__tests__/plugin.test.ts +556 -129
- package/dist/templates/plugin-starter/src/__tests__/test-utils.ts +347 -115
- package/dist/templates/plugin-starter/src/plugin.ts +18 -22
- package/dist/templates/project-starter/.gitignore +57 -0
- package/dist/templates/project-starter/.npmignore +11 -0
- package/dist/templates/project-starter/README.md +1 -1
- package/dist/templates/project-starter/package.json +4 -4
- package/dist/templates/project-starter/src/__tests__/env.test.ts +3 -1
- package/dist/templates/project-starter/src/__tests__/file-structure.test.ts +3 -2
- package/dist/templates/project-starter/src/__tests__/integration.test.ts +1 -1
- package/dist/templates/project-starter/tsup.config.ts +2 -1
- package/dist/templates/project-tee-starter/.dockerignore +64 -14
- package/dist/templates/project-tee-starter/.gitignore +57 -0
- package/dist/templates/project-tee-starter/.npmignore +6 -0
- package/dist/templates/project-tee-starter/Dockerfile +9 -5
- package/dist/templates/project-tee-starter/GUIDE.md +103 -42
- package/dist/templates/project-tee-starter/README.md +39 -19
- package/dist/templates/project-tee-starter/__tests__/build-order.test.ts +62 -0
- package/dist/templates/project-tee-starter/__tests__/character.test.ts +19 -17
- package/dist/templates/project-tee-starter/__tests__/config.test.ts +10 -3
- package/dist/templates/project-tee-starter/__tests__/env.test.ts +2 -1
- package/dist/templates/project-tee-starter/__tests__/file-structure.test.ts +14 -3
- package/dist/templates/project-tee-starter/__tests__/frontend.test.ts +459 -0
- package/dist/templates/project-tee-starter/__tests__/plugin.test.ts +4 -2
- package/dist/templates/project-tee-starter/__tests__/routes.test.ts +15 -6
- package/dist/templates/project-tee-starter/__tests__/tee-validation.test.ts +295 -0
- package/dist/templates/project-tee-starter/__tests__/vite-config-utils.ts +39 -0
- package/dist/templates/project-tee-starter/docker-compose.yaml +5 -2
- package/dist/templates/{plugin-starter/dist → project-tee-starter}/index.html +3 -3
- package/dist/templates/project-tee-starter/package.json +34 -14
- package/dist/templates/project-tee-starter/postcss.config.js +3 -0
- package/dist/templates/project-tee-starter/scripts/install-test-deps.js +52 -0
- package/dist/templates/project-tee-starter/scripts/test-all.sh +82 -0
- package/dist/templates/project-tee-starter/src/frontend/index.css +106 -0
- package/dist/templates/project-tee-starter/src/frontend/index.html +20 -0
- package/dist/templates/project-tee-starter/src/frontend/index.tsx +370 -0
- package/dist/templates/project-tee-starter/src/frontend/panels.tsx +17 -0
- package/dist/templates/project-tee-starter/src/frontend/utils.ts +6 -0
- package/dist/templates/project-tee-starter/src/index.ts +6 -6
- package/dist/templates/project-tee-starter/src/plugin.ts +209 -59
- package/dist/templates/project-tee-starter/tailwind.config.js +62 -0
- package/dist/templates/project-tee-starter/tsconfig.build.json +2 -2
- package/dist/templates/project-tee-starter/tsconfig.json +8 -5
- package/dist/templates/project-tee-starter/tsup.config.ts +3 -2
- package/dist/templates/project-tee-starter/vite.config.ts +39 -0
- package/dist/url-utils-CKc_Ebt_.d.ts +35 -0
- package/dist/{utils-H66532NB.js → utils-DBLSDYBF.js} +2 -2
- package/package.json +12 -7
- package/templates/plugin-quick-starter/.gitignore +66 -0
- package/templates/plugin-quick-starter/.npmignore +5 -0
- package/templates/plugin-quick-starter/package.json +11 -3
- package/templates/plugin-quick-starter/src/__tests__/plugin.test.ts +499 -146
- package/templates/plugin-quick-starter/src/__tests__/test-utils.ts +316 -115
- package/templates/plugin-quick-starter/src/plugin.ts +7 -13
- package/templates/plugin-starter/.gitignore +66 -0
- package/templates/plugin-starter/.npmignore +5 -0
- package/templates/plugin-starter/README.md +1 -1
- package/templates/plugin-starter/package.json +11 -3
- package/templates/plugin-starter/src/__tests__/integration.test.ts +13 -13
- package/templates/plugin-starter/src/__tests__/plugin.test.ts +556 -129
- package/templates/plugin-starter/src/__tests__/test-utils.ts +347 -115
- package/templates/plugin-starter/src/plugin.ts +18 -22
- package/templates/project-starter/.gitignore +57 -0
- package/templates/project-starter/.npmignore +11 -0
- package/templates/project-starter/README.md +1 -1
- package/templates/project-starter/package.json +4 -4
- package/templates/project-starter/src/__tests__/env.test.ts +3 -1
- package/templates/project-starter/src/__tests__/file-structure.test.ts +3 -2
- package/templates/project-starter/src/__tests__/integration.test.ts +1 -1
- package/templates/project-starter/tsup.config.ts +2 -1
- package/templates/project-tee-starter/.dockerignore +64 -14
- package/templates/project-tee-starter/.gitignore +57 -0
- package/templates/project-tee-starter/.npmignore +6 -0
- package/templates/project-tee-starter/Dockerfile +9 -5
- package/templates/project-tee-starter/GUIDE.md +103 -42
- package/templates/project-tee-starter/README.md +39 -19
- package/templates/project-tee-starter/__tests__/build-order.test.ts +62 -0
- package/templates/project-tee-starter/__tests__/character.test.ts +19 -17
- package/templates/project-tee-starter/__tests__/config.test.ts +10 -3
- package/templates/project-tee-starter/__tests__/env.test.ts +2 -1
- package/templates/project-tee-starter/__tests__/file-structure.test.ts +14 -3
- package/templates/project-tee-starter/__tests__/frontend.test.ts +459 -0
- package/templates/project-tee-starter/__tests__/plugin.test.ts +4 -2
- package/templates/project-tee-starter/__tests__/routes.test.ts +15 -6
- package/templates/project-tee-starter/__tests__/tee-validation.test.ts +295 -0
- package/templates/project-tee-starter/__tests__/vite-config-utils.ts +39 -0
- package/templates/project-tee-starter/docker-compose.yaml +5 -2
- package/templates/{plugin-starter/dist → project-tee-starter}/index.html +3 -3
- package/templates/project-tee-starter/package.json +34 -14
- package/templates/project-tee-starter/postcss.config.js +3 -0
- package/templates/project-tee-starter/scripts/install-test-deps.js +52 -0
- package/templates/project-tee-starter/scripts/test-all.sh +82 -0
- package/templates/project-tee-starter/src/frontend/index.css +106 -0
- package/templates/project-tee-starter/src/frontend/index.html +20 -0
- package/templates/project-tee-starter/src/frontend/index.tsx +370 -0
- package/templates/project-tee-starter/src/frontend/panels.tsx +17 -0
- package/templates/project-tee-starter/src/frontend/utils.ts +6 -0
- package/templates/project-tee-starter/src/index.ts +6 -6
- package/templates/project-tee-starter/src/plugin.ts +209 -59
- package/templates/project-tee-starter/tailwind.config.js +62 -0
- package/templates/project-tee-starter/tsconfig.build.json +2 -2
- package/templates/project-tee-starter/tsconfig.json +8 -5
- package/templates/project-tee-starter/tsup.config.ts +3 -2
- package/templates/project-tee-starter/vite.config.ts +39 -0
- package/dist/chunk-4O6EZU37.js +0 -14
- package/dist/migration-guides/advanced-migration-guide.md +0 -459
- package/dist/migration-guides/completion-requirements.md +0 -379
- package/dist/migration-guides/integrated-migration-loop.md +0 -392
- package/dist/migration-guides/migration-guide.md +0 -712
- package/dist/migration-guides/prompt-and-generation-guide.md +0 -702
- package/dist/migration-guides/state-and-providers-guide.md +0 -544
- package/dist/migration-guides/testing-guide.md +0 -1021
- package/dist/templates/plugin-starter/dist/assets/index-CgkejLs_.css +0 -1
- package/dist/templates/plugin-starter/dist/assets/index-D1cHX53P.js +0 -49
- package/dist/templates/plugin-starter/dist/index.js +0 -387
- package/dist/templates/plugin-starter/dist/index.js.map +0 -1
- package/templates/plugin-starter/dist/.vite/manifest.json +0 -11
- package/templates/plugin-starter/dist/assets/index-CgkejLs_.css +0 -1
- package/templates/plugin-starter/dist/assets/index-D1cHX53P.js +0 -49
- package/templates/plugin-starter/dist/index.d.ts +0 -14
- package/templates/plugin-starter/dist/index.js +0 -387
- package/templates/plugin-starter/dist/index.js.map +0 -1
|
@@ -1,182 +1,609 @@
|
|
|
1
1
|
import { describe, expect, it, spyOn, beforeEach, afterEach, beforeAll, afterAll } from 'bun:test';
|
|
2
2
|
import { starterPlugin, StarterService } from '../index';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type IAgentRuntime,
|
|
5
|
+
type Memory,
|
|
6
|
+
type State,
|
|
7
|
+
type Content,
|
|
8
|
+
type HandlerCallback,
|
|
9
|
+
EventType,
|
|
10
|
+
type MessagePayload,
|
|
11
|
+
type WorldPayload,
|
|
12
|
+
type UUID,
|
|
13
|
+
ModelType,
|
|
14
|
+
logger,
|
|
15
|
+
} from '@elizaos/core';
|
|
4
16
|
import dotenv from 'dotenv';
|
|
17
|
+
import { z } from 'zod';
|
|
18
|
+
import {
|
|
19
|
+
createMockRuntime,
|
|
20
|
+
createTestMemory,
|
|
21
|
+
createTestState,
|
|
22
|
+
createUUID,
|
|
23
|
+
testFixtures,
|
|
24
|
+
assertSpyCalledWith,
|
|
25
|
+
} from './test-utils';
|
|
5
26
|
|
|
6
27
|
// Setup environment variables
|
|
7
28
|
dotenv.config();
|
|
8
29
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
30
|
+
describe('Plugin Configuration', () => {
|
|
31
|
+
it('should have correct plugin metadata', () => {
|
|
32
|
+
// Check that plugin has required metadata (values will change when template is used)
|
|
33
|
+
expect(starterPlugin.name).toBeDefined();
|
|
34
|
+
expect(starterPlugin.name).toMatch(/^[a-z0-9-]+$/); // Valid plugin name format
|
|
35
|
+
expect(starterPlugin.description).toBeDefined();
|
|
36
|
+
expect(starterPlugin.description.length).toBeGreaterThan(0);
|
|
37
|
+
expect(starterPlugin.actions).toBeDefined();
|
|
38
|
+
expect(starterPlugin.actions?.length).toBeGreaterThan(0);
|
|
39
|
+
expect(starterPlugin.providers).toBeDefined();
|
|
40
|
+
expect(starterPlugin.providers?.length).toBeGreaterThan(0);
|
|
41
|
+
expect(starterPlugin.services).toBeDefined();
|
|
42
|
+
expect(starterPlugin.services?.length).toBeGreaterThan(0);
|
|
43
|
+
expect(starterPlugin.models).toBeDefined();
|
|
44
|
+
expect(starterPlugin.models?.[ModelType.TEXT_SMALL]).toBeDefined();
|
|
45
|
+
expect(starterPlugin.models?.[ModelType.TEXT_LARGE]).toBeDefined();
|
|
46
|
+
expect(starterPlugin.routes).toBeDefined();
|
|
47
|
+
expect(starterPlugin.routes?.length).toBeGreaterThan(0);
|
|
48
|
+
expect(starterPlugin.events).toBeDefined();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should initialize with valid configuration', async () => {
|
|
52
|
+
const runtime = createMockRuntime();
|
|
53
|
+
const config = { EXAMPLE_PLUGIN_VARIABLE: 'test-value' };
|
|
54
|
+
|
|
55
|
+
if (starterPlugin.init) {
|
|
56
|
+
await starterPlugin.init(config, runtime);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Note: registerService is not called in init, services are registered later
|
|
60
|
+
// This is handled by the runtime during plugin loading
|
|
61
|
+
expect(process.env.EXAMPLE_PLUGIN_VARIABLE).toBe('test-value');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should handle initialization without config', async () => {
|
|
65
|
+
const runtime = createMockRuntime();
|
|
66
|
+
|
|
67
|
+
if (starterPlugin.init) {
|
|
68
|
+
// Init should not throw even with empty config
|
|
69
|
+
await starterPlugin.init({}, runtime);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should throw error for invalid configuration', async () => {
|
|
74
|
+
const runtime = createMockRuntime({
|
|
75
|
+
getSetting: () => 'invalid-json',
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const zodError = new z.ZodError([
|
|
79
|
+
{
|
|
80
|
+
code: 'invalid_type',
|
|
81
|
+
expected: 'object',
|
|
82
|
+
received: 'string',
|
|
83
|
+
path: [],
|
|
84
|
+
message: 'Expected object, received string',
|
|
85
|
+
},
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
if (starterPlugin.init) {
|
|
89
|
+
// The init function validates the config but doesn't throw for invalid JSON in getSetting
|
|
90
|
+
// It only validates the config passed to init
|
|
91
|
+
await starterPlugin.init({}, runtime);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
15
94
|
});
|
|
16
95
|
|
|
17
|
-
|
|
18
|
-
|
|
96
|
+
describe('Hello World Action', () => {
|
|
97
|
+
let runtime: IAgentRuntime;
|
|
98
|
+
const helloWorldAction = starterPlugin.actions?.[0];
|
|
99
|
+
|
|
100
|
+
beforeEach(() => {
|
|
101
|
+
runtime = createMockRuntime();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should have hello world action', () => {
|
|
105
|
+
expect(helloWorldAction).toBeDefined();
|
|
106
|
+
expect(helloWorldAction?.name).toBe('HELLO_WORLD');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should always validate messages (current implementation)', async () => {
|
|
110
|
+
if (!helloWorldAction?.validate) {
|
|
111
|
+
throw new Error('Hello world action validate not found');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// The simple implementation always returns true
|
|
115
|
+
const testCases = [
|
|
116
|
+
{ text: 'say hello', expected: true },
|
|
117
|
+
{ text: 'hello world', expected: true },
|
|
118
|
+
{ text: 'goodbye', expected: true },
|
|
119
|
+
{ text: '', expected: true },
|
|
120
|
+
{ text: ' ', expected: true },
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
for (const { text, expected } of testCases) {
|
|
124
|
+
const message = createTestMemory({
|
|
125
|
+
content: { text, source: 'test' },
|
|
126
|
+
});
|
|
127
|
+
const isValid = await helloWorldAction.validate(runtime, message);
|
|
128
|
+
expect(isValid).toBe(expected);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should validate even without text content', async () => {
|
|
133
|
+
if (!helloWorldAction?.validate) {
|
|
134
|
+
throw new Error('Hello world action validate not found');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const messageWithoutText = createTestMemory({
|
|
138
|
+
content: { source: 'test' } as Content,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const isValid = await helloWorldAction.validate(runtime, messageWithoutText);
|
|
142
|
+
// Always returns true in simple implementation
|
|
143
|
+
expect(isValid).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should properly validate hello messages', async () => {
|
|
147
|
+
if (!helloWorldAction?.validate) {
|
|
148
|
+
throw new Error('Hello world action validate not found');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Test that it accepts hello-related keywords
|
|
152
|
+
const helloMessages = ['hello', 'hi there', 'hey!', 'greetings', 'howdy partner'];
|
|
153
|
+
for (const text of helloMessages) {
|
|
154
|
+
const message = createTestMemory({
|
|
155
|
+
content: { text, source: 'test' },
|
|
156
|
+
});
|
|
157
|
+
const isValid = await helloWorldAction.validate(runtime, message);
|
|
158
|
+
expect(isValid).toBe(true);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Test that it accepts all messages (simple implementation)
|
|
162
|
+
const nonHelloMessages = ['goodbye', 'what is the weather', 'tell me a joke', ''];
|
|
163
|
+
for (const text of nonHelloMessages) {
|
|
164
|
+
const message = createTestMemory({
|
|
165
|
+
content: { text, source: 'test' },
|
|
166
|
+
});
|
|
167
|
+
const isValid = await helloWorldAction.validate(runtime, message);
|
|
168
|
+
expect(isValid).toBe(true);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should handle hello world action with callback', async () => {
|
|
173
|
+
if (!helloWorldAction?.handler) {
|
|
174
|
+
throw new Error('Hello world action handler not found');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const message = createTestMemory({
|
|
178
|
+
content: { text: 'say hello', source: 'test' },
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
let callbackContent: any = null;
|
|
182
|
+
const callback: HandlerCallback = async (content: Content) => {
|
|
183
|
+
callbackContent = content;
|
|
184
|
+
return [];
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const result = await helloWorldAction.handler(runtime, message, undefined, undefined, callback);
|
|
188
|
+
|
|
189
|
+
// The action returns a simple greeting
|
|
190
|
+
expect(result).toHaveProperty('text', 'Hello world!');
|
|
191
|
+
expect(result).toHaveProperty('success', true);
|
|
192
|
+
expect(result).toHaveProperty('data');
|
|
193
|
+
expect((result as any).data).toHaveProperty('actions', ['HELLO_WORLD']);
|
|
194
|
+
expect((result as any).data).toHaveProperty('source', 'test');
|
|
195
|
+
|
|
196
|
+
// Callback should receive the same greeting
|
|
197
|
+
expect(callbackContent).toBeDefined();
|
|
198
|
+
expect(callbackContent.text).toBe('Hello world!');
|
|
199
|
+
expect(callbackContent.actions).toEqual(['HELLO_WORLD']);
|
|
200
|
+
expect(callbackContent.source).toBe('test');
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should handle errors gracefully', async () => {
|
|
204
|
+
if (!helloWorldAction?.handler) {
|
|
205
|
+
throw new Error('Hello world action handler not found');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const message = createTestMemory({
|
|
209
|
+
content: { text: 'say hello', source: 'test' },
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const errorCallback: HandlerCallback = async () => {
|
|
213
|
+
throw new Error('Callback error');
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const result = await helloWorldAction.handler(
|
|
217
|
+
runtime,
|
|
218
|
+
message,
|
|
219
|
+
undefined,
|
|
220
|
+
undefined,
|
|
221
|
+
errorCallback
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
expect(result).toHaveProperty('success', false);
|
|
225
|
+
expect(result).toHaveProperty('error');
|
|
226
|
+
expect((result as any).error?.message).toBe('Callback error');
|
|
227
|
+
// Logger is mocked but not set up as a spy in runtime
|
|
228
|
+
expect(logger.error).toHaveBeenCalled();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should handle missing callback gracefully', async () => {
|
|
232
|
+
if (!helloWorldAction?.handler) {
|
|
233
|
+
throw new Error('Hello world action handler not found');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const message = createTestMemory({
|
|
237
|
+
content: { text: 'say hello', source: 'test' },
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const result = await helloWorldAction.handler(
|
|
241
|
+
runtime,
|
|
242
|
+
message,
|
|
243
|
+
undefined,
|
|
244
|
+
undefined,
|
|
245
|
+
undefined
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
// The action returns a simple greeting
|
|
249
|
+
expect(result).toHaveProperty('text', 'Hello world!');
|
|
250
|
+
expect(result).toHaveProperty('success', true);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('should handle state parameter correctly', async () => {
|
|
254
|
+
if (!helloWorldAction?.handler) {
|
|
255
|
+
throw new Error('Hello world action handler not found');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const message = createTestMemory({
|
|
259
|
+
content: { text: 'say hello', source: 'test' },
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
const state = createTestState({
|
|
263
|
+
values: { customValue: 'test-state' },
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const result = await helloWorldAction.handler(runtime, message, state, undefined, undefined);
|
|
267
|
+
|
|
268
|
+
expect(result).toHaveProperty('success', true);
|
|
269
|
+
});
|
|
19
270
|
});
|
|
20
271
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// Create a real service instance if needed
|
|
26
|
-
const createService = (serviceType: string) => {
|
|
27
|
-
if (serviceType === StarterService.serviceType) {
|
|
28
|
-
return new StarterService({
|
|
29
|
-
character: {
|
|
30
|
-
name: 'Test Character',
|
|
31
|
-
system: 'You are a helpful assistant for testing.',
|
|
32
|
-
},
|
|
33
|
-
} as any);
|
|
34
|
-
}
|
|
35
|
-
return null;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
character: {
|
|
40
|
-
name: 'Test Character',
|
|
41
|
-
system: 'You are a helpful assistant for testing.',
|
|
42
|
-
plugins: [],
|
|
43
|
-
settings: {},
|
|
44
|
-
},
|
|
45
|
-
getSetting: (key: string) => null,
|
|
46
|
-
models: starterPlugin.models,
|
|
47
|
-
db: {
|
|
48
|
-
get: async (key: string) => null,
|
|
49
|
-
set: async (key: string, value: any) => true,
|
|
50
|
-
delete: async (key: string) => true,
|
|
51
|
-
getKeys: async (pattern: string) => [],
|
|
52
|
-
},
|
|
53
|
-
getService: (serviceType: string) => {
|
|
54
|
-
// Log the service request for debugging
|
|
55
|
-
logger.debug(`Requesting service: ${serviceType}`);
|
|
56
|
-
|
|
57
|
-
// Get from cache or create new
|
|
58
|
-
if (!services.has(serviceType)) {
|
|
59
|
-
logger.debug(`Creating new service: ${serviceType}`);
|
|
60
|
-
services.set(serviceType, createService(serviceType));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return services.get(serviceType);
|
|
64
|
-
},
|
|
65
|
-
registerService: (serviceType: string, service: any) => {
|
|
66
|
-
logger.debug(`Registering service: ${serviceType}`);
|
|
67
|
-
services.set(serviceType, service);
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
}
|
|
272
|
+
describe('Hello World Provider', () => {
|
|
273
|
+
const provider = starterPlugin.providers?.[0];
|
|
274
|
+
let runtime: IAgentRuntime;
|
|
71
275
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
expect(starterPlugin.name).toBe('plugin-starter');
|
|
75
|
-
expect(starterPlugin.description).toBe('Plugin starter for elizaOS');
|
|
76
|
-
expect(starterPlugin.config).toBeDefined();
|
|
276
|
+
beforeEach(() => {
|
|
277
|
+
runtime = createMockRuntime();
|
|
77
278
|
});
|
|
78
279
|
|
|
79
|
-
it('should
|
|
80
|
-
expect(
|
|
280
|
+
it('should have hello world provider', () => {
|
|
281
|
+
expect(provider).toBeDefined();
|
|
282
|
+
expect(provider?.name).toBe('HELLO_WORLD_PROVIDER');
|
|
81
283
|
});
|
|
82
284
|
|
|
83
|
-
it('should
|
|
84
|
-
|
|
285
|
+
it('should provide hello world data', async () => {
|
|
286
|
+
if (!provider?.get) {
|
|
287
|
+
throw new Error('Hello world provider not found');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const message = createTestMemory();
|
|
291
|
+
const state = createTestState();
|
|
85
292
|
|
|
86
|
-
|
|
87
|
-
process.env.EXAMPLE_PLUGIN_VARIABLE = 'test-value';
|
|
293
|
+
const result = await provider.get(runtime, message, state);
|
|
88
294
|
|
|
89
|
-
|
|
90
|
-
|
|
295
|
+
expect(result).toHaveProperty('text', 'I am a provider');
|
|
296
|
+
expect(result).toHaveProperty('data');
|
|
297
|
+
expect(result).toHaveProperty('values');
|
|
298
|
+
expect(result.data).toEqual({});
|
|
299
|
+
expect(result.values).toEqual({});
|
|
300
|
+
});
|
|
91
301
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
} finally {
|
|
97
|
-
process.env.EXAMPLE_PLUGIN_VARIABLE = originalEnv;
|
|
302
|
+
it('should provide consistent structure across calls', async () => {
|
|
303
|
+
if (!provider?.get) {
|
|
304
|
+
throw new Error('Hello world provider not found');
|
|
98
305
|
}
|
|
306
|
+
|
|
307
|
+
const message = createTestMemory();
|
|
308
|
+
const state = createTestState();
|
|
309
|
+
|
|
310
|
+
const result1 = await provider.get(runtime, message, state);
|
|
311
|
+
const result2 = await provider.get(runtime, message, state);
|
|
312
|
+
|
|
313
|
+
// Simple provider returns consistent static results
|
|
314
|
+
expect(result1.text).toBe('I am a provider');
|
|
315
|
+
expect(result2.text).toBe('I am a provider');
|
|
316
|
+
expect(result1.data).toEqual({});
|
|
317
|
+
expect(result2.data).toEqual({});
|
|
318
|
+
expect(result1.values).toEqual({});
|
|
319
|
+
expect(result2.values).toEqual({});
|
|
99
320
|
});
|
|
100
321
|
|
|
101
|
-
it('should
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// Check if the config has expected EXAMPLE_PLUGIN_VARIABLE property
|
|
105
|
-
expect(Object.keys(starterPlugin.config)).toContain('EXAMPLE_PLUGIN_VARIABLE');
|
|
322
|
+
it('should handle different input states', async () => {
|
|
323
|
+
if (!provider?.get) {
|
|
324
|
+
throw new Error('Hello world provider not found');
|
|
106
325
|
}
|
|
326
|
+
|
|
327
|
+
const message = createTestMemory({ content: { text: 'different message' } });
|
|
328
|
+
const customState = createTestState({
|
|
329
|
+
values: { custom: 'value' },
|
|
330
|
+
data: { custom: 'data' },
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
const result = await provider.get(runtime, message, customState);
|
|
334
|
+
|
|
335
|
+
// Provider output is static in simple implementation
|
|
336
|
+
expect(result.text).toBe('I am a provider');
|
|
337
|
+
expect(result.data).toEqual({});
|
|
338
|
+
expect(result.values).toEqual({});
|
|
107
339
|
});
|
|
108
340
|
});
|
|
109
341
|
|
|
110
|
-
describe('
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
342
|
+
describe('Model Handlers', () => {
|
|
343
|
+
let runtime: IAgentRuntime;
|
|
344
|
+
|
|
345
|
+
beforeEach(() => {
|
|
346
|
+
runtime = createMockRuntime();
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it('should handle TEXT_SMALL model', async () => {
|
|
350
|
+
const handler = starterPlugin.models?.[ModelType.TEXT_SMALL];
|
|
351
|
+
if (!handler) {
|
|
352
|
+
throw new Error('TEXT_SMALL model handler not found');
|
|
115
353
|
}
|
|
354
|
+
|
|
355
|
+
const result = await handler(
|
|
356
|
+
{
|
|
357
|
+
params: {
|
|
358
|
+
prompt: 'Test prompt',
|
|
359
|
+
temperature: 0.7,
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
runtime
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
expect(result).toContain('Never gonna give you up');
|
|
116
366
|
});
|
|
117
367
|
|
|
118
|
-
it('should
|
|
119
|
-
|
|
120
|
-
if (
|
|
121
|
-
|
|
368
|
+
it('should handle TEXT_LARGE model with custom parameters', async () => {
|
|
369
|
+
const handler = starterPlugin.models?.[ModelType.TEXT_LARGE];
|
|
370
|
+
if (!handler) {
|
|
371
|
+
throw new Error('TEXT_LARGE model handler not found');
|
|
122
372
|
}
|
|
373
|
+
|
|
374
|
+
const result = await handler(
|
|
375
|
+
{
|
|
376
|
+
params: {
|
|
377
|
+
prompt: 'Test prompt with custom settings',
|
|
378
|
+
temperature: 0.9,
|
|
379
|
+
maxTokens: 500,
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
runtime
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
expect(result).toContain('Never gonna make you cry');
|
|
123
386
|
});
|
|
124
387
|
|
|
125
|
-
it('should
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
388
|
+
it('should handle empty prompt', async () => {
|
|
389
|
+
const handler = starterPlugin.models?.[ModelType.TEXT_SMALL];
|
|
390
|
+
if (!handler) {
|
|
391
|
+
throw new Error('TEXT_SMALL model handler not found');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const result = await handler(
|
|
395
|
+
{
|
|
396
|
+
params: {
|
|
397
|
+
prompt: '',
|
|
398
|
+
temperature: 0.7,
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
runtime
|
|
402
|
+
);
|
|
131
403
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
404
|
+
expect(typeof result).toBe('string');
|
|
405
|
+
expect(result.length).toBeGreaterThan(0);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('should handle missing parameters', async () => {
|
|
409
|
+
const handler = starterPlugin.models?.[ModelType.TEXT_LARGE];
|
|
410
|
+
if (!handler) {
|
|
411
|
+
throw new Error('TEXT_LARGE model handler not found');
|
|
136
412
|
}
|
|
413
|
+
|
|
414
|
+
const result = await handler(
|
|
415
|
+
{
|
|
416
|
+
params: {
|
|
417
|
+
prompt: 'Test prompt',
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
runtime
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
expect(typeof result).toBe('string');
|
|
424
|
+
expect(result.length).toBeGreaterThan(0);
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
describe('API Routes', () => {
|
|
429
|
+
let runtime: IAgentRuntime;
|
|
430
|
+
|
|
431
|
+
beforeEach(() => {
|
|
432
|
+
runtime = createMockRuntime();
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('should handle hello world route', async () => {
|
|
436
|
+
const helloRoute = starterPlugin.routes?.find((r) => r.name === 'hello-world-route');
|
|
437
|
+
if (!helloRoute?.handler) {
|
|
438
|
+
throw new Error('Hello world route handler not found');
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const mockRes = {
|
|
442
|
+
json: (data: any) => {
|
|
443
|
+
mockRes._jsonData = data;
|
|
444
|
+
},
|
|
445
|
+
_jsonData: null as any,
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
await helloRoute.handler({}, mockRes, runtime);
|
|
449
|
+
|
|
450
|
+
expect(mockRes._jsonData).toBeDefined();
|
|
451
|
+
expect(mockRes._jsonData.message).toBe('Hello World!');
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
it('should validate route configuration', () => {
|
|
455
|
+
const helloRoute = starterPlugin.routes?.find((r) => r.name === 'hello-world-route');
|
|
456
|
+
|
|
457
|
+
expect(helloRoute).toBeDefined();
|
|
458
|
+
expect(helloRoute?.path).toBe('/helloworld');
|
|
459
|
+
expect(helloRoute?.type).toBe('GET');
|
|
460
|
+
// Routes don't have a public property in the current implementation
|
|
461
|
+
expect(helloRoute?.handler).toBeDefined();
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it('should handle request with query parameters', async () => {
|
|
465
|
+
const helloRoute = starterPlugin.routes?.find((r) => r.name === 'hello-world-route');
|
|
466
|
+
if (!helloRoute?.handler) {
|
|
467
|
+
throw new Error('Hello world route handler not found');
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
const mockReq = {
|
|
471
|
+
query: {
|
|
472
|
+
name: 'Test User',
|
|
473
|
+
},
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
const mockRes = {
|
|
477
|
+
json: (data: any) => {
|
|
478
|
+
mockRes._jsonData = data;
|
|
479
|
+
},
|
|
480
|
+
_jsonData: null as any,
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
await helloRoute.handler(mockReq, mockRes, runtime);
|
|
484
|
+
|
|
485
|
+
expect(mockRes._jsonData).toBeDefined();
|
|
486
|
+
expect(mockRes._jsonData.message).toBe('Hello World!');
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
describe('Event Handlers', () => {
|
|
491
|
+
beforeEach(() => {
|
|
492
|
+
// Clear logger spy calls
|
|
493
|
+
(logger.debug as any).calls = [];
|
|
494
|
+
(logger.info as any).calls = [];
|
|
495
|
+
(logger.error as any).calls = [];
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
it('should log when MESSAGE_RECEIVED event is triggered', async () => {
|
|
499
|
+
const handler = starterPlugin.events?.[EventType.MESSAGE_RECEIVED]?.[0];
|
|
500
|
+
if (!handler) {
|
|
501
|
+
throw new Error('MESSAGE_RECEIVED event handler not found');
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const payload = testFixtures.messagePayload();
|
|
505
|
+
await handler(payload);
|
|
506
|
+
|
|
507
|
+
expect(logger.debug).toHaveBeenCalled();
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
it('should handle malformed event payload', async () => {
|
|
511
|
+
const handler = starterPlugin.events?.[EventType.MESSAGE_RECEIVED]?.[0];
|
|
512
|
+
if (!handler) {
|
|
513
|
+
throw new Error('MESSAGE_RECEIVED event handler not found');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const malformedPayload = {
|
|
517
|
+
// Missing required fields
|
|
518
|
+
runtime: createMockRuntime(),
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
// Should not throw
|
|
522
|
+
// Handler doesn't actually use the payload, just logs
|
|
523
|
+
await handler(malformedPayload as any);
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('should handle event with empty message content', async () => {
|
|
527
|
+
const handler = starterPlugin.events?.[EventType.MESSAGE_RECEIVED]?.[0];
|
|
528
|
+
if (!handler) {
|
|
529
|
+
throw new Error('MESSAGE_RECEIVED event handler not found');
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const payload = testFixtures.messagePayload({
|
|
533
|
+
content: {},
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
await handler(payload);
|
|
537
|
+
expect(logger.debug).toHaveBeenCalled();
|
|
137
538
|
});
|
|
138
539
|
});
|
|
139
540
|
|
|
140
541
|
describe('StarterService', () => {
|
|
141
|
-
|
|
142
|
-
const runtime = createRealRuntime();
|
|
143
|
-
const startResult = await StarterService.start(runtime as any);
|
|
542
|
+
let runtime: IAgentRuntime;
|
|
144
543
|
|
|
145
|
-
|
|
146
|
-
|
|
544
|
+
beforeEach(() => {
|
|
545
|
+
runtime = createMockRuntime();
|
|
546
|
+
// Clear logger spy calls
|
|
547
|
+
(logger.info as any).calls = [];
|
|
548
|
+
(logger.error as any).calls = [];
|
|
549
|
+
});
|
|
147
550
|
|
|
148
|
-
|
|
149
|
-
|
|
551
|
+
it('should start the service', async () => {
|
|
552
|
+
const service = await StarterService.start(runtime);
|
|
553
|
+
expect(service).toBeInstanceOf(StarterService);
|
|
554
|
+
expect(logger.info).toHaveBeenCalled();
|
|
150
555
|
});
|
|
151
556
|
|
|
152
|
-
it('should
|
|
153
|
-
|
|
557
|
+
it('should have correct service type', () => {
|
|
558
|
+
expect(StarterService.serviceType).toBe('starter');
|
|
559
|
+
});
|
|
154
560
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
561
|
+
it('should stop service correctly', async () => {
|
|
562
|
+
// Start service
|
|
563
|
+
const service = await StarterService.start(runtime);
|
|
158
564
|
|
|
159
|
-
//
|
|
160
|
-
const
|
|
565
|
+
// Create a new runtime with the service registered
|
|
566
|
+
const runtimeWithService = createMockRuntime({
|
|
567
|
+
getService: () => service as any,
|
|
568
|
+
});
|
|
161
569
|
|
|
162
|
-
//
|
|
163
|
-
await StarterService.stop(
|
|
570
|
+
// Stop service
|
|
571
|
+
await StarterService.stop(runtimeWithService);
|
|
572
|
+
expect(logger.info).toHaveBeenCalled();
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
it('should throw error when stopping non-existent service', async () => {
|
|
576
|
+
const emptyRuntime = createMockRuntime({
|
|
577
|
+
getService: () => null,
|
|
578
|
+
});
|
|
164
579
|
|
|
165
|
-
|
|
166
|
-
expect(stopSpy).toHaveBeenCalled();
|
|
580
|
+
await expect(StarterService.stop(emptyRuntime)).rejects.toThrow('Starter service not found');
|
|
167
581
|
});
|
|
168
582
|
|
|
169
|
-
it('should
|
|
170
|
-
|
|
171
|
-
|
|
583
|
+
it('should handle multiple start/stop cycles', async () => {
|
|
584
|
+
// First cycle
|
|
585
|
+
const service1 = await StarterService.start(runtime);
|
|
586
|
+
expect(service1).toBeInstanceOf(StarterService);
|
|
172
587
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
588
|
+
const runtimeWithService1 = createMockRuntime({
|
|
589
|
+
getService: () => service1 as any,
|
|
590
|
+
});
|
|
591
|
+
await StarterService.stop(runtimeWithService1);
|
|
176
592
|
|
|
177
|
-
|
|
593
|
+
// Second cycle
|
|
594
|
+
const service2 = await StarterService.start(runtime);
|
|
595
|
+
expect(service2).toBeInstanceOf(StarterService);
|
|
596
|
+
|
|
597
|
+
const runtimeWithService2 = createMockRuntime({
|
|
598
|
+
getService: () => service2 as any,
|
|
599
|
+
});
|
|
600
|
+
await StarterService.stop(runtimeWithService2);
|
|
601
|
+
});
|
|
178
602
|
|
|
179
|
-
|
|
180
|
-
|
|
603
|
+
it('should provide capability description', async () => {
|
|
604
|
+
const service = await StarterService.start(runtime);
|
|
605
|
+
expect(service.capabilityDescription).toBe(
|
|
606
|
+
'This is a starter service which is attached to the agent through the starter plugin.'
|
|
607
|
+
);
|
|
181
608
|
});
|
|
182
609
|
});
|