@elizaos/plugin-farcaster 1.0.2 → 1.0.5

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 CHANGED
@@ -1,26 +1,41 @@
1
1
  # ElizaOS Farcaster Plugin
2
2
 
3
- A plugin for ElizaOS that enables agent integration with the Farcaster social network.
3
+ A comprehensive plugin for ElizaOS that enables AI agents to fully participate in the Farcaster social network with posting, replying, and engagement capabilities.
4
4
 
5
5
  ## Overview
6
6
 
7
- The ElizaOS Farcaster Plugin allows AI agents to interact with the Farcaster social network by:
7
+ The ElizaOS Farcaster Plugin provides a complete integration with Farcaster, allowing AI agents to:
8
8
 
9
- - Publishing original casts (posts)
10
- - Responding to mentions and replies
11
- - Interacting with other users' content
12
- - Processing user engagement automatically
9
+ - **Post & Reply**: Create original casts and reply to conversations
10
+ - **Monitor Mentions**: Track and respond to mentions automatically
11
+ - **Engage with Content**: Like, recast, and interact with other users' posts
12
+ - **Context-Aware Responses**: Maintain conversation threads and context
13
+ - **Real-time Interaction**: Process interactions in real-time with configurable intervals
13
14
 
14
- This plugin leverages the [Neynar API](https://neynar.com) to interact with Farcaster, providing a robust integration between ElizaOS agents and the Farcaster social graph.
15
+ This plugin leverages the [Neynar API](https://neynar.com) and implements full ElizaOS service interfaces for seamless integration.
15
16
 
16
17
  ## Features
17
18
 
18
- - **Automated Posting**: Schedule and publish regular casts with configurable intervals
19
- - **Engagement Monitoring**: Track mentions, replies, and interactions
20
- - **Conversation Threading**: Build and maintain conversation context for natural interactions
21
- - **Dry Run Mode**: Test functionality without actually posting to Farcaster
22
- - **Configurable Settings**: Customize behavior via environment variables
23
- - **Caching**: Efficient caching of profiles and casts for improved performance
19
+ ### Core Services
20
+ - **FarcasterService**: Main service managing agent connections and lifecycle
21
+ - **MessageService**: Implements `IMessageService` for sending/receiving messages
22
+ - **CastService**: Implements `IPostService` for creating and managing casts
23
+
24
+ ### Actions
25
+ - **SEND_CAST**: Post casts based on user requests
26
+ - **REPLY_TO_CAST**: Reply to existing casts with context
27
+
28
+ ### Providers
29
+ - **farcasterProfile**: Provides agent's Farcaster profile information
30
+ - **farcasterTimeline**: Supplies recent timeline casts for context
31
+
32
+ ### Additional Features
33
+ - **Automated Posting**: Schedule and publish regular casts
34
+ - **Engagement Monitoring**: Track mentions and interactions
35
+ - **Conversation Threading**: Maintain conversation context
36
+ - **Metadata Tracking**: Store cast metadata for reference
37
+ - **Health Monitoring**: Built-in health check functionality
38
+ - **Caching**: Efficient caching for improved performance
24
39
 
25
40
  ## Installation
26
41
 
@@ -28,6 +43,36 @@ This plugin leverages the [Neynar API](https://neynar.com) to interact with Farc
28
43
  npm install @elizaos/plugin-farcaster
29
44
  ```
30
45
 
46
+ ## Setup
47
+
48
+ ### 1. Get Farcaster Credentials
49
+
50
+ 1. **Create a Farcaster Account**: If you don't have one, sign up at [Warpcast](https://warpcast.com)
51
+ 2. **Note your FID**: Find your Farcaster ID in your profile settings
52
+ 3. **Get Neynar API Access**:
53
+ - Sign up at [Neynar Developer Portal](https://dev.neynar.com/)
54
+ - Create a new application
55
+ - Copy your API key
56
+ 4. **Create a Signer**:
57
+ - In the Neynar dashboard, go to "Signers"
58
+ - Create a new signer for your FID
59
+ - Copy the Signer UUID
60
+
61
+ ### 2. Configure Environment
62
+
63
+ Copy the example environment file and fill in your credentials:
64
+
65
+ ```bash
66
+ cp env.example .env
67
+ ```
68
+
69
+ Edit `.env` with your credentials:
70
+ ```env
71
+ FARCASTER_FID=your-fid-here
72
+ FARCASTER_NEYNAR_API_KEY=your-api-key-here
73
+ FARCASTER_SIGNER_UUID=your-signer-uuid-here
74
+ ```
75
+
31
76
  ## Configuration
32
77
 
33
78
  The plugin requires the following configurations, which can be set via environment variables or ElizaOS runtime settings:
@@ -37,7 +82,7 @@ The plugin requires the following configurations, which can be set via environme
37
82
  | Parameter | Description |
38
83
  | ------------------------------ | -------------------------------------- |
39
84
  | `FARCASTER_NEYNAR_API_KEY` | Neynar API key for accessing Farcaster |
40
- | `FARCASTER_NEYNAR_SIGNER_UUID` | Signer UUID for your Farcaster account |
85
+ | `FARCASTER_SIGNER_UUID` | Signer UUID for your Farcaster account |
41
86
  | `FARCASTER_FID` | Your Farcaster FID (identifier) |
42
87
 
43
88
  ### Optional Settings
@@ -47,33 +92,66 @@ The plugin requires the following configurations, which can be set via environme
47
92
  | `FARCASTER_DRY_RUN` | Run in simulation mode without posting (true/false) | false |
48
93
  | `MAX_CAST_LENGTH` | Maximum length of casts | 320 |
49
94
  | `FARCASTER_POLL_INTERVAL` | Interval for checking mentions (minutes) | 2 |
50
- | `ENABLE_POST` | Enable automatic posting (true/false) | true |
51
- | `POST_INTERVAL_MIN` | Minimum time between posts (minutes) | 90 |
52
- | `POST_INTERVAL_MAX` | Maximum time between posts (minutes) | 180 |
95
+ | `ENABLE_CAST` | Enable automatic casting (true/false) | true |
96
+ | `CAST_INTERVAL_MIN` | Minimum time between casts (minutes) | 90 |
97
+ | `CAST_INTERVAL_MAX` | Maximum time between casts (minutes) | 180 |
53
98
  | `ENABLE_ACTION_PROCESSING` | Enable processing interactions (true/false) | false |
54
99
  | `ACTION_INTERVAL` | Interval for processing actions (minutes) | 5 |
55
- | `POST_IMMEDIATELY` | Post immediately on startup (true/false) | false |
100
+ | `CAST_IMMEDIATELY` | Cast immediately on startup (true/false) | false |
56
101
  | `MAX_ACTIONS_PROCESSING` | Maximum actions to process in one cycle | 1 |
57
102
  | `ACTION_TIMELINE_TYPE` | Type of timeline to use for actions | ForYou |
58
103
 
59
104
  ## Usage
60
105
 
61
- ### Basic Integration with ElizaOS
106
+ ### Basic Integration
107
+
108
+ 1. **In your agent's character file**:
109
+
110
+ ```json
111
+ {
112
+ "name": "MyFarcasterAgent",
113
+ "bio": "An AI agent on Farcaster",
114
+ "plugins": ["@elizaos/plugin-farcaster"],
115
+ "settings": {
116
+ "FARCASTER_FID": "123456",
117
+ "FARCASTER_NEYNAR_API_KEY": "your-api-key",
118
+ "FARCASTER_SIGNER_UUID": "your-signer-uuid"
119
+ }
120
+ }
121
+ ```
62
122
 
63
- ```typescript
64
- import { ElizaOS } from '@elizaos/core';
65
- import farcasterPlugin from '@elizaos-plugins/client-farcaster';
123
+ 2. **Start your agent**:
66
124
 
67
- // Initialize ElizaOS
68
- const elizaOs = new ElizaOS({
69
- // ElizaOS configuration
70
- });
125
+ ```bash
126
+ elizaos start --character path/to/character.json
127
+ ```
71
128
 
72
- // Register the Farcaster plugin
73
- elizaOs.registerPlugin(farcasterPlugin);
129
+ ### Using Actions
74
130
 
75
- // Start ElizaOS
76
- elizaOs.start();
131
+ The plugin provides actions that can be triggered through natural language:
132
+
133
+ ```
134
+ User: "Can you post about the new ElizaOS features on Farcaster?"
135
+ Agent: "I'll post about the new ElizaOS features on Farcaster now."
136
+ [Agent posts to Farcaster]
137
+
138
+ User: "Reply to that cast and thank them for the feedback"
139
+ Agent: "I'll reply with a thank you message."
140
+ [Agent replies to the cast]
141
+ ```
142
+
143
+ ### Programmatic Usage
144
+
145
+ ```typescript
146
+ import farcasterPlugin from '@elizaos/plugin-farcaster';
147
+
148
+ // The plugin exports its components
149
+ const { actions, providers, services } = farcasterPlugin;
150
+
151
+ // Access specific services programmatically
152
+ const farcasterService = runtime.getService('farcaster');
153
+ const messageService = farcasterService.getMessageService(agentId);
154
+ const castService = farcasterService.getCastService(agentId);
77
155
  ```
78
156
 
79
157
  ### Customizing Cast Templates
@@ -123,28 +201,69 @@ npm run dev
123
201
 
124
202
  ## Architecture
125
203
 
126
- The client is organized into several core components:
204
+ The plugin is organized into several core components:
127
205
 
128
- - **FarcasterClient**: Base client for interacting with the Farcaster network via Neynar
129
- - **FarcasterPostManager**: Manages autonomous posting schedule and generation
130
- - **FarcasterInteractionManager**: Handles mentions, replies, and other interactions
131
- - **Memory Management**: Stores conversation context and history
206
+ ### Services
207
+ - **FarcasterService**: Main service managing agent lifecycle and health monitoring
208
+ - **MessageService**: Handles sending/receiving messages, implements `IMessageService`
209
+ - **CastService**: Manages casts and interactions, implements `IPostService`
132
210
 
133
- ## Dependencies
211
+ ### Managers
212
+ - **FarcasterClient**: Base client for Neynar API interactions
213
+ - **FarcasterAgentManager**: Manages agent-specific connections
214
+ - **FarcasterInteractionManager**: Handles mentions and replies
215
+ - **FarcasterCastManager**: Manages autonomous casting
134
216
 
135
- - [@neynar/nodejs-sdk](https://www.npmjs.com/package/@neynar/nodejs-sdk): Official SDK for Neynar API
136
- - [@elizaos/core](https://www.npmjs.com/package/@elizaos/core): ElizaOS core framework
217
+ ### Components
218
+ - **Actions**: User-triggered capabilities (SEND_CAST, REPLY_TO_CAST)
219
+ - **Providers**: Context providers for agent awareness
220
+ - **Event Handlers**: Metadata tracking and event processing
137
221
 
138
222
  ## Testing
139
223
 
140
- The client includes comprehensive tests for:
224
+ The plugin includes comprehensive test coverage:
225
+
226
+ ### Unit Tests
227
+ Located in `__tests__/unit/`:
228
+ - Service functionality tests
229
+ - Action validation tests
230
+ - Provider output tests
141
231
 
142
- - Cast creation and management
143
- - Interaction handling
144
- - Timeline processing
232
+ ### E2E Tests
233
+ Located in `__tests__/e2e/`:
234
+ - Real account interactions
235
+ - Full conversation flows
236
+ - Error handling scenarios
145
237
 
146
- Run the tests with:
238
+ ### Running Tests
147
239
 
148
240
  ```bash
241
+ # Run all tests
149
242
  npm test
243
+
244
+ # Run unit tests only
245
+ npm run test:unit
246
+
247
+ # Run E2E tests (requires API keys)
248
+ npm run test:e2e
249
+
250
+ # Run with coverage
251
+ npm run test:coverage
150
252
  ```
253
+
254
+ For E2E tests, ensure your `.env` file contains valid API credentials.
255
+
256
+ ## Dependencies
257
+
258
+ - [@neynar/nodejs-sdk](https://www.npmjs.com/package/@neynar/nodejs-sdk): Official SDK for Neynar API
259
+ - [@elizaos/core](https://www.npmjs.com/package/@elizaos/core): ElizaOS core framework
260
+ - [lru-cache](https://www.npmjs.com/package/lru-cache): Efficient caching
261
+ - [zod](https://www.npmjs.com/package/zod): Schema validation
262
+
263
+ ## Contributing
264
+
265
+ Contributions are welcome! Please ensure all tests pass and add new tests for any new functionality.
266
+
267
+ ## License
268
+
269
+ This plugin is part of the ElizaOS ecosystem and follows the same licensing terms.
@@ -0,0 +1,83 @@
1
+ import {
2
+ FARCASTER_SERVICE_NAME
3
+ } from "./chunk-Y2URJ4EZ.js";
4
+
5
+ // src/providers/timelineProvider.ts
6
+ import {
7
+ logger
8
+ } from "@elizaos/core";
9
+ var farcasterTimelineProvider = {
10
+ name: "farcasterTimeline",
11
+ description: "Provides recent casts from the agent's Farcaster timeline",
12
+ get: async (runtime, message, state) => {
13
+ var _a, _b, _c;
14
+ try {
15
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
16
+ const castService = service == null ? void 0 : service.getCastService(runtime.agentId);
17
+ if (!castService) {
18
+ return {
19
+ text: "Farcaster timeline not available.",
20
+ data: { available: false }
21
+ };
22
+ }
23
+ const casts = await castService.getCasts({
24
+ agentId: runtime.agentId,
25
+ limit: 5
26
+ });
27
+ if (!casts || casts.length === 0) {
28
+ return {
29
+ text: "No recent casts in your timeline.",
30
+ data: {
31
+ available: true,
32
+ casts: [],
33
+ count: 0
34
+ }
35
+ };
36
+ }
37
+ const formattedCasts = casts.map((cast, index) => {
38
+ const timeAgo = getTimeAgo(new Date(cast.timestamp));
39
+ return `${index + 1}. @${cast.username} (${timeAgo}): ${cast.text}`;
40
+ }).join("\n");
41
+ return {
42
+ text: `Recent casts from your timeline:
43
+ ${formattedCasts}`,
44
+ data: {
45
+ available: true,
46
+ casts: casts.map((c) => {
47
+ var _a2;
48
+ return {
49
+ id: c.id,
50
+ username: c.username,
51
+ text: c.text,
52
+ timestamp: c.timestamp,
53
+ castHash: (_a2 = c.metadata) == null ? void 0 : _a2.castHash
54
+ };
55
+ }),
56
+ count: casts.length
57
+ },
58
+ values: {
59
+ latestCastHash: (_b = (_a = casts[0]) == null ? void 0 : _a.metadata) == null ? void 0 : _b.castHash,
60
+ latestCastText: (_c = casts[0]) == null ? void 0 : _c.text
61
+ }
62
+ };
63
+ } catch (error) {
64
+ logger.error("[FarcasterTimelineProvider] Error:", error);
65
+ return {
66
+ text: "Unable to fetch Farcaster timeline.",
67
+ data: { available: false, error: error instanceof Error ? error.message : "Unknown error" }
68
+ };
69
+ }
70
+ }
71
+ };
72
+ function getTimeAgo(date) {
73
+ const seconds = Math.floor(((/* @__PURE__ */ new Date()).getTime() - date.getTime()) / 1e3);
74
+ if (seconds < 60) return "just now";
75
+ if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
76
+ if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;
77
+ return `${Math.floor(seconds / 86400)}d ago`;
78
+ }
79
+
80
+ export {
81
+ farcasterTimelineProvider
82
+ };
83
+ //# sourceMappingURL=chunk-FNDASAYG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/timelineProvider.ts"],"sourcesContent":["import {\n type Provider,\n type IAgentRuntime,\n type Memory,\n type State,\n type ProviderResult,\n logger,\n} from '@elizaos/core';\nimport { FARCASTER_SERVICE_NAME } from '../common/constants';\nimport type { FarcasterService } from '../service';\n\nexport const farcasterTimelineProvider: Provider = {\n name: 'farcasterTimeline',\n description: \"Provides recent casts from the agent's Farcaster timeline\",\n\n get: async (runtime: IAgentRuntime, message: Memory, state: State): Promise<ProviderResult> => {\n try {\n const service = runtime.getService(FARCASTER_SERVICE_NAME) as FarcasterService;\n const castService = service?.getCastService(runtime.agentId);\n\n if (!castService) {\n return {\n text: 'Farcaster timeline not available.',\n data: { available: false },\n };\n }\n\n // Get recent casts from timeline\n const casts = await castService.getCasts({\n agentId: runtime.agentId,\n limit: 5,\n });\n\n if (!casts || casts.length === 0) {\n return {\n text: 'No recent casts in your timeline.',\n data: {\n available: true,\n casts: [],\n count: 0,\n },\n };\n }\n\n // Format casts for context\n const formattedCasts = casts\n .map((cast, index) => {\n const timeAgo = getTimeAgo(new Date(cast.timestamp));\n return `${index + 1}. @${cast.username} (${timeAgo}): ${cast.text}`;\n })\n .join('\\n');\n\n return {\n text: `Recent casts from your timeline:\\n${formattedCasts}`,\n data: {\n available: true,\n casts: casts.map((c) => ({\n id: c.id,\n username: c.username,\n text: c.text,\n timestamp: c.timestamp,\n castHash: c.metadata?.castHash,\n })),\n count: casts.length,\n },\n values: {\n latestCastHash: casts[0]?.metadata?.castHash,\n latestCastText: casts[0]?.text,\n },\n };\n } catch (error) {\n logger.error('[FarcasterTimelineProvider] Error:', error);\n return {\n text: 'Unable to fetch Farcaster timeline.',\n data: { available: false, error: error instanceof Error ? error.message : 'Unknown error' },\n };\n }\n },\n};\n\n// Helper function to format time ago\nfunction getTimeAgo(date: Date): string {\n const seconds = Math.floor((new Date().getTime() - date.getTime()) / 1000);\n\n if (seconds < 60) return 'just now';\n if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;\n if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;\n return `${Math.floor(seconds / 86400)}d ago`;\n}\n"],"mappings":";;;;;AAAA;AAAA,EAME;AAAA,OACK;AAIA,IAAM,4BAAsC;AAAA,EACjD,MAAM;AAAA,EACN,aAAa;AAAA,EAEb,KAAK,OAAO,SAAwB,SAAiB,UAA0C;AAfjG;AAgBI,QAAI;AACF,YAAM,UAAU,QAAQ,WAAW,sBAAsB;AACzD,YAAM,cAAc,mCAAS,eAAe,QAAQ;AAEpD,UAAI,CAAC,aAAa;AAChB,eAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM,EAAE,WAAW,MAAM;AAAA,QAC3B;AAAA,MACF;AAGA,YAAM,QAAQ,MAAM,YAAY,SAAS;AAAA,QACvC,SAAS,QAAQ;AAAA,QACjB,OAAO;AAAA,MACT,CAAC;AAED,UAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,eAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM;AAAA,YACJ,WAAW;AAAA,YACX,OAAO,CAAC;AAAA,YACR,OAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAGA,YAAM,iBAAiB,MACpB,IAAI,CAAC,MAAM,UAAU;AACpB,cAAM,UAAU,WAAW,IAAI,KAAK,KAAK,SAAS,CAAC;AACnD,eAAO,GAAG,QAAQ,CAAC,MAAM,KAAK,QAAQ,KAAK,OAAO,MAAM,KAAK,IAAI;AAAA,MACnE,CAAC,EACA,KAAK,IAAI;AAEZ,aAAO;AAAA,QACL,MAAM;AAAA,EAAqC,cAAc;AAAA,QACzD,MAAM;AAAA,UACJ,WAAW;AAAA,UACX,OAAO,MAAM,IAAI,CAAC,MAAG;AAxD/B,gBAAAA;AAwDmC;AAAA,cACvB,IAAI,EAAE;AAAA,cACN,UAAU,EAAE;AAAA,cACZ,MAAM,EAAE;AAAA,cACR,WAAW,EAAE;AAAA,cACb,WAAUA,MAAA,EAAE,aAAF,gBAAAA,IAAY;AAAA,YACxB;AAAA,WAAE;AAAA,UACF,OAAO,MAAM;AAAA,QACf;AAAA,QACA,QAAQ;AAAA,UACN,iBAAgB,iBAAM,CAAC,MAAP,mBAAU,aAAV,mBAAoB;AAAA,UACpC,iBAAgB,WAAM,CAAC,MAAP,mBAAU;AAAA,QAC5B;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO,MAAM,sCAAsC,KAAK;AACxD,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM,EAAE,WAAW,OAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,gBAAgB;AAAA,MAC5F;AAAA,IACF;AAAA,EACF;AACF;AAGA,SAAS,WAAW,MAAoB;AACtC,QAAM,UAAU,KAAK,QAAO,oBAAI,KAAK,GAAE,QAAQ,IAAI,KAAK,QAAQ,KAAK,GAAI;AAEzE,MAAI,UAAU,GAAI,QAAO;AACzB,MAAI,UAAU,KAAM,QAAO,GAAG,KAAK,MAAM,UAAU,EAAE,CAAC;AACtD,MAAI,UAAU,MAAO,QAAO,GAAG,KAAK,MAAM,UAAU,IAAI,CAAC;AACzD,SAAO,GAAG,KAAK,MAAM,UAAU,KAAK,CAAC;AACvC;","names":["_a"]}
@@ -0,0 +1,72 @@
1
+ import {
2
+ FARCASTER_SERVICE_NAME
3
+ } from "./chunk-Y2URJ4EZ.js";
4
+
5
+ // src/providers/profileProvider.ts
6
+ import {
7
+ logger
8
+ } from "@elizaos/core";
9
+ var farcasterProfileProvider = {
10
+ name: "farcasterProfile",
11
+ description: "Provides information about the agent's Farcaster profile",
12
+ get: async (runtime, message, state) => {
13
+ try {
14
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
15
+ const managers = service == null ? void 0 : service.getActiveManagers();
16
+ if (!managers || managers.size === 0) {
17
+ return {
18
+ text: "Farcaster profile not available.",
19
+ data: { available: false }
20
+ };
21
+ }
22
+ const manager = managers.get(runtime.agentId);
23
+ if (!manager) {
24
+ return {
25
+ text: "Farcaster profile not available for this agent.",
26
+ data: { available: false }
27
+ };
28
+ }
29
+ const fid = parseInt(runtime.getSetting("FARCASTER_FID"), 10);
30
+ if (!fid || isNaN(fid)) {
31
+ return {
32
+ text: "Invalid Farcaster FID configured.",
33
+ data: { available: false, error: "Invalid FID" }
34
+ };
35
+ }
36
+ try {
37
+ const profile = await manager.client.getProfile(fid);
38
+ return {
39
+ text: `Your Farcaster profile: @${profile.username} (FID: ${profile.fid}). ${profile.name ? `Display name: ${profile.name}` : ""}`,
40
+ data: {
41
+ available: true,
42
+ fid: profile.fid,
43
+ username: profile.username,
44
+ name: profile.name,
45
+ pfp: profile.pfp
46
+ },
47
+ values: {
48
+ fid: profile.fid,
49
+ username: profile.username
50
+ }
51
+ };
52
+ } catch (error) {
53
+ logger.error("[FarcasterProfileProvider] Error fetching profile:", error);
54
+ return {
55
+ text: "Unable to fetch Farcaster profile at this time.",
56
+ data: { available: false, error: "Fetch failed" }
57
+ };
58
+ }
59
+ } catch (error) {
60
+ logger.error("[FarcasterProfileProvider] Error:", error);
61
+ return {
62
+ text: "Farcaster service is not available.",
63
+ data: { available: false }
64
+ };
65
+ }
66
+ }
67
+ };
68
+
69
+ export {
70
+ farcasterProfileProvider
71
+ };
72
+ //# sourceMappingURL=chunk-IOTLJXKN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/profileProvider.ts"],"sourcesContent":["import {\n type Provider,\n type IAgentRuntime,\n type Memory,\n type State,\n type ProviderResult,\n logger,\n} from '@elizaos/core';\nimport { FARCASTER_SERVICE_NAME } from '../common/constants';\nimport type { FarcasterService } from '../service';\n\nexport const farcasterProfileProvider: Provider = {\n name: 'farcasterProfile',\n description: \"Provides information about the agent's Farcaster profile\",\n\n get: async (runtime: IAgentRuntime, message: Memory, state: State): Promise<ProviderResult> => {\n try {\n const service = runtime.getService(FARCASTER_SERVICE_NAME) as FarcasterService;\n const managers = service?.getActiveManagers();\n\n if (!managers || managers.size === 0) {\n return {\n text: 'Farcaster profile not available.',\n data: { available: false },\n };\n }\n\n const manager = managers.get(runtime.agentId);\n if (!manager) {\n return {\n text: 'Farcaster profile not available for this agent.',\n data: { available: false },\n };\n }\n\n const fid = parseInt(runtime.getSetting('FARCASTER_FID') as string, 10);\n if (!fid || isNaN(fid)) {\n return {\n text: 'Invalid Farcaster FID configured.',\n data: { available: false, error: 'Invalid FID' },\n };\n }\n\n try {\n const profile = await manager.client.getProfile(fid);\n\n return {\n text: `Your Farcaster profile: @${profile.username} (FID: ${profile.fid}). ${profile.name ? `Display name: ${profile.name}` : ''}`,\n data: {\n available: true,\n fid: profile.fid,\n username: profile.username,\n name: profile.name,\n pfp: profile.pfp,\n },\n values: {\n fid: profile.fid,\n username: profile.username,\n },\n };\n } catch (error) {\n logger.error('[FarcasterProfileProvider] Error fetching profile:', error);\n return {\n text: 'Unable to fetch Farcaster profile at this time.',\n data: { available: false, error: 'Fetch failed' },\n };\n }\n } catch (error) {\n logger.error('[FarcasterProfileProvider] Error:', error);\n return {\n text: 'Farcaster service is not available.',\n data: { available: false },\n };\n }\n },\n};\n"],"mappings":";;;;;AAAA;AAAA,EAME;AAAA,OACK;AAIA,IAAM,2BAAqC;AAAA,EAChD,MAAM;AAAA,EACN,aAAa;AAAA,EAEb,KAAK,OAAO,SAAwB,SAAiB,UAA0C;AAC7F,QAAI;AACF,YAAM,UAAU,QAAQ,WAAW,sBAAsB;AACzD,YAAM,WAAW,mCAAS;AAE1B,UAAI,CAAC,YAAY,SAAS,SAAS,GAAG;AACpC,eAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM,EAAE,WAAW,MAAM;AAAA,QAC3B;AAAA,MACF;AAEA,YAAM,UAAU,SAAS,IAAI,QAAQ,OAAO;AAC5C,UAAI,CAAC,SAAS;AACZ,eAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM,EAAE,WAAW,MAAM;AAAA,QAC3B;AAAA,MACF;AAEA,YAAM,MAAM,SAAS,QAAQ,WAAW,eAAe,GAAa,EAAE;AACtE,UAAI,CAAC,OAAO,MAAM,GAAG,GAAG;AACtB,eAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM,EAAE,WAAW,OAAO,OAAO,cAAc;AAAA,QACjD;AAAA,MACF;AAEA,UAAI;AACF,cAAM,UAAU,MAAM,QAAQ,OAAO,WAAW,GAAG;AAEnD,eAAO;AAAA,UACL,MAAM,4BAA4B,QAAQ,QAAQ,UAAU,QAAQ,GAAG,MAAM,QAAQ,OAAO,iBAAiB,QAAQ,IAAI,KAAK,EAAE;AAAA,UAChI,MAAM;AAAA,YACJ,WAAW;AAAA,YACX,KAAK,QAAQ;AAAA,YACb,UAAU,QAAQ;AAAA,YAClB,MAAM,QAAQ;AAAA,YACd,KAAK,QAAQ;AAAA,UACf;AAAA,UACA,QAAQ;AAAA,YACN,KAAK,QAAQ;AAAA,YACb,UAAU,QAAQ;AAAA,UACpB;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AACd,eAAO,MAAM,sDAAsD,KAAK;AACxE,eAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM,EAAE,WAAW,OAAO,OAAO,eAAe;AAAA,QAClD;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO,MAAM,qCAAqC,KAAK;AACvD,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM,EAAE,WAAW,MAAM;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,105 @@
1
+ import {
2
+ FARCASTER_SERVICE_NAME
3
+ } from "./chunk-Y2URJ4EZ.js";
4
+
5
+ // src/actions/sendCast.ts
6
+ import {
7
+ logger,
8
+ createUniqueUuid
9
+ } from "@elizaos/core";
10
+ var sendCastAction = {
11
+ name: "SEND_CAST",
12
+ description: "Posts a cast (message) on Farcaster",
13
+ examples: [
14
+ [
15
+ {
16
+ name: "user",
17
+ content: { text: "Can you post about the new ElizaOS features on Farcaster?" }
18
+ },
19
+ {
20
+ name: "assistant",
21
+ content: {
22
+ text: "I'll post about the new ElizaOS features on Farcaster now.",
23
+ actions: ["SEND_CAST"]
24
+ }
25
+ }
26
+ ],
27
+ [
28
+ {
29
+ name: "user",
30
+ content: { text: "Share on Farcaster that we just launched version 2.0!" }
31
+ },
32
+ {
33
+ name: "assistant",
34
+ content: {
35
+ text: "I'll share the version 2.0 launch announcement on Farcaster.",
36
+ actions: ["SEND_CAST"]
37
+ }
38
+ }
39
+ ]
40
+ ],
41
+ validate: async (runtime, message) => {
42
+ var _a;
43
+ const text = ((_a = message.content.text) == null ? void 0 : _a.toLowerCase()) || "";
44
+ const keywords = ["post", "cast", "share", "announce", "farcaster", "tweet"];
45
+ const hasKeyword = keywords.some((keyword) => text.includes(keyword));
46
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
47
+ const isServiceAvailable = !!(service == null ? void 0 : service.getCastService(runtime.agentId));
48
+ return hasKeyword && isServiceAvailable;
49
+ },
50
+ handler: async (runtime, message, state) => {
51
+ var _a;
52
+ try {
53
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
54
+ const postService = service == null ? void 0 : service.getCastService(runtime.agentId);
55
+ if (!postService) {
56
+ logger.error("[SEND_CAST] PostService not available");
57
+ return false;
58
+ }
59
+ let castContent = "";
60
+ if (state == null ? void 0 : state.castContent) {
61
+ castContent = state.castContent;
62
+ } else {
63
+ const prompt = `Based on this request: "${message.content.text}", generate a concise Farcaster cast (max 320 characters). Be engaging and use appropriate hashtags if relevant.`;
64
+ const response = await runtime.useModel("text_large", { prompt });
65
+ castContent = typeof response === "string" ? response : response.text || "";
66
+ }
67
+ if (castContent.length > 320) {
68
+ castContent = castContent.substring(0, 317) + "...";
69
+ }
70
+ const cast = await postService.createCast({
71
+ agentId: runtime.agentId,
72
+ roomId: createUniqueUuid(runtime, "farcaster-timeline"),
73
+ text: castContent
74
+ });
75
+ logger.info(`[SEND_CAST] Successfully posted cast: ${cast.id}`);
76
+ await runtime.createMemory(
77
+ {
78
+ agentId: runtime.agentId,
79
+ roomId: cast.roomId,
80
+ // userId removed - not part of Memory type
81
+ entityId: runtime.agentId,
82
+ content: {
83
+ text: castContent,
84
+ source: "farcaster",
85
+ metadata: {
86
+ castHash: (_a = cast.metadata) == null ? void 0 : _a.castHash,
87
+ action: "SEND_CAST"
88
+ }
89
+ },
90
+ createdAt: cast.timestamp
91
+ },
92
+ "messages"
93
+ );
94
+ return true;
95
+ } catch (error) {
96
+ logger.error("[SEND_CAST] Error posting cast:", error);
97
+ throw error;
98
+ }
99
+ }
100
+ };
101
+
102
+ export {
103
+ sendCastAction
104
+ };
105
+ //# sourceMappingURL=chunk-OAXQ6Z2Q.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/actions/sendCast.ts"],"sourcesContent":["import {\n type Action,\n type IAgentRuntime,\n type Memory,\n type State,\n logger,\n createUniqueUuid,\n} from '@elizaos/core';\nimport { FARCASTER_SERVICE_NAME } from '../common/constants';\nimport type { FarcasterService } from '../service';\n\nexport const sendCastAction: Action = {\n name: 'SEND_CAST',\n description: 'Posts a cast (message) on Farcaster',\n examples: [\n [\n {\n name: 'user',\n content: { text: 'Can you post about the new ElizaOS features on Farcaster?' },\n },\n {\n name: 'assistant',\n content: {\n text: \"I'll post about the new ElizaOS features on Farcaster now.\",\n actions: ['SEND_CAST'],\n },\n },\n ],\n [\n {\n name: 'user',\n content: { text: 'Share on Farcaster that we just launched version 2.0!' },\n },\n {\n name: 'assistant',\n content: {\n text: \"I'll share the version 2.0 launch announcement on Farcaster.\",\n actions: ['SEND_CAST'],\n },\n },\n ],\n ],\n\n validate: async (runtime: IAgentRuntime, message: Memory): Promise<boolean> => {\n const text = message.content.text?.toLowerCase() || '';\n const keywords = ['post', 'cast', 'share', 'announce', 'farcaster', 'tweet'];\n\n // Check if the message contains relevant keywords\n const hasKeyword = keywords.some((keyword) => text.includes(keyword));\n\n // Check if Farcaster service is available\n const service = runtime.getService(FARCASTER_SERVICE_NAME) as FarcasterService;\n const isServiceAvailable = !!service?.getCastService(runtime.agentId);\n\n return hasKeyword && isServiceAvailable;\n },\n\n handler: async (runtime: IAgentRuntime, message: Memory, state?: State): Promise<boolean> => {\n try {\n const service = runtime.getService(FARCASTER_SERVICE_NAME) as FarcasterService;\n const postService = service?.getCastService(runtime.agentId);\n\n if (!postService) {\n logger.error('[SEND_CAST] PostService not available');\n return false;\n }\n\n // Extract the content to post from the message or generate it\n let castContent = '';\n\n if (state?.castContent) {\n // Use provided cast content from state\n castContent = state.castContent as string;\n } else {\n // Generate content based on the conversation context\n const prompt = `Based on this request: \"${message.content.text}\", generate a concise Farcaster cast (max 320 characters). Be engaging and use appropriate hashtags if relevant.`;\n\n const response = await runtime.useModel('text_large', { prompt });\n castContent = typeof response === 'string' ? response : response.text || '';\n }\n\n // Ensure content fits Farcaster's character limit\n if (castContent.length > 320) {\n castContent = castContent.substring(0, 317) + '...';\n }\n\n // Create the cast\n const cast = await postService.createCast({\n agentId: runtime.agentId,\n roomId: createUniqueUuid(runtime, 'farcaster-timeline'),\n text: castContent,\n });\n\n logger.info(`[SEND_CAST] Successfully posted cast: ${cast.id}`);\n\n // Store the cast in memory\n await runtime.createMemory(\n {\n agentId: runtime.agentId,\n roomId: cast.roomId,\n // userId removed - not part of Memory type\n entityId: runtime.agentId,\n content: {\n text: castContent,\n source: 'farcaster',\n metadata: {\n castHash: cast.metadata?.castHash,\n action: 'SEND_CAST',\n },\n },\n createdAt: cast.timestamp,\n },\n 'messages'\n );\n\n return true;\n } catch (error) {\n logger.error('[SEND_CAST] Error posting cast:', error);\n // Re-throw the error so it's visible in the agent's logs\n throw error;\n }\n },\n};\n"],"mappings":";;;;;AAAA;AAAA,EAKE;AAAA,EACA;AAAA,OACK;AAIA,IAAM,iBAAyB;AAAA,EACpC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,IACR;AAAA,MACE;AAAA,QACE,MAAM;AAAA,QACN,SAAS,EAAE,MAAM,4DAA4D;AAAA,MAC/E;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,UACP,MAAM;AAAA,UACN,SAAS,CAAC,WAAW;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,QACE,MAAM;AAAA,QACN,SAAS,EAAE,MAAM,wDAAwD;AAAA,MAC3E;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,UACP,MAAM;AAAA,UACN,SAAS,CAAC,WAAW;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,UAAU,OAAO,SAAwB,YAAsC;AA3CjF;AA4CI,UAAM,SAAO,aAAQ,QAAQ,SAAhB,mBAAsB,kBAAiB;AACpD,UAAM,WAAW,CAAC,QAAQ,QAAQ,SAAS,YAAY,aAAa,OAAO;AAG3E,UAAM,aAAa,SAAS,KAAK,CAAC,YAAY,KAAK,SAAS,OAAO,CAAC;AAGpE,UAAM,UAAU,QAAQ,WAAW,sBAAsB;AACnD,UAAM,qBAAqB,CAAC,EAAC,mCAAS,eAAe,QAAQ;AAEnE,WAAO,cAAc;AAAA,EACvB;AAAA,EAEA,SAAS,OAAO,SAAwB,SAAiB,UAAoC;AAzD/F;AA0DI,QAAI;AACF,YAAM,UAAU,QAAQ,WAAW,sBAAsB;AACzD,YAAM,cAAc,mCAAS,eAAe,QAAQ;AAEpD,UAAI,CAAC,aAAa;AAChB,eAAO,MAAM,uCAAuC;AACpD,eAAO;AAAA,MACT;AAGA,UAAI,cAAc;AAElB,UAAI,+BAAO,aAAa;AAEtB,sBAAc,MAAM;AAAA,MACtB,OAAO;AAEL,cAAM,SAAS,2BAA2B,QAAQ,QAAQ,IAAI;AAE9D,cAAM,WAAW,MAAM,QAAQ,SAAS,cAAc,EAAE,OAAO,CAAC;AAChE,sBAAc,OAAO,aAAa,WAAW,WAAW,SAAS,QAAQ;AAAA,MAC3E;AAGA,UAAI,YAAY,SAAS,KAAK;AAC5B,sBAAc,YAAY,UAAU,GAAG,GAAG,IAAI;AAAA,MAChD;AAGA,YAAM,OAAO,MAAM,YAAY,WAAW;AAAA,QACxC,SAAS,QAAQ;AAAA,QACjB,QAAQ,iBAAiB,SAAS,oBAAoB;AAAA,QACtD,MAAM;AAAA,MACR,CAAC;AAED,aAAO,KAAK,yCAAyC,KAAK,EAAE,EAAE;AAG9D,YAAM,QAAQ;AAAA,QACZ;AAAA,UACE,SAAS,QAAQ;AAAA,UACjB,QAAQ,KAAK;AAAA;AAAA,UAEb,UAAU,QAAQ;AAAA,UAClB,SAAS;AAAA,YACP,MAAM;AAAA,YACN,QAAQ;AAAA,YACR,UAAU;AAAA,cACR,WAAU,UAAK,aAAL,mBAAe;AAAA,cACzB,QAAQ;AAAA,YACV;AAAA,UACF;AAAA,UACA,WAAW,KAAK;AAAA,QAClB;AAAA,QACA;AAAA,MACF;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,aAAO,MAAM,mCAAmC,KAAK;AAErD,YAAM;AAAA,IACR;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,21 @@
1
+ // src/common/constants.ts
2
+ var FARCASTER_SERVICE_NAME = "farcaster";
3
+ var FARCASTER_SOURCE = "farcaster";
4
+ var DEFAULT_MAX_CAST_LENGTH = 320;
5
+ var DEFAULT_POLL_INTERVAL = 120;
6
+ var DEFAULT_CAST_INTERVAL_MIN = 90;
7
+ var DEFAULT_CAST_INTERVAL_MAX = 180;
8
+ var DEFAULT_CAST_CACHE_TTL = 1e3 * 30 * 60;
9
+ var DEFAULT_CAST_CACHE_SIZE = 9e3;
10
+
11
+ export {
12
+ FARCASTER_SERVICE_NAME,
13
+ FARCASTER_SOURCE,
14
+ DEFAULT_MAX_CAST_LENGTH,
15
+ DEFAULT_POLL_INTERVAL,
16
+ DEFAULT_CAST_INTERVAL_MIN,
17
+ DEFAULT_CAST_INTERVAL_MAX,
18
+ DEFAULT_CAST_CACHE_TTL,
19
+ DEFAULT_CAST_CACHE_SIZE
20
+ };
21
+ //# sourceMappingURL=chunk-Y2URJ4EZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/common/constants.ts"],"sourcesContent":["export const FARCASTER_SERVICE_NAME = 'farcaster';\nexport const FARCASTER_SOURCE = 'farcaster';\nexport const DEFAULT_MAX_CAST_LENGTH = 320;\nexport const DEFAULT_POLL_INTERVAL = 120; // 2 minutes\nexport const DEFAULT_CAST_INTERVAL_MIN = 90; // 1.5 hours\nexport const DEFAULT_CAST_INTERVAL_MAX = 180; // 3 hours\nexport const DEFAULT_CAST_CACHE_TTL = 1000 * 30 * 60; // 30 minutes\nexport const DEFAULT_CAST_CACHE_SIZE = 9000;\n"],"mappings":";AAAO,IAAM,yBAAyB;AAC/B,IAAM,mBAAmB;AACzB,IAAM,0BAA0B;AAChC,IAAM,wBAAwB;AAC9B,IAAM,4BAA4B;AAClC,IAAM,4BAA4B;AAClC,IAAM,yBAAyB,MAAO,KAAK;AAC3C,IAAM,0BAA0B;","names":[]}