@elizaos/cli 1.2.12 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-OXCJTWT3.js → chunk-2CUIHNPL.js} +31 -0
- package/dist/{chunk-WEAYAAIM.js → chunk-I77ZRNYO.js} +1 -1
- package/dist/commands/create/actions/index.js +1 -1
- package/dist/commands/create/index.js +2 -2
- package/dist/index.js +37 -4
- package/dist/templates/plugin-quick-starter/package.json +1 -1
- package/dist/templates/plugin-quick-starter/src/plugin.ts +1 -1
- package/dist/templates/plugin-starter/CLAUDE.md +465 -0
- package/dist/templates/plugin-starter/dist/assets/{index-DUtsQhKX.js → index-D1cHX53P.js} +1 -1
- package/dist/templates/plugin-starter/dist/index.html +1 -1
- package/dist/templates/plugin-starter/package.json +1 -1
- package/dist/templates/project-starter/CLAUDE.md +698 -0
- package/dist/templates/project-starter/package.json +4 -4
- package/dist/templates/project-tee-starter/package.json +3 -3
- package/package.json +5 -5
- package/templates/plugin-quick-starter/package.json +1 -1
- package/templates/plugin-quick-starter/src/plugin.ts +1 -1
- package/templates/plugin-starter/CLAUDE.md +465 -0
- package/templates/plugin-starter/dist/.vite/manifest.json +1 -1
- package/templates/plugin-starter/dist/assets/{index-DUtsQhKX.js → index-D1cHX53P.js} +1 -1
- package/templates/plugin-starter/dist/index.html +1 -1
- package/templates/plugin-starter/package.json +1 -1
- package/templates/project-starter/CLAUDE.md +698 -0
- package/templates/project-starter/package.json +4 -4
- package/templates/project-tee-starter/package.json +3 -3
|
@@ -176,6 +176,23 @@ var baseCharacter = {
|
|
|
176
176
|
}
|
|
177
177
|
]
|
|
178
178
|
],
|
|
179
|
+
postExamples: [
|
|
180
|
+
"Sometimes the best debugging tool is a fresh cup of coffee and a walk around the block.",
|
|
181
|
+
"The magic happens when developers stop competing and start collaborating. Build together, grow together.",
|
|
182
|
+
"Reminder: Your code doesn't have to be perfect on the first try. Progress over perfection.",
|
|
183
|
+
"Community tip: The person asking 'obvious' questions today might solve your toughest problem tomorrow. Be kind.",
|
|
184
|
+
"Hot take: Good documentation is more valuable than clever code.",
|
|
185
|
+
"The best feature you can add to your project? A welcoming community.",
|
|
186
|
+
"Debugging is just a conversation with your past self. Make it easier by leaving good comments.",
|
|
187
|
+
"Your daily reminder that impostor syndrome affects even the most experienced developers. You belong here.",
|
|
188
|
+
"Pro tip: Read the error message. Then read it again. The answer is usually there.",
|
|
189
|
+
"Building in public isn't about showing off. It's about learning together and helping others avoid your mistakes.",
|
|
190
|
+
"The difference between junior and senior developers? Seniors know when NOT to write code.",
|
|
191
|
+
"Community > Competition. Always.",
|
|
192
|
+
"Remember: Every expert was once a beginner who refused to give up.",
|
|
193
|
+
"Code reviews aren't personal attacks. They're opportunities to level up together.",
|
|
194
|
+
"The most powerful tool in development? Asking for help when you need it."
|
|
195
|
+
],
|
|
179
196
|
style: {
|
|
180
197
|
all: [
|
|
181
198
|
"Keep responses concise but informative",
|
|
@@ -194,6 +211,20 @@ var baseCharacter = {
|
|
|
194
211
|
"Engage with the topic at hand",
|
|
195
212
|
"Be helpful and informative",
|
|
196
213
|
"Show personality and warmth"
|
|
214
|
+
],
|
|
215
|
+
post: [
|
|
216
|
+
"Keep it concise and punchy - every word counts",
|
|
217
|
+
"Share insights, not platitudes",
|
|
218
|
+
"Be authentic and conversational, not corporate",
|
|
219
|
+
"Use specific examples over generic advice",
|
|
220
|
+
"Add value with each post - teach, inspire, or entertain",
|
|
221
|
+
"One clear thought per post",
|
|
222
|
+
"Avoid excessive hashtags or mentions",
|
|
223
|
+
"Write like you are talking to a friend",
|
|
224
|
+
"Share personal observations and hot takes",
|
|
225
|
+
"Be helpful without being preachy",
|
|
226
|
+
"Use emojis sparingly and purposefully",
|
|
227
|
+
"End with something thought-provoking when appropriate"
|
|
197
228
|
]
|
|
198
229
|
}
|
|
199
230
|
};
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
setupAIModelConfig,
|
|
9
9
|
setupEmbeddingModelConfig,
|
|
10
10
|
setupProjectEnvironment
|
|
11
|
-
} from "../../../chunk-
|
|
11
|
+
} from "../../../chunk-2CUIHNPL.js";
|
|
12
12
|
import "../../../chunk-2ALAPQLV.js";
|
|
13
13
|
import "../../../chunk-FDEDLANP.js";
|
|
14
14
|
import "../../../chunk-4O6EZU37.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
create
|
|
3
|
-
} from "../../chunk-
|
|
4
|
-
import "../../chunk-
|
|
3
|
+
} from "../../chunk-I77ZRNYO.js";
|
|
4
|
+
import "../../chunk-2CUIHNPL.js";
|
|
5
5
|
import "../../chunk-2ALAPQLV.js";
|
|
6
6
|
import "../../chunk-FDEDLANP.js";
|
|
7
7
|
import "../../chunk-4O6EZU37.js";
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import {
|
|
3
3
|
create
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-I77ZRNYO.js";
|
|
5
5
|
import {
|
|
6
6
|
getElizaCharacter
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2CUIHNPL.js";
|
|
8
8
|
import {
|
|
9
9
|
TestRunner,
|
|
10
10
|
UserEnvironment,
|
|
@@ -284,6 +284,9 @@ function setupEnvironment() {
|
|
|
284
284
|
env2.PATH = localBinPath;
|
|
285
285
|
}
|
|
286
286
|
env2.FORCE_COLOR = "1";
|
|
287
|
+
if (process.env.ELIZA_TEST_MODE) {
|
|
288
|
+
env2.ELIZA_TEST_MODE = process.env.ELIZA_TEST_MODE;
|
|
289
|
+
}
|
|
287
290
|
return env2;
|
|
288
291
|
}
|
|
289
292
|
async function startServerProcess(args = []) {
|
|
@@ -299,13 +302,40 @@ async function startServerProcess(args = []) {
|
|
|
299
302
|
scriptPath = process.argv[1];
|
|
300
303
|
}
|
|
301
304
|
const env2 = setupEnvironment();
|
|
302
|
-
const
|
|
303
|
-
|
|
305
|
+
const isTestMode = process.env.ELIZA_TEST_MODE === "true";
|
|
306
|
+
const commandArgs = [nodeExecutable, scriptPath, "start", ...args];
|
|
307
|
+
if (isTestMode) {
|
|
308
|
+
console.info(`Executing command: ${commandArgs.join(" ")}`);
|
|
309
|
+
}
|
|
310
|
+
const childProcess = Bun.spawn(commandArgs, {
|
|
311
|
+
stdio: isTestMode ? ["inherit", "pipe", "pipe"] : ["inherit", "inherit", "inherit"],
|
|
304
312
|
env: env2,
|
|
305
313
|
cwd: process.cwd()
|
|
306
314
|
});
|
|
307
315
|
serverState.process = childProcess;
|
|
308
316
|
serverState.isRunning = true;
|
|
317
|
+
if (isTestMode && childProcess.stdout && childProcess.stderr) {
|
|
318
|
+
childProcess.stdout.pipeTo(
|
|
319
|
+
new WritableStream({
|
|
320
|
+
write(chunk) {
|
|
321
|
+
process.stdout.write(chunk);
|
|
322
|
+
return Promise.resolve();
|
|
323
|
+
}
|
|
324
|
+
})
|
|
325
|
+
).catch((error) => {
|
|
326
|
+
console.error("Error piping stdout:", error);
|
|
327
|
+
});
|
|
328
|
+
childProcess.stderr.pipeTo(
|
|
329
|
+
new WritableStream({
|
|
330
|
+
write(chunk) {
|
|
331
|
+
process.stderr.write(chunk);
|
|
332
|
+
return Promise.resolve();
|
|
333
|
+
}
|
|
334
|
+
})
|
|
335
|
+
).catch((error) => {
|
|
336
|
+
console.error("Error piping stderr:", error);
|
|
337
|
+
});
|
|
338
|
+
}
|
|
309
339
|
childProcess.exited.then((exitCode) => {
|
|
310
340
|
if (exitCode !== 0) {
|
|
311
341
|
console.warn(`Server process exited with code ${exitCode}`);
|
|
@@ -455,6 +485,9 @@ async function startDevMode(options) {
|
|
|
455
485
|
console.info(`Running in ${modeDescription} mode`);
|
|
456
486
|
await performInitialBuild(context);
|
|
457
487
|
}
|
|
488
|
+
if (process.env.ELIZA_TEST_MODE === "true") {
|
|
489
|
+
console.info(`[DEV] Starting server with args: ${cliArgs.join(" ")}`);
|
|
490
|
+
}
|
|
458
491
|
await serverManager2.start(cliArgs);
|
|
459
492
|
if (isProject || isPlugin2 || isMonorepo) {
|
|
460
493
|
await watchDirectory(context.watchDirectory, rebuildAndRestart);
|
|
@@ -266,7 +266,7 @@ export const starterPlugin: Plugin = {
|
|
|
266
266
|
services: [StarterService],
|
|
267
267
|
actions: [helloWorldAction],
|
|
268
268
|
providers: [helloWorldProvider],
|
|
269
|
-
// dependencies: ['@elizaos/plugin-knowledge'], <--- plugin
|
|
269
|
+
// dependencies: ['@elizaos/plugin-knowledge'], <--- plugin dependencies go here (if requires another plugin)
|
|
270
270
|
};
|
|
271
271
|
|
|
272
272
|
export default starterPlugin;
|
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
# ElizaOS Plugin Development Guide for Claude
|
|
2
|
+
|
|
3
|
+
> **Optimized for Claude LLM** - Complete reference for building ElizaOS plugins
|
|
4
|
+
|
|
5
|
+
## 📋 Project Overview
|
|
6
|
+
|
|
7
|
+
| Property | Value |
|
|
8
|
+
| ------------------- | --------------------- |
|
|
9
|
+
| **Project Type** | ElizaOS Plugin |
|
|
10
|
+
| **Package Manager** | `bun` (REQUIRED) |
|
|
11
|
+
| **Language** | TypeScript (Required) |
|
|
12
|
+
| **Testing** | Bun test |
|
|
13
|
+
| **Runtime** | ElizaOS Agent Runtime |
|
|
14
|
+
|
|
15
|
+
## 🏗️ Plugin Architecture
|
|
16
|
+
|
|
17
|
+
ElizaOS plugins follow a **component-based architecture** with four main types:
|
|
18
|
+
|
|
19
|
+
### 🔄 **Services** (Required for External APIs)
|
|
20
|
+
|
|
21
|
+
**Purpose:** Handle stateful operations and external integrations
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
export class ExampleService extends Service {
|
|
25
|
+
static serviceType = 'example';
|
|
26
|
+
private apiClient: ExternalAPI;
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
super();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async initialize(runtime: IAgentRuntime): Promise<void> {
|
|
33
|
+
// Initialize SDK connections, databases, etc.
|
|
34
|
+
this.apiClient = new ExternalAPI(process.env.API_KEY);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async processData(data: any): Promise<any> {
|
|
38
|
+
// Your business logic here
|
|
39
|
+
return await this.apiClient.process(data);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Services are for:**
|
|
45
|
+
|
|
46
|
+
- ✅ API connections and SDK management
|
|
47
|
+
- ✅ Database operations
|
|
48
|
+
- ✅ State management
|
|
49
|
+
- ✅ Authentication handling
|
|
50
|
+
- ❌ NOT for simple data formatting (use Providers)
|
|
51
|
+
|
|
52
|
+
### ⚡ **Actions** (Required for User Interactions)
|
|
53
|
+
|
|
54
|
+
**Purpose:** Handle user commands and generate responses
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { Action, ActionResult } from '@elizaos/core';
|
|
58
|
+
|
|
59
|
+
export const exampleAction: Action = {
|
|
60
|
+
name: 'EXAMPLE_ACTION',
|
|
61
|
+
description: 'Processes user requests for example functionality',
|
|
62
|
+
|
|
63
|
+
validate: async (runtime: IAgentRuntime, message: Memory) => {
|
|
64
|
+
const text = message.content.text.toLowerCase();
|
|
65
|
+
return text.includes('example') || text.includes('demo');
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
handler: async (runtime, message, state, options, callback): Promise<ActionResult> => {
|
|
69
|
+
try {
|
|
70
|
+
const service = runtime.getService<ExampleService>('example');
|
|
71
|
+
const result = await service.processData(message.content);
|
|
72
|
+
|
|
73
|
+
await callback({
|
|
74
|
+
text: `Here's your result: ${result}`,
|
|
75
|
+
action: 'EXAMPLE_ACTION',
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
success: true,
|
|
80
|
+
text: `Successfully processed: ${result}`,
|
|
81
|
+
values: {
|
|
82
|
+
lastProcessed: result,
|
|
83
|
+
processedAt: Date.now(),
|
|
84
|
+
},
|
|
85
|
+
data: {
|
|
86
|
+
actionName: 'EXAMPLE_ACTION',
|
|
87
|
+
result,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
} catch (error) {
|
|
91
|
+
await callback({
|
|
92
|
+
text: 'I encountered an error processing your request.',
|
|
93
|
+
error: true,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
success: false,
|
|
98
|
+
text: 'Failed to process request',
|
|
99
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
100
|
+
data: {
|
|
101
|
+
actionName: 'EXAMPLE_ACTION',
|
|
102
|
+
errorMessage: error instanceof Error ? error.message : 'Unknown error',
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Actions handle:**
|
|
111
|
+
|
|
112
|
+
- ✅ User input validation
|
|
113
|
+
- ✅ Command parsing and routing
|
|
114
|
+
- ✅ Service coordination
|
|
115
|
+
- ✅ Response generation
|
|
116
|
+
- ❌ NOT direct API calls (use Services)
|
|
117
|
+
|
|
118
|
+
**Important: Callbacks vs ActionResult:**
|
|
119
|
+
|
|
120
|
+
- **`callback()`** → Sends messages to the user in chat
|
|
121
|
+
- **`ActionResult` return** → Passes data/state to next action in chain
|
|
122
|
+
- Both are used together: callback for user communication, return for action chaining
|
|
123
|
+
|
|
124
|
+
### 📊 **Providers** (Optional - Context Supply)
|
|
125
|
+
|
|
126
|
+
**Purpose:** Supply read-only contextual information
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
export const exampleProvider: Provider = {
|
|
130
|
+
get: async (runtime: IAgentRuntime, message: Memory) => {
|
|
131
|
+
const service = runtime.getService<ExampleService>('example');
|
|
132
|
+
const status = await service.getStatus();
|
|
133
|
+
|
|
134
|
+
return `Current system status: ${status.state}
|
|
135
|
+
Available features: ${status.features.join(', ')}
|
|
136
|
+
Last updated: ${status.timestamp}`;
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Providers supply:**
|
|
142
|
+
|
|
143
|
+
- ✅ Formatted contextual data
|
|
144
|
+
- ✅ Real-time information
|
|
145
|
+
- ✅ System state summaries
|
|
146
|
+
- ❌ NOT for state modification
|
|
147
|
+
|
|
148
|
+
### 🧠 **Evaluators** (Optional - Post-Processing)
|
|
149
|
+
|
|
150
|
+
**Purpose:** Learn from interactions and analyze outcomes
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
export const exampleEvaluator: Evaluator = {
|
|
154
|
+
name: 'EXAMPLE_EVALUATOR',
|
|
155
|
+
|
|
156
|
+
evaluate: async (runtime: IAgentRuntime, message: Memory, state?: any) => {
|
|
157
|
+
// Analyze the interaction outcome
|
|
158
|
+
const success = state?.lastActionSuccess || false;
|
|
159
|
+
|
|
160
|
+
if (success) {
|
|
161
|
+
// Store successful patterns
|
|
162
|
+
await runtime.addMemory({
|
|
163
|
+
content: { text: 'Successful example interaction pattern' },
|
|
164
|
+
type: 'learning',
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return { success, confidence: 0.8 };
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 📁 Project Structure
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
src/
|
|
177
|
+
├── 📂 actions/ # User command handlers
|
|
178
|
+
│ ├── exampleAction.ts
|
|
179
|
+
│ └── index.ts
|
|
180
|
+
├── 📂 services/ # External integrations (REQUIRED)
|
|
181
|
+
│ ├── ExampleService.ts
|
|
182
|
+
│ └── index.ts
|
|
183
|
+
├── 📂 providers/ # Context suppliers (optional)
|
|
184
|
+
│ ├── exampleProvider.ts
|
|
185
|
+
│ └── index.ts
|
|
186
|
+
├── 📂 evaluators/ # Learning components (optional)
|
|
187
|
+
│ ├── exampleEvaluator.ts
|
|
188
|
+
│ └── index.ts
|
|
189
|
+
├── 📂 types/ # TypeScript definitions
|
|
190
|
+
│ └── index.ts
|
|
191
|
+
├── 📄 index.ts # Plugin export
|
|
192
|
+
└── 📄 package.json # Dependencies and metadata
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## 📦 Plugin Export Pattern
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// src/index.ts
|
|
199
|
+
import { Plugin } from '@elizaos/core';
|
|
200
|
+
import { ExampleService } from './services';
|
|
201
|
+
import { exampleAction } from './actions';
|
|
202
|
+
import { exampleProvider } from './providers';
|
|
203
|
+
import { exampleEvaluator } from './evaluators';
|
|
204
|
+
|
|
205
|
+
export const plugin: Plugin = {
|
|
206
|
+
name: 'example-plugin',
|
|
207
|
+
description: 'Demonstrates ElizaOS plugin patterns',
|
|
208
|
+
|
|
209
|
+
// Core components
|
|
210
|
+
services: [ExampleService],
|
|
211
|
+
actions: [exampleAction],
|
|
212
|
+
|
|
213
|
+
// Optional components
|
|
214
|
+
providers: [exampleProvider],
|
|
215
|
+
evaluators: [exampleEvaluator],
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export default plugin;
|
|
219
|
+
|
|
220
|
+
// Re-export components for external use
|
|
221
|
+
export { ExampleService } from './services';
|
|
222
|
+
export * from './types';
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## 🚀 Development Workflow
|
|
226
|
+
|
|
227
|
+
### Quick Start Commands
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Install dependencies
|
|
231
|
+
bun install
|
|
232
|
+
|
|
233
|
+
# Start development with hot reload
|
|
234
|
+
elizaos dev
|
|
235
|
+
|
|
236
|
+
# Run tests
|
|
237
|
+
bun test
|
|
238
|
+
|
|
239
|
+
# Build for production
|
|
240
|
+
bun run build
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### 🧪 Testing Your Plugin
|
|
244
|
+
|
|
245
|
+
#### **Method 1: Dev Mode (Recommended)**
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
elizaos dev
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
This automatically:
|
|
252
|
+
|
|
253
|
+
- Loads your plugin from current directory
|
|
254
|
+
- Creates a test character with your plugin
|
|
255
|
+
- Starts interactive chat interface
|
|
256
|
+
- Enables hot reloading
|
|
257
|
+
|
|
258
|
+
#### **Method 2: Unit Testing**
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
// tests/actions.test.ts
|
|
262
|
+
import { describe, it, expect } from 'bun:test';
|
|
263
|
+
import { exampleAction } from '../src/actions';
|
|
264
|
+
|
|
265
|
+
describe('ExampleAction', () => {
|
|
266
|
+
it('validates trigger words correctly', async () => {
|
|
267
|
+
const mockMessage = {
|
|
268
|
+
content: { text: 'show me an example' },
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const isValid = await exampleAction.validate(mockRuntime, mockMessage);
|
|
272
|
+
|
|
273
|
+
expect(isValid).toBe(true);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## 🎯 Best Practices
|
|
279
|
+
|
|
280
|
+
### ✅ **DO**
|
|
281
|
+
|
|
282
|
+
- **Use Services for APIs**: All external calls go through services
|
|
283
|
+
- **Validate User Input**: Always validate in action handlers
|
|
284
|
+
- **Handle Errors Gracefully**: Provide meaningful error messages
|
|
285
|
+
- **Follow TypeScript**: Use strict typing throughout
|
|
286
|
+
- **Test Thoroughly**: Write tests for core functionality
|
|
287
|
+
|
|
288
|
+
### ❌ **DON'T**
|
|
289
|
+
|
|
290
|
+
- **API Calls in Actions**: Use services instead
|
|
291
|
+
- **State in Providers**: Keep providers read-only
|
|
292
|
+
- **Parse Input in Evaluators**: Use actions for input handling
|
|
293
|
+
- **Hardcode Credentials**: Use environment variables
|
|
294
|
+
- **Skip Error Handling**: Always handle potential failures
|
|
295
|
+
|
|
296
|
+
### 🔧 **Common Patterns**
|
|
297
|
+
|
|
298
|
+
#### Error Handling Pattern
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
export const robustAction: Action = {
|
|
302
|
+
name: 'ROBUST_ACTION',
|
|
303
|
+
description: 'Demonstrates robust error handling',
|
|
304
|
+
|
|
305
|
+
validate: async (runtime: IAgentRuntime, message: Memory) => {
|
|
306
|
+
// Validate user input before processing
|
|
307
|
+
const text = message.content.text.toLowerCase();
|
|
308
|
+
return text.includes('process') || text.includes('execute');
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
handler: async (runtime, message, state, options, callback): Promise<ActionResult> => {
|
|
312
|
+
try {
|
|
313
|
+
const service = runtime.getService<YourService>('yourService');
|
|
314
|
+
if (!service) {
|
|
315
|
+
throw new Error('Service not available');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const result = await service.performOperation();
|
|
319
|
+
|
|
320
|
+
await callback({
|
|
321
|
+
text: `Operation completed: ${result}`,
|
|
322
|
+
action: 'ROBUST_ACTION',
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
success: true,
|
|
327
|
+
text: `Successfully completed operation`,
|
|
328
|
+
values: {
|
|
329
|
+
operationResult: result,
|
|
330
|
+
processedAt: Date.now(),
|
|
331
|
+
},
|
|
332
|
+
data: {
|
|
333
|
+
actionName: 'ROBUST_ACTION',
|
|
334
|
+
result,
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
} catch (error) {
|
|
338
|
+
console.error(`Action failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
339
|
+
|
|
340
|
+
await callback({
|
|
341
|
+
text: "I'm sorry, I couldn't complete that request. Please try again.",
|
|
342
|
+
error: true,
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
return {
|
|
346
|
+
success: false,
|
|
347
|
+
text: 'Failed to complete operation',
|
|
348
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
349
|
+
data: {
|
|
350
|
+
actionName: 'ROBUST_ACTION',
|
|
351
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
#### Service Initialization Pattern
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
export class RobustService extends Service {
|
|
363
|
+
private client: ExternalClient;
|
|
364
|
+
private isInitialized = false;
|
|
365
|
+
|
|
366
|
+
async initialize(runtime: IAgentRuntime): Promise<void> {
|
|
367
|
+
try {
|
|
368
|
+
this.client = new ExternalClient({
|
|
369
|
+
apiKey: process.env.EXTERNAL_API_KEY,
|
|
370
|
+
timeout: 30000,
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
await this.client.authenticate();
|
|
374
|
+
this.isInitialized = true;
|
|
375
|
+
|
|
376
|
+
console.log('Service initialized successfully');
|
|
377
|
+
} catch (error) {
|
|
378
|
+
console.error('Service initialization failed:', error);
|
|
379
|
+
throw error;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
private ensureInitialized(): void {
|
|
384
|
+
if (!this.isInitialized) {
|
|
385
|
+
throw new Error('Service not initialized');
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async performOperation(): Promise<any> {
|
|
390
|
+
this.ensureInitialized();
|
|
391
|
+
return await this.client.operation();
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## 🐛 Debugging Guide
|
|
397
|
+
|
|
398
|
+
### Environment Variables
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
# Enable detailed logging
|
|
402
|
+
LOG_LEVEL=debug elizaos dev
|
|
403
|
+
|
|
404
|
+
# Test specific components
|
|
405
|
+
elizaos test --filter "action-name"
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Common Issues & Solutions
|
|
409
|
+
|
|
410
|
+
| Issue | Cause | Solution |
|
|
411
|
+
| ----------------------- | ------------------------------ | ---------------------------- |
|
|
412
|
+
| "Service not found" | Service not registered | Add to plugin services array |
|
|
413
|
+
| "Action not triggering" | Validation function too strict | Check validate() logic |
|
|
414
|
+
| "Provider not updating" | Provider has state | Make provider stateless |
|
|
415
|
+
| "Memory errors" | Database connection issues | Check database adapter setup |
|
|
416
|
+
|
|
417
|
+
## 📋 Package.json Template
|
|
418
|
+
|
|
419
|
+
```json
|
|
420
|
+
{
|
|
421
|
+
"name": "@your-org/elizaos-plugin-example",
|
|
422
|
+
"version": "1.0.0",
|
|
423
|
+
"description": "ElizaOS plugin for example functionality",
|
|
424
|
+
"type": "module",
|
|
425
|
+
"main": "dist/index.js",
|
|
426
|
+
"types": "dist/index.d.ts",
|
|
427
|
+
"files": ["dist"],
|
|
428
|
+
|
|
429
|
+
"scripts": {
|
|
430
|
+
"build": "bun run build:types && bun run build:js",
|
|
431
|
+
"build:types": "tsc",
|
|
432
|
+
"build:js": "bun build src/index.ts --outdir dist",
|
|
433
|
+
"test": "bun test",
|
|
434
|
+
"dev": "elizaos dev"
|
|
435
|
+
},
|
|
436
|
+
|
|
437
|
+
"peerDependencies": {
|
|
438
|
+
"@elizaos/core": "*"
|
|
439
|
+
},
|
|
440
|
+
|
|
441
|
+
"devDependencies": {
|
|
442
|
+
"@types/bun": "latest",
|
|
443
|
+
"typescript": "^5.0.0"
|
|
444
|
+
},
|
|
445
|
+
|
|
446
|
+
"keywords": ["elizaos", "plugin", "ai-agent"]
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
## 🎯 Final Checklist
|
|
451
|
+
|
|
452
|
+
Before publishing your plugin:
|
|
453
|
+
|
|
454
|
+
- [ ] All services have proper initialization
|
|
455
|
+
- [ ] Actions validate user input correctly
|
|
456
|
+
- [ ] Error handling covers edge cases
|
|
457
|
+
- [ ] Tests pass for core functionality
|
|
458
|
+
- [ ] TypeScript compiles without errors
|
|
459
|
+
- [ ] Plugin exports are correct
|
|
460
|
+
- [ ] Documentation is complete
|
|
461
|
+
- [ ] Environment variables are documented
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
**🎉 Ready to build your ElizaOS plugin!** Start with the dev mode and iterate based on real testing.
|