From 9dd74863ed7b798e33667d981ca96144d16d7138 Mon Sep 17 00:00:00 2001 From: gerrystev Date: Fri, 17 Apr 2026 14:35:19 +0800 Subject: [PATCH] update: agent browser skills --- docs/api/picoclaw.postman_collection.json | 91 +++++- docs/chromium-memory-optimization.md | 327 ++++++++++++++++++++++ infrastructure/index.ts | 7 +- workspace/skills/agent-browser/SKILL.md | 69 +++++ 4 files changed, 491 insertions(+), 3 deletions(-) create mode 100644 docs/chromium-memory-optimization.md diff --git a/docs/api/picoclaw.postman_collection.json b/docs/api/picoclaw.postman_collection.json index b89c64d17..3a405223f 100644 --- a/docs/api/picoclaw.postman_collection.json +++ b/docs/api/picoclaw.postman_collection.json @@ -24,7 +24,8 @@ { "key": "skill_name", "value": "", "type": "string" }, { "key": "oauth_flow_id", "value": "", "type": "string" }, { "key": "weixin_flow_id", "value": "", "type": "string" }, - { "key": "wecom_flow_id", "value": "", "type": "string" } + { "key": "wecom_flow_id", "value": "", "type": "string" }, + { "key": "webhook_job_id", "value": "", "type": "string" } ], "item": [ { @@ -704,6 +705,94 @@ } ] }, + { + "name": "Webhook", + "description": "Asynchronous webhook processing. Submit jobs that run in the background and POST results to your webhook URL.", + "item": [ + { + "name": "Submit Processing Job", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "if (pm.response.code === 202) {", + " const response = pm.response.json();", + " pm.collectionVariables.set('webhook_job_id', response.job_id);", + " console.log('Job ID saved:', response.job_id);", + "}" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "url": "{{base_url}}/api/webhook/process", + "header": [ + { "key": "Content-Type", "value": "application/json" } + ], + "body": { + "mode": "raw", + "raw": "{\n \"webhook_url\": \"https://webhook.site/your-unique-id\",\n \"payload\": {\n \"data\": \"your data here\",\n \"priority\": \"high\",\n \"timestamp\": \"{{$isoTimestamp}}\"\n }\n}", + "options": { "raw": { "language": "json" } } + }, + "description": "Submit an async job. Returns 202 Accepted with job_id. Job runs in background and results are POSTed to webhook_url.\n\nTest with webhook.site:\n1. Visit https://webhook.site\n2. Copy your unique URL\n3. Replace webhook_url above\n4. Send request\n5. Watch callback arrive at webhook.site\n\nResponse: {job_id, status: \"processing\", timestamp}\n\nWebhook receives: {job_id, status: \"completed\"|\"failed\", result: {...}|error: \"...\", timestamp}" + } + }, + { + "name": "Get Job Status", + "request": { + "method": "GET", + "url": { + "raw": "{{base_url}}/api/webhook/status?job_id={{webhook_job_id}}", + "host": ["{{base_url}}"], + "path": ["api", "webhook", "status"], + "query": [ + { + "key": "job_id", + "value": "{{webhook_job_id}}", + "description": "Job UUID from POST /api/webhook/process response" + } + ] + }, + "description": "Query job status by job_id. Jobs are retained for 2 hours.\n\nResponse:\n{\n \"ID\": \"uuid\",\n \"WebhookURL\": \"https://...\",\n \"Payload\": {...},\n \"Status\": \"processing\"|\"completed\"|\"failed\",\n \"CreatedAt\": \"2026-04-17T10:00:00Z\",\n \"CompletedAt\": \"2026-04-17T10:00:05Z\" (nullable)\n}" + } + }, + { + "name": "Submit Job - Example 1 (Simple)", + "request": { + "method": "POST", + "url": "{{base_url}}/api/webhook/process", + "header": [ + { "key": "Content-Type", "value": "application/json" } + ], + "body": { + "mode": "raw", + "raw": "{\n \"webhook_url\": \"https://webhook.site/test\",\n \"payload\": {\n \"message\": \"Hello, World!\"\n }\n}", + "options": { "raw": { "language": "json" } } + }, + "description": "Simple example with minimal payload." + } + }, + { + "name": "Submit Job - Example 2 (Complex)", + "request": { + "method": "POST", + "url": "{{base_url}}/api/webhook/process", + "header": [ + { "key": "Content-Type", "value": "application/json" } + ], + "body": { + "mode": "raw", + "raw": "{\n \"webhook_url\": \"https://your-app.com/webhook/callback\",\n \"payload\": {\n \"task\": \"process_document\",\n \"document\": {\n \"url\": \"https://example.com/document.pdf\",\n \"pages\": [1, 2, 3]\n },\n \"options\": {\n \"extract_tables\": true,\n \"ocr\": true\n },\n \"metadata\": {\n \"user_id\": \"12345\",\n \"request_id\": \"req_{{$randomUUID}}\"\n }\n }\n}", + "options": { "raw": { "language": "json" } } + }, + "description": "Complex example with nested payload structure." + } + } + ] + }, { "name": "Gateway Health", "description": "Endpoints served on port 18790 (backend-only mode). No auth required for /health and /ready.", diff --git a/docs/chromium-memory-optimization.md b/docs/chromium-memory-optimization.md new file mode 100644 index 000000000..5bceae137 --- /dev/null +++ b/docs/chromium-memory-optimization.md @@ -0,0 +1,327 @@ +# Chromium Memory Optimization for Picoclaw Heavy + +> When using picoclaw-heavy with agent-browser (Chromium), memory usage increases significantly. This guide helps optimize memory usage for production deployments. + +## Memory Usage Breakdown + +### Base Memory Usage +- **Picoclaw binary**: 10-20MB +- **Node.js 24 runtime**: 50-100MB +- **Python 3 + pip**: 50MB +- **System overhead (Alpine)**: 20-30MB +- **Base total**: ~150-200MB + +### Chromium Browser (agent-browser) +- **Chromium base**: 200-400MB +- **Per tab**: 100-300MB additional +- **With JavaScript execution**: +50-200MB per page +- **Peak usage**: 500-800MB per browser session + +### Total Memory Requirements +- **Minimum (no browser)**: 200MB +- **Light browser usage**: 512MB - 1GB +- **Normal browser usage**: 1GB - 2GB โœ… **Recommended** +- **Heavy browser usage**: 2GB - 4GB + +--- + +## ๐ŸŽฏ Optimization Strategies + +### 1. Chromium Launch Flags (Most Effective) + +Set these environment variables to reduce Chromium memory usage: + +```bash +# Essential flags for Cloud Run / containerized environments +CHROME_FLAGS="--disable-dev-shm-usage --no-sandbox --disable-setuid-sandbox --disable-gpu" + +# Additional memory-saving flags +CHROME_FLAGS="$CHROME_FLAGS --disable-software-rasterizer --disable-extensions" +CHROME_FLAGS="$CHROME_FLAGS --disable-background-networking --disable-sync" +CHROME_FLAGS="$CHROME_FLAGS --disable-translate --disable-breakpad" +CHROME_FLAGS="$CHROME_FLAGS --disable-background-timer-throttling" +CHROME_FLAGS="$CHROME_FLAGS --disable-backgrounding-occluded-windows" +CHROME_FLAGS="$CHROME_FLAGS --disable-renderer-backgrounding" +CHROME_FLAGS="$CHROME_FLAGS --metrics-recording-only --mute-audio" + +# Use new headless mode (lighter than old headless) +PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW=1 +``` + +**Memory Savings**: 100-200MB reduction + +#### Flag Explanations + +| Flag | Purpose | Memory Saved | +|------|---------|--------------| +| `--disable-dev-shm-usage` | Use `/tmp` instead of `/dev/shm` (critical for Cloud Run) | ~50-100MB | +| `--no-sandbox` | Disable sandboxing (container already isolated) | ~20-50MB | +| `--disable-gpu` | Disable GPU acceleration | ~30-80MB | +| `--disable-extensions` | No extension loading | ~10-20MB | +| `--disable-background-networking` | No background network requests | ~5-10MB | +| `--disable-sync` | No Chrome sync | ~5-10MB | +| `--disable-translate` | No translation service | ~5-10MB | + +### 2. Browser Session Management + +**Close browser when not in use:** +```bash +# After completing browser tasks +agent-browser close +``` + +**Reuse browser sessions:** +Instead of opening/closing frequently, keep one session and navigate: +```bash +agent-browser open https://example.com +agent-browser snapshot -i +# Do work... +agent-browser open https://another-site.com # Reuses same browser instance +``` + +**Memory Savings**: 200-400MB per closed session + +### 3. Limit Concurrent Operations + +Configure in `~/.picoclaw/config.json`: + +```json +{ + "agents": { + "defaults": { + "max_tool_iterations": 15, // Reduced from 20 + "max_parallel_tools": 1 // Prevent multiple browser sessions + } + } +} +``` + +### 4. Use Regular Picoclaw for Non-Browser Tasks + +If your task doesn't need browser automation, use the regular picoclaw image: + +```yaml +# docker-compose.yml +services: + picoclaw-gateway: + image: sipeed/picoclaw:latest # Regular image (40MB, <100MB RAM) + # vs + # dockerfile: docker/Dockerfile.heavy # Heavy image (1.92GB, ~2GB RAM) +``` + +### 5. Cloud Run Specific Optimizations + +#### Configure Memory Limits + +```typescript +// infrastructure/index.ts +resources: { + limits: { + cpu: "2", // More CPU helps Chromium render faster + memory: "2048Mi", // 2GB for comfortable browser automation + }, + cpuIdle: true, // Scale to zero when idle (save costs) +}, +``` + +#### Adjust Scaling + +```typescript +scaling: { + minInstanceCount: 0, // Scale to zero when idle + maxInstanceCount: 3, // Limit concurrent instances +}, +``` + +#### Add /dev/shm Volume (Optional) + +If not using `--disable-dev-shm-usage`: + +```typescript +volumeMounts: [ + { + name: "dshm", + mountPath: "/dev/shm", + }, +], +// ... +volumes: [ + { + name: "dshm", + emptyDir: { + medium: "Memory", + sizeLimit: "512Mi", + }, + }, +], +``` + +--- + +## ๐Ÿ”ข Memory Allocation Guide + +### Cloud Run Memory Recommendations + +| Use Case | Memory | CPU | Notes | +|----------|--------|-----|-------| +| **No browser** | 512Mi | 1 | Regular picoclaw image | +| **Light browser** (1-2 simple pages) | 1024Mi | 1 | Basic automation | +| **Normal browser** (multiple pages) | 2048Mi | 2 | โœ… **Recommended** | +| **Heavy browser** (complex SPAs, multiple tabs) | 4096Mi | 2-4 | Large scale automation | + +### Cost Considerations (GCP us-central1) + +| Memory | vCPU | Cost per hour | Cost per 1M requests (avg 10s) | +|--------|------|---------------|--------------------------------| +| 512Mi | 1 | $0.024 | $66.67 | +| 1024Mi | 1 | $0.048 | $133.33 | +| 2048Mi | 2 | $0.144 | $400.00 | +| 4096Mi | 4 | $0.576 | $1,600.00 | + +> With `cpuIdle: true` and `minInstanceCount: 0`, you only pay when the service is actively handling requests. + +--- + +## ๐Ÿงช Testing Your Configuration + +### 1. Local Testing + +```bash +# Build the heavy image +docker build -f docker/Dockerfile.heavy -t picoclaw-heavy:test . + +# Run with memory limit +docker run --memory=2g --cpus=2 \ + -e CHROME_FLAGS="--disable-dev-shm-usage --no-sandbox --disable-gpu" \ + -e PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW=1 \ + picoclaw-heavy:test + +# Monitor memory usage +docker stats +``` + +### 2. Cloud Run Testing + +```bash +# Deploy with new configuration +pulumi up + +# Monitor logs +gcloud run services logs read picoclaw-gateway --region=asia-southeast1 + +# Check memory usage in Cloud Run metrics +gcloud monitoring read --filter="resource.type=cloud_run_revision" \ + --project=YOUR_PROJECT +``` + +### 3. Load Testing + +```bash +# Test browser automation under load +for i in {1..10}; do + curl -X POST https://your-service.run.app/api/chat \ + -H "Content-Type: application/json" \ + -d '{"message": "Open https://example.com and take a screenshot"}' +done + +# Watch for OOM kills +gcloud run services logs read picoclaw-gateway --region=asia-southeast1 | grep -i "memory\|oom\|killed" +``` + +--- + +## ๐Ÿšจ Troubleshooting + +### OOM (Out of Memory) Errors + +**Symptoms:** +``` +Error: Failed to launch browser: spawn Unknown system error -12 +Error: page.goto: Navigation timeout of 30000 ms exceeded +Container terminated: memory limit exceeded +``` + +**Solutions:** +1. โœ… Increase memory to 2GB or 4GB +2. โœ… Add `--disable-dev-shm-usage` flag +3. โœ… Close browser after each session +4. โœ… Reduce concurrent operations + +### Slow Browser Performance + +**Symptoms:** +- Timeouts on page loads +- Commands taking >60s + +**Solutions:** +1. โœ… Increase CPU to 2 or 4 cores +2. โœ… Add `--disable-gpu` flag +3. โœ… Increase timeout in tool calls +4. โœ… Use `networkidle` wait less frequently + +### High Costs + +**Solutions:** +1. โœ… Use `minInstanceCount: 0` to scale to zero +2. โœ… Reduce `maxInstanceCount` to limit concurrent instances +3. โœ… Use regular picoclaw image for non-browser tasks +4. โœ… Implement request queuing to reuse instances + +--- + +## ๐Ÿ“‹ Quick Setup Checklist + +For Cloud Run deployment with browser automation: + +- [ ] Set memory to **2048Mi** (2GB) +- [ ] Set CPU to **2 cores** +- [ ] Add `CHROME_FLAGS` environment variable +- [ ] Add `PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW=1` +- [ ] Enable `cpuIdle: true` for cost savings +- [ ] Set `minInstanceCount: 0` to scale to zero +- [ ] Test with actual browser automation workload +- [ ] Monitor memory usage in Cloud Run console +- [ ] Set up alerts for OOM errors + +--- + +## ๐Ÿ“š Additional Resources + +- [Playwright Docker Guide](https://playwright.dev/docs/docker) +- [Chrome Headless Flags](https://peter.sh/experiments/chromium-command-line-switches/) +- [GCP Cloud Run Memory Settings](https://cloud.google.com/run/docs/configuring/memory-limits) +- [agent-browser Documentation](https://agent-browser.dev) + +--- + +## ๐ŸŽฏ Recommended Configuration + +For most production use cases with browser automation: + +```typescript +// infrastructure/index.ts +resources: { + limits: { + cpu: "2", + memory: "2048Mi", // 2GB + }, + cpuIdle: true, +}, +envs: [ + { + name: "CHROME_FLAGS", + value: "--disable-dev-shm-usage --no-sandbox --disable-gpu --disable-software-rasterizer --disable-extensions --disable-background-networking --disable-sync --metrics-recording-only --mute-audio" + }, + { + name: "PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW", + value: "1" + }, + // ... other env vars +], +``` + +This provides a good balance between: +- โœ… Reliable browser automation +- โœ… Reasonable costs (~$0.144/hour active time) +- โœ… Good performance for most web pages +- โœ… Room for memory spikes diff --git a/infrastructure/index.ts b/infrastructure/index.ts index 30b6fce98..ba2c9b125 100644 --- a/infrastructure/index.ts +++ b/infrastructure/index.ts @@ -91,6 +91,9 @@ const gatewayService = new gcp.cloudrunv2.Service("picoclaw-gateway", { }, envs: [ { name: "PICOCLAW_GATEWAY_HOST", value: "0.0.0.0" }, + // Chromium memory optimization flags + { name: "CHROME_FLAGS", value: "--disable-dev-shm-usage --no-sandbox --disable-setuid-sandbox --disable-gpu --disable-software-rasterizer --disable-extensions --disable-background-networking --disable-sync --disable-translate --disable-breakpad --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-renderer-backgrounding --metrics-recording-only --mute-audio" }, + { name: "PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW", value: "1" }, { name: "AWS_ACCESS_KEY_ID", valueSource: { @@ -139,8 +142,8 @@ const gatewayService = new gcp.cloudrunv2.Service("picoclaw-gateway", { ], resources: { limits: { - cpu: "1", - memory: "1024Mi", + cpu: "2", + memory: "2048Mi", // Increased for Chromium browser automation }, cpuIdle: true, }, diff --git a/workspace/skills/agent-browser/SKILL.md b/workspace/skills/agent-browser/SKILL.md index 43505996d..533158757 100644 --- a/workspace/skills/agent-browser/SKILL.md +++ b/workspace/skills/agent-browser/SKILL.md @@ -127,3 +127,72 @@ Always close sessions when done: agent-browser close agent-browser --session s1 close ``` + +## Memory Optimization + +Browser automation consumes significant memory (200-800MB per session). Follow these practices to minimize memory usage: + +### 1. Close Browser After Each Task +```bash +# โœ… Good: Close when done +agent-browser open https://example.com +agent-browser snapshot -i +agent-browser close + +# โŒ Bad: Leaving browser open +agent-browser open https://example.com +# ... browser stays open, consuming memory +``` + +### 2. Reuse Browser Sessions +Instead of opening/closing frequently, keep one session and navigate: +```bash +# โœ… Good: Reuse session +agent-browser open https://site-a.com +agent-browser snapshot -i +# Do work... +agent-browser open https://site-b.com # Reuses same browser +agent-browser close # Close when all done + +# โŒ Bad: Multiple open/close cycles +agent-browser open https://site-a.com && agent-browser close +agent-browser open https://site-b.com && agent-browser close +``` + +### 3. Avoid Unnecessary Screenshots +Full-page screenshots consume extra memory during rendering: +```bash +# โœ… Use snapshot for element inspection (lighter) +agent-browser snapshot -i + +# โš ๏ธ Use screenshots only when visual output is needed +agent-browser screenshot --full +``` + +### 4. Chain Commands to Reduce Context Switches +```bash +# โœ… Good: Single command chain +agent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser snapshot -i && agent-browser close + +# โŒ Bad: Multiple separate commands +agent-browser open https://example.com +agent-browser wait --load networkidle +agent-browser snapshot -i +agent-browser close +``` + +### 5. Limit Parallel Sessions +```bash +# โš ๏ธ Each session = 200-400MB memory +agent-browser --session s1 open https://site-a.com # +300MB +agent-browser --session s2 open https://site-b.com # +300MB +agent-browser --session s3 open https://site-c.com # +300MB (900MB total!) + +# โœ… Better: Use one session, navigate sequentially +agent-browser open https://site-a.com +# ... work +agent-browser open https://site-b.com +# ... work +agent-browser close +``` +