|
| 1 | +# @elizaos/plugin-dummy-services |
| 2 | + |
| 3 | +Mock/dummy service implementations for testing ElizaOS agents without external API dependencies. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +This plugin provides dummy implementations of common ElizaOS services, enabling developers to test agent functionality without requiring external API keys, network connections, or third-party services. All services return predictable mock data, making them ideal for unit tests, integration tests, and local development. |
| 8 | + |
| 9 | +## Installation |
| 10 | + |
| 11 | +```bash |
| 12 | +bun add @elizaos/plugin-dummy-services |
| 13 | +``` |
| 14 | + |
| 15 | +## Available Services |
| 16 | + |
| 17 | +| Service | Service Type | Description | |
| 18 | +|---------|--------------|-------------| |
| 19 | +| `DummyTokenDataService` | `token_data` | Mock token/cryptocurrency data with prices, market caps, and volume | |
| 20 | +| `DummyLpService` | `lp` | Mock liquidity pool operations (add/remove liquidity, swaps) | |
| 21 | +| `DummyWalletService` | `wallet` | Mock wallet with balance tracking and portfolio management | |
| 22 | +| `DummyPdfService` | `pdf` | Mock PDF operations (extract text, generate, merge, split) | |
| 23 | +| `DummyVideoService` | `video` | Mock video processing (info, download, extract audio/frames) | |
| 24 | +| `DummyBrowserService` | `browser` | Mock browser automation (navigate, screenshot, click, type) | |
| 25 | +| `DummyTranscriptionService` | `transcription` | Mock speech-to-text and text-to-speech operations | |
| 26 | +| `DummyWebSearchService` | `web_search` | Mock web, news, image, and video search | |
| 27 | +| `DummyEmailService` | `email` | Mock email operations (send, search, folders) | |
| 28 | + |
| 29 | +## Usage |
| 30 | + |
| 31 | +### Using the Full Plugin |
| 32 | + |
| 33 | +Import and register the plugin to load all dummy services at once: |
| 34 | + |
| 35 | +```typescript |
| 36 | +import { dummyServicesPlugin } from '@elizaos/plugin-dummy-services'; |
| 37 | + |
| 38 | +const character = { |
| 39 | + name: 'TestAgent', |
| 40 | + plugins: [dummyServicesPlugin], |
| 41 | + // ... other character config |
| 42 | +}; |
| 43 | +``` |
| 44 | + |
| 45 | +### Using Individual Services |
| 46 | + |
| 47 | +Import specific services for targeted testing: |
| 48 | + |
| 49 | +```typescript |
| 50 | +import { |
| 51 | + DummyTokenDataService, |
| 52 | + DummyWalletService, |
| 53 | + DummyBrowserService, |
| 54 | +} from '@elizaos/plugin-dummy-services'; |
| 55 | + |
| 56 | +// Access services via runtime |
| 57 | +const tokenService = runtime.getService<DummyTokenDataService>('token_data'); |
| 58 | +const walletService = runtime.getService<DummyWalletService>('wallet'); |
| 59 | +const browserService = runtime.getService<DummyBrowserService>('browser'); |
| 60 | +``` |
| 61 | + |
| 62 | +## Service Details |
| 63 | + |
| 64 | +### DummyTokenDataService |
| 65 | + |
| 66 | +Provides mock cryptocurrency/token data: |
| 67 | + |
| 68 | +```typescript |
| 69 | +const tokenService = runtime.getService<DummyTokenDataService>('token_data'); |
| 70 | + |
| 71 | +// Get token data by address |
| 72 | +const token = await tokenService.getTokenData('0x...'); |
| 73 | +// Returns: { symbol, name, priceUsd, marketCapUsd, volume24hUsd, ... } |
| 74 | + |
| 75 | +// Get token by symbol |
| 76 | +const token = await tokenService.getTokenDataBySymbol('ETH'); |
| 77 | + |
| 78 | +// Get trending tokens |
| 79 | +const trending = await tokenService.getTrendingTokens('solana', 10); |
| 80 | + |
| 81 | +// Search tokens |
| 82 | +const results = await tokenService.searchTokens('BTC', 'ethereum', 5); |
| 83 | +``` |
| 84 | + |
| 85 | +### DummyLpService |
| 86 | + |
| 87 | +Provides mock liquidity pool operations: |
| 88 | + |
| 89 | +```typescript |
| 90 | +const lpService = runtime.getService<DummyLpService>('lp'); |
| 91 | + |
| 92 | +// Get pool info |
| 93 | +const pool = await lpService.getPoolInfo('0xPoolAddress'); |
| 94 | + |
| 95 | +// Add liquidity |
| 96 | +const result = await lpService.addLiquidity({ |
| 97 | + poolAddress: '0x...', |
| 98 | + tokenAMint: '0x...', |
| 99 | + tokenBMint: '0x...', |
| 100 | + tokenAAmountLamports: '1000000000', |
| 101 | + slippageBps: 50, |
| 102 | +}); |
| 103 | + |
| 104 | +// Remove liquidity |
| 105 | +const result = await lpService.removeLiquidity({ |
| 106 | + poolAddress: '0x...', |
| 107 | + lpTokenMint: '0x...', |
| 108 | + lpTokenAmountLamports: '100000000', |
| 109 | + slippageBps: 50, |
| 110 | +}); |
| 111 | + |
| 112 | +// Get available pools |
| 113 | +const pools = await lpService.getPools(); |
| 114 | +``` |
| 115 | + |
| 116 | +### DummyWalletService |
| 117 | + |
| 118 | +Provides mock wallet with balance management: |
| 119 | + |
| 120 | +```typescript |
| 121 | +const walletService = runtime.getService<DummyWalletService>('wallet'); |
| 122 | + |
| 123 | +// Get balance |
| 124 | +const balance = await walletService.getBalance('USDC'); |
| 125 | + |
| 126 | +// Set portfolio holdings (for test setup) |
| 127 | +walletService.setPortfolioHolding('ETH', 10, 2000); // 10 ETH at $2000 |
| 128 | + |
| 129 | +// Get full portfolio |
| 130 | +const portfolio = walletService.getPortfolio(); |
| 131 | +// Returns: { totalValueUsd, assets: [{ symbol, balance, valueUsd, allocation }] } |
| 132 | + |
| 133 | +// Reset wallet to initial state |
| 134 | +walletService.resetWallet(10000, 'USDC'); // $10,000 USDC |
| 135 | +``` |
| 136 | + |
| 137 | +### DummyPdfService |
| 138 | + |
| 139 | +Provides mock PDF operations: |
| 140 | + |
| 141 | +```typescript |
| 142 | +const pdfService = runtime.getService<DummyPdfService>('pdf'); |
| 143 | + |
| 144 | +// Extract text from PDF |
| 145 | +const result = await pdfService.extractText(pdfBuffer); |
| 146 | +// Returns: { text, metadata: { title, author, pages, creationDate } } |
| 147 | + |
| 148 | +// Generate PDF from content |
| 149 | +const pdf = await pdfService.generatePdf('Hello World', { format: 'A4' }); |
| 150 | + |
| 151 | +// Merge multiple PDFs |
| 152 | +const merged = await pdfService.mergePdfs([pdf1, pdf2, pdf3]); |
| 153 | + |
| 154 | +// Split PDF into parts |
| 155 | +const parts = await pdfService.splitPdf(pdfBuffer, [[1, 5], [6, 10]]); |
| 156 | +``` |
| 157 | + |
| 158 | +### DummyVideoService |
| 159 | + |
| 160 | +Provides mock video processing: |
| 161 | + |
| 162 | +```typescript |
| 163 | +const videoService = runtime.getService<DummyVideoService>('video'); |
| 164 | + |
| 165 | +// Get video info |
| 166 | +const info = await videoService.getVideoInfo('https://example.com/video'); |
| 167 | +// Returns: { title, duration, resolution, format, size, fps, codec } |
| 168 | + |
| 169 | +// Download video |
| 170 | +const buffer = await videoService.downloadVideo(url, { quality: 'highest' }); |
| 171 | + |
| 172 | +// Extract audio |
| 173 | +const audio = await videoService.extractAudio(videoBuffer); |
| 174 | + |
| 175 | +// Extract frames at specific timestamps |
| 176 | +const frames = await videoService.extractFrames(videoBuffer, [0, 5, 10]); |
| 177 | + |
| 178 | +// Get available formats |
| 179 | +const formats = await videoService.getAvailableFormats(url); |
| 180 | +``` |
| 181 | + |
| 182 | +### DummyBrowserService |
| 183 | + |
| 184 | +Provides mock browser automation: |
| 185 | + |
| 186 | +```typescript |
| 187 | +const browserService = runtime.getService<DummyBrowserService>('browser'); |
| 188 | + |
| 189 | +// Navigate to URL |
| 190 | +await browserService.navigate('https://example.com', { waitUntil: 'load' }); |
| 191 | + |
| 192 | +// Take screenshot |
| 193 | +const screenshot = await browserService.screenshot({ fullPage: true }); |
| 194 | + |
| 195 | +// Extract content |
| 196 | +const content = await browserService.extractContent([ |
| 197 | + { selector: '.main-content', type: 'css' } |
| 198 | +]); |
| 199 | + |
| 200 | +// Interact with elements |
| 201 | +await browserService.click({ selector: '#submit-btn', type: 'css' }); |
| 202 | +await browserService. type({ selector: '#email', type: 'css' }, '[email protected]'); |
| 203 | + |
| 204 | +// Navigation history |
| 205 | +await browserService.goBack(); |
| 206 | +await browserService.goForward(); |
| 207 | +await browserService.refresh(); |
| 208 | +``` |
| 209 | + |
| 210 | +### DummyTranscriptionService |
| 211 | + |
| 212 | +Provides mock speech-to-text and text-to-speech: |
| 213 | + |
| 214 | +```typescript |
| 215 | +const transcriptionService = runtime.getService<DummyTranscriptionService>('transcription'); |
| 216 | + |
| 217 | +// Transcribe audio |
| 218 | +const result = await transcriptionService.transcribeAudio(audioBuffer, { |
| 219 | + language: 'en', |
| 220 | + timestamps: true, |
| 221 | +}); |
| 222 | +// Returns: { text, language, duration, segments, words } |
| 223 | + |
| 224 | +// Speech to text |
| 225 | +const text = await transcriptionService.speechToText(audioBuffer); |
| 226 | + |
| 227 | +// Text to speech |
| 228 | +const audio = await transcriptionService.textToSpeech('Hello world', { |
| 229 | + voice: 'en-US', |
| 230 | + format: 'mp3', |
| 231 | +}); |
| 232 | + |
| 233 | +// Detect language |
| 234 | +const language = await transcriptionService.detectLanguage(audioBuffer); |
| 235 | + |
| 236 | +// Translate audio |
| 237 | +const translated = await transcriptionService.translateAudio(audioBuffer, 'es', 'en'); |
| 238 | +``` |
| 239 | + |
| 240 | +### DummyWebSearchService |
| 241 | + |
| 242 | +Provides mock web search operations: |
| 243 | + |
| 244 | +```typescript |
| 245 | +const searchService = runtime.getService<DummyWebSearchService>('web_search'); |
| 246 | + |
| 247 | +// Web search |
| 248 | +const results = await searchService.search({ |
| 249 | + query: 'ElizaOS', |
| 250 | + limit: 10, |
| 251 | +}); |
| 252 | +// Returns: { results: [{ title, url, description, relevanceScore }], totalResults } |
| 253 | + |
| 254 | +// News search |
| 255 | +const news = await searchService.searchNews({ |
| 256 | + query: 'AI agents', |
| 257 | + sortBy: 'date', |
| 258 | +}); |
| 259 | + |
| 260 | +// Image search |
| 261 | +const images = await searchService.searchImages({ |
| 262 | + query: 'robots', |
| 263 | + size: 'large', |
| 264 | +}); |
| 265 | + |
| 266 | +// Video search |
| 267 | +const videos = await searchService.searchVideos({ |
| 268 | + query: 'tutorial', |
| 269 | + duration: 'medium', |
| 270 | +}); |
| 271 | + |
| 272 | +// Autocomplete suggestions |
| 273 | +const suggestions = await searchService.autocomplete('eliza'); |
| 274 | + |
| 275 | +// Trending searches |
| 276 | +const trending = await searchService.getTrendingSearches('US'); |
| 277 | +``` |
| 278 | + |
| 279 | +### DummyEmailService |
| 280 | + |
| 281 | +Provides mock email operations: |
| 282 | + |
| 283 | +```typescript |
| 284 | +const emailService = runtime.getService<DummyEmailService>('email'); |
| 285 | + |
| 286 | +// Send email |
| 287 | +const messageId = await emailService.sendEmail( |
| 288 | + [{ address: '[email protected]', name: 'Recipient' }], |
| 289 | + 'Test Subject', |
| 290 | + 'Email body content', |
| 291 | + { |
| 292 | + cc: [{ address: '[email protected]' }], |
| 293 | + attachments: [{ filename: 'doc.pdf', content: buffer }], |
| 294 | + } |
| 295 | +); |
| 296 | + |
| 297 | +// Search emails |
| 298 | +const emails = await emailService.searchEmails({ |
| 299 | + |
| 300 | + subject: 'important', |
| 301 | + limit: 10, |
| 302 | +}); |
| 303 | + |
| 304 | +// Get specific email |
| 305 | +const email = await emailService.getEmail(messageId); |
| 306 | + |
| 307 | +// Folder operations |
| 308 | +const folders = await emailService.getFolders(); |
| 309 | +await emailService.createFolder('Projects'); |
| 310 | +await emailService.moveToFolder(messageId, 'Projects'); |
| 311 | + |
| 312 | +// Reply and forward |
| 313 | +await emailService.replyToEmail(messageId, 'Reply body', { replyAll: true }); |
| 314 | +await emailService. forwardEmail( messageId, [{ address: '[email protected]' }]); |
| 315 | +``` |
| 316 | + |
| 317 | +## When to Use Dummy Services vs Real Services |
| 318 | + |
| 319 | +| Scenario | Recommended | |
| 320 | +|----------|-------------| |
| 321 | +| Unit tests | Dummy services | |
| 322 | +| Integration tests (isolated) | Dummy services | |
| 323 | +| E2E tests (full stack) | Real services or configurable | |
| 324 | +| Local development without API keys | Dummy services | |
| 325 | +| CI/CD pipelines | Dummy services | |
| 326 | +| Production | Real services | |
| 327 | +| Demo/showcase environments | Dummy services | |
| 328 | +| Performance testing | Real services | |
| 329 | + |
| 330 | +## Testing |
| 331 | + |
| 332 | +The plugin includes built-in E2E test scenarios: |
| 333 | + |
| 334 | +```typescript |
| 335 | +import { dummyServicesScenariosSuite } from '@elizaos/plugin-dummy-services'; |
| 336 | + |
| 337 | +// The test suite is automatically registered with the plugin |
| 338 | +// Run tests via: bun test |
| 339 | +``` |
| 340 | + |
| 341 | +## License |
| 342 | + |
| 343 | +MIT |
0 commit comments