locoagent-social-media-automation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLocoAgent Social Media Automation
LocoAgent 社交媒体自动化
Skill by ara.so — AI Agent Skills collection.
LocoAgent is an AI-powered social media agent that autonomously operates social media accounts through real browser automation. It combines an LLM-driven agentic loop with Chrome DevTools Protocol (CDP) to perceive, decide, and act on live web pages — performing tasks like liking posts, writing replies, following users, and publishing content.
Key capabilities:
- Real browser automation with Chrome CDP (uses actual login sessions)
- Platform skill system (32+ operations for X.com built-in)
- Workflow engine for deterministic automation pipelines
- Operation log for persistent deduplication across sessions
- Multi-provider LLM support (OpenRouter, DeepSeek, Ollama, etc.)
由ara.so提供的Skill — AI Agent技能合集。
LocoAgent是一款基于AI的社交媒体Agent,通过真实浏览器自动化自主运营社交媒体账号。它将LLM驱动的智能循环与Chrome DevTools Protocol (CDP)相结合,能够感知、决策并操作实时网页,执行点赞帖子、撰写回复、关注用户、发布内容等任务。
核心功能:
- 基于Chrome CDP的真实浏览器自动化(使用实际登录会话)
- 平台技能系统(内置32+种X.com操作)
- 用于确定性自动化流水线的工作流引擎
- 跨会话持久去重的操作日志
- 多提供商LLM支持(OpenRouter、DeepSeek、Ollama等)
Installation
安装步骤
Prerequisites
前置条件
Install required dependencies:
bash
undefined安装所需依赖:
bash
undefinedInstall Bun runtime
Install Bun runtime
curl -fsSL https://bun.sh/install | bash
curl -fsSL https://bun.sh/install | bash
Install agent-browser CLI
Install agent-browser CLI
npm install -g @vercel/agent-browser
undefinednpm install -g @vercel/agent-browser
undefinedProject Setup
项目设置
bash
git clone https://github.com/LocoreMind/locoagent.git
cd locoagent
bun installbash
git clone https://github.com/LocoreMind/locoagent.git
cd locoagent
bun installConfiguration
配置
Create file in project root:
.envenv
undefined在项目根目录创建文件:
.envenv
undefinedOpenRouter (recommended - access 200+ models)
OpenRouter (recommended - access 200+ models)
CLAUDE_CODE_USE_OPENAI=1
OPENAI_API_KEY=sk-or-v1-...
OPENAI_BASE_URL=https://openrouter.ai/api/v1
OPENAI_MODEL=anthropic/claude-sonnet-4.5
CLAUDE_CODE_USE_OPENAI=1
OPENAI_API_KEY=sk-or-v1-...
OPENAI_BASE_URL=https://openrouter.ai/api/v1
OPENAI_MODEL=anthropic/claude-sonnet-4.5
Required for automated mode
Required for automated mode
SKIP_PERMISSIONS=1
Alternative provider configurations:
```envSKIP_PERMISSIONS=1
其他提供商配置示例:
```envDeepSeek (with thinking mode)
DeepSeek (with thinking mode)
CLAUDE_CODE_USE_OPENAI=1
OPENAI_API_KEY=<DEEPSEEK_API_KEY>
OPENAI_BASE_URL=https://api.deepseek.com
OPENAI_MODEL=deepseek-v4-flash
CLAUDE_CODE_USE_OPENAI=1
OPENAI_API_KEY=<DEEPSEEK_API_KEY>
OPENAI_BASE_URL=https://api.deepseek.com
OPENAI_MODEL=deepseek-v4-flash
Ollama (local models)
Ollama (local models)
CLAUDE_CODE_USE_OPENAI=1
OPENAI_API_KEY=ollama
OPENAI_BASE_URL=http://localhost:11434/v1
OPENAI_MODEL=llama3.2
CLAUDE_CODE_USE_OPENAI=1
OPENAI_API_KEY=ollama
OPENAI_BASE_URL=http://localhost:11434/v1
OPENAI_MODEL=llama3.2
Anthropic direct (native SDK)
Anthropic direct (native SDK)
ANTHROPIC_API_KEY=<ANTHROPIC_API_KEY>
undefinedANTHROPIC_API_KEY=<ANTHROPIC_API_KEY>
undefinedBrowser Setup
浏览器设置
bash
undefinedbash
undefinedOne-time: copy Chrome profile and launch with CDP
One-time: copy Chrome profile and launch with CDP
bun run setup-chrome
bun run setup-chrome
Connect agent-browser to running Chrome
Connect agent-browser to running Chrome
agent-browser connect 9222
undefinedagent-browser connect 9222
undefinedCore Commands
核心命令
Interactive Mode
交互模式
bash
undefinedbash
undefinedStart interactive session
Start interactive session
bun start
bun start
Load X.com skill and execute task
Load X.com skill and execute task
/x-com open home timeline, like first 3 posts about AI
/x-com open home timeline, like first 3 posts about AI
Check operation history
Check operation history
/operation-log recent --limit 20
undefined/operation-log recent --limit 20
undefinedHeadless Mode
无头模式
bash
undefinedbash
undefinedSingle query execution
Single query execution
bun start -p "open X.com and like the first post about AI agents"
bun start -p "open X.com and like the first post about AI agents"
With specific model
With specific model
bun start --model anthropic/claude-sonnet-4.5 -p "/x-com like 5 posts about LLMs"
bun start --model anthropic/claude-sonnet-4.5 -p "/x-com like 5 posts about LLMs"
Platform-specific task
Platform-specific task
bun start -p "/x-com like 5 posts about 'large language models', then follow the authors"
undefinedbun start -p "/x-com like 5 posts about 'large language models', then follow the authors"
undefinedPlatform Skills
平台技能
Skills inject complete operation playbooks into the agent's context.
技能会将完整的操作手册注入Agent的上下文。
X.com Skill
X.com技能
bash
undefinedbash
undefinedInteractive
Interactive
/x-com open home timeline, like first 3 posts about AI, reply to the best one
/x-com open home timeline, like first 3 posts about AI, reply to the best one
Headless
Headless
bun start -p "/x-com like 5 posts about 'machine learning', follow authors with >1k followers"
Available X.com operations (32+):
- Navigation: home, notifications, messages, profile, search
- Engagement: like, retweet, reply, quote tweet
- Social graph: follow, unfollow, mute, block
- Content: post tweet, post thread, upload media
- Profile: edit bio, change avatar, update banner
- Lists: create, add members, viewbun start -p "/x-com like 5 posts about 'machine learning', follow authors with >1k followers"
可用的X.com操作(32+种):
- 导航:首页、通知、消息、个人主页、搜索
- 互动:点赞、转发、回复、引用转发
- 社交关系:关注、取消关注、静音、屏蔽
- 内容:发布推文、发布推文线程、上传媒体
- 个人资料:编辑简介、更换头像、更新横幅
- 列表:创建、添加成员、查看Creating Custom Skills
创建自定义技能
Create :
skills/linkedin/SKILL.mdmarkdown
---
description: "LinkedIn platform operations playbook"
allowed-tools:
- Bash
user-invocable: true
---创建:
skills/linkedin/SKILL.mdmarkdown
---
description: "LinkedIn platform operations playbook"
allowed-tools:
- Bash
user-invocable: true
---LinkedIn Operations
LinkedIn Operations
1. Navigation
1. Navigation
Open Home Feed
Open Home Feed
bash
agent-browser open https://www.linkedin.com/feedbash
agent-browser open https://www.linkedin.com/feedSearch Posts
Search Posts
bash
agent-browser open "https://www.linkedin.com/search/results/content/?keywords=AI%20agents"
agent-browser snapshot -i -c -s 'div[data-post-id]'bash
agent-browser open "https://www.linkedin.com/search/results/content/?keywords=AI%20agents"
agent-browser snapshot -i -c -s 'div[data-post-id]'2. Engagement
2. Engagement
Like Post
Like Post
- Find post element with
agent-browser snapshot -i - Locate like button (usually )
button[aria-label*="Like"] - Click:
agent-browser click @e<ref>
- Find post element with
agent-browser snapshot -i - Locate like button (usually )
button[aria-label*="Like"] - Click:
agent-browser click @e<ref>
Comment on Post
Comment on Post
- Find comment input (usually )
div[role="textbox"] - Click to focus:
agent-browser click @e<ref> - Type comment:
agent-browser fill @e<ref> "Insightful post!" - Find submit button and click
Load the skill:
```bash
bun start
> /linkedin search for posts about 'AI safety', like top 3- Find comment input (usually )
div[role="textbox"] - Click to focus:
agent-browser click @e<ref> - Type comment:
agent-browser fill @e<ref> "Insightful post!" - Find submit button and click
加载技能:
```bash
bun start
> /linkedin search for posts about 'AI safety', like top 3Workflow Engine
工作流引擎
Workflows are deterministic browser-automation pipelines that run without LLM involvement.
工作流是无需LLM参与即可运行的确定性浏览器自动化流水线。
Built-in Workflows
内置工作流
bash
undefinedbash
undefinedList all workflows
List all workflows
bun run workflow list
bun run workflow list
Run once (blocking)
Run once (blocking)
bun run workflow run --id hf-papers-to-x
bun run workflow run --id hf-papers-to-x
Run once (background)
Run once (background)
bun run workflow start --id hf-papers-to-x
bun run workflow start --id hf-papers-to-x
Daemon mode (every 3 minutes)
Daemon mode (every 3 minutes)
bun run workflow daemon --id x-search-reply --interval 3
bun run workflow daemon --id x-search-reply --interval 3
Stop workflow
Stop workflow
bun run workflow stop --id x-search-reply
bun run workflow stop --id x-search-reply
View status
View status
bun run workflow status
bun run workflow status
View execution history
View execution history
bun run workflow history --id hf-papers-to-x
undefinedbun run workflow history --id hf-papers-to-x
undefinedCreating Custom Workflows
创建自定义工作流
Step 1: Create workflow definition :
workflows/linkedin-engagement.jsonjson
{
"id": "linkedin-engagement",
"name": "LinkedIn Daily Engagement",
"description": "Search for AI posts on LinkedIn and engage",
"schedule": "daily",
"executor": "executors/linkedin-engagement.ts",
"config": {
"searchQuery": "artificial intelligence",
"maxPosts": 5,
"cdpPort": 9222
}
}Step 2: Create executor :
workflows/executors/linkedin-engagement.tstypescript
#!/usr/bin/env bun
import { execSync } from 'node:child_process'
// Parse config from workflow engine
const configArg = process.argv.find((_, i, a) => a[i - 1] === '--config')
const config = JSON.parse(configArg!)
// agent-browser helper
function ab(cmd: string): string {
return execSync(`agent-browser --cdp ${config.cdpPort} ${cmd}`, {
encoding: 'utf-8',
timeout: 30000,
}).trim()
}
// Helper to check operation log
function hasEngaged(postUrl: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform linkedin --action like --url "${postUrl}"`, {
encoding: 'utf-8',
stdio: 'ignore'
})
return true // exit 0 = already done
} catch {
return false // exit 1 = not done
}
}
// Helper to log operation
function logOperation(postUrl: string, action: string, status: string, note: string) {
execSync(`bun run scripts/log-operation.ts add --platform linkedin --action ${action} --url "${postUrl}" --status ${status} --note "${note}"`, {
encoding: 'utf-8',
stdio: 'inherit'
})
}
console.error('[linkedin-engagement] Starting workflow...')
// Step 1: Navigate to search
console.error(`[linkedin-engagement] Searching for: ${config.searchQuery}`)
const searchUrl = `https://www.linkedin.com/search/results/content/?keywords=${encodeURIComponent(config.searchQuery)}`
ab(`open "${searchUrl}"`)
ab('wait 3000')
// Step 2: Get posts
console.error('[linkedin-engagement] Getting posts...')
const snapshot = ab('snapshot -i -c -s \'div[data-post-id]\'')
const posts = JSON.parse(snapshot)
let engaged = 0
const stepsTotal = Math.min(posts.length, config.maxPosts)
// Step 3: Engage with posts
for (let i = 0; i < stepsTotal; i++) {
const post = posts[i]
const postUrl = post.attributes?.['data-urn'] || `post-${i}`
// Check if already engaged
if (hasEngaged(postUrl)) {
console.error(`[linkedin-engagement] Already engaged with ${postUrl}, skipping`)
continue
}
// Find like button
const likeButton = post.children?.find((el: any) =>
el.attributes?.['aria-label']?.includes('Like')
)
if (likeButton?.ref) {
ab(`click ${likeButton.ref}`)
logOperation(postUrl, 'like', 'success', `Workflow: ${config.searchQuery}`)
engaged++
console.error(`[linkedin-engagement] Liked post ${i + 1}/${stepsTotal}`)
ab('wait 2000') // Rate limiting
}
}
// Output final summary (required)
console.log(JSON.stringify({
stepsCompleted: engaged,
stepsTotal,
searchQuery: config.searchQuery
}))Step 3: Run workflow:
bash
bun run workflow run --id linkedin-engagement步骤1: 创建工作流定义:
workflows/linkedin-engagement.jsonjson
{
"id": "linkedin-engagement",
"name": "LinkedIn Daily Engagement",
"description": "Search for AI posts on LinkedIn and engage",
"schedule": "daily",
"executor": "executors/linkedin-engagement.ts",
"config": {
"searchQuery": "artificial intelligence",
"maxPosts": 5,
"cdpPort": 9222
}
}步骤2: 创建执行器:
workflows/executors/linkedin-engagement.tstypescript
#!/usr/bin/env bun
import { execSync } from 'node:child_process'
// Parse config from workflow engine
const configArg = process.argv.find((_, i, a) => a[i - 1] === '--config')
const config = JSON.parse(configArg!)
// agent-browser helper
function ab(cmd: string): string {
return execSync(`agent-browser --cdp ${config.cdpPort} ${cmd}`, {
encoding: 'utf-8',
timeout: 30000,
}).trim()
}
// Helper to check operation log
function hasEngaged(postUrl: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform linkedin --action like --url "${postUrl}"`, {
encoding: 'utf-8',
stdio: 'ignore'
})
return true // exit 0 = already done
} catch {
return false // exit 1 = not done
}
}
// Helper to log operation
function logOperation(postUrl: string, action: string, status: string, note: string) {
execSync(`bun run scripts/log-operation.ts add --platform linkedin --action ${action} --url "${postUrl}" --status ${status} --note "${note}"`, {
encoding: 'utf-8',
stdio: 'inherit'
})
}
console.error('[linkedin-engagement] Starting workflow...')
// Step 1: Navigate to search
console.error(`[linkedin-engagement] Searching for: ${config.searchQuery}`)
const searchUrl = `https://www.linkedin.com/search/results/content/?keywords=${encodeURIComponent(config.searchQuery)}`
ab(`open "${searchUrl}"`)
ab('wait 3000')
// Step 2: Get posts
console.error('[linkedin-engagement] Getting posts...')
const snapshot = ab('snapshot -i -c -s \'div[data-post-id]\'')
const posts = JSON.parse(snapshot)
let engaged = 0
const stepsTotal = Math.min(posts.length, config.maxPosts)
// Step 3: Engage with posts
for (let i = 0; i < stepsTotal; i++) {
const post = posts[i]
const postUrl = post.attributes?.['data-urn'] || `post-${i}`
// Check if already engaged
if (hasEngaged(postUrl)) {
console.error(`[linkedin-engagement] Already engaged with ${postUrl}, skipping`)
continue
}
// Find like button
const likeButton = post.children?.find((el: any) =>
el.attributes?.['aria-label']?.includes('Like')
)
if (likeButton?.ref) {
ab(`click ${likeButton.ref}`)
logOperation(postUrl, 'like', 'success', `Workflow: ${config.searchQuery}`)
engaged++
console.error(`[linkedin-engagement] Liked post ${i + 1}/${stepsTotal}`)
ab('wait 2000') // Rate limiting
}
}
// Output final summary (required)
console.log(JSON.stringify({
stepsCompleted: engaged,
stepsTotal,
searchQuery: config.searchQuery
}))步骤3: 运行工作流:
bash
bun run workflow run --id linkedin-engagementOperation Log
操作日志
Persistent memory prevents duplicate actions across sessions.
持久化记忆可防止跨会话重复执行操作。
Check Before Acting
操作前检查
typescript
import { execSync } from 'node:child_process'
function hasLiked(postUrl: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform x --action like --url "${postUrl}"`, {
encoding: 'utf-8',
stdio: 'ignore'
})
return true // exit 0 = already done
} catch {
return false // exit 1 = not done
}
}
const url = "https://x.com/user/status/123"
if (hasLiked(url)) {
console.log("Already liked this post")
} else {
// Perform like action
execSync(`agent-browser click @e5`)
// Log operation
execSync(`bun run scripts/log-operation.ts add --platform x --action like --url "${url}" --status success --note "AI research post"`)
}typescript
import { execSync } from 'node:child_process'
function hasLiked(postUrl: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform x --action like --url "${postUrl}"`, {
encoding: 'utf-8',
stdio: 'ignore'
})
return true // exit 0 = already done
} catch {
return false // exit 1 = not done
}
}
const url = "https://x.com/user/status/123"
if (hasLiked(url)) {
console.log("Already liked this post")
} else {
// Perform like action
execSync(`agent-browser click @e5`)
// Log operation
execSync(`bun run scripts/log-operation.ts add --platform x --action like --url "${url}" --status success --note "AI research post"`)
}CLI Operations
CLI操作
bash
undefinedbash
undefinedCheck if operation was performed (exit 0 = done, exit 1 = not done)
Check if operation was performed (exit 0 = done, exit 1 = not done)
bun run scripts/log-operation.ts check
--platform x
--action like
--url "https://x.com/user/status/123"
--platform x
--action like
--url "https://x.com/user/status/123"
bun run scripts/log-operation.ts check
--platform x
--action like
--url "https://x.com/user/status/123"
--platform x
--action like
--url "https://x.com/user/status/123"
Record operation
Record operation
bun run scripts/log-operation.ts add
--platform x
--action like
--url "https://x.com/user/status/123"
--status success
--note "AI agents research post"
--platform x
--action like
--url "https://x.com/user/status/123"
--status success
--note "AI agents research post"
bun run scripts/log-operation.ts add
--platform x
--action like
--url "https://x.com/user/status/123"
--status success
--note "AI agents research post"
--platform x
--action like
--url "https://x.com/user/status/123"
--status success
--note "AI agents research post"
View recent operations
View recent operations
bun run scripts/log-operation.ts recent --limit 20
bun run scripts/log-operation.ts recent --limit 20
30-day summary
30-day summary
bun run scripts/log-operation.ts summary --days 30
State stored in `persona/operation-log.json`.bun run scripts/log-operation.ts summary --days 30
状态存储在`persona/operation-log.json`中。Task Scheduling
任务调度
Structure daily/weekly tasks instead of ad-hoc prompts.
将日常/每周任务结构化,而非使用临时提示词。
Define Tasks
定义任务
Edit :
persona/tasks.mdmarkdown
undefined编辑:
persona/tasks.mdmarkdown
undefinedDaily Tasks
Daily Tasks
- Engage with AI research content (like 5-10 posts)
- Monitor project mentions and respond
- Leave 1-2 technical comments on relevant posts
- Engage with AI research content (like 5-10 posts)
- Monitor project mentions and respond
- Leave 1-2 technical comments on relevant posts
Weekly Tasks (Monday)
Weekly Tasks (Monday)
- Follow 3-5 relevant researchers or developers
- Post 1 original tweet about recent findings
- Follow 3-5 relevant researchers or developers
- Post 1 original tweet about recent findings
Session Constraints
Session Constraints
| Action | Max per session |
|---|---|
| Likes | 10 |
| Comments | 2 |
| Follows | 5 |
| Posts | 1 |
undefined| Action | Max per session |
|---|---|
| Likes | 10 |
| Comments | 2 |
| Follows | 5 |
| Posts | 1 |
undefinedRun Tasks
运行任务
bash
undefinedbash
undefinedExecute today's tasks
Execute today's tasks
bun run run-tasks
bun run run-tasks
Preview prompt without running
Preview prompt without running
bun run run-tasks:dry
bun run run-tasks:dry
Restrict to one platform
Restrict to one platform
bun run run-tasks -- --platform x
undefinedbun run run-tasks -- --platform x
undefinedReal-time Trajectory Monitor
实时轨迹监控
Watch live execution status instead of black-box mode.
--printbash
undefined无需使用黑盒模式,即可查看实时执行状态。
--printbash
undefinedTerminal 1: start monitor
Terminal 1: start monitor
bun run tail
bun run tail
Terminal 2: run agent
Terminal 2: run agent
bun start -p "/x-com open timeline, like first post"
Output shows live execution:
═══ New Task ═══
/x-com open timeline, like first post
[6:30:47 PM] ⚡ Bash: agent-browser connect 9222
[6:30:47 PM] ✓ Result: Done
[6:31:10 PM] ⚡ Bash: agent-browser open https://x.com/home
[6:31:27 PM] ⚡ Bash: agent-browser snapshot -i -c -s 'article'
[6:31:44 PM] ● Agent: Found first post, like button ref=e136
[6:31:44 PM] ⚡ Bash: agent-browser click e136
[6:31:45 PM] ✓ Result: Done
Additional commands:
```bashbun start -p "/x-com open timeline, like first post"
输出会显示实时执行过程:
═══ New Task ═══
/x-com open timeline, like first post
[6:30:47 PM] ⚡ Bash: agent-browser connect 9222
[6:30:47 PM] ✓ Result: Done
[6:31:10 PM] ⚡ Bash: agent-browser open https://x.com/home
[6:31:27 PM] ⚡ Bash: agent-browser snapshot -i -c -s 'article'
[6:31:44 PM] ● Agent: Found first post, like button ref=e136
[6:31:44 PM] ⚡ Bash: agent-browser click e136
[6:31:45 PM] ✓ Result: Done
其他命令:
```bashReplay latest session from beginning
Replay latest session from beginning
bun run tail:history
bun run tail:history
List recent sessions
List recent sessions
bun run tail:list
bun run tail:list
Watch specific session
Watch specific session
bun run tail <session-id>
undefinedbun run tail <session-id>
undefinedCommon Patterns
常见模式
Pattern: Safe Engagement Loop
模式:安全互动循环
typescript
#!/usr/bin/env bun
import { execSync } from 'node:child_process'
function ab(cmd: string): string {
return execSync(`agent-browser --cdp 9222 ${cmd}`, {
encoding: 'utf-8',
timeout: 30000,
}).trim()
}
function hasEngaged(platform: string, action: string, url: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform ${platform} --action ${action} --url "${url}"`, {
stdio: 'ignore'
})
return true
} catch {
return false
}
}
function logEngagement(platform: string, action: string, url: string, note: string) {
execSync(`bun run scripts/log-operation.ts add --platform ${platform} --action ${action} --url "${url}" --status success --note "${note}"`, {
stdio: 'inherit'
})
}
// Navigate to page
ab('open https://x.com/search?q=AI%20agents&f=live')
ab('wait 3000')
// Get posts
const snapshot = JSON.parse(ab('snapshot -i -c -s \'article\''))
const posts = snapshot.slice(0, 5)
for (const post of posts) {
const postUrl = post.attributes?.['data-testid'] || `post-${Math.random()}`
// Skip if already engaged
if (hasEngaged('x', 'like', postUrl)) {
console.error(`Already liked ${postUrl}`)
continue
}
// Find like button
const likeBtn = post.children?.find((el: any) =>
el.attributes?.['data-testid'] === 'like'
)
if (likeBtn?.ref) {
ab(`click ${likeBtn.ref}`)
logEngagement('x', 'like', postUrl, 'AI agents search result')
ab('wait 2000') // Rate limiting
}
}typescript
#!/usr/bin/env bun
import { execSync } from 'node:child_process'
function ab(cmd: string): string {
return execSync(`agent-browser --cdp 9222 ${cmd}`, {
encoding: 'utf-8',
timeout: 30000,
}).trim()
}
function hasEngaged(platform: string, action: string, url: string): boolean {
try {
execSync(`bun run scripts/log-operation.ts check --platform ${platform} --action ${action} --url "${url}"`, {
stdio: 'ignore'
})
return true
} catch {
return false
}
}
function logEngagement(platform: string, action: string, url: string, note: string) {
execSync(`bun run scripts/log-operation.ts add --platform ${platform} --action ${action} --url "${url}" --status success --note "${note}"`, {
stdio: 'inherit'
})
}
// Navigate to page
ab('open https://x.com/search?q=AI%20agents&f=live')
ab('wait 3000')
// Get posts
const snapshot = JSON.parse(ab('snapshot -i -c -s \'article\''))
const posts = snapshot.slice(0, 5)
for (const post of posts) {
const postUrl = post.attributes?.['data-testid'] || `post-${Math.random()}`
// Skip if already engaged
if (hasEngaged('x', 'like', postUrl)) {
console.error(`Already liked ${postUrl}`)
continue
}
// Find like button
const likeBtn = post.children?.find((el: any) =>
el.attributes?.['data-testid'] === 'like'
)
if (likeBtn?.ref) {
ab(`click ${likeBtn.ref}`)
logEngagement('x', 'like', postUrl, 'AI agents search result')
ab('wait 2000') // Rate limiting
}
}Pattern: Multi-Step Workflow with Checkpoints
模式:带检查点的多步骤工作流
typescript
#!/usr/bin/env bun
import { execSync } from 'node:child_process'
import { writeFileSync, readFileSync, existsSync } from 'fs'
const CHECKPOINT_FILE = '/tmp/workflow-checkpoint.json'
function loadCheckpoint(): any {
if (existsSync(CHECKPOINT_FILE)) {
return JSON.parse(readFileSync(CHECKPOINT_FILE, 'utf-8'))
}
return { step: 0, data: {} }
}
function saveCheckpoint(step: number, data: any) {
writeFileSync(CHECKPOINT_FILE, JSON.stringify({ step, data }))
}
const checkpoint = loadCheckpoint()
let currentStep = checkpoint.step
// Step 1: Fetch data
if (currentStep === 0) {
console.error('[workflow] Step 1: Fetching data...')
const data = { papers: ['paper1', 'paper2', 'paper3'] }
saveCheckpoint(1, data)
currentStep = 1
}
// Step 2: Process data
if (currentStep === 1) {
console.error('[workflow] Step 2: Processing data...')
const { data } = loadCheckpoint()
// Process papers
saveCheckpoint(2, { ...data, processed: true })
currentStep = 2
}
// Step 3: Post to social
if (currentStep === 2) {
console.error('[workflow] Step 3: Posting to social...')
const { data } = loadCheckpoint()
// Post each paper
saveCheckpoint(3, data)
currentStep = 3
}
// Cleanup checkpoint on success
if (existsSync(CHECKPOINT_FILE)) {
execSync(`rm ${CHECKPOINT_FILE}`)
}
console.log(JSON.stringify({ stepsCompleted: 3, stepsTotal: 3 }))typescript
#!/usr/bin/env bun
import { execSync } from 'node:child_process'
import { writeFileSync, readFileSync, existsSync } from 'fs'
const CHECKPOINT_FILE = '/tmp/workflow-checkpoint.json'
function loadCheckpoint(): any {
if (existsSync(CHECKPOINT_FILE)) {
return JSON.parse(readFileSync(CHECKPOINT_FILE, 'utf-8'))
}
return { step: 0, data: {} }
}
function saveCheckpoint(step: number, data: any) {
writeFileSync(CHECKPOINT_FILE, JSON.stringify({ step, data }))
}
const checkpoint = loadCheckpoint()
let currentStep = checkpoint.step
// Step 1: Fetch data
if (currentStep === 0) {
console.error('[workflow] Step 1: Fetching data...')
const data = { papers: ['paper1', 'paper2', 'paper3'] }
saveCheckpoint(1, data)
currentStep = 1
}
// Step 2: Process data
if (currentStep === 1) {
console.error('[workflow] Step 2: Processing data...')
const { data } = loadCheckpoint()
// Process papers
saveCheckpoint(2, { ...data, processed: true })
currentStep = 2
}
// Step 3: Post to social
if (currentStep === 2) {
console.error('[workflow] Step 3: Posting to social...')
const { data } = loadCheckpoint()
// Post each paper
saveCheckpoint(3, data)
currentStep = 3
}
// Cleanup checkpoint on success
if (existsSync(CHECKPOINT_FILE)) {
execSync(`rm ${CHECKPOINT_FILE}`)
}
console.log(JSON.stringify({ stepsCompleted: 3, stepsTotal: 3 }))Troubleshooting
故障排查
Browser Connection Issues
浏览器连接问题
bash
undefinedbash
undefinedCheck if Chrome is running with CDP
Check if Chrome is running with CDP
ps aux | grep chrome | grep remote-debugging-port
ps aux | grep chrome | grep remote-debugging-port
Kill existing Chrome and restart
Kill existing Chrome and restart
pkill -f chrome
bun run setup-chrome
pkill -f chrome
bun run setup-chrome
Verify CDP port is accessible
Verify CDP port is accessible
undefinedundefinedOperation Log Not Working
操作日志无法正常工作
bash
undefinedbash
undefinedCheck log file exists and is readable
Check log file exists and is readable
cat persona/operation-log.json
cat persona/operation-log.json
Reset log if corrupted
Reset log if corrupted
echo '[]' > persona/operation-log.json
echo '[]' > persona/operation-log.json
Verify log script works
Verify log script works
bun run scripts/log-operation.ts recent --limit 5
undefinedbun run scripts/log-operation.ts recent --limit 5
undefinedWorkflow Execution Fails
工作流执行失败
bash
undefinedbash
undefinedCheck workflow status
Check workflow status
bun run workflow status
bun run workflow status
View detailed logs
View detailed logs
bun run workflow history --id <workflow-id>
bun run workflow history --id <workflow-id>
Run with debug output
Run with debug output
DEBUG=1 bun run workflow run --id <workflow-id>
DEBUG=1 bun run workflow run --id <workflow-id>
Check executor is executable
Check executor is executable
chmod +x workflows/executors/<executor>.ts
undefinedchmod +x workflows/executors/<executor>.ts
undefinedLLM Provider Errors
LLM提供商错误
bash
undefinedbash
undefinedVerify API key is set
Verify API key is set
echo $OPENAI_API_KEY
echo $OPENAI_API_KEY
Test connection
Test connection
curl -H "Authorization: Bearer $OPENAI_API_KEY"
$OPENAI_BASE_URL/models
$OPENAI_BASE_URL/models
curl -H "Authorization: Bearer $OPENAI_API_KEY"
$OPENAI_BASE_URL/models
$OPENAI_BASE_URL/models
Check model availability
Check model availability
bun start --model <model-name> -p "test"
undefinedbun start --model <model-name> -p "test"
undefinedAgent Not Finding Elements
Agent无法找到元素
bash
undefinedbash
undefinedGet detailed snapshot
Get detailed snapshot
agent-browser snapshot -i -c -s 'article' > snapshot.json
agent-browser snapshot -i -c -s 'article' > snapshot.json
Check element refs are valid
Check element refs are valid
cat snapshot.json | jq '.[] | .ref'
cat snapshot.json | jq '.[] | .ref'
Try broader selector
Try broader selector
agent-browser snapshot -i -c -s 'div'
agent-browser snapshot -i -c -s 'div'
Wait for page to load
Wait for page to load
agent-browser wait 5000
agent-browser snapshot -i
undefinedagent-browser wait 5000
agent-browser snapshot -i
undefined