Skip to content

Commit 112c552

Browse files
author
mike dupont
committed
wip
1 parent 9370f32 commit 112c552

24 files changed

+1341
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.turbo
2+
dist
3+
node_modules
4+
.env
5+
*.env
6+
.env.local
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Plugin Starter
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"name": "@elizaos/plugin-starter",
3+
"description": "Plugin starter for elizaOS",
4+
"version": "1.0.0-beta.7",
5+
"private": true,
6+
"type": "module",
7+
"main": "dist/index.js",
8+
"module": "dist/index.js",
9+
"types": "dist/index.d.ts",
10+
"repository": {
11+
"type": "git",
12+
"url": "https://github.com/elizaos-plugins/plugin-starter"
13+
},
14+
"exports": {
15+
"./package.json": "./package.json",
16+
".": {
17+
"import": {
18+
"types": "./dist/index.d.ts",
19+
"default": "./dist/index.js"
20+
}
21+
}
22+
},
23+
"files": [
24+
"dist"
25+
],
26+
"dependencies": {
27+
"@elizaos/cli": "^1.0.0-beta.0",
28+
"@elizaos/core": "^1.0.0-beta.0",
29+
"zod": "3.24.2"
30+
},
31+
"devDependencies": {
32+
"tsup": "8.4.0",
33+
"prettier": "3.5.3"
34+
},
35+
"scripts": {
36+
"start": "npx @elizaos/cli start",
37+
"test-with-cli": "cd ../cli && bun run build && cd ../plugin-starter && elizaos test",
38+
"dev": "npx @elizaos/cli dev",
39+
"build": "tsup",
40+
"lint": "prettier --write ./src",
41+
"test": "npx @elizaos/cli test",
42+
"publish": "npx @elizaos/cli plugin publish",
43+
"format": "prettier --write ./src",
44+
"format:check": "prettier --check ./src"
45+
},
46+
"publishConfig": {
47+
"access": "public"
48+
},
49+
"resolutions": {
50+
"zod": "3.24.2"
51+
},
52+
"gitHead": "b165ad83e5f7a21bc1edbd83374ca087e3cd6b33"
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
import type { Plugin } from '@elizaos/core';
2+
import {
3+
type Action,
4+
type Content,
5+
type GenerateTextParams,
6+
type HandlerCallback,
7+
type IAgentRuntime,
8+
type Memory,
9+
ModelType,
10+
type Provider,
11+
type ProviderResult,
12+
Service,
13+
type State,
14+
logger,
15+
} from '@elizaos/core';
16+
import { z } from 'zod';
17+
18+
/**
19+
* Defines the configuration schema for a plugin, including the validation rules for the plugin name.
20+
*
21+
* @type {import('zod').ZodObject<{ EXAMPLE_PLUGIN_VARIABLE: import('zod').ZodString }>}
22+
*/
23+
const configSchema = z.object({
24+
EXAMPLE_PLUGIN_VARIABLE: z
25+
.string()
26+
.min(1, 'Example plugin variable is not provided')
27+
.optional()
28+
.transform((val) => {
29+
if (!val) {
30+
logger.warn('Example plugin variable is not provided (this is expected)');
31+
}
32+
return val;
33+
}),
34+
});
35+
36+
/**
37+
* Example HelloWorld action
38+
* This demonstrates the simplest possible action structure
39+
*/
40+
/**
41+
* Action representing a hello world message.
42+
* @typedef {Object} Action
43+
* @property {string} name - The name of the action.
44+
* @property {string[]} similes - An array of related actions.
45+
* @property {string} description - A brief description of the action.
46+
* @property {Function} validate - Asynchronous function to validate the action.
47+
* @property {Function} handler - Asynchronous function to handle the action and generate a response.
48+
* @property {Object[]} examples - An array of example inputs and expected outputs for the action.
49+
*/
50+
const helloWorldAction: Action = {
51+
name: 'HELLO_WORLD',
52+
similes: ['GREET', 'SAY_HELLO'],
53+
description: 'Responds with a simple hello world message',
54+
55+
validate: async (_runtime: IAgentRuntime, _message: Memory, _state: State): Promise<boolean> => {
56+
// Always valid
57+
return true;
58+
},
59+
60+
handler: async (
61+
_runtime: IAgentRuntime,
62+
message: Memory,
63+
_state: State,
64+
_options: any,
65+
callback: HandlerCallback,
66+
_responses: Memory[]
67+
) => {
68+
try {
69+
logger.info('Handling HELLO_WORLD action');
70+
71+
// Simple response content
72+
const responseContent: Content = {
73+
text: 'hello world!',
74+
actions: ['HELLO_WORLD'],
75+
source: message.content.source,
76+
};
77+
78+
// Call back with the hello world message
79+
await callback(responseContent);
80+
81+
return responseContent;
82+
} catch (error) {
83+
logger.error('Error in HELLO_WORLD action:', error);
84+
throw error;
85+
}
86+
},
87+
88+
examples: [
89+
[
90+
{
91+
name: '{{name1}}',
92+
content: {
93+
text: 'Can you say hello?',
94+
},
95+
},
96+
{
97+
name: '{{name2}}',
98+
content: {
99+
text: 'hello world!',
100+
actions: ['HELLO_WORLD'],
101+
},
102+
},
103+
],
104+
],
105+
};
106+
107+
/**
108+
* Example Hello World Provider
109+
* This demonstrates the simplest possible provider implementation
110+
*/
111+
const helloWorldProvider: Provider = {
112+
name: 'HELLO_WORLD_PROVIDER',
113+
description: 'A simple example provider',
114+
115+
get: async (
116+
_runtime: IAgentRuntime,
117+
_message: Memory,
118+
_state: State
119+
): Promise<ProviderResult> => {
120+
return {
121+
text: 'I am a provider',
122+
values: {},
123+
data: {},
124+
};
125+
},
126+
};
127+
128+
export class StarterService extends Service {
129+
static serviceType = 'starter';
130+
capabilityDescription =
131+
'This is a starter service which is attached to the agent through the starter plugin.';
132+
constructor(protected runtime: IAgentRuntime) {
133+
super(runtime);
134+
}
135+
136+
static async start(runtime: IAgentRuntime) {
137+
logger.info(`*** Starting starter service - MODIFIED: ${new Date().toISOString()} ***`);
138+
const service = new StarterService(runtime);
139+
return service;
140+
}
141+
142+
static async stop(runtime: IAgentRuntime) {
143+
logger.info('*** TESTING DEV MODE - STOP MESSAGE CHANGED! ***');
144+
// get the service from the runtime
145+
const service = runtime.getService(StarterService.serviceType);
146+
if (!service) {
147+
throw new Error('Starter service not found');
148+
}
149+
service.stop();
150+
}
151+
152+
async stop() {
153+
logger.info('*** THIRD CHANGE - TESTING FILE WATCHING! ***');
154+
}
155+
}
156+
157+
export const starterPlugin: Plugin = {
158+
name: 'plugin-starter',
159+
description: 'Plugin starter for elizaOS',
160+
config: {
161+
EXAMPLE_PLUGIN_VARIABLE: process.env.EXAMPLE_PLUGIN_VARIABLE,
162+
},
163+
async init(config: Record<string, string>) {
164+
logger.info('*** TESTING DEV MODE - PLUGIN MODIFIED AND RELOADED! ***');
165+
try {
166+
const validatedConfig = await configSchema.parseAsync(config);
167+
168+
// Set all environment variables at once
169+
for (const [key, value] of Object.entries(validatedConfig)) {
170+
if (value) process.env[key] = value;
171+
}
172+
} catch (error) {
173+
if (error instanceof z.ZodError) {
174+
throw new Error(
175+
`Invalid plugin configuration: ${error.errors.map((e) => e.message).join(', ')}`
176+
);
177+
}
178+
throw error;
179+
}
180+
},
181+
models: {
182+
[ModelType.TEXT_SMALL]: async (
183+
_runtime,
184+
{ prompt, stopSequences = [] }: GenerateTextParams
185+
) => {
186+
return 'Never gonna give you up, never gonna let you down, never gonna run around and desert you...';
187+
},
188+
[ModelType.TEXT_LARGE]: async (
189+
_runtime,
190+
{
191+
prompt,
192+
stopSequences = [],
193+
maxTokens = 8192,
194+
temperature = 0.7,
195+
frequencyPenalty = 0.7,
196+
presencePenalty = 0.7,
197+
}: GenerateTextParams
198+
) => {
199+
return 'Never gonna make you cry, never gonna say goodbye, never gonna tell a lie and hurt you...';
200+
},
201+
},
202+
tests: [
203+
{
204+
name: 'plugin_starter_test_suite',
205+
tests: [
206+
{
207+
name: 'example_test',
208+
fn: async (runtime) => {
209+
logger.debug('example_test run by ', runtime.character.name);
210+
// Add a proper assertion that will pass
211+
if (runtime.character.name !== 'Eliza') {
212+
throw new Error(
213+
`Expected character name to be "Eliza" but got "${runtime.character.name}"`
214+
);
215+
}
216+
// Verify the plugin is loaded properly
217+
const service = runtime.getService('starter');
218+
if (!service) {
219+
throw new Error('Starter service not found');
220+
}
221+
// Don't return anything to match the void return type
222+
},
223+
},
224+
{
225+
name: 'should_have_hello_world_action',
226+
fn: async (runtime) => {
227+
// Check if the hello world action is registered
228+
// Look for the action in our plugin's actions
229+
// The actual action name in this plugin is "helloWorld", not "hello"
230+
const actionExists = starterPlugin.actions.some((a) => a.name === 'HELLO_WORLD');
231+
if (!actionExists) {
232+
throw new Error('Hello world action not found in plugin');
233+
}
234+
},
235+
},
236+
],
237+
},
238+
],
239+
routes: [
240+
{
241+
path: '/helloworld',
242+
type: 'GET',
243+
handler: async (_req: any, res: any) => {
244+
// send a response
245+
res.json({
246+
message: 'Hello World!',
247+
});
248+
},
249+
},
250+
],
251+
events: {
252+
MESSAGE_RECEIVED: [
253+
async (params) => {
254+
logger.debug('MESSAGE_RECEIVED event received');
255+
// print the keys
256+
logger.debug(Object.keys(params));
257+
},
258+
],
259+
VOICE_MESSAGE_RECEIVED: [
260+
async (params) => {
261+
logger.debug('VOICE_MESSAGE_RECEIVED event received');
262+
// print the keys
263+
logger.debug(Object.keys(params));
264+
},
265+
],
266+
WORLD_CONNECTED: [
267+
async (params) => {
268+
logger.debug('WORLD_CONNECTED event received');
269+
// print the keys
270+
logger.debug(Object.keys(params));
271+
},
272+
],
273+
WORLD_JOINED: [
274+
async (params) => {
275+
logger.debug('WORLD_JOINED event received');
276+
// print the keys
277+
logger.debug(Object.keys(params));
278+
},
279+
],
280+
},
281+
services: [StarterService],
282+
actions: [helloWorldAction],
283+
providers: [helloWorldProvider],
284+
};
285+
286+
export default starterPlugin;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"rootDir": "./src",
5+
"outDir": "./dist",
6+
"sourceMap": true,
7+
"inlineSources": true,
8+
"declaration": true,
9+
"emitDeclarationOnly": true
10+
},
11+
"include": ["src/**/*.ts"],
12+
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"compilerOptions": {
3+
"outDir": "dist",
4+
"rootDir": "src",
5+
"lib": ["ESNext"],
6+
"target": "ESNext",
7+
"module": "Preserve",
8+
"moduleResolution": "Bundler",
9+
"strict": false,
10+
"esModuleInterop": true,
11+
"skipLibCheck": true,
12+
"forceConsistentCasingInFileNames": false,
13+
"allowImportingTsExtensions": true,
14+
"declaration": true,
15+
"emitDeclarationOnly": true,
16+
"resolveJsonModule": true,
17+
"noImplicitAny": false,
18+
"allowJs": true,
19+
"checkJs": false,
20+
"noEmitOnError": false,
21+
"moduleDetection": "force",
22+
"allowArbitraryExtensions": true,
23+
"baseUrl": ".",
24+
"paths": {
25+
"@elizaos/core": ["../core/src"],
26+
"@elizaos/core/*": ["../core/src/*"]
27+
}
28+
},
29+
"include": ["src/**/*.ts"]
30+
}

0 commit comments

Comments
 (0)