Skip to content

Feat/outbound agent#7

Merged
arvindrk merged 14 commits into
mainfrom
feat/outbound-agent
May 7, 2026
Merged

Feat/outbound agent#7
arvindrk merged 14 commits into
mainfrom
feat/outbound-agent

Conversation

@arvindrk
Copy link
Copy Markdown
Owner

@arvindrk arvindrk commented May 7, 2026

What

Adds an outbound engagement agent triggered every 2 hours via POST /cron/outbound-engagement — it discovers tweets to like, retweet, reply to, and accounts to follow, fully autonomously.

Why

The system previously only engaged inbound (mentions/replies via webhook). Growth requires proactive outreach: following relevant accounts, engaging quality content, and joining AI/LLM discussions before they come to us.

How

New layers added (bottom-up):

  • src/agents/safety.ts — extracted shared pure utilities (sanitizeUntrusted, isReplySafe, AI_DISCLOSURE_PATTERNS) from inbound-engagement.ts. Both agents now share these without duplication.
  • src/db/schema.tsoutbound_action enum + outbound_engagement_log table with a unique index on (tweet_id, action) for DB-level dedup.
  • src/db/outbound-engagement.repo.ts — 4 batch-safe functions: getAlreadyActedPairs, getCooledDownAuthorIds, getFollowedAuthorIds, logOutboundAction. All handle empty inputs without querying.
  • src/x/api.tsSearchedTweet type + searchTweets, followUser, retweetPost, getFollowingHandles via xClient (OAuth1, no raw fetch).
  • src/agents/outbound-engagement.tsgenerateObject with grok-4-latest. Full safety parity with inbound: <untrusted> wrapping on all tweet content, 280-char retry loop, isReplySafe guard, same voice/non-disclosure rules in system prompt.
  • src/services/outbound-engagement.ts — orchestrates the full pipeline. Two co-located pure functions: meetsSignalThreshold (signal pre-filter) and applyConstraints (enforces per-run caps + cooldowns without touching I/O). Caps: 10 likes / 5 replies / 3 retweets / 3 follows per run.
  • src/routes/cron.tsPOST /cron/outbound-engagement following the exact fire-and-forget 202 pattern of /cron/daily.

Non-obvious decisions:

  • applyConstraints is a pure function: agent decides on content quality, service enforces operational limits (caps, 6h account cooldown, follow dedup) as a post-processing step. The agent never knows about rate limits.
  • Follow dedup uses our own outbound_engagement_log (zero extra API calls) rather than fetching the full following list on every run. getFollowingHandles is only called for seed expansion (building the 4th search query from accounts we already follow).
  • All 4 X API calls in the execution loop are individually try/caught and logged to DB with an error field — a failed like never aborts the retweet or reply for that decision.
  • Seed expansion searches for people engaging with accounts we follow (via @handle query), not fetching their follower lists (which would be expensive and paginated).

Checklist

  • bun run typecheck passes
  • bun run test passes (85 tests, 0 failures — 17 new tests added)
  • bun run format:check passes
  • Layer rules in AGENTS.md respected (no cross-layer imports)
  • No dead, commented-out, or duplicate code introduced

@cursor
Copy link
Copy Markdown

cursor Bot commented May 7, 2026

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
twitter-agent Ready Ready Preview, Comment May 7, 2026 3:38am

@arvindrk arvindrk merged commit 329d879 into main May 7, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant