Skip to content

Feat/twitter post reader#122

Merged
nicky-ru merged 33 commits into
mainfrom
feat/twitter-post-reader
Feb 4, 2026
Merged

Feat/twitter post reader#122
nicky-ru merged 33 commits into
mainfrom
feat/twitter-post-reader

Conversation

@nicky-ru
Copy link
Copy Markdown

What does this PR do?

Risks

Background

nicky-ru and others added 11 commits January 30, 2026 12:00
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Implement extractTweetId function to parse and extract tweet IDs from various Twitter/X URL formats including:
- x.com and twitter.com domains
- Mobile variants (mobile.x.com, mobile.twitter.com)
- URLs with query parameters, www prefix, and trailing slashes

Validates URL structure and throws error for invalid formats.
Comprehensive test coverage with 25 test cases.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Implement formatTweet function to convert Tweet objects into readable text format including:
- Author name and username
- Tweet text content
- Engagement metrics (likes, retweets, replies, views)
- Media attachments (photos and videos)
- Mentions, hashtags, and URLs
- Relative timestamp conversion (e.g., '2 hours ago')

Handles null/undefined optional fields gracefully.
Refactored with helper functions for improved maintainability.
15 comprehensive test cases covering all scenarios.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Move extractTweetId to src/utils/extractTweetId.ts
- Move formatTweet to src/utils/formatTweet.ts with helper functions
- Update src/actions/readTweet.ts to re-export utilities
- Split tests by responsibility:
  - src/test/extractTweetId.test.ts (23 tests)
  - src/test/formatTweet.test.ts (15 tests)
- Follow plugin-depin structure pattern
- All 38 tests still passing

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Implement AC4-6: Comprehensive error handling for Twitter tweet reading
with user-friendly error messages and robust error recovery.

Changes:
- Added error handling for invalid URL formats (AC4)
- Added error handling for deleted/protected/non-existent tweets (AC5)
- Added error handling for rate limit errors (AC6)
- Created 15 comprehensive tests for all error scenarios
- Added type guards for API error type safety
- Added null safety checks in formatTweet utility
- Added tweet structure validation before formatting
- Wrapped formatTweet call in defensive try-catch
- Extracted URL regex pattern as constant

All 53 tests passing (23 URL parsing + 15 formatting + 15 error handling)

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Add READ_TWEET to similes array (plugin-depin pattern compliance)
- Import and export readTweetAction from plugin index.ts
- Add readTweetAction to plugin actions array
- Extract plugin name and description to constants
- Add 29 integration tests for AC7-8 (action properties, plugin integration, coverage validation)
- All 82 tests passing (23 URL parsing + 15 formatting + 15 error handling + 29 integration)
- Refactored for code quality with named constants

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Reduce global AGENTS.md from 174 to 85 lines
- Reduce plugin-twitter AGENTS.md from 730 to 75 lines
- Remove internal duplications between docs
- Remove redundant explanations and examples
- Keep only critical gotchas and actionable commands
- Follow Factory AGENTS.md best practices (≤150 lines)
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Jan 30, 2026

Codecov Report

❌ Patch coverage is 98.48229% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.00%. Comparing base (26ade61) to head (063b015).

Files with missing lines Patch % Lines
...ages/plugin-twitter/src/actions/readTweet/utils.ts 95.45% 5 Missing ⚠️
packages/plugin-twitter/src/actions/readTweet.ts 98.70% 4 Missing ⚠️

❌ Your project status has failed because the head coverage (52.00%) is below the target coverage (70.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #122      +/-   ##
==========================================
+ Coverage   50.87%   52.00%   +1.13%     
==========================================
  Files         180      188       +8     
  Lines       24441    25036     +595     
  Branches     2251     2379     +128     
==========================================
+ Hits        12435    13021     +586     
- Misses      11962    11971       +9     
  Partials       44       44              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

nicky-ru and others added 18 commits February 3, 2026 10:05
Fixed TypeScript module resolution error by creating local type definitions
instead of importing from @elizaos/client-twitter/src/types which is not
exposed through package exports. This avoids adding an unnecessary dependency
on the client package while maintaining type safety.

Changes:
- Created src/types.ts with local Tweet, Photo, Video, and Mention types
- Updated imports in formatTweet.ts and formatTweet.test.ts to use local types
Added TwitterReadClient that works independently of loaded Twitter client:
- Minimal TwitterApiV2 wrapper (125 lines)
- Returns raw API responses for LLM processing
- Works with just TWITTER_BEARER_TOKEN env var
- No transformation logic - LLM handles data interpretation

Tests:
- 28 comprehensive tests (100% coverage for client.ts)
- Tests constructor, getTweet(), error handling
- Mocks twitter-api-v2 appropriately
- All 112 package tests pass

Dependencies:
- Added twitter-api-v2@^1.27.0 to package.json
Added tweetResponseTemplate for persona-aware, contextual responses:
- Provides structured template with recent messages, tweet data, and user request
- Instructions guide LLM to analyze tweets in character's voice
- Exported from index.ts for character configurations
- Follows pattern used in plugin-depin (ASK_SENTAI)

Template enables:
- Content summarization
- Metrics analysis (likes, retweets, views)
- Media attachments description
- Hashtags/mentions/URLs highlighting
- Author discussion
- Flexible responses based on user's question
Major refactoring following established plugin patterns:
- Removed formatTweet dependency (162 lines deleted)
- Handler now passes raw tweet data to LLM via template
- Added state management with updateRecentMessageState
- Integrated with generateMessageResponse for LLM processing
- Works independently of loaded Twitter client

Test improvements:
- Added 17 new tests (61 total, up from 44)
- Coverage: 100% (was 70.43%)
- New tests cover: state management, generic errors, lightweight client creation
- All 112 package tests pass

Handler flow:
1. Validate URL and extract tweet ID
2. Get/create Twitter client (runtime or lightweight)
3. Fetch raw tweet data
4. Pass to LLM via template context
5. Generate persona-aware response

Benefits:
- Works without Twitter client loaded
- LLM generates natural, contextual responses
- Follows ASK_SENTAI pattern (plugin-depin)
- Simpler, more maintainable code
Removed heavy formatting logic now that LLM handles responses:
- Deleted src/utils/formatTweet.ts (162 lines)
- Deleted src/test/formatTweet.test.ts (15 tests, 384 lines)
- No longer needed with LLM-driven approach

Total reduction: 546 lines of code
Documentation improvements:
- Archived TDD context to archive/tdd-context-readTweet-coverage-2026-02-03.md
- Updated AGENTS.md with:
  - Current coverage metrics (100% statements, 97.36% branches)
  - LLM-driven architecture pattern
  - Lightweight Twitter client documentation
  - Updated file structure
  - New code patterns (state management, LLM mocking)
  - Migration history with commit references
  - Expanded common pitfalls section
Remove invalid 'state' parameter and add required 'modelClass' and 'tags'
parameters to generateMessageResponse call. Add ModelClass import.

- Remove: state parameter (not in function signature)
- Add: modelClass: ModelClass.LARGE (required)
- Add: tags: ["read-tweet"] (required)
- Add: message: message (optional, for context)

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Move bearer token validation from handler to validate function to fail fast
when TWITTER_BEARER_TOKEN is not configured. The validate function now checks
for the presence of a non-empty bearer token before attempting to execute
the action.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add extractImageUrls function to extract image URLs from tweet data's photos
array and add them to state for use in LLM context generation.

Changes:
- Add extractImageUrls helper function to handle photo extraction
- Call extractImageUrls in readTweetHandler after fetching tweet data
- Add imageUrls to state before LLM context composition
- Update tweetResponseTemplate to display image URLs when present
- Add tests for extracting images from tweets with photos, empty photos, and undefined photos

Acceptance Criteria Implemented:
- AC1: When a tweet contains 1-4 images, extract all image URLs from the tweet data

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add IImageDescriptionService import and use generic type parameter with
getService to fix TypeScript error.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Fixed template rendering of image descriptions which was displaying
"[object Object]" instead of properly formatted image metadata.

**Changes**:
- Updated template to use Handlebars iteration syntax for imageDescriptions array
- Added templatingEngine: "handlebars" parameter to composeContext call
- Each image now displays title and description on separate lines
- Added fallback message when no images present

**Before**: Images in Tweet: [object Object]
**After**:
  Images in Tweet:
  - Image: [title]
    Description: [description]

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Implement cache-aside pattern for tweet caching in READ_TWEET action:
- Cache hit returns cached tweet without API call
- Cache miss triggers API fetch and caches result
- Graceful degradation on cache errors
- Cache key format: twitter/tweets/{tweetId}

All 149 tests passing with comprehensive TDD coverage.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Split the monolithic readTweet.ts file into focused modules:
- types.ts: All TypeScript type definitions
- utils.ts: Utility functions for tweet processing
- clientUtils.ts: Twitter client management
- readTweet.ts: Core handler logic (45% reduction in size)

Benefits:
- Better code organization by concern
- Improved maintainability and readability
- Enhanced reusability of utility functions
- All 145 tests passing
- 96.57% statement coverage maintained

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
nicky-ru and others added 4 commits February 4, 2026 13:33
Consolidated redundant test cases to reduce duplication:
- AC6: Rate limit tests (3 → 1)
- AC10: Error handling tests (7 → 3)
- AC4: Cache manager tests (7 → 3)
- AC1: Cache hit tests (5 → 2)

Results:
- 94 tests (down from 104)
- 2835 lines (down from 2987)
- 96.57% statement coverage maintained
- 93.18% branch coverage maintained
- All critical functionality preserved

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…ity-first design

Remove all hardcoded error messages from readTweet action and use LLM-generated,
persona-aware responses for all scenarios while maintaining security by NOT exposing
internal API details to the LLM.

**Security-First Approach:**
- Only safe error types exposed to LLM (invalid_url, tweet_not_found, etc.)
- Raw API codes (404, 403, 429) never reach LLM
- Raw API error messages never reach LLM
- Rate limit timing details never reach LLM
- Internal implementation details abstracted away

**Implementation:**
- Added SAFE_ERROR_TYPES constant with 8 safe error types
- Created mapApiErrorToSafeType() for internal error mapping
- Created processTweetError() for LLM-driven error responses
- Created tweetErrorResponseTemplate with Handlebars conditionals
- Refactored all 9 error paths to use safe mapping + LLM
- Removed hardcoded error message constants

**Error Type Mapping:**
- 404 → tweet_not_found
- 403 (protected/suspended) → tweet_protected
- 403 (other) → tweet_forbidden
- 429 → rate_limited (no timing details)
- Invalid URL → invalid_url
- Client null → client_error
- Data null → data_unavailable
- Catch-all → api_error

**Testing:**
- Added 21 new tests for safe error type mapping
- Updated 21+ tests to verify LLM invocation vs exact strings
- All 166 tests passing
- Lint passing (0 errors)
- Build successful

**Benefits:**
- Consistent character voice across all responses
- Contextual, persona-aware error messages
- Automatic internationalization via LLM
- No hardcoded strings to maintain
- Extensible error handling with safe abstractions

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Root AGENTS.md: Updated to reflect actual package layout (21+ packages)
- plugin-twitter AGENTS.md: Updated to reflect modular action structure
- Removed outdated migration history and stale coverage stats
- Streamlined both documents to follow init skill template
- Focused on actionable patterns over historical context

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@nicky-ru nicky-ru merged commit 60a238b into main Feb 4, 2026
4 checks passed
@nicky-ru nicky-ru deleted the feat/twitter-post-reader branch February 4, 2026 15:51
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.

2 participants