@elizaos/plugin-browser 1.0.0-beta.8 → 1.0.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/README.md +32 -352
- package/dist/index.d.ts +5 -0
- package/dist/index.js +26 -8
- package/dist/index.js.map +1 -1
- package/package.json +29 -21
- package/scripts/postinstall.js +0 -67
- package/tsup.config.ts +0 -23
package/README.md
CHANGED
|
@@ -1,384 +1,64 @@
|
|
|
1
1
|
# @elizaos/plugin-browser
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The Node plugin serves as a foundational component of Eliza OS, bridging core Node.js capabilities with the Eliza ecosystem. It provides crucial services for file operations, media processing, speech synthesis, and cloud integrations, enabling both local and cloud-based functionality for Eliza agents.
|
|
3
|
+
Browser plugin for Eliza OS that provides web browsing and scraping capabilities.
|
|
8
4
|
|
|
9
5
|
## Features
|
|
10
6
|
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **Speech Synthesis**: Text-to-speech using ElevenLabs and VITS
|
|
16
|
-
- **Transcription**: Speech-to-text using various providers (OpenAI, Deepgram, Local)
|
|
17
|
-
- **Video Processing**: YouTube video download and transcription
|
|
18
|
-
- **LLaMA Integration**: Local LLM support with LLaMA models
|
|
7
|
+
- **Web Browsing**: Navigate and interact with web pages
|
|
8
|
+
- **Content Extraction**: Extract text and metadata from web pages
|
|
9
|
+
- **CAPTCHA Solving**: Automatic CAPTCHA detection and solving
|
|
10
|
+
- **Stealth Mode**: Reduced bot detection with proper user agents and headers
|
|
19
11
|
|
|
20
12
|
## Installation
|
|
21
13
|
|
|
22
14
|
```bash
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Configuration
|
|
27
|
-
|
|
28
|
-
The plugin requires various environment variables depending on which services you plan to use:
|
|
29
|
-
|
|
30
|
-
### Core Settings
|
|
31
|
-
|
|
32
|
-
```env
|
|
33
|
-
OPENAI_API_KEY=your_openai_api_key
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### Voice Settings (Optional)
|
|
37
|
-
|
|
38
|
-
```env
|
|
39
|
-
ELEVENLABS_API_KEY=your_elevenlabs_api_key
|
|
40
|
-
ELEVENLABS_MODEL_ID=eleven_monolingual_v1
|
|
41
|
-
ELEVENLABS_VOICE_ID=your_voice_id
|
|
42
|
-
ELEVENLABS_VOICE_STABILITY=0.5
|
|
43
|
-
ELEVENLABS_VOICE_SIMILARITY_BOOST=0.75
|
|
44
|
-
ELEVENLABS_OPTIMIZE_STREAMING_LATENCY=0
|
|
45
|
-
ELEVENLABS_OUTPUT_FORMAT=pcm_16000
|
|
46
|
-
VITS_VOICE=en_US-hfc_female-medium
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### AWS Settings (Optional)
|
|
50
|
-
|
|
51
|
-
```env
|
|
52
|
-
AWS_ACCESS_KEY_ID=your_aws_access_key
|
|
53
|
-
AWS_SECRET_ACCESS_KEY=your_aws_secret_key
|
|
54
|
-
AWS_REGION=your_aws_region
|
|
55
|
-
AWS_S3_BUCKET=your_s3_bucket
|
|
56
|
-
AWS_S3_UPLOAD_PATH=your_upload_path
|
|
57
|
-
AWS_S3_ENDPOINT=an_alternative_endpoint
|
|
58
|
-
AWS_S3_SSL_ENABLED=boolean(true|false)
|
|
59
|
-
AWS_S3_FORCE_PATH_STYLE=boolean(true|false)
|
|
15
|
+
npm install @elizaos/plugin-browser
|
|
60
16
|
```
|
|
61
17
|
|
|
62
18
|
## Usage
|
|
63
19
|
|
|
64
20
|
```typescript
|
|
65
|
-
import {
|
|
66
|
-
|
|
67
|
-
// Initialize the plugin
|
|
68
|
-
const nodePlugin = createNodePlugin();
|
|
21
|
+
import { browserPlugin } from '@elizaos/plugin-browser';
|
|
69
22
|
|
|
70
|
-
//
|
|
71
|
-
|
|
23
|
+
// Add to your Eliza configuration
|
|
24
|
+
export default {
|
|
25
|
+
plugins: [browserPlugin],
|
|
26
|
+
// ... other config
|
|
27
|
+
};
|
|
72
28
|
```
|
|
73
29
|
|
|
74
|
-
##
|
|
75
|
-
|
|
76
|
-
### AwsS3Service
|
|
77
|
-
|
|
78
|
-
Handles file uploads and management with AWS S3.
|
|
79
|
-
|
|
80
|
-
### BrowserService
|
|
81
|
-
|
|
82
|
-
Provides web scraping and content extraction capabilities using Playwright.
|
|
83
|
-
|
|
84
|
-
### ImageDescriptionService
|
|
85
|
-
|
|
86
|
-
Processes and analyzes images to generate descriptions. Supports multiple providers:
|
|
87
|
-
|
|
88
|
-
- Local processing using Florence model
|
|
89
|
-
- OpenAI Vision API
|
|
90
|
-
- Google Gemini
|
|
91
|
-
|
|
92
|
-
Configuration:
|
|
93
|
-
|
|
94
|
-
```env
|
|
95
|
-
# For OpenAI Vision
|
|
96
|
-
OPENAI_API_KEY=your_openai_api_key
|
|
97
|
-
|
|
98
|
-
# For Google Gemini
|
|
99
|
-
GOOGLE_GENERATIVE_AI_API_KEY=your_google_api_key
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Provider selection:
|
|
103
|
-
|
|
104
|
-
- If `imageVisionModelProvider` is set to `google/openai`, it will use this one.
|
|
105
|
-
- Else if `model` is set to `google/openai`, it will use this one.
|
|
106
|
-
- Default if nothing is set is OpenAI.
|
|
107
|
-
|
|
108
|
-
The service automatically handles different image formats, including GIFs (first frame extraction).
|
|
109
|
-
|
|
110
|
-
Features by provider:
|
|
111
|
-
|
|
112
|
-
**Local (Florence):**
|
|
113
|
-
|
|
114
|
-
- Basic image captioning
|
|
115
|
-
- Local processing without API calls
|
|
116
|
-
|
|
117
|
-
**OpenAI Vision:**
|
|
118
|
-
|
|
119
|
-
- Detailed image descriptions
|
|
120
|
-
- Text detection
|
|
121
|
-
- Object recognition
|
|
122
|
-
|
|
123
|
-
**Google Gemini 1.5:**
|
|
124
|
-
|
|
125
|
-
- High-quality image understanding
|
|
126
|
-
- Detailed descriptions with natural language
|
|
127
|
-
- Multi-modal context understanding
|
|
128
|
-
- Support for complex scenes and content
|
|
129
|
-
|
|
130
|
-
The provider can be configured through the runtime settings, allowing easy switching between providers based on your needs.
|
|
131
|
-
|
|
132
|
-
### LlamaService
|
|
133
|
-
|
|
134
|
-
Provides local LLM capabilities using LLaMA models.
|
|
135
|
-
|
|
136
|
-
### PdfService
|
|
137
|
-
|
|
138
|
-
Extracts and processes text content from PDF files.
|
|
139
|
-
|
|
140
|
-
### SpeechService
|
|
141
|
-
|
|
142
|
-
Handles text-to-speech conversion using ElevenLabs and VITS.
|
|
143
|
-
|
|
144
|
-
### TranscriptionService
|
|
145
|
-
|
|
146
|
-
Converts speech to text using various providers.
|
|
147
|
-
|
|
148
|
-
### VideoService
|
|
149
|
-
|
|
150
|
-
Processes video content, including YouTube video downloads and transcription.
|
|
151
|
-
|
|
152
|
-
## Actions
|
|
153
|
-
|
|
154
|
-
### describeImage
|
|
155
|
-
|
|
156
|
-
Analyzes and generates descriptions for images.
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
// Example usage
|
|
160
|
-
const result = await runtime.executeAction('DESCRIBE_IMAGE', {
|
|
161
|
-
imageUrl: 'path/to/image.jpg',
|
|
162
|
-
});
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
## Dependencies
|
|
166
|
-
|
|
167
|
-
The plugin requires several peer dependencies:
|
|
168
|
-
|
|
169
|
-
- `onnxruntime-node`: 1.20.1
|
|
170
|
-
- `whatwg-url`: 7.1.0
|
|
171
|
-
|
|
172
|
-
And trusted dependencies:
|
|
173
|
-
|
|
174
|
-
- `onnxruntime-node`: 1.20.1
|
|
175
|
-
- `sharp`: 0.33.5
|
|
176
|
-
|
|
177
|
-
## Safety & Security
|
|
178
|
-
|
|
179
|
-
### File Operations
|
|
180
|
-
|
|
181
|
-
- **Path Sanitization**: All file paths are sanitized to prevent directory traversal attacks
|
|
182
|
-
- **File Size Limits**: Enforced limits on upload sizes
|
|
183
|
-
- **Type Checking**: Strict file type validation
|
|
184
|
-
- **Temporary File Cleanup**: Automatic cleanup of temporary files
|
|
185
|
-
|
|
186
|
-
### API Keys & Credentials
|
|
187
|
-
|
|
188
|
-
- **Environment Isolation**: Sensitive credentials are isolated in environment variables
|
|
189
|
-
- **Access Scoping**: Services are initialized with minimum required permissions
|
|
190
|
-
- **Key Rotation**: Support for credential rotation without service interruption
|
|
191
|
-
|
|
192
|
-
### Media Processing
|
|
193
|
-
|
|
194
|
-
- **Resource Limits**: Memory and CPU usage limits for media processing
|
|
195
|
-
- **Timeout Controls**: Automatic termination of long-running processes
|
|
196
|
-
- **Format Validation**: Strict media format validation before processing
|
|
197
|
-
|
|
198
|
-
## Troubleshooting
|
|
30
|
+
## Configuration
|
|
199
31
|
|
|
200
|
-
|
|
32
|
+
The plugin uses the following environment variables:
|
|
201
33
|
|
|
202
|
-
|
|
34
|
+
- `CAPSOLVER_API_KEY` - API key for CAPTCHA solving service (optional)
|
|
203
35
|
|
|
204
|
-
|
|
205
|
-
Error: Service initialization failed
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
- Verify environment variables are properly set
|
|
209
|
-
- Check service dependencies are installed
|
|
210
|
-
- Ensure sufficient system permissions
|
|
211
|
-
|
|
212
|
-
2. **Media Processing Errors**
|
|
36
|
+
## Services
|
|
213
37
|
|
|
214
|
-
|
|
215
|
-
Error: Failed to process media file
|
|
216
|
-
```
|
|
38
|
+
### BrowserService
|
|
217
39
|
|
|
218
|
-
|
|
219
|
-
-
|
|
220
|
-
-
|
|
40
|
+
Provides web browsing capabilities including:
|
|
41
|
+
- Page content extraction
|
|
42
|
+
- CAPTCHA detection and solving
|
|
43
|
+
- Alternative source fallbacks (Internet Archive, Google Search)
|
|
44
|
+
- Content caching for performance
|
|
221
45
|
|
|
222
|
-
|
|
46
|
+
## Development
|
|
223
47
|
|
|
224
48
|
```bash
|
|
225
|
-
|
|
226
|
-
|
|
49
|
+
# Install dependencies
|
|
50
|
+
npm install
|
|
227
51
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
- Ensure correct region configuration
|
|
52
|
+
# Build the plugin
|
|
53
|
+
npm run build
|
|
231
54
|
|
|
232
|
-
|
|
55
|
+
# Development mode with watch
|
|
56
|
+
npm run dev
|
|
233
57
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
```typescript
|
|
237
|
-
process.env.DEBUG = 'eliza:plugin-node:*';
|
|
58
|
+
# Format code
|
|
59
|
+
npm run format
|
|
238
60
|
```
|
|
239
61
|
|
|
240
|
-
### System Requirements
|
|
241
|
-
|
|
242
|
-
- Node.js 16.x or higher
|
|
243
|
-
- FFmpeg for media processing
|
|
244
|
-
- Minimum 4GB RAM recommended
|
|
245
|
-
- CUDA-compatible GPU (optional, for ML features)
|
|
246
|
-
|
|
247
|
-
### Performance Optimization
|
|
248
|
-
|
|
249
|
-
1. **Cache Management**
|
|
250
|
-
|
|
251
|
-
- Regular cleanup of `content_cache` directory
|
|
252
|
-
- Implement cache size limits
|
|
253
|
-
- Monitor disk usage
|
|
254
|
-
|
|
255
|
-
2. **Memory Usage**
|
|
256
|
-
|
|
257
|
-
- Configure max buffer sizes
|
|
258
|
-
- Implement streaming for large files
|
|
259
|
-
- Monitor memory consumption
|
|
260
|
-
|
|
261
|
-
3. **Concurrent Operations**
|
|
262
|
-
- Adjust queue size limits
|
|
263
|
-
- Configure worker threads
|
|
264
|
-
- Monitor process pool
|
|
265
|
-
|
|
266
|
-
## Support
|
|
267
|
-
|
|
268
|
-
For issues and feature requests, please:
|
|
269
|
-
|
|
270
|
-
1. Check the troubleshooting guide above
|
|
271
|
-
2. Review existing GitHub issues
|
|
272
|
-
3. Submit a new issue with:
|
|
273
|
-
- System information
|
|
274
|
-
- Error logs
|
|
275
|
-
- Steps to reproduce
|
|
276
|
-
|
|
277
|
-
## Future Enhancements
|
|
278
|
-
|
|
279
|
-
1. **File Operations**
|
|
280
|
-
|
|
281
|
-
- Enhanced streaming capabilities
|
|
282
|
-
- Advanced compression options
|
|
283
|
-
- Batch file processing
|
|
284
|
-
- File type detection
|
|
285
|
-
- Metadata management
|
|
286
|
-
- Version control integration
|
|
287
|
-
|
|
288
|
-
2. **Media Processing**
|
|
289
|
-
|
|
290
|
-
- Additional video formats
|
|
291
|
-
- Advanced image processing
|
|
292
|
-
- Audio enhancement tools
|
|
293
|
-
- Real-time processing
|
|
294
|
-
- Quality optimization
|
|
295
|
-
- Format conversion
|
|
296
|
-
|
|
297
|
-
3. **Cloud Integration**
|
|
298
|
-
|
|
299
|
-
- Multi-cloud support
|
|
300
|
-
- Advanced caching
|
|
301
|
-
- CDN optimization
|
|
302
|
-
- Auto-scaling features
|
|
303
|
-
- Cost optimization
|
|
304
|
-
- Backup automation
|
|
305
|
-
|
|
306
|
-
4. **Speech Services**
|
|
307
|
-
|
|
308
|
-
- Additional voice models
|
|
309
|
-
- Language expansion
|
|
310
|
-
- Emotion detection
|
|
311
|
-
- Voice cloning
|
|
312
|
-
- Real-time synthesis
|
|
313
|
-
- Custom voice training
|
|
314
|
-
|
|
315
|
-
5. **Browser Automation**
|
|
316
|
-
|
|
317
|
-
- Headless optimization
|
|
318
|
-
- Parallel processing
|
|
319
|
-
- Session management
|
|
320
|
-
- Cookie handling
|
|
321
|
-
- Proxy support
|
|
322
|
-
- Resource optimization
|
|
323
|
-
|
|
324
|
-
6. **Security Features**
|
|
325
|
-
|
|
326
|
-
- Enhanced encryption
|
|
327
|
-
- Access control
|
|
328
|
-
- Audit logging
|
|
329
|
-
- Threat detection
|
|
330
|
-
- Rate limiting
|
|
331
|
-
- Compliance tools
|
|
332
|
-
|
|
333
|
-
7. **Performance Optimization**
|
|
334
|
-
|
|
335
|
-
- Memory management
|
|
336
|
-
- CPU utilization
|
|
337
|
-
- Concurrent operations
|
|
338
|
-
- Resource pooling
|
|
339
|
-
- Cache strategies
|
|
340
|
-
- Load balancing
|
|
341
|
-
|
|
342
|
-
8. **Developer Tools**
|
|
343
|
-
- Enhanced debugging
|
|
344
|
-
- Testing framework
|
|
345
|
-
- Documentation generator
|
|
346
|
-
- CLI improvements
|
|
347
|
-
- Monitoring tools
|
|
348
|
-
- Integration templates
|
|
349
|
-
|
|
350
|
-
We welcome community feedback and contributions to help prioritize these enhancements.
|
|
351
|
-
|
|
352
|
-
## Contributing
|
|
353
|
-
|
|
354
|
-
Contributions are welcome! Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for more information.
|
|
355
|
-
|
|
356
|
-
## Credits
|
|
357
|
-
|
|
358
|
-
This plugin integrates with and builds upon several key technologies:
|
|
359
|
-
|
|
360
|
-
- [Node.js](https://nodejs.org/) - The core runtime environment
|
|
361
|
-
- [FFmpeg](https://ffmpeg.org/) - Media processing capabilities
|
|
362
|
-
- [ElevenLabs](https://elevenlabs.io/) - Voice synthesis
|
|
363
|
-
- [OpenAI](https://openai.com/) - Transcription and AI services
|
|
364
|
-
- [AWS S3](https://aws.amazon.com/s3/) - Cloud storage
|
|
365
|
-
- [Playwright](https://playwright.dev/) - Browser automation
|
|
366
|
-
- [LLaMA](https://github.com/facebookresearch/llama) - Local language models
|
|
367
|
-
- [VITS](https://github.com/jaywalnut310/vits) - Voice synthesis
|
|
368
|
-
- [Deepgram](https://deepgram.com/) - Speech recognition
|
|
369
|
-
- [Sharp](https://sharp.pixelplumbing.com/) - Image processing
|
|
370
|
-
|
|
371
|
-
Special thanks to:
|
|
372
|
-
|
|
373
|
-
- The Node.js community and all the open-source contributors who make these integrations possible.
|
|
374
|
-
- The Eliza community for their contributions and feedback.
|
|
375
|
-
|
|
376
|
-
For more information about Node.js capabilities:
|
|
377
|
-
|
|
378
|
-
- [Node.js Documentation](https://nodejs.org/en/docs/)
|
|
379
|
-
- [Node.js Developer Portal](https://nodejs.org/en/about/)
|
|
380
|
-
- [Node.js GitHub Repository](https://github.com/nodejs/node)
|
|
381
|
-
|
|
382
62
|
## License
|
|
383
63
|
|
|
384
|
-
|
|
64
|
+
MIT
|
package/dist/index.d.ts
ADDED
package/dist/index.js
CHANGED
|
@@ -11,11 +11,11 @@ import {
|
|
|
11
11
|
import CaptchaSolver from "capsolver-npm";
|
|
12
12
|
import { chromium } from "patchright";
|
|
13
13
|
async function generateSummary(runtime, text) {
|
|
14
|
-
|
|
14
|
+
const trimmedText = await trimTokens(text, 1e5, runtime);
|
|
15
15
|
const prompt = `Please generate a concise summary for the following text:
|
|
16
16
|
|
|
17
17
|
Text: """
|
|
18
|
-
${
|
|
18
|
+
${trimmedText}
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
21
|
Respond with a JSON object in the following format:
|
|
@@ -166,6 +166,7 @@ var BrowserService = class _BrowserService extends Service {
|
|
|
166
166
|
try {
|
|
167
167
|
if (!this.context) {
|
|
168
168
|
logger.log("Browser context not initialized. Call initializeBrowser() first.");
|
|
169
|
+
throw new Error("Browser context not initialized");
|
|
169
170
|
}
|
|
170
171
|
page = await this.context.newPage();
|
|
171
172
|
await page.setExtraHTTPHeaders({
|
|
@@ -174,6 +175,7 @@ var BrowserService = class _BrowserService extends Service {
|
|
|
174
175
|
const response = await page.goto(url, { waitUntil: "networkidle" });
|
|
175
176
|
if (!response) {
|
|
176
177
|
logger.error("Failed to load the page");
|
|
178
|
+
throw new Error("Failed to load the page");
|
|
177
179
|
}
|
|
178
180
|
if (response.status() === 403 || response.status() === 404) {
|
|
179
181
|
return await this.tryAlternativeSources(url, runtime);
|
|
@@ -312,13 +314,13 @@ ${bodyContent}`
|
|
|
312
314
|
} catch (error) {
|
|
313
315
|
logger.error("Error fetching from Google Search:", error);
|
|
314
316
|
logger.error("Failed to fetch content from alternative sources");
|
|
315
|
-
return {
|
|
316
|
-
title: url,
|
|
317
|
-
description: "Error, could not fetch content from alternative sources",
|
|
318
|
-
bodyContent: ""
|
|
319
|
-
};
|
|
320
317
|
}
|
|
321
318
|
}
|
|
319
|
+
return {
|
|
320
|
+
title: url,
|
|
321
|
+
description: "Error, could not fetch content from alternative sources",
|
|
322
|
+
bodyContent: ""
|
|
323
|
+
};
|
|
322
324
|
}
|
|
323
325
|
};
|
|
324
326
|
|
|
@@ -327,7 +329,23 @@ var browserPlugin = {
|
|
|
327
329
|
name: "browser-plugin",
|
|
328
330
|
description: "Plugin for browser actions",
|
|
329
331
|
services: [BrowserService],
|
|
330
|
-
actions: []
|
|
332
|
+
actions: [],
|
|
333
|
+
tests: [
|
|
334
|
+
{
|
|
335
|
+
name: "test browser service",
|
|
336
|
+
tests: [
|
|
337
|
+
{
|
|
338
|
+
name: "Browser service initialization",
|
|
339
|
+
fn: async (runtime) => {
|
|
340
|
+
const service = await BrowserService.start(runtime);
|
|
341
|
+
if (!service) {
|
|
342
|
+
throw new Error("Failed to initialize BrowserService");
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
]
|
|
347
|
+
}
|
|
348
|
+
]
|
|
331
349
|
};
|
|
332
350
|
export {
|
|
333
351
|
browserPlugin
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/services/browser.ts","../src/index.ts"],"sourcesContent":["import {\n type IAgentRuntime,\n type IBrowserService,\n ModelType,\n Service,\n type ServiceTypeName,\n ServiceType,\n logger,\n parseJSONObjectFromText,\n stringToUuid,\n trimTokens,\n} from '@elizaos/core';\nimport CaptchaSolver from 'capsolver-npm';\nimport { type Browser, type BrowserContext, type Page, chromium } from 'patchright';\n\n/**\n * Asynchronously generates a summary for a given text using a machine learning model.\n *\n * @param {IAgentRuntime} runtime - The runtime environment for the agent\n * @param {string} text - The text to generate a summary for\n * @returns {Promise<{ title: string; description: string }>} A promise that resolves to an object containing the generated title and summary\n */\nasync function generateSummary(\n runtime: IAgentRuntime,\n text: string\n): Promise<{ title: string; description: string }> {\n // make sure text is under 128k characters\n text = await trimTokens(text, 100000, runtime);\n\n const prompt = `Please generate a concise summary for the following text:\n\n Text: \"\"\"\n ${text}\n \"\"\"\n\n Respond with a JSON object in the following format:\n \\`\\`\\`json\n {\n \"title\": \"Generated Title\",\n \"summary\": \"Generated summary and/or description of the text\"\n }\n \\`\\`\\``;\n\n const response = await runtime.useModel(ModelType.TEXT_SMALL, {\n prompt,\n });\n\n const parsedResponse = parseJSONObjectFromText(response);\n\n if (parsedResponse?.title && parsedResponse?.summary) {\n return {\n title: parsedResponse.title,\n description: parsedResponse.summary,\n };\n }\n\n return {\n title: '',\n description: '',\n };\n}\n\n/**\n * Represents the content of a page.\n * @typedef { Object } PageContent\n * @property { string } title - The title of the page.\n * @property { string } description - The description of the page.\n * @property { string } bodyContent - The main content of the page.\n */\ntype PageContent = {\n title: string;\n description: string;\n bodyContent: string;\n};\n\n/**\n * Represents a BrowserService class that extends Service and implements IBrowserService interface.\n * Provides methods for initializing browser, stopping browser, fetching page content, solving CAPTCHAs, detecting CAPTCHAs, and getting cache key.\n * @extends Service\n * @implements IBrowserService\n */\nexport class BrowserService extends Service implements IBrowserService {\n private browser: Browser | undefined;\n private context: BrowserContext | undefined;\n private captchaSolver: CaptchaSolver;\n private cacheKey = 'content/browser';\n\n static serviceType: ServiceTypeName = ServiceType.BROWSER;\n capabilityDescription = 'The agent is able to browse the web and fetch content';\n\n /**\n * Constructor for the Agent class.\n * @param {IAgentRuntime} runtime - The runtime object for the agent.\n */\n constructor(runtime: IAgentRuntime) {\n super();\n this.runtime = runtime;\n this.browser = undefined;\n this.context = undefined;\n this.captchaSolver = new CaptchaSolver(runtime.getSetting('CAPSOLVER_API_KEY') || '');\n }\n\n /**\n * Starts the BrowserService asynchronously.\n *\n * @param {IAgentRuntime} runtime - The runtime for the agent.\n * @returns {Promise<BrowserService>} A promise that resolves to the initialized BrowserService.\n */\n static async start(runtime: IAgentRuntime): Promise<BrowserService> {\n const service = new BrowserService(runtime);\n await service.initializeBrowser();\n return service;\n }\n\n /**\n * Function to stop the browser service asynchronously.\n *\n * @param {IAgentRuntime} runtime - The runtime environment for the agent.\n */\n static async stop(runtime: IAgentRuntime) {\n const service = runtime.getService(ServiceType.BROWSER);\n if (service) {\n await service.stop();\n }\n }\n\n /**\n * Initializes the browser by launching Chromium with specified options and setting the user agent based on the platform.\n * @returns {Promise<void>} A promise that resolves once the browser is successfully initialized.\n */\n async initializeBrowser() {\n if (!this.browser) {\n this.browser = await chromium.launch({\n headless: true,\n args: [\n '--disable-dev-shm-usage', // Uses /tmp instead of /dev/shm. Prevents memory issues on low-memory systems\n '--block-new-web-contents', // Prevents creation of new windows/tabs\n ],\n });\n\n const platform = process.platform;\n let userAgent = '';\n\n // Change the user agent to match the platform to reduce bot detection\n switch (platform) {\n case 'darwin':\n userAgent =\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\n break;\n case 'win32':\n userAgent =\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\n break;\n case 'linux':\n userAgent =\n 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\n break;\n default:\n userAgent =\n 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\n }\n\n this.context = await this.browser.newContext({\n userAgent,\n acceptDownloads: false,\n });\n }\n }\n\n /**\n * Asynchronously stops the browser and context if they are currently running.\n */\n async stop() {\n if (this.context) {\n await this.context.close();\n this.context = undefined;\n }\n if (this.browser) {\n await this.browser.close();\n this.browser = undefined;\n }\n }\n\n /**\n * Asynchronously fetches the content of a web page.\n *\n * @param {string} url - The URL of the web page to fetch content from.\n * @param {IAgentRuntime} runtime - The runtime environment for the web scraping agent.\n * @returns {Promise<PageContent>} A Promise that resolves with the content of the web page.\n */\n async getPageContent(url: string, runtime: IAgentRuntime): Promise<PageContent> {\n await this.initializeBrowser();\n return await this.fetchPageContent(url, runtime);\n }\n\n /**\n * Generates a cache key for the provided URL by converting it to a UUID string.\n *\n * @param {string} url - The URL for which a cache key is being generated.\n * @returns {string} A UUID string representing the cache key for the URL.\n */\n private getCacheKey(url: string): string {\n return stringToUuid(url);\n }\n\n /**\n * Fetches the content of a page from the specified URL using a headless browser.\n *\n * @param {string} url - The URL of the page to fetch the content from.\n * @param {IAgentRuntime} runtime - The runtime environment for the agent.\n * @returns {Promise<PageContent>} A promise that resolves to the content of the fetched page.\n */\n private async fetchPageContent(url: string, runtime: IAgentRuntime): Promise<PageContent> {\n const cacheKey = this.getCacheKey(url);\n const cached = await runtime.getCache<any>(`${this.cacheKey}/${cacheKey}`);\n\n if (cached) {\n return cached.content;\n }\n\n let page: Page | undefined;\n\n try {\n if (!this.context) {\n logger.log('Browser context not initialized. Call initializeBrowser() first.');\n }\n\n page = await this.context.newPage();\n\n // Enable stealth mode\n await page.setExtraHTTPHeaders({\n 'Accept-Language': 'en-US,en;q=0.9',\n });\n\n const response = await page.goto(url, { waitUntil: 'networkidle' });\n\n if (!response) {\n logger.error('Failed to load the page');\n }\n\n if (response.status() === 403 || response.status() === 404) {\n return await this.tryAlternativeSources(url, runtime);\n }\n\n // Check for CAPTCHA\n const captchaDetected = await this.detectCaptcha(page);\n if (captchaDetected) {\n await this.solveCaptcha(page, url);\n }\n const documentTitle = await page.evaluate(() => document.title);\n const bodyContent = await page.evaluate(() => document.body.innerText);\n const { title: parsedTitle, description } = await generateSummary(\n runtime,\n `${documentTitle}\\n${bodyContent}`\n );\n const content = { title: parsedTitle, description, bodyContent };\n await runtime.setCache<any>(`${this.cacheKey}/${cacheKey}`, {\n url,\n content,\n });\n return content;\n } catch (error) {\n logger.error('Error:', error);\n return {\n title: url,\n description: 'Error, could not fetch content',\n bodyContent: '',\n };\n } finally {\n if (page) {\n await page.close();\n }\n }\n }\n\n /**\n * Detects if a captcha is present on the page based on the specified selectors.\n *\n * @param {Page} page The Puppeteer page to check for captcha.\n * @returns {Promise<boolean>} A boolean indicating whether a captcha was detected.\n */\n private async detectCaptcha(page: Page): Promise<boolean> {\n const captchaSelectors = [\n 'iframe[src*=\"captcha\"]',\n 'div[class*=\"captcha\"]',\n '#captcha',\n '.g-recaptcha',\n '.h-captcha',\n ];\n\n for (const selector of captchaSelectors) {\n const element = await page.$(selector);\n if (element) return true;\n }\n\n return false;\n }\n\n /**\n * Solves the CAPTCHA challenge on the provided page using either hCaptcha or reCaptcha.\n *\n * @param {Page} page - The page where the CAPTCHA challenge needs to be solved.\n * @param {string} url - The URL of the website with the CAPTCHA challenge.\n * @returns {Promise<void>} - A promise that resolves once the CAPTCHA is solved.\n */\n private async solveCaptcha(page: Page, url: string): Promise<void> {\n try {\n const hcaptchaKey = await this.getHCaptchaWebsiteKey(page);\n if (hcaptchaKey) {\n const solution = await this.captchaSolver.hcaptchaProxyless({\n websiteURL: url,\n websiteKey: hcaptchaKey,\n });\n await page.evaluate((token) => {\n // eslint-disable-next-line\n // @ts-ignore\n window.hcaptcha.setResponse(token);\n }, solution.gRecaptchaResponse);\n return;\n }\n\n const recaptchaKey = await this.getReCaptchaWebsiteKey(page);\n if (recaptchaKey) {\n const solution = await this.captchaSolver.recaptchaV2Proxyless({\n websiteURL: url,\n websiteKey: recaptchaKey,\n });\n await page.evaluate((token) => {\n // eslint-disable-next-line\n // @ts-ignore\n document.getElementById('g-recaptcha-response').innerHTML = token;\n }, solution.gRecaptchaResponse);\n }\n } catch (error) {\n logger.error('Error solving CAPTCHA:', error);\n }\n }\n\n /**\n * Get the hCaptcha website key from the given Page\n * @param {Page} page - The Page object to extract the hCaptcha website key from\n * @returns {Promise<string>} The hCaptcha website key\n */\n private async getHCaptchaWebsiteKey(page: Page): Promise<string> {\n return page.evaluate(() => {\n const hcaptchaIframe = document.querySelector('iframe[src*=\"hcaptcha.com\"]');\n if (hcaptchaIframe) {\n const src = hcaptchaIframe.getAttribute('src');\n const match = src?.match(/sitekey=([^&]*)/);\n return match ? match[1] : '';\n }\n return '';\n });\n }\n\n /**\n * Retrieves the ReCaptcha website key from a given page.\n * @param {Page} page - The page to extract the ReCaptcha website key from.\n * @returns {Promise<string>} The ReCaptcha website key, or an empty string if not found.\n */\n private async getReCaptchaWebsiteKey(page: Page): Promise<string> {\n return page.evaluate(() => {\n const recaptchaElement = document.querySelector('.g-recaptcha');\n return recaptchaElement ? recaptchaElement.getAttribute('data-sitekey') || '' : '';\n });\n }\n\n /**\n * Try fetching content from alternative sources if the original source fails.\n *\n * @param {string} url - The URL of the content to fetch.\n * @param {IAgentRuntime} runtime - The runtime environment.\n * @returns {Promise<{ title: string; description: string; bodyContent: string }>} The fetched content with title, description, and body.\n */\n private async tryAlternativeSources(\n url: string,\n runtime: IAgentRuntime\n ): Promise<{ title: string; description: string; bodyContent: string }> {\n // because this (tryAlternativeSources) calls fetchPageContent\n // and fetchPageContent calls tryAlternativeSources\n // we need these url.matches to progress\n // through the things to try\n if (!url.match(/web.archive.org\\/web/)) {\n // Try Internet Archive\n const archiveUrl = `https://web.archive.org/web/${url}`;\n try {\n return await this.fetchPageContent(archiveUrl, runtime);\n } catch (error) {\n logger.error('Error fetching from Internet Archive:', error);\n }\n }\n\n if (!url.match(/www.google.com\\/search/)) {\n // Try Google Search as a last resort\n const googleSearchUrl = `https://www.google.com/search?q=${encodeURIComponent(url)}`;\n try {\n return await this.fetchPageContent(googleSearchUrl, runtime);\n } catch (error) {\n logger.error('Error fetching from Google Search:', error);\n logger.error('Failed to fetch content from alternative sources');\n return {\n title: url,\n description: 'Error, could not fetch content from alternative sources',\n bodyContent: '',\n };\n }\n }\n }\n}\n","import type { Plugin } from '@elizaos/core';\n\nimport { BrowserService } from './services/browser';\n\nexport const browserPlugin: Plugin = {\n name: 'browser-plugin',\n description: 'Plugin for browser actions',\n services: [BrowserService],\n actions: [],\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/services/browser.ts","../src/index.ts"],"sourcesContent":["import {\n type IAgentRuntime,\n ModelType,\n Service,\n type ServiceTypeName,\n ServiceType,\n logger,\n parseJSONObjectFromText,\n stringToUuid,\n trimTokens,\n} from '@elizaos/core';\nimport CaptchaSolver from 'capsolver-npm';\nimport { type Browser, type BrowserContext, type Page, chromium } from 'patchright';\n\n// Type for cached content\ninterface CachedContent {\n url: string;\n content: PageContent;\n}\n\n/**\n * Asynchronously generates a summary for a given text using a machine learning model.\n *\n * @param {IAgentRuntime} runtime - The runtime environment for the agent\n * @param {string} text - The text to generate a summary for\n * @returns {Promise<{ title: string; description: string }>} A promise that resolves to an object containing the generated title and summary\n */\nasync function generateSummary(\n runtime: IAgentRuntime,\n text: string\n): Promise<{ title: string; description: string }> {\n // make sure text is under 128k characters\n const trimmedText = await trimTokens(text, 100000, runtime);\n\n const prompt = `Please generate a concise summary for the following text:\n\n Text: \"\"\"\n ${trimmedText}\n \"\"\"\n\n Respond with a JSON object in the following format:\n \\`\\`\\`json\n {\n \"title\": \"Generated Title\",\n \"summary\": \"Generated summary and/or description of the text\"\n }\n \\`\\`\\``;\n\n const response = await runtime.useModel(ModelType.TEXT_SMALL, {\n prompt,\n });\n\n const parsedResponse = parseJSONObjectFromText(response);\n\n if (parsedResponse?.title && parsedResponse?.summary) {\n return {\n title: parsedResponse.title,\n description: parsedResponse.summary,\n };\n }\n\n return {\n title: '',\n description: '',\n };\n}\n\n/**\n * Represents the content of a page.\n * @typedef { Object } PageContent\n * @property { string } title - The title of the page.\n * @property { string } description - The description of the page.\n * @property { string } bodyContent - The main content of the page.\n */\ntype PageContent = {\n title: string;\n description: string;\n bodyContent: string;\n};\n\n/**\n * Represents a BrowserService class that extends Service.\n * Provides methods for initializing browser, stopping browser, fetching page content, solving CAPTCHAs, detecting CAPTCHAs, and getting cache key.\n * @extends Service\n */\nexport class BrowserService extends Service {\n private browser: Browser | undefined;\n private context: BrowserContext | undefined;\n private captchaSolver: CaptchaSolver;\n private cacheKey = 'content/browser';\n\n static serviceType: ServiceTypeName = ServiceType.BROWSER;\n capabilityDescription = 'The agent is able to browse the web and fetch content';\n\n /**\n * Constructor for the Agent class.\n * @param {IAgentRuntime} runtime - The runtime object for the agent.\n */\n constructor(runtime: IAgentRuntime) {\n super();\n this.runtime = runtime;\n this.browser = undefined;\n this.context = undefined;\n this.captchaSolver = new CaptchaSolver(runtime.getSetting('CAPSOLVER_API_KEY') || '');\n }\n\n /**\n * Starts the BrowserService asynchronously.\n *\n * @param {IAgentRuntime} runtime - The runtime for the agent.\n * @returns {Promise<BrowserService>} A promise that resolves to the initialized BrowserService.\n */\n static async start(runtime: IAgentRuntime): Promise<BrowserService> {\n const service = new BrowserService(runtime);\n await service.initializeBrowser();\n return service;\n }\n\n /**\n * Function to stop the browser service asynchronously.\n *\n * @param {IAgentRuntime} runtime - The runtime environment for the agent.\n */\n static async stop(runtime: IAgentRuntime) {\n const service = runtime.getService(ServiceType.BROWSER);\n if (service) {\n await service.stop();\n }\n }\n\n /**\n * Initializes the browser by launching Chromium with specified options and setting the user agent based on the platform.\n * @returns {Promise<void>} A promise that resolves once the browser is successfully initialized.\n */\n async initializeBrowser() {\n if (!this.browser) {\n this.browser = await chromium.launch({\n headless: true,\n args: [\n '--disable-dev-shm-usage', // Uses /tmp instead of /dev/shm. Prevents memory issues on low-memory systems\n '--block-new-web-contents', // Prevents creation of new windows/tabs\n ],\n });\n\n const platform = process.platform;\n let userAgent = '';\n\n // Change the user agent to match the platform to reduce bot detection\n switch (platform) {\n case 'darwin':\n userAgent =\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\n break;\n case 'win32':\n userAgent =\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\n break;\n case 'linux':\n userAgent =\n 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\n break;\n default:\n userAgent =\n 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\n }\n\n this.context = await this.browser.newContext({\n userAgent,\n acceptDownloads: false,\n });\n }\n }\n\n /**\n * Asynchronously stops the browser and context if they are currently running.\n */\n async stop() {\n if (this.context) {\n await this.context.close();\n this.context = undefined;\n }\n if (this.browser) {\n await this.browser.close();\n this.browser = undefined;\n }\n }\n\n /**\n * Asynchronously fetches the content of a web page.\n *\n * @param {string} url - The URL of the web page to fetch content from.\n * @param {IAgentRuntime} runtime - The runtime environment for the web scraping agent.\n * @returns {Promise<PageContent>} A Promise that resolves with the content of the web page.\n */\n async getPageContent(url: string, runtime: IAgentRuntime): Promise<PageContent> {\n await this.initializeBrowser();\n return await this.fetchPageContent(url, runtime);\n }\n\n /**\n * Generates a cache key for the provided URL by converting it to a UUID string.\n *\n * @param {string} url - The URL for which a cache key is being generated.\n * @returns {string} A UUID string representing the cache key for the URL.\n */\n private getCacheKey(url: string): string {\n return stringToUuid(url);\n }\n\n /**\n * Fetches the content of a page from the specified URL using a headless browser.\n *\n * @param {string} url - The URL of the page to fetch the content from.\n * @param {IAgentRuntime} runtime - The runtime environment for the agent.\n * @returns {Promise<PageContent>} A promise that resolves to the content of the fetched page.\n */\n private async fetchPageContent(url: string, runtime: IAgentRuntime): Promise<PageContent> {\n const cacheKey = this.getCacheKey(url);\n const cached = await runtime.getCache<CachedContent>(`${this.cacheKey}/${cacheKey}`);\n\n if (cached) {\n return cached.content;\n }\n\n let page: Page | undefined;\n\n try {\n if (!this.context) {\n logger.log('Browser context not initialized. Call initializeBrowser() first.');\n throw new Error('Browser context not initialized');\n }\n\n page = await this.context.newPage();\n\n // Enable stealth mode\n await page.setExtraHTTPHeaders({\n 'Accept-Language': 'en-US,en;q=0.9',\n });\n\n const response = await page.goto(url, { waitUntil: 'networkidle' });\n\n if (!response) {\n logger.error('Failed to load the page');\n throw new Error('Failed to load the page');\n }\n\n if (response.status() === 403 || response.status() === 404) {\n return await this.tryAlternativeSources(url, runtime);\n }\n\n // Check for CAPTCHA\n const captchaDetected = await this.detectCaptcha(page);\n if (captchaDetected) {\n await this.solveCaptcha(page, url);\n }\n const documentTitle = await page.evaluate(() => document.title);\n const bodyContent = await page.evaluate(() => document.body.innerText);\n const { title: parsedTitle, description } = await generateSummary(\n runtime,\n `${documentTitle}\\n${bodyContent}`\n );\n const content = { title: parsedTitle, description, bodyContent };\n await runtime.setCache<CachedContent>(`${this.cacheKey}/${cacheKey}`, {\n url,\n content,\n });\n return content;\n } catch (error) {\n logger.error('Error:', error);\n return {\n title: url,\n description: 'Error, could not fetch content',\n bodyContent: '',\n };\n } finally {\n if (page) {\n await page.close();\n }\n }\n }\n\n /**\n * Detects if a captcha is present on the page based on the specified selectors.\n *\n * @param {Page} page The Puppeteer page to check for captcha.\n * @returns {Promise<boolean>} A boolean indicating whether a captcha was detected.\n */\n private async detectCaptcha(page: Page): Promise<boolean> {\n const captchaSelectors = [\n 'iframe[src*=\"captcha\"]',\n 'div[class*=\"captcha\"]',\n '#captcha',\n '.g-recaptcha',\n '.h-captcha',\n ];\n\n for (const selector of captchaSelectors) {\n const element = await page.$(selector);\n if (element) return true;\n }\n\n return false;\n }\n\n /**\n * Solves the CAPTCHA challenge on the provided page using either hCaptcha or reCaptcha.\n *\n * @param {Page} page - The page where the CAPTCHA challenge needs to be solved.\n * @param {string} url - The URL of the website with the CAPTCHA challenge.\n * @returns {Promise<void>} - A promise that resolves once the CAPTCHA is solved.\n */\n private async solveCaptcha(page: Page, url: string): Promise<void> {\n try {\n const hcaptchaKey = await this.getHCaptchaWebsiteKey(page);\n if (hcaptchaKey) {\n const solution = await this.captchaSolver.hcaptchaProxyless({\n websiteURL: url,\n websiteKey: hcaptchaKey,\n });\n await page.evaluate((token) => {\n // eslint-disable-next-line\n // @ts-ignore\n window.hcaptcha.setResponse(token);\n }, solution.gRecaptchaResponse);\n return;\n }\n\n const recaptchaKey = await this.getReCaptchaWebsiteKey(page);\n if (recaptchaKey) {\n const solution = await this.captchaSolver.recaptchaV2Proxyless({\n websiteURL: url,\n websiteKey: recaptchaKey,\n });\n await page.evaluate((token) => {\n // eslint-disable-next-line\n // @ts-ignore\n document.getElementById('g-recaptcha-response').innerHTML = token;\n }, solution.gRecaptchaResponse);\n }\n } catch (error) {\n logger.error('Error solving CAPTCHA:', error);\n }\n }\n\n /**\n * Get the hCaptcha website key from the given Page\n * @param {Page} page - The Page object to extract the hCaptcha website key from\n * @returns {Promise<string>} The hCaptcha website key\n */\n private async getHCaptchaWebsiteKey(page: Page): Promise<string> {\n return page.evaluate(() => {\n const hcaptchaIframe = document.querySelector('iframe[src*=\"hcaptcha.com\"]');\n if (hcaptchaIframe) {\n const src = hcaptchaIframe.getAttribute('src');\n const match = src?.match(/sitekey=([^&]*)/);\n return match ? match[1] : '';\n }\n return '';\n });\n }\n\n /**\n * Retrieves the ReCaptcha website key from a given page.\n * @param {Page} page - The page to extract the ReCaptcha website key from.\n * @returns {Promise<string>} The ReCaptcha website key, or an empty string if not found.\n */\n private async getReCaptchaWebsiteKey(page: Page): Promise<string> {\n return page.evaluate(() => {\n const recaptchaElement = document.querySelector('.g-recaptcha');\n return recaptchaElement ? recaptchaElement.getAttribute('data-sitekey') || '' : '';\n });\n }\n\n /**\n * Try fetching content from alternative sources if the original source fails.\n *\n * @param {string} url - The URL of the content to fetch.\n * @param {IAgentRuntime} runtime - The runtime environment.\n * @returns {Promise<{ title: string; description: string; bodyContent: string }>} The fetched content with title, description, and body.\n */\n private async tryAlternativeSources(\n url: string,\n runtime: IAgentRuntime\n ): Promise<{ title: string; description: string; bodyContent: string }> {\n // because this (tryAlternativeSources) calls fetchPageContent\n // and fetchPageContent calls tryAlternativeSources\n // we need these url.matches to progress\n // through the things to try\n if (!url.match(/web.archive.org\\/web/)) {\n // Try Internet Archive\n const archiveUrl = `https://web.archive.org/web/${url}`;\n try {\n return await this.fetchPageContent(archiveUrl, runtime);\n } catch (error) {\n logger.error('Error fetching from Internet Archive:', error);\n }\n }\n\n if (!url.match(/www.google.com\\/search/)) {\n // Try Google Search as a last resort\n const googleSearchUrl = `https://www.google.com/search?q=${encodeURIComponent(url)}`;\n try {\n return await this.fetchPageContent(googleSearchUrl, runtime);\n } catch (error) {\n logger.error('Error fetching from Google Search:', error);\n logger.error('Failed to fetch content from alternative sources');\n }\n }\n\n // Return error content if all alternatives fail\n return {\n title: url,\n description: 'Error, could not fetch content from alternative sources',\n bodyContent: '',\n };\n }\n}\n","import type { Plugin , IAgentRuntime} from \"@elizaos/core\";\n\nimport { BrowserService } from \"./services/browser\";\n\nexport const browserPlugin: Plugin = {\n name: \"browser-plugin\",\n description: \"Plugin for browser actions\",\n services: [BrowserService],\n actions: [],\n tests: [\n {\n name: \"test browser service\",\n tests: [\n {\n name: \"Browser service initialization\",\n fn: async (runtime: IAgentRuntime) => {\n const service = await BrowserService.start(runtime);\n if (!service) {\n throw new Error(\"Failed to initialize BrowserService\");\n }\n },\n },\n ],\n }\n ],\n};\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elizaos/plugin-browser",
|
|
3
|
-
"
|
|
3
|
+
"description": "Plugin for browser actions and web scraping",
|
|
4
|
+
"version": "1.0.0",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"module": "dist/index.js",
|
|
7
8
|
"types": "dist/index.d.ts",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"plugin",
|
|
11
|
+
"elizaos",
|
|
12
|
+
"browser",
|
|
13
|
+
"web-scraping"
|
|
14
|
+
],
|
|
8
15
|
"repository": {
|
|
9
16
|
"type": "git",
|
|
10
|
-
"url": "
|
|
17
|
+
"url": ""
|
|
11
18
|
},
|
|
12
19
|
"exports": {
|
|
13
20
|
"./package.json": "./package.json",
|
|
@@ -19,39 +26,37 @@
|
|
|
19
26
|
}
|
|
20
27
|
},
|
|
21
28
|
"files": [
|
|
22
|
-
"dist"
|
|
23
|
-
"scripts",
|
|
24
|
-
"package.json",
|
|
25
|
-
"LICENSE",
|
|
26
|
-
"tsup.config.ts"
|
|
29
|
+
"dist"
|
|
27
30
|
],
|
|
28
31
|
"dependencies": {
|
|
29
|
-
"@elizaos/core": "^1.0.0
|
|
32
|
+
"@elizaos/core": "^1.0.0",
|
|
33
|
+
"@elizaos/plugin-anthropic": "^1.0.0-beta.54",
|
|
34
|
+
"@elizaos/plugin-bootstrap": "^1.0.0-beta.76",
|
|
35
|
+
"@elizaos/plugin-knowledge": "^1.0.0-beta.78",
|
|
36
|
+
"@elizaos/plugin-openai": "^1.0.0-beta.74",
|
|
37
|
+
"@elizaos/plugin-telegram": "^1.0.0-beta.55",
|
|
38
|
+
"@elizaos/plugin-twitter": "^1.0.0-beta.57",
|
|
30
39
|
"@types/uuid": "10.0.0",
|
|
31
40
|
"capsolver-npm": "2.0.2",
|
|
32
41
|
"fluent-ffmpeg": "2.1.3",
|
|
33
42
|
"glob": "11.0.0",
|
|
34
43
|
"patchright": "1.50.1",
|
|
35
|
-
"uuid": "11.0.3"
|
|
44
|
+
"uuid": "11.0.3",
|
|
45
|
+
"zod": "3.25.23"
|
|
36
46
|
},
|
|
37
47
|
"devDependencies": {
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"vitest": "^1.6.1",
|
|
42
|
-
"zod": "^3.22.4"
|
|
48
|
+
"tsup": "8.5.0",
|
|
49
|
+
"typescript": "5.8.3",
|
|
50
|
+
"prettier": "3.5.3"
|
|
43
51
|
},
|
|
44
52
|
"scripts": {
|
|
45
|
-
"build": "tsup",
|
|
46
53
|
"dev": "tsup --watch",
|
|
47
|
-
"
|
|
54
|
+
"build": "tsup",
|
|
48
55
|
"lint": "prettier --write ./src",
|
|
49
|
-
"
|
|
56
|
+
"test": "elizaos test",
|
|
50
57
|
"format": "prettier --write ./src",
|
|
51
58
|
"format:check": "prettier --check ./src",
|
|
52
|
-
"
|
|
53
|
-
"test:watch": "vitest",
|
|
54
|
-
"test:coverage": "vitest run --coverage"
|
|
59
|
+
"clean": "rm -rf dist .turbo node_modules .turbo-tsconfig.json tsconfig.tsbuildinfo"
|
|
55
60
|
},
|
|
56
61
|
"peerDependencies": {
|
|
57
62
|
"whatwg-url": "7.1.0"
|
|
@@ -59,5 +64,8 @@
|
|
|
59
64
|
"publishConfig": {
|
|
60
65
|
"access": "public"
|
|
61
66
|
},
|
|
62
|
-
"
|
|
67
|
+
"resolutions": {
|
|
68
|
+
"zod": "3.25.23"
|
|
69
|
+
},
|
|
70
|
+
"gitHead": "646c632924826e2b75c2304a75ee56959fe4a460"
|
|
63
71
|
}
|
package/scripts/postinstall.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { execSync } from 'node:child_process';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import os from 'node:os';
|
|
4
|
-
|
|
5
|
-
const platform = os.platform();
|
|
6
|
-
const rel = os.release();
|
|
7
|
-
|
|
8
|
-
if (platform !== 'linux') {
|
|
9
|
-
console.log('Skipping [patchright] installation: non-Linux platform detected:', platform);
|
|
10
|
-
process.exit(0);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function getDistroName() {
|
|
14
|
-
try {
|
|
15
|
-
const osReleaseContent = fs.readFileSync('/etc/os-release', 'utf8');
|
|
16
|
-
const lines = osReleaseContent.split('\n');
|
|
17
|
-
const info = {};
|
|
18
|
-
for (const line of lines) {
|
|
19
|
-
const [key, value] = line.split('=');
|
|
20
|
-
if (key && value) {
|
|
21
|
-
info[key.toLowerCase()] = value.replace(/"/g, '').toLowerCase().trim();
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return info.id || info.id_like || null;
|
|
25
|
-
} catch (err) {
|
|
26
|
-
console.error('Error reading /etc/os-release:', err.message);
|
|
27
|
-
}
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const distro = getDistroName();
|
|
32
|
-
console.log('Detected Linux distribution:', distro || 'unknown');
|
|
33
|
-
|
|
34
|
-
const supportedDistros = [
|
|
35
|
-
'ubuntu',
|
|
36
|
-
'debian',
|
|
37
|
-
'pve',
|
|
38
|
-
'raspbian',
|
|
39
|
-
'pop',
|
|
40
|
-
'zorin',
|
|
41
|
-
'linuxmint',
|
|
42
|
-
'elementary',
|
|
43
|
-
'pureos',
|
|
44
|
-
'kali',
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
if (!distro || !supportedDistros.some((name) => distro.includes(name))) {
|
|
48
|
-
console.log(
|
|
49
|
-
'Skipping [patchright] installation on unsupported platform:',
|
|
50
|
-
platform,
|
|
51
|
-
rel,
|
|
52
|
-
distro || 'unknown distro'
|
|
53
|
-
);
|
|
54
|
-
process.exit(0);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
execSync('npx patchright install', {
|
|
59
|
-
stdio: 'inherit',
|
|
60
|
-
});
|
|
61
|
-
} catch (err) {
|
|
62
|
-
console.error(
|
|
63
|
-
"Failed to install [patchright] you may need to install [patchright] deps with 'sudo npx patchright install-deps'. Error: ",
|
|
64
|
-
err.message
|
|
65
|
-
);
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
package/tsup.config.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'tsup';
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
entry: ['src/index.ts'],
|
|
5
|
-
outDir: 'dist',
|
|
6
|
-
tsconfig: './tsconfig.build.json', // Use build-specific tsconfig
|
|
7
|
-
sourcemap: true,
|
|
8
|
-
clean: true,
|
|
9
|
-
format: ['esm'], // Ensure you're targeting CommonJS
|
|
10
|
-
dts: false, // Skip DTS generation to avoid external import issues // Ensure you're targeting CommonJS
|
|
11
|
-
external: [
|
|
12
|
-
'dotenv', // Externalize dotenv to prevent bundling
|
|
13
|
-
'fs', // Externalize fs to use Node.js built-in module
|
|
14
|
-
'path', // Externalize other built-ins if necessary
|
|
15
|
-
'@reflink/reflink',
|
|
16
|
-
'https',
|
|
17
|
-
'http',
|
|
18
|
-
'agentkeepalive',
|
|
19
|
-
'zod',
|
|
20
|
-
'@elizaos/core',
|
|
21
|
-
// Add other modules you want to externalize
|
|
22
|
-
],
|
|
23
|
-
});
|