@elizaos/cli 1.3.1 → 1.4.2

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