@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,12 +1,28 @@
|
|
|
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
|
+
ModelType,
|
|
10
|
+
logger,
|
|
11
|
+
EventType,
|
|
12
|
+
} from '@elizaos/core';
|
|
4
13
|
import dotenv from 'dotenv';
|
|
14
|
+
import {
|
|
15
|
+
createMockRuntime,
|
|
16
|
+
createTestMemory,
|
|
17
|
+
createTestState,
|
|
18
|
+
createUUID,
|
|
19
|
+
testFixtures,
|
|
20
|
+
} from './test-utils';
|
|
5
21
|
|
|
6
22
|
// Setup environment variables
|
|
7
23
|
dotenv.config();
|
|
8
24
|
|
|
9
|
-
// Need to spy on logger
|
|
25
|
+
// Need to spy on logger
|
|
10
26
|
beforeAll(() => {
|
|
11
27
|
spyOn(logger, 'info');
|
|
12
28
|
spyOn(logger, 'error');
|
|
@@ -18,192 +34,529 @@ afterAll(() => {
|
|
|
18
34
|
// No global restore needed in bun:test
|
|
19
35
|
});
|
|
20
36
|
|
|
21
|
-
// Create a real runtime for testing
|
|
22
|
-
function createRealRuntime(): Partial<IAgentRuntime> {
|
|
23
|
-
const services = new Map<string, Service>();
|
|
24
|
-
|
|
25
|
-
// Create a real service instance if needed
|
|
26
|
-
const createService = (serviceType: string): Service | null => {
|
|
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 IAgentRuntime);
|
|
34
|
-
}
|
|
35
|
-
return null;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
character: {
|
|
40
|
-
name: 'Test Character',
|
|
41
|
-
system: 'You are a helpful assistant for testing.',
|
|
42
|
-
bio: 'A test character for unit testing',
|
|
43
|
-
plugins: [],
|
|
44
|
-
settings: {},
|
|
45
|
-
},
|
|
46
|
-
getSetting: (key: string) => null,
|
|
47
|
-
db: {
|
|
48
|
-
get: async (key: string) => null,
|
|
49
|
-
set: async (key: string, value: unknown) => true,
|
|
50
|
-
delete: async (key: string) => true,
|
|
51
|
-
getKeys: async (pattern: string) => [],
|
|
52
|
-
},
|
|
53
|
-
getService: <T extends Service>(serviceType: string): T | null => {
|
|
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
|
-
const service = createService(serviceType);
|
|
61
|
-
if (service) {
|
|
62
|
-
services.set(serviceType, service);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return (services.get(serviceType) as T) || null;
|
|
67
|
-
},
|
|
68
|
-
registerService: async (ServiceClass: typeof Service): Promise<void> => {
|
|
69
|
-
logger.debug(`Registering service: ${ServiceClass.serviceType}`);
|
|
70
|
-
const runtime = {
|
|
71
|
-
character: {
|
|
72
|
-
name: 'Test Character',
|
|
73
|
-
system: 'You are a helpful assistant for testing.',
|
|
74
|
-
bio: 'A test character for unit testing',
|
|
75
|
-
},
|
|
76
|
-
} as IAgentRuntime;
|
|
77
|
-
const service = await ServiceClass.start(runtime);
|
|
78
|
-
services.set(ServiceClass.serviceType, service);
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
37
|
describe('Plugin Configuration', () => {
|
|
84
38
|
it('should have correct plugin metadata', () => {
|
|
85
|
-
|
|
86
|
-
expect(starterPlugin.
|
|
87
|
-
expect(starterPlugin.
|
|
39
|
+
// Check that plugin has required metadata (values will change when template is used)
|
|
40
|
+
expect(starterPlugin.name).toBeDefined();
|
|
41
|
+
expect(starterPlugin.name).toMatch(/^[a-z0-9-]+$/); // Valid plugin name format
|
|
42
|
+
expect(starterPlugin.description).toBeDefined();
|
|
43
|
+
expect(starterPlugin.description.length).toBeGreaterThan(0);
|
|
44
|
+
expect(starterPlugin.actions).toBeDefined();
|
|
45
|
+
expect(starterPlugin.actions?.length).toBeGreaterThan(0);
|
|
46
|
+
expect(starterPlugin.providers).toBeDefined();
|
|
47
|
+
expect(starterPlugin.providers?.length).toBeGreaterThan(0);
|
|
48
|
+
expect(starterPlugin.services).toBeDefined();
|
|
49
|
+
expect(starterPlugin.services?.length).toBeGreaterThan(0);
|
|
50
|
+
expect(starterPlugin.models).toBeDefined();
|
|
51
|
+
expect(starterPlugin.models?.[ModelType.TEXT_SMALL]).toBeDefined();
|
|
52
|
+
expect(starterPlugin.models?.[ModelType.TEXT_LARGE]).toBeDefined();
|
|
53
|
+
expect(starterPlugin.routes).toBeDefined();
|
|
54
|
+
expect(starterPlugin.routes?.length).toBeGreaterThan(0);
|
|
55
|
+
expect(starterPlugin.events).toBeDefined();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should initialize with valid configuration', async () => {
|
|
59
|
+
const runtime = createMockRuntime();
|
|
60
|
+
const config = { EXAMPLE_PLUGIN_VARIABLE: 'test-value' };
|
|
61
|
+
|
|
62
|
+
if (starterPlugin.init) {
|
|
63
|
+
await starterPlugin.init(config, runtime);
|
|
64
|
+
expect(process.env.EXAMPLE_PLUGIN_VARIABLE).toBe('test-value');
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should handle initialization without config', async () => {
|
|
69
|
+
const runtime = createMockRuntime();
|
|
70
|
+
|
|
71
|
+
if (starterPlugin.init) {
|
|
72
|
+
// Init should not throw even with empty config
|
|
73
|
+
await starterPlugin.init({}, runtime);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should throw error for invalid configuration', async () => {
|
|
78
|
+
const runtime = createMockRuntime();
|
|
79
|
+
const invalidConfig = { EXAMPLE_PLUGIN_VARIABLE: 123 }; // Should be string
|
|
80
|
+
|
|
81
|
+
if (starterPlugin.init) {
|
|
82
|
+
await expect(starterPlugin.init(invalidConfig as any, runtime)).rejects.toThrow(
|
|
83
|
+
'Invalid plugin configuration'
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('Hello World Action', () => {
|
|
90
|
+
let runtime: IAgentRuntime;
|
|
91
|
+
let helloWorldAction: any;
|
|
92
|
+
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
runtime = createMockRuntime();
|
|
95
|
+
helloWorldAction = starterPlugin.actions?.[0];
|
|
96
|
+
// Clear all spies before each test
|
|
97
|
+
(logger.info as any).calls = [];
|
|
98
|
+
(logger.error as any).calls = [];
|
|
99
|
+
(logger.debug as any).calls = [];
|
|
100
|
+
(logger.warn as any).calls = [];
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should have hello world action', () => {
|
|
104
|
+
expect(helloWorldAction).toBeDefined();
|
|
105
|
+
expect(helloWorldAction?.name).toBe('HELLO_WORLD');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should always validate messages (current implementation)', async () => {
|
|
109
|
+
if (!helloWorldAction?.validate) {
|
|
110
|
+
throw new Error('Hello world action validate not found');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const validMessages = ['say hello', 'hello world', 'Please say HELLO', 'can you say hello?'];
|
|
114
|
+
|
|
115
|
+
// The current implementation always returns true
|
|
116
|
+
// This test documents the actual behavior
|
|
117
|
+
for (const text of validMessages) {
|
|
118
|
+
const message = createTestMemory({
|
|
119
|
+
content: { text, source: 'test' },
|
|
120
|
+
});
|
|
121
|
+
const isValid = await helloWorldAction.validate(runtime, message);
|
|
122
|
+
expect(isValid).toBe(true);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should properly validate hello messages', async () => {
|
|
127
|
+
if (!helloWorldAction?.validate) {
|
|
128
|
+
throw new Error('Hello world action validate not found');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// The current implementation always returns true
|
|
132
|
+
// Test that it accepts all messages
|
|
133
|
+
const helloMessages = ['hello', 'hi there', 'hey!', 'greetings', 'howdy partner'];
|
|
134
|
+
for (const text of helloMessages) {
|
|
135
|
+
const message = createTestMemory({
|
|
136
|
+
content: { text, source: 'test' },
|
|
137
|
+
});
|
|
138
|
+
const isValid = await helloWorldAction.validate(runtime, message);
|
|
139
|
+
expect(isValid).toBe(true);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Should also accept non-hello messages since validate always returns true
|
|
143
|
+
const nonHelloMessages = ['goodbye', 'what is the weather', 'tell me a joke'];
|
|
144
|
+
for (const text of nonHelloMessages) {
|
|
145
|
+
const message = createTestMemory({
|
|
146
|
+
content: { text, source: 'test' },
|
|
147
|
+
});
|
|
148
|
+
const isValid = await helloWorldAction.validate(runtime, message);
|
|
149
|
+
expect(isValid).toBe(true);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Test empty string - also returns true
|
|
153
|
+
const emptyMessage = createTestMemory({
|
|
154
|
+
content: { text: '', source: 'test' },
|
|
155
|
+
});
|
|
156
|
+
const isEmptyValid = await helloWorldAction.validate(runtime, emptyMessage);
|
|
157
|
+
expect(isEmptyValid).toBe(true);
|
|
88
158
|
});
|
|
89
159
|
|
|
90
|
-
it('should
|
|
91
|
-
|
|
160
|
+
it('should validate even without text content', async () => {
|
|
161
|
+
if (!helloWorldAction?.validate) {
|
|
162
|
+
throw new Error('Hello world action validate not found');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const messageWithoutText = createTestMemory({
|
|
166
|
+
content: { source: 'test' } as Content,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const isValid = await helloWorldAction.validate(runtime, messageWithoutText);
|
|
170
|
+
// Always returns true since validate always returns true
|
|
171
|
+
expect(isValid).toBe(true);
|
|
92
172
|
});
|
|
93
173
|
|
|
94
|
-
it('should
|
|
95
|
-
|
|
174
|
+
it('should handle hello world action with callback', async () => {
|
|
175
|
+
if (!helloWorldAction?.handler) {
|
|
176
|
+
throw new Error('Hello world action handler not found');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const message = createTestMemory({
|
|
180
|
+
content: { text: 'say hello', source: 'test' },
|
|
181
|
+
});
|
|
96
182
|
|
|
97
|
-
|
|
98
|
-
|
|
183
|
+
let callbackContent: any = null;
|
|
184
|
+
const callback: HandlerCallback = async (content: Content) => {
|
|
185
|
+
callbackContent = content;
|
|
186
|
+
return [];
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const result = await helloWorldAction.handler(runtime, message, undefined, undefined, callback);
|
|
99
190
|
|
|
100
|
-
|
|
101
|
-
|
|
191
|
+
expect(result).toHaveProperty('text', 'Hello world!');
|
|
192
|
+
expect(result).toHaveProperty('success', true);
|
|
193
|
+
expect(result).toHaveProperty('data');
|
|
194
|
+
expect((result as any).data).toHaveProperty('actions', ['HELLO_WORLD']);
|
|
195
|
+
expect((result as any).data).toHaveProperty('source', 'test');
|
|
102
196
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
197
|
+
expect(callbackContent).toEqual({
|
|
198
|
+
text: 'Hello world!',
|
|
199
|
+
actions: ['HELLO_WORLD'],
|
|
200
|
+
source: 'test',
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should handle errors gracefully', async () => {
|
|
205
|
+
if (!helloWorldAction?.handler) {
|
|
206
|
+
throw new Error('Hello world action handler not found');
|
|
112
207
|
}
|
|
208
|
+
|
|
209
|
+
const message = createTestMemory({
|
|
210
|
+
content: { text: 'say hello', source: 'test' },
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
const errorCallback: HandlerCallback = async () => {
|
|
214
|
+
throw new Error('Callback error');
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const result = await helloWorldAction.handler(
|
|
218
|
+
runtime,
|
|
219
|
+
message,
|
|
220
|
+
undefined,
|
|
221
|
+
undefined,
|
|
222
|
+
errorCallback
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
expect(result).toHaveProperty('success', false);
|
|
226
|
+
expect(result).toHaveProperty('error');
|
|
227
|
+
expect((result as any).error?.message).toBe('Callback error');
|
|
228
|
+
// Quick-starter plugin doesn't log errors
|
|
113
229
|
});
|
|
114
230
|
|
|
115
|
-
it('should
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// Check if the config has expected EXAMPLE_PLUGIN_VARIABLE property
|
|
119
|
-
expect(Object.keys(starterPlugin.config)).toContain('EXAMPLE_PLUGIN_VARIABLE');
|
|
231
|
+
it('should handle missing callback gracefully', async () => {
|
|
232
|
+
if (!helloWorldAction?.handler) {
|
|
233
|
+
throw new Error('Hello world action handler not found');
|
|
120
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
|
+
expect(result).toHaveProperty('text', 'Hello world!');
|
|
249
|
+
expect(result).toHaveProperty('success', true);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('should handle state parameter correctly', async () => {
|
|
253
|
+
if (!helloWorldAction?.handler) {
|
|
254
|
+
throw new Error('Hello world action handler not found');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const message = createTestMemory({
|
|
258
|
+
content: { text: 'say hello', source: 'test' },
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
const state = createTestState({
|
|
262
|
+
values: { customValue: 'test-state' },
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const result = await helloWorldAction.handler(runtime, message, state, undefined, undefined);
|
|
266
|
+
|
|
267
|
+
expect(result).toHaveProperty('success', true);
|
|
121
268
|
});
|
|
122
269
|
});
|
|
123
270
|
|
|
124
|
-
describe('
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
271
|
+
describe('Hello World Provider', () => {
|
|
272
|
+
const provider = starterPlugin.providers?.[0];
|
|
273
|
+
let runtime: IAgentRuntime;
|
|
274
|
+
|
|
275
|
+
beforeEach(() => {
|
|
276
|
+
runtime = createMockRuntime();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('should have hello world provider', () => {
|
|
280
|
+
expect(provider).toBeDefined();
|
|
281
|
+
expect(provider?.name).toBe('HELLO_WORLD_PROVIDER');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('should provide hello world data', async () => {
|
|
285
|
+
if (!provider?.get) {
|
|
286
|
+
throw new Error('Hello world provider not found');
|
|
129
287
|
}
|
|
288
|
+
|
|
289
|
+
const message = createTestMemory();
|
|
290
|
+
const state = createTestState();
|
|
291
|
+
|
|
292
|
+
const result = await provider.get(runtime, message, state);
|
|
293
|
+
|
|
294
|
+
expect(result).toHaveProperty('text', 'I am a provider');
|
|
295
|
+
expect(result).toHaveProperty('values');
|
|
296
|
+
expect(result.values).toEqual({});
|
|
297
|
+
expect(result).toHaveProperty('data');
|
|
298
|
+
expect(result.data).toEqual({});
|
|
130
299
|
});
|
|
131
300
|
|
|
132
|
-
it('should
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
301
|
+
it('should provide consistent structure across calls', async () => {
|
|
302
|
+
if (!provider?.get) {
|
|
303
|
+
throw new Error('Hello world provider not found');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const message = createTestMemory();
|
|
307
|
+
const state = createTestState();
|
|
308
|
+
|
|
309
|
+
const result1 = await provider.get(runtime, message, state);
|
|
310
|
+
const result2 = await provider.get(runtime, message, state);
|
|
311
|
+
|
|
312
|
+
// Text and structure should be consistent
|
|
313
|
+
expect(result1.text).toBe(result2.text);
|
|
314
|
+
expect(result1.values).toEqual(result2.values);
|
|
315
|
+
expect(result1.data).toEqual(result2.data);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
describe('Model Handlers', () => {
|
|
320
|
+
let runtime: IAgentRuntime;
|
|
321
|
+
|
|
322
|
+
beforeEach(() => {
|
|
323
|
+
runtime = createMockRuntime();
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should handle TEXT_SMALL model', async () => {
|
|
327
|
+
const handler = starterPlugin.models?.[ModelType.TEXT_SMALL];
|
|
328
|
+
if (!handler) {
|
|
329
|
+
throw new Error('TEXT_SMALL model handler not found');
|
|
136
330
|
}
|
|
331
|
+
|
|
332
|
+
const result = await handler(runtime, { prompt: 'Test prompt' });
|
|
333
|
+
|
|
334
|
+
expect(result).toContain('Never gonna give you up');
|
|
137
335
|
});
|
|
138
336
|
|
|
139
|
-
it('should
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
});
|
|
337
|
+
it('should handle TEXT_LARGE model with custom parameters', async () => {
|
|
338
|
+
const handler = starterPlugin.models?.[ModelType.TEXT_LARGE];
|
|
339
|
+
if (!handler) {
|
|
340
|
+
throw new Error('TEXT_LARGE model handler not found');
|
|
341
|
+
}
|
|
145
342
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
343
|
+
const result = await handler(runtime, {
|
|
344
|
+
prompt: 'Test prompt with custom settings',
|
|
345
|
+
maxTokens: 1000,
|
|
346
|
+
temperature: 0.5,
|
|
347
|
+
frequencyPenalty: 0.5,
|
|
348
|
+
presencePenalty: 0.5,
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
expect(result).toContain('Never gonna make you cry');
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it('should handle empty prompt', async () => {
|
|
355
|
+
const handler = starterPlugin.models?.[ModelType.TEXT_SMALL];
|
|
356
|
+
if (!handler) {
|
|
357
|
+
throw new Error('TEXT_SMALL model handler not found');
|
|
150
358
|
}
|
|
359
|
+
|
|
360
|
+
const result = await handler(runtime, { prompt: '' });
|
|
361
|
+
|
|
362
|
+
expect(typeof result).toBe('string');
|
|
363
|
+
expect(result.length).toBeGreaterThan(0);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('should handle missing parameters', async () => {
|
|
367
|
+
const handler = starterPlugin.models?.[ModelType.TEXT_LARGE];
|
|
368
|
+
if (!handler) {
|
|
369
|
+
throw new Error('TEXT_LARGE model handler not found');
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const result = await handler(runtime, { prompt: 'Test prompt' });
|
|
373
|
+
|
|
374
|
+
expect(typeof result).toBe('string');
|
|
375
|
+
expect(result.length).toBeGreaterThan(0);
|
|
151
376
|
});
|
|
152
377
|
});
|
|
153
378
|
|
|
154
|
-
describe('
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
379
|
+
describe('API Routes', () => {
|
|
380
|
+
let runtime: IAgentRuntime;
|
|
381
|
+
|
|
382
|
+
beforeEach(() => {
|
|
383
|
+
runtime = createMockRuntime();
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('should handle status route', async () => {
|
|
387
|
+
const statusRoute = starterPlugin.routes?.[0];
|
|
388
|
+
if (!statusRoute?.handler) {
|
|
389
|
+
throw new Error('Status route handler not found');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const mockRes = {
|
|
393
|
+
json: (data: any) => {
|
|
394
|
+
mockRes._jsonData = data;
|
|
395
|
+
},
|
|
396
|
+
_jsonData: null as any,
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
await statusRoute.handler({}, mockRes, runtime);
|
|
400
|
+
|
|
401
|
+
expect(mockRes._jsonData).toBeDefined();
|
|
402
|
+
expect(mockRes._jsonData.status).toBe('ok');
|
|
403
|
+
expect(mockRes._jsonData.plugin).toBe('quick-starter');
|
|
404
|
+
expect(mockRes._jsonData.timestamp).toBeDefined();
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it('should validate route configuration', () => {
|
|
408
|
+
const statusRoute = starterPlugin.routes?.[0];
|
|
409
|
+
|
|
410
|
+
expect(statusRoute).toBeDefined();
|
|
411
|
+
expect(statusRoute?.path).toBe('/api/status');
|
|
412
|
+
expect(statusRoute?.type).toBe('GET');
|
|
413
|
+
// Routes don't have a public property in the current implementation
|
|
414
|
+
expect(statusRoute?.handler).toBeDefined();
|
|
415
|
+
});
|
|
158
416
|
|
|
159
|
-
|
|
160
|
-
|
|
417
|
+
it('should handle request with query parameters', async () => {
|
|
418
|
+
const statusRoute = starterPlugin.routes?.[0];
|
|
419
|
+
if (!statusRoute?.handler) {
|
|
420
|
+
throw new Error('Status route handler not found');
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const mockReq = {
|
|
424
|
+
query: {
|
|
425
|
+
verbose: 'true',
|
|
426
|
+
},
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
const mockRes = {
|
|
430
|
+
json: (data: any) => {
|
|
431
|
+
mockRes._jsonData = data;
|
|
432
|
+
},
|
|
433
|
+
_jsonData: null as any,
|
|
434
|
+
};
|
|
161
435
|
|
|
162
|
-
|
|
163
|
-
|
|
436
|
+
await statusRoute.handler(mockReq, mockRes, runtime);
|
|
437
|
+
|
|
438
|
+
expect(mockRes._jsonData).toBeDefined();
|
|
439
|
+
expect(mockRes._jsonData.status).toBe('ok');
|
|
164
440
|
});
|
|
441
|
+
});
|
|
165
442
|
|
|
166
|
-
|
|
167
|
-
|
|
443
|
+
describe('Event Handlers', () => {
|
|
444
|
+
beforeEach(() => {
|
|
445
|
+
// Clear logger spy calls
|
|
446
|
+
(logger.debug as any).calls = [];
|
|
447
|
+
(logger.info as any).calls = [];
|
|
448
|
+
(logger.error as any).calls = [];
|
|
449
|
+
});
|
|
168
450
|
|
|
169
|
-
|
|
170
|
-
const
|
|
451
|
+
it('should log when MESSAGE_RECEIVED event is triggered', async () => {
|
|
452
|
+
const handler = starterPlugin.events?.[EventType.MESSAGE_RECEIVED]?.[0];
|
|
453
|
+
if (!handler) {
|
|
454
|
+
throw new Error('MESSAGE_RECEIVED event handler not found');
|
|
455
|
+
}
|
|
171
456
|
|
|
172
|
-
|
|
173
|
-
|
|
457
|
+
const payload = testFixtures.messagePayload();
|
|
458
|
+
await handler(payload);
|
|
174
459
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
460
|
+
expect(logger.debug).toHaveBeenCalled();
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('should handle malformed event payload', async () => {
|
|
464
|
+
const handler = starterPlugin.events?.[EventType.MESSAGE_RECEIVED]?.[0];
|
|
465
|
+
if (!handler) {
|
|
466
|
+
throw new Error('MESSAGE_RECEIVED event handler not found');
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const malformedPayload = {
|
|
470
|
+
// Missing required fields
|
|
471
|
+
runtime: createMockRuntime(),
|
|
182
472
|
};
|
|
183
473
|
|
|
184
|
-
//
|
|
185
|
-
|
|
474
|
+
// Should not throw
|
|
475
|
+
// Handler doesn't actually use the payload, just logs
|
|
476
|
+
await handler(malformedPayload as any);
|
|
477
|
+
});
|
|
186
478
|
|
|
187
|
-
|
|
188
|
-
|
|
479
|
+
it('should handle event with empty message content', async () => {
|
|
480
|
+
const handler = starterPlugin.events?.[EventType.MESSAGE_RECEIVED]?.[0];
|
|
481
|
+
if (!handler) {
|
|
482
|
+
throw new Error('MESSAGE_RECEIVED event handler not found');
|
|
483
|
+
}
|
|
189
484
|
|
|
190
|
-
|
|
191
|
-
|
|
485
|
+
const payload = testFixtures.messagePayload({
|
|
486
|
+
content: {},
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
await handler(payload);
|
|
490
|
+
expect(logger.debug).toHaveBeenCalled();
|
|
192
491
|
});
|
|
492
|
+
});
|
|
193
493
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
// Don't register a service, so getService will return null
|
|
494
|
+
describe('StarterService', () => {
|
|
495
|
+
let runtime: IAgentRuntime;
|
|
197
496
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
497
|
+
beforeEach(() => {
|
|
498
|
+
runtime = createMockRuntime();
|
|
499
|
+
// Clear logger spy calls
|
|
500
|
+
(logger.info as any).calls = [];
|
|
501
|
+
(logger.error as any).calls = [];
|
|
502
|
+
});
|
|
201
503
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
);
|
|
504
|
+
it('should start the service', async () => {
|
|
505
|
+
const service = await StarterService.start(runtime);
|
|
506
|
+
expect(service).toBeInstanceOf(StarterService);
|
|
507
|
+
expect(logger.info).toHaveBeenCalled();
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
it('should have correct service type', () => {
|
|
511
|
+
expect(StarterService.serviceType).toBe('starter');
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it('should stop service correctly', async () => {
|
|
515
|
+
// Start service
|
|
516
|
+
const service = await StarterService.start(runtime);
|
|
517
|
+
|
|
518
|
+
// Create a new runtime with the service registered
|
|
519
|
+
const runtimeWithService = createMockRuntime({
|
|
520
|
+
getService: () => service as any,
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
// Stop service
|
|
524
|
+
await StarterService.stop(runtimeWithService);
|
|
525
|
+
expect(logger.info).toHaveBeenCalled();
|
|
526
|
+
});
|
|
205
527
|
|
|
206
|
-
|
|
207
|
-
|
|
528
|
+
it('should throw error when stopping non-existent service', async () => {
|
|
529
|
+
const emptyRuntime = createMockRuntime({
|
|
530
|
+
getService: () => null,
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
await expect(StarterService.stop(emptyRuntime)).rejects.toThrow('Starter service not found');
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
it('should handle multiple start/stop cycles', async () => {
|
|
537
|
+
// First cycle
|
|
538
|
+
const service1 = await StarterService.start(runtime);
|
|
539
|
+
expect(service1).toBeInstanceOf(StarterService);
|
|
540
|
+
|
|
541
|
+
const runtimeWithService1 = createMockRuntime({
|
|
542
|
+
getService: () => service1 as any,
|
|
543
|
+
});
|
|
544
|
+
await StarterService.stop(runtimeWithService1);
|
|
545
|
+
|
|
546
|
+
// Second cycle
|
|
547
|
+
const service2 = await StarterService.start(runtime);
|
|
548
|
+
expect(service2).toBeInstanceOf(StarterService);
|
|
549
|
+
|
|
550
|
+
const runtimeWithService2 = createMockRuntime({
|
|
551
|
+
getService: () => service2 as any,
|
|
552
|
+
});
|
|
553
|
+
await StarterService.stop(runtimeWithService2);
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it('should provide capability description', async () => {
|
|
557
|
+
const service = await StarterService.start(runtime);
|
|
558
|
+
expect(service.capabilityDescription).toBe(
|
|
559
|
+
'This is a starter service which is attached to the agent through the starter plugin.'
|
|
560
|
+
);
|
|
208
561
|
});
|
|
209
562
|
});
|