@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/dist/index.js CHANGED
@@ -1,15 +1,25 @@
1
- // src/service.ts
2
- import { logger as logger6, Service } from "@elizaos/core";
1
+ import {
2
+ sendCastAction
3
+ } from "./chunk-OAXQ6Z2Q.js";
4
+ import {
5
+ farcasterProfileProvider
6
+ } from "./chunk-IOTLJXKN.js";
7
+ import {
8
+ farcasterTimelineProvider
9
+ } from "./chunk-FNDASAYG.js";
10
+ import {
11
+ DEFAULT_CAST_CACHE_SIZE,
12
+ DEFAULT_CAST_CACHE_TTL,
13
+ DEFAULT_CAST_INTERVAL_MAX,
14
+ DEFAULT_CAST_INTERVAL_MIN,
15
+ DEFAULT_MAX_CAST_LENGTH,
16
+ DEFAULT_POLL_INTERVAL,
17
+ FARCASTER_SERVICE_NAME,
18
+ FARCASTER_SOURCE
19
+ } from "./chunk-Y2URJ4EZ.js";
3
20
 
4
- // src/common/constants.ts
5
- var FARCASTER_SERVICE_NAME = "farcaster";
6
- var FARCASTER_SOURCE = "farcaster";
7
- var DEFAULT_MAX_CAST_LENGTH = 320;
8
- var DEFAULT_POLL_INTERVAL = 120;
9
- var DEFAULT_POST_INTERVAL_MIN = 90;
10
- var DEFAULT_POST_INTERVAL_MAX = 180;
11
- var DEFAULT_CAST_CACHE_TTL = 1e3 * 30 * 60;
12
- var DEFAULT_CAST_CACHE_SIZE = 9e3;
21
+ // src/service.ts
22
+ import { logger as logger8, Service } from "@elizaos/core";
13
23
 
14
24
  // src/managers/agent.ts
15
25
  import { logger as logger4 } from "@elizaos/core";
@@ -18,7 +28,7 @@ import { Configuration, NeynarAPIClient } from "@neynar/nodejs-sdk";
18
28
  // src/client.ts
19
29
  import { elizaLogger } from "@elizaos/core";
20
30
  import { isApiErrorResponse } from "@neynar/nodejs-sdk";
21
- import { CastParamType } from "@neynar/nodejs-sdk/build/api/models/cast-param-type";
31
+ import { CastParamType } from "@neynar/nodejs-sdk/build/api/index.js";
22
32
  import { LRUCache } from "lru-cache";
23
33
 
24
34
  // src/common/utils.ts
@@ -33,30 +43,30 @@ function castUuid(props) {
33
43
  function splitPostContent(content, maxLength = MAX_CAST_LENGTH) {
34
44
  const paragraphs = content.split("\n\n").map((p) => p.trim());
35
45
  const posts = [];
36
- let currentTweet = "";
46
+ let currentCast = "";
37
47
  for (const paragraph of paragraphs) {
38
48
  if (!paragraph) continue;
39
- if ((currentTweet + "\n\n" + paragraph).trim().length <= maxLength) {
40
- if (currentTweet) {
41
- currentTweet += "\n\n" + paragraph;
49
+ if ((currentCast + "\n\n" + paragraph).trim().length <= maxLength) {
50
+ if (currentCast) {
51
+ currentCast += "\n\n" + paragraph;
42
52
  } else {
43
- currentTweet = paragraph;
53
+ currentCast = paragraph;
44
54
  }
45
55
  } else {
46
- if (currentTweet) {
47
- posts.push(currentTweet.trim());
56
+ if (currentCast) {
57
+ posts.push(currentCast.trim());
48
58
  }
49
59
  if (paragraph.length <= maxLength) {
50
- currentTweet = paragraph;
60
+ currentCast = paragraph;
51
61
  } else {
52
62
  const chunks = splitParagraph(paragraph, maxLength);
53
63
  posts.push(...chunks.slice(0, -1));
54
- currentTweet = chunks[chunks.length - 1];
64
+ currentCast = chunks[chunks.length - 1];
55
65
  }
56
66
  }
57
67
  }
58
- if (currentTweet) {
59
- posts.push(currentTweet.trim());
68
+ if (currentCast) {
69
+ posts.push(currentCast.trim());
60
70
  }
61
71
  return posts;
62
72
  }
@@ -106,6 +116,7 @@ function lastCastCacheKey(fid) {
106
116
  return `farcaster/${fid}/lastCast`;
107
117
  }
108
118
  function neynarCastToCast(neynarCast) {
119
+ var _a;
109
120
  return {
110
121
  hash: neynarCast.hash,
111
122
  authorFid: neynarCast.author.fid,
@@ -116,7 +127,7 @@ function neynarCastToCast(neynarCast) {
116
127
  name: neynarCast.author.display_name || "anon",
117
128
  username: neynarCast.author.username
118
129
  },
119
- ...neynarCast.parent_hash ? {
130
+ ...neynarCast.parent_hash && ((_a = neynarCast.parent_author) == null ? void 0 : _a.fid) ? {
120
131
  inReplyTo: {
121
132
  hash: neynarCast.parent_hash,
122
133
  fid: neynarCast.parent_author.fid
@@ -436,14 +447,14 @@ var FarcasterConfigSchema = z.object({
436
447
  FARCASTER_FID: z.number().int().min(1, "Farcaster fid is required"),
437
448
  MAX_CAST_LENGTH: z.number().int().default(DEFAULT_MAX_CAST_LENGTH),
438
449
  FARCASTER_POLL_INTERVAL: z.number().int().default(DEFAULT_POLL_INTERVAL),
439
- ENABLE_POST: z.union([z.boolean(), z.string()]).transform((val) => typeof val === "string" ? val.toLowerCase() === "true" : val),
440
- POST_INTERVAL_MIN: z.number().int(),
441
- POST_INTERVAL_MAX: z.number().int(),
450
+ ENABLE_CAST: z.union([z.boolean(), z.string()]).transform((val) => typeof val === "string" ? val.toLowerCase() === "true" : val),
451
+ CAST_INTERVAL_MIN: z.number().int(),
452
+ CAST_INTERVAL_MAX: z.number().int(),
442
453
  ENABLE_ACTION_PROCESSING: z.union([z.boolean(), z.string()]).transform((val) => typeof val === "string" ? val.toLowerCase() === "true" : val),
443
454
  ACTION_INTERVAL: z.number().int(),
444
- POST_IMMEDIATELY: z.union([z.boolean(), z.string()]).transform((val) => typeof val === "string" ? val.toLowerCase() === "true" : val),
455
+ CAST_IMMEDIATELY: z.union([z.boolean(), z.string()]).transform((val) => typeof val === "string" ? val.toLowerCase() === "true" : val),
445
456
  MAX_ACTIONS_PROCESSING: z.number().int(),
446
- FARCASTER_NEYNAR_SIGNER_UUID: z.string().min(1, "FARCASTER_NEYNAR_SIGNER_UUID is not set"),
457
+ FARCASTER_SIGNER_UUID: z.string().min(1, "FARCASTER_SIGNER_UUID is not set"),
447
458
  FARCASTER_NEYNAR_API_KEY: z.string().min(1, "FARCASTER_NEYNAR_API_KEY is not set"),
448
459
  FARCASTER_HUB_URL: z.string().min(1, "FARCASTER_HUB_URL is not set")
449
460
  });
@@ -676,7 +687,7 @@ var FarcasterInteractionManager = class {
676
687
 
677
688
  // src/managers/post.ts
678
689
  import { createUniqueUuid as createUniqueUuid2, EventType as EventType2, logger as logger3 } from "@elizaos/core";
679
- var FarcasterPostManager = class {
690
+ var FarcasterCastManager = class {
680
691
  client;
681
692
  runtime;
682
693
  fid;
@@ -690,7 +701,7 @@ var FarcasterPostManager = class {
690
701
  this.fid = this.config.FARCASTER_FID;
691
702
  }
692
703
  async start() {
693
- if (this.isRunning || !this.config.ENABLE_POST) {
704
+ if (this.isRunning || !this.config.ENABLE_CAST) {
694
705
  return;
695
706
  }
696
707
  this.isRunning = true;
@@ -701,14 +712,14 @@ var FarcasterPostManager = class {
701
712
  this.isRunning = false;
702
713
  }
703
714
  calculateDelay() {
704
- const minMinutes = this.config.POST_INTERVAL_MIN;
705
- const maxMinutes = this.config.POST_INTERVAL_MAX;
715
+ const minMinutes = this.config.CAST_INTERVAL_MIN;
716
+ const maxMinutes = this.config.CAST_INTERVAL_MAX;
706
717
  const randomMinutes = Math.floor(Math.random() * (maxMinutes - minMinutes + 1)) + minMinutes;
707
718
  const delay = randomMinutes * 60 * 1e3;
708
719
  return { delay, randomMinutes };
709
720
  }
710
721
  async runPeriodically() {
711
- if (this.config.POST_IMMEDIATELY) {
722
+ if (this.config.CAST_IMMEDIATELY) {
712
723
  await this.generateNewCast();
713
724
  }
714
725
  while (this.isRunning) {
@@ -722,7 +733,7 @@ var FarcasterPostManager = class {
722
733
  logger3.log(`Next cast scheduled in ${randomMinutes} minutes`);
723
734
  await new Promise((resolve) => this.timeout = setTimeout(resolve, delay));
724
735
  } catch (error) {
725
- logger3.error("[Farcaster] Error in periodic post:", this.runtime.agentId, error);
736
+ logger3.error("[Farcaster] Error in periodic cast loop:", this.runtime.agentId, error);
726
737
  }
727
738
  }
728
739
  }
@@ -744,7 +755,7 @@ var FarcasterPostManager = class {
744
755
  });
745
756
  }
746
757
  });
747
- this.runtime.emitEvent([EventType2.POST_GENERATED, "FARCASTER_POST_GENERATED" /* POST_GENERATED */], {
758
+ this.runtime.emitEvent([EventType2.POST_GENERATED, "FARCASTER_CAST_GENERATED" /* CAST_GENERATED */], {
748
759
  runtime: this.runtime,
749
760
  callback,
750
761
  worldId,
@@ -762,24 +773,24 @@ var FarcasterPostManager = class {
762
773
  var FarcasterAgentManager = class {
763
774
  runtime;
764
775
  client;
765
- posts;
776
+ casts;
766
777
  interactions;
767
778
  constructor(runtime, config) {
768
779
  this.runtime = runtime;
769
- const signerUuid = config.FARCASTER_NEYNAR_SIGNER_UUID;
780
+ const signerUuid = config.FARCASTER_SIGNER_UUID;
770
781
  const neynarConfig = new Configuration({ apiKey: config.FARCASTER_NEYNAR_API_KEY });
771
782
  const neynar = new NeynarAPIClient(neynarConfig);
772
783
  const client = new FarcasterClient({ neynar, signerUuid });
773
784
  this.client = client;
774
785
  logger4.success("Farcaster Neynar client initialized.");
775
- this.posts = new FarcasterPostManager({ client, runtime, config });
786
+ this.casts = new FarcasterCastManager({ client, runtime, config });
776
787
  this.interactions = new FarcasterInteractionManager({ client, runtime, config });
777
788
  }
778
789
  async start() {
779
- await Promise.all([this.posts.start(), this.interactions.start()]);
790
+ await Promise.all([this.casts.start(), this.interactions.start()]);
780
791
  }
781
792
  async stop() {
782
- await Promise.all([this.posts.stop(), this.interactions.stop()]);
793
+ await Promise.all([this.casts.stop(), this.interactions.stop()]);
783
794
  }
784
795
  };
785
796
 
@@ -793,7 +804,7 @@ function safeParseInt(value, defaultValue) {
793
804
  }
794
805
  function hasFarcasterEnabled(runtime) {
795
806
  const fid = runtime.getSetting("FARCASTER_FID") || process.env.FARCASTER_FID;
796
- const neynarSignerUuid = runtime.getSetting("FARCASTER_NEYNAR_SIGNER_UUID") || process.env.FARCASTER_NEYNAR_SIGNER_UUID;
807
+ const neynarSignerUuid = runtime.getSetting("FARCASTER_SIGNER_UUID") || process.env.FARCASTER_SIGNER_UUID;
797
808
  const neynarApiKey = runtime.getSetting("FARCASTER_NEYNAR_API_KEY") || process.env.FARCASTER_NEYNAR_API_KEY;
798
809
  return fid && neynarSignerUuid && neynarApiKey;
799
810
  }
@@ -811,14 +822,14 @@ function validateFarcasterConfig(runtime) {
811
822
  runtime.getSetting("FARCASTER_POLL_INTERVAL") || process.env.FARCASTER_POLL_INTERVAL,
812
823
  DEFAULT_POLL_INTERVAL
813
824
  ),
814
- ENABLE_POST: runtime.getSetting("ENABLE_POST") || parseBooleanFromText(process.env.ENABLE_POST || "true"),
815
- POST_INTERVAL_MIN: safeParseInt(
816
- runtime.getSetting("POST_INTERVAL_MIN") || process.env.POST_INTERVAL_MIN,
817
- DEFAULT_POST_INTERVAL_MIN
825
+ ENABLE_CAST: runtime.getSetting("ENABLE_CAST") || parseBooleanFromText(process.env.ENABLE_CAST || "true"),
826
+ CAST_INTERVAL_MIN: safeParseInt(
827
+ runtime.getSetting("CAST_INTERVAL_MIN") || process.env.CAST_INTERVAL_MIN,
828
+ DEFAULT_CAST_INTERVAL_MIN
818
829
  ),
819
- POST_INTERVAL_MAX: safeParseInt(
820
- runtime.getSetting("POST_INTERVAL_MAX") || process.env.POST_INTERVAL_MAX,
821
- DEFAULT_POST_INTERVAL_MAX
830
+ CAST_INTERVAL_MAX: safeParseInt(
831
+ runtime.getSetting("CAST_INTERVAL_MAX") || process.env.CAST_INTERVAL_MAX,
832
+ DEFAULT_CAST_INTERVAL_MAX
822
833
  ),
823
834
  ENABLE_ACTION_PROCESSING: runtime.getSetting("ENABLE_ACTION_PROCESSING") || parseBooleanFromText(process.env.ENABLE_ACTION_PROCESSING || "false"),
824
835
  ACTION_INTERVAL: safeParseInt(
@@ -826,12 +837,12 @@ function validateFarcasterConfig(runtime) {
826
837
  5
827
838
  ),
828
839
  // 5 minutes
829
- POST_IMMEDIATELY: runtime.getSetting("POST_IMMEDIATELY") || parseBooleanFromText(process.env.POST_IMMEDIATELY || "false"),
840
+ CAST_IMMEDIATELY: runtime.getSetting("CAST_IMMEDIATELY") || parseBooleanFromText(process.env.CAST_IMMEDIATELY || "false"),
830
841
  MAX_ACTIONS_PROCESSING: safeParseInt(
831
842
  runtime.getSetting("MAX_ACTIONS_PROCESSING") || process.env.MAX_ACTIONS_PROCESSING,
832
843
  1
833
844
  ),
834
- FARCASTER_NEYNAR_SIGNER_UUID: runtime.getSetting("FARCASTER_NEYNAR_SIGNER_UUID") || process.env.FARCASTER_NEYNAR_SIGNER_UUID,
845
+ FARCASTER_SIGNER_UUID: runtime.getSetting("FARCASTER_SIGNER_UUID") || process.env.FARCASTER_SIGNER_UUID,
835
846
  FARCASTER_NEYNAR_API_KEY: runtime.getSetting("FARCASTER_NEYNAR_API_KEY") || process.env.FARCASTER_NEYNAR_API_KEY,
836
847
  FARCASTER_HUB_URL: runtime.getSetting("FARCASTER_HUB_URL") || process.env.FARCASTER_HUB_URL || "hub.pinata.cloud"
837
848
  };
@@ -840,12 +851,12 @@ function validateFarcasterConfig(runtime) {
840
851
  logger5.log("Farcaster Client Configuration:");
841
852
  logger5.log(`- FID: ${config.FARCASTER_FID}`);
842
853
  logger5.log(`- Dry Run Mode: ${isDryRun ? "enabled" : "disabled"}`);
843
- logger5.log(`- Enable Post: ${config.ENABLE_POST ? "enabled" : "disabled"}`);
844
- if (config.ENABLE_POST) {
854
+ logger5.log(`- Enable Cast: ${config.ENABLE_CAST ? "enabled" : "disabled"}`);
855
+ if (config.ENABLE_CAST) {
845
856
  logger5.log(
846
- `- Post Interval: ${config.POST_INTERVAL_MIN}-${config.POST_INTERVAL_MAX} minutes`
857
+ `- Cast Interval: ${config.CAST_INTERVAL_MIN}-${config.CAST_INTERVAL_MAX} minutes`
847
858
  );
848
- logger5.log(`- Post Immediately: ${config.POST_IMMEDIATELY ? "enabled" : "disabled"}`);
859
+ logger5.log(`- Cast Immediately: ${config.CAST_IMMEDIATELY ? "enabled" : "disabled"}`);
849
860
  }
850
861
  logger5.log(`- Action Processing: ${config.ENABLE_ACTION_PROCESSING ? "enabled" : "disabled"}`);
851
862
  logger5.log(`- Action Interval: ${config.ACTION_INTERVAL} minutes`);
@@ -863,11 +874,389 @@ ${errorMessages}`);
863
874
  }
864
875
  }
865
876
 
877
+ // src/services/MessageService.ts
878
+ import {
879
+ logger as logger6,
880
+ createUniqueUuid as createUniqueUuid3
881
+ } from "@elizaos/core";
882
+ var FarcasterMessageService = class {
883
+ constructor(client, runtime) {
884
+ this.client = client;
885
+ this.runtime = runtime;
886
+ }
887
+ async getMessages(options) {
888
+ try {
889
+ const { roomId, limit = 20 } = options;
890
+ const { timeline } = await this.client.getTimeline({
891
+ fid: parseInt(
892
+ this.runtime.getSetting("FARCASTER_FID") || this.runtime.config.FARCASTER_FID
893
+ ),
894
+ pageSize: limit
895
+ });
896
+ const messages = timeline.filter((cast) => {
897
+ if (roomId) {
898
+ const castRoomId = createUniqueUuid3(this.runtime, cast.threadId || cast.hash);
899
+ return castRoomId === roomId;
900
+ }
901
+ return true;
902
+ }).map((cast) => ({
903
+ id: castUuid({ hash: cast.hash, agentId: this.runtime.agentId }),
904
+ agentId: this.runtime.agentId,
905
+ roomId: createUniqueUuid3(this.runtime, cast.threadId || cast.hash),
906
+ userId: cast.profile.fid.toString(),
907
+ username: cast.profile.username,
908
+ text: cast.text,
909
+ type: cast.inReplyTo ? "REPLY" /* REPLY */ : "CAST" /* CAST */,
910
+ timestamp: cast.timestamp.getTime(),
911
+ inReplyTo: cast.inReplyTo ? castUuid({ hash: cast.inReplyTo.hash, agentId: this.runtime.agentId }) : void 0,
912
+ metadata: {
913
+ castHash: cast.hash,
914
+ threadId: cast.threadId,
915
+ authorFid: cast.authorFid
916
+ }
917
+ }));
918
+ return messages;
919
+ } catch (error) {
920
+ logger6.error("[Farcaster] Error fetching messages:", error);
921
+ return [];
922
+ }
923
+ }
924
+ async sendMessage(options) {
925
+ var _a;
926
+ try {
927
+ const { text, type, roomId, replyToId, agentId } = options;
928
+ let inReplyTo = void 0;
929
+ if (replyToId && type === "REPLY" /* REPLY */) {
930
+ const parentHash = ((_a = options.metadata) == null ? void 0 : _a.parentHash) || replyToId;
931
+ inReplyTo = {
932
+ hash: parentHash,
933
+ fid: parseInt(
934
+ this.runtime.getSetting("FARCASTER_FID") || this.runtime.config.FARCASTER_FID
935
+ )
936
+ };
937
+ }
938
+ const casts = await this.client.sendCast({
939
+ content: { text },
940
+ inReplyTo
941
+ });
942
+ if (casts.length === 0) {
943
+ throw new Error("No cast was created");
944
+ }
945
+ const cast = neynarCastToCast(casts[0]);
946
+ const message = {
947
+ id: castUuid({ hash: cast.hash, agentId }),
948
+ agentId,
949
+ roomId,
950
+ userId: cast.profile.fid.toString(),
951
+ username: cast.profile.username,
952
+ text: cast.text,
953
+ type,
954
+ timestamp: cast.timestamp.getTime(),
955
+ inReplyTo: inReplyTo ? castUuid({ hash: inReplyTo.hash, agentId }) : void 0,
956
+ metadata: {
957
+ ...options.metadata,
958
+ castHash: cast.hash,
959
+ threadId: cast.threadId,
960
+ authorFid: cast.authorFid
961
+ }
962
+ };
963
+ await this.runtime.emitEvent("FARCASTER_CAST_GENERATED" /* CAST_GENERATED */, {
964
+ runtime: this.runtime,
965
+ castHash: cast.hash,
966
+ message,
967
+ threadId: cast.threadId
968
+ });
969
+ return message;
970
+ } catch (error) {
971
+ logger6.error("[Farcaster] Error sending message:", error);
972
+ throw error;
973
+ }
974
+ }
975
+ async deleteMessage(messageId, agentId) {
976
+ logger6.warn("[Farcaster] Cast deletion is not supported by the Farcaster API");
977
+ }
978
+ async getMessage(messageId, agentId) {
979
+ try {
980
+ const castHash = messageId;
981
+ const cast = await this.client.getCast(castHash);
982
+ const farcasterCast = neynarCastToCast(cast);
983
+ const message = {
984
+ id: castUuid({ hash: farcasterCast.hash, agentId }),
985
+ agentId,
986
+ roomId: createUniqueUuid3(this.runtime, farcasterCast.threadId || farcasterCast.hash),
987
+ userId: farcasterCast.profile.fid.toString(),
988
+ username: farcasterCast.profile.username,
989
+ text: farcasterCast.text,
990
+ type: farcasterCast.inReplyTo ? "REPLY" /* REPLY */ : "CAST" /* CAST */,
991
+ timestamp: farcasterCast.timestamp.getTime(),
992
+ inReplyTo: farcasterCast.inReplyTo ? castUuid({ hash: farcasterCast.inReplyTo.hash, agentId }) : void 0,
993
+ metadata: {
994
+ castHash: farcasterCast.hash,
995
+ threadId: farcasterCast.threadId,
996
+ authorFid: farcasterCast.authorFid
997
+ }
998
+ };
999
+ return message;
1000
+ } catch (error) {
1001
+ logger6.error("[Farcaster] Error fetching message:", error);
1002
+ return null;
1003
+ }
1004
+ }
1005
+ async markAsRead(messageIds, agentId) {
1006
+ logger6.debug("[Farcaster] Mark as read is not applicable for Farcaster casts");
1007
+ }
1008
+ };
1009
+
1010
+ // src/services/CastService.ts
1011
+ import {
1012
+ logger as logger7,
1013
+ ModelType as ModelType2,
1014
+ createUniqueUuid as createUniqueUuid4
1015
+ } from "@elizaos/core";
1016
+ var FarcasterCastService = class {
1017
+ constructor(client, runtime) {
1018
+ this.client = client;
1019
+ this.runtime = runtime;
1020
+ }
1021
+ static serviceType = "ICastService";
1022
+ /**
1023
+ * Get recent casts from the timeline
1024
+ */
1025
+ async getCasts(params) {
1026
+ var _a, _b;
1027
+ try {
1028
+ const { timeline } = await this.client.getTimeline({
1029
+ fid: ((_a = this.runtime.config) == null ? void 0 : _a.FARCASTER_FID) || ((_b = this.runtime.settings) == null ? void 0 : _b.FARCASTER_FID),
1030
+ pageSize: params.limit || 50
1031
+ });
1032
+ return timeline.map((cast) => this.castToFarcasterCast(cast, params.agentId));
1033
+ } catch (error) {
1034
+ logger7.error("Failed to get casts", { params, error });
1035
+ return [];
1036
+ }
1037
+ }
1038
+ /**
1039
+ * Create a new cast
1040
+ */
1041
+ async createCast(params) {
1042
+ var _a;
1043
+ try {
1044
+ let castText = params.text;
1045
+ if (!castText || castText.trim() === "") {
1046
+ castText = await this.generateCastContent();
1047
+ }
1048
+ if (castText.length > 320) {
1049
+ castText = await this.truncateCast(castText);
1050
+ }
1051
+ const casts = await this.client.sendCast({
1052
+ content: { text: castText },
1053
+ inReplyTo: params.replyTo ? { hash: params.replyTo.hash, fid: params.replyTo.fid } : void 0
1054
+ });
1055
+ if (casts.length === 0) {
1056
+ throw new Error("No cast was created");
1057
+ }
1058
+ const cast = neynarCastToCast(casts[0]);
1059
+ const farcasterCast = {
1060
+ id: castUuid({ hash: cast.hash, agentId: params.agentId }),
1061
+ agentId: params.agentId,
1062
+ roomId: params.roomId,
1063
+ userId: cast.profile.fid.toString(),
1064
+ username: cast.profile.username,
1065
+ text: cast.text,
1066
+ timestamp: cast.timestamp.getTime(),
1067
+ inReplyTo: (_a = params.replyTo) == null ? void 0 : _a.hash,
1068
+ media: [],
1069
+ // TODO: Handle media upload when Farcaster API supports it
1070
+ metadata: {
1071
+ castHash: cast.hash,
1072
+ threadId: cast.threadId,
1073
+ authorFid: cast.authorFid,
1074
+ source: FARCASTER_SOURCE
1075
+ }
1076
+ };
1077
+ await this.storeCastInMemory(params.roomId, farcasterCast);
1078
+ return farcasterCast;
1079
+ } catch (error) {
1080
+ logger7.error("Failed to create cast", { params, error });
1081
+ throw error;
1082
+ }
1083
+ }
1084
+ /**
1085
+ * Delete a cast
1086
+ */
1087
+ async deleteCast(params) {
1088
+ try {
1089
+ logger7.warn("Cast deletion is not supported by the Farcaster API", { castHash: params.castHash });
1090
+ } catch (error) {
1091
+ logger7.error("Failed to delete cast", { params, error });
1092
+ throw error;
1093
+ }
1094
+ }
1095
+ /**
1096
+ * Like a cast
1097
+ */
1098
+ async likeCast(params) {
1099
+ try {
1100
+ logger7.info("Like functionality not yet implemented for cast", { castHash: params.castHash });
1101
+ } catch (error) {
1102
+ logger7.error("Failed to like cast", { params, error });
1103
+ throw error;
1104
+ }
1105
+ }
1106
+ /**
1107
+ * Unlike a cast
1108
+ */
1109
+ async unlikeCast(params) {
1110
+ try {
1111
+ logger7.info("Unlike functionality not yet implemented for cast", { castHash: params.castHash });
1112
+ } catch (error) {
1113
+ logger7.error("Failed to unlike cast", { params, error });
1114
+ throw error;
1115
+ }
1116
+ }
1117
+ /**
1118
+ * Recast a cast
1119
+ */
1120
+ async recast(params) {
1121
+ try {
1122
+ logger7.info("Recast functionality not yet implemented for cast", { castHash: params.castHash });
1123
+ } catch (error) {
1124
+ logger7.error("Failed to recast", { params, error });
1125
+ throw error;
1126
+ }
1127
+ }
1128
+ /**
1129
+ * Remove a recast
1130
+ */
1131
+ async unrecast(params) {
1132
+ try {
1133
+ logger7.info("Remove recast functionality not yet implemented for cast", { castHash: params.castHash });
1134
+ } catch (error) {
1135
+ logger7.error("Failed to remove recast", { params, error });
1136
+ throw error;
1137
+ }
1138
+ }
1139
+ /**
1140
+ * Get mentions
1141
+ */
1142
+ async getMentions(params) {
1143
+ var _a, _b;
1144
+ try {
1145
+ const mentions = await this.client.getMentions({
1146
+ fid: ((_a = this.runtime.config) == null ? void 0 : _a.FARCASTER_FID) || ((_b = this.runtime.settings) == null ? void 0 : _b.FARCASTER_FID),
1147
+ pageSize: params.limit || 20
1148
+ });
1149
+ return mentions.map((castWithInteractions) => {
1150
+ const cast = neynarCastToCast(castWithInteractions);
1151
+ return this.castToFarcasterCast(cast, params.agentId);
1152
+ });
1153
+ } catch (error) {
1154
+ logger7.error("Failed to get mentions", { params, error });
1155
+ return [];
1156
+ }
1157
+ }
1158
+ /**
1159
+ * Generate cast content using AI
1160
+ */
1161
+ async generateCastContent() {
1162
+ const prompt = `Generate an interesting and engaging Farcaster cast. It should be conversational, authentic, and under 320 characters. Topics can include technology, AI, crypto, decentralized social media, or general observations about life.`;
1163
+ try {
1164
+ const response = await this.runtime.useModel(ModelType2.TEXT_SMALL, {
1165
+ prompt,
1166
+ maxTokens: 100
1167
+ });
1168
+ return response;
1169
+ } catch (error) {
1170
+ logger7.error("Failed to generate cast content", { error });
1171
+ return "Hello Farcaster! \u{1F44B}";
1172
+ }
1173
+ }
1174
+ /**
1175
+ * Truncate cast to fit character limit
1176
+ */
1177
+ async truncateCast(text) {
1178
+ const prompt = `Shorten this text to under 320 characters while keeping the main message intact: "${text}"`;
1179
+ try {
1180
+ const response = await this.runtime.useModel(ModelType2.TEXT_SMALL, {
1181
+ prompt,
1182
+ maxTokens: 100
1183
+ });
1184
+ const truncated = response;
1185
+ if (truncated.length > 320) {
1186
+ return truncated.substring(0, 317) + "...";
1187
+ }
1188
+ return truncated;
1189
+ } catch (error) {
1190
+ logger7.error("Failed to truncate cast", { error });
1191
+ return text.substring(0, 317) + "...";
1192
+ }
1193
+ }
1194
+ /**
1195
+ * Store cast in agent memory
1196
+ */
1197
+ async storeCastInMemory(roomId, cast) {
1198
+ var _a;
1199
+ try {
1200
+ const memory = {
1201
+ id: createUniqueUuid4(this.runtime, cast.id),
1202
+ agentId: this.runtime.agentId,
1203
+ content: {
1204
+ text: cast.text,
1205
+ castHash: (_a = cast.metadata) == null ? void 0 : _a.castHash,
1206
+ castId: cast.id,
1207
+ author: cast.username,
1208
+ timestamp: cast.timestamp
1209
+ },
1210
+ roomId,
1211
+ userId: cast.userId,
1212
+ createdAt: Date.now()
1213
+ };
1214
+ if (typeof this.runtime.storeMemory === "function") {
1215
+ await this.runtime.storeMemory(memory);
1216
+ } else if (this.runtime.memory && typeof this.runtime.memory.create === "function") {
1217
+ await this.runtime.memory.create(memory);
1218
+ } else {
1219
+ logger7.warn("Memory storage method not available in runtime");
1220
+ }
1221
+ } catch (error) {
1222
+ logger7.error("Failed to store cast in memory", { error });
1223
+ }
1224
+ }
1225
+ /**
1226
+ * Convert internal Cast type to FarcasterCast
1227
+ */
1228
+ castToFarcasterCast(cast, agentId) {
1229
+ return {
1230
+ id: castUuid({ hash: cast.hash, agentId }),
1231
+ agentId,
1232
+ roomId: createUniqueUuid4(this.runtime, cast.threadId || cast.hash),
1233
+ userId: cast.profile.fid.toString(),
1234
+ username: cast.profile.username,
1235
+ text: cast.text,
1236
+ timestamp: cast.timestamp.getTime(),
1237
+ media: [],
1238
+ // Farcaster casts can have embedded media but not in our Cast type
1239
+ metadata: {
1240
+ castHash: cast.hash,
1241
+ threadId: cast.threadId,
1242
+ authorFid: cast.authorFid,
1243
+ source: FARCASTER_SOURCE,
1244
+ stats: cast.stats
1245
+ }
1246
+ };
1247
+ }
1248
+ };
1249
+
866
1250
  // src/service.ts
867
1251
  var FarcasterService = class _FarcasterService extends Service {
868
1252
  static instance;
869
1253
  managers = /* @__PURE__ */ new Map();
1254
+ messageServices = /* @__PURE__ */ new Map();
1255
+ castServices = /* @__PURE__ */ new Map();
1256
+ // Properly implement serviceType for discoverability
870
1257
  static serviceType = FARCASTER_SERVICE_NAME;
1258
+ // Add service description
1259
+ description = "Farcaster integration service for sending and receiving casts";
871
1260
  capabilityDescription = "The agent is able to send and receive messages on farcaster";
872
1261
  static getInstance() {
873
1262
  if (!_FarcasterService.instance) {
@@ -875,23 +1264,31 @@ var FarcasterService = class _FarcasterService extends Service {
875
1264
  }
876
1265
  return _FarcasterService.instance;
877
1266
  }
1267
+ // Required by ElizaOS Service base class
1268
+ async initialize(runtime) {
1269
+ await _FarcasterService.start(runtime);
1270
+ }
878
1271
  // Called to start a single Farcaster service
879
1272
  static async start(runtime) {
880
1273
  const service = _FarcasterService.getInstance();
881
1274
  let manager = service.managers.get(runtime.agentId);
882
1275
  if (manager) {
883
- logger6.warn("Farcaster service already started", runtime.agentId);
1276
+ logger8.warn("Farcaster service already started", runtime.agentId);
884
1277
  return service;
885
1278
  }
886
1279
  if (!hasFarcasterEnabled(runtime)) {
887
- logger6.debug("Farcaster service not enabled", runtime.agentId);
1280
+ logger8.debug("Farcaster service not enabled", runtime.agentId);
888
1281
  return service;
889
1282
  }
890
1283
  const farcasterConfig = validateFarcasterConfig(runtime);
891
1284
  manager = new FarcasterAgentManager(runtime, farcasterConfig);
892
1285
  service.managers.set(runtime.agentId, manager);
1286
+ const messageService = new FarcasterMessageService(manager.client, runtime);
1287
+ const castService = new FarcasterCastService(manager.client, runtime);
1288
+ service.messageServices.set(runtime.agentId, messageService);
1289
+ service.castServices.set(runtime.agentId, castService);
893
1290
  await manager.start();
894
- logger6.success("Farcaster client started", runtime.agentId);
1291
+ logger8.success("Farcaster client started", runtime.agentId);
895
1292
  return service;
896
1293
  }
897
1294
  // Called to stop a single Farcaster service
@@ -901,33 +1298,84 @@ var FarcasterService = class _FarcasterService extends Service {
901
1298
  if (manager) {
902
1299
  await manager.stop();
903
1300
  service.managers.delete(runtime.agentId);
904
- logger6.info("Farcaster client stopped", runtime.agentId);
1301
+ service.messageServices.delete(runtime.agentId);
1302
+ service.castServices.delete(runtime.agentId);
1303
+ logger8.info("Farcaster client stopped", runtime.agentId);
905
1304
  } else {
906
- logger6.debug("Farcaster service not running", runtime.agentId);
1305
+ logger8.debug("Farcaster service not running", runtime.agentId);
907
1306
  }
908
1307
  }
909
1308
  // Called to stop all Farcaster services
910
1309
  async stop() {
911
- logger6.debug("Stopping ALL Farcaster services");
1310
+ logger8.debug("Stopping ALL Farcaster services");
912
1311
  for (const manager of Array.from(this.managers.values())) {
913
1312
  const agentId = manager.runtime.agentId;
914
1313
  try {
915
1314
  await _FarcasterService.stop(manager.runtime);
916
1315
  } catch (error) {
917
- logger6.error("Error stopping Farcaster service", agentId, error);
1316
+ logger8.error("Error stopping Farcaster service", agentId, error);
918
1317
  }
919
1318
  }
920
1319
  }
1320
+ // Get the MessageService for a specific agent
1321
+ getMessageService(agentId) {
1322
+ return this.messageServices.get(agentId);
1323
+ }
1324
+ /**
1325
+ * Get the PostService for a specific agent (for compatibility)
1326
+ * @deprecated Use getCastService() instead. Will be removed in a future major release.
1327
+ */
1328
+ getPostService(agentId) {
1329
+ return this.castServices.get(agentId);
1330
+ }
1331
+ // Get the CastService for a specific agent
1332
+ getCastService(agentId) {
1333
+ return this.castServices.get(agentId);
1334
+ }
1335
+ // Add health check method
1336
+ async healthCheck() {
1337
+ const managerStatuses = {};
1338
+ let overallHealthy = true;
1339
+ for (const [agentId, manager] of Array.from(this.managers.entries())) {
1340
+ try {
1341
+ const profile = await manager.client.getProfile(
1342
+ parseInt(manager.runtime.getSetting("FARCASTER_FID"))
1343
+ );
1344
+ managerStatuses[agentId] = {
1345
+ status: "healthy",
1346
+ fid: profile.fid,
1347
+ username: profile.username
1348
+ };
1349
+ } catch (error) {
1350
+ managerStatuses[agentId] = {
1351
+ status: "unhealthy",
1352
+ error: error instanceof Error ? error.message : "Unknown error"
1353
+ };
1354
+ overallHealthy = false;
1355
+ }
1356
+ }
1357
+ return {
1358
+ healthy: overallHealthy,
1359
+ details: {
1360
+ activeManagers: this.managers.size,
1361
+ managerStatuses
1362
+ }
1363
+ };
1364
+ }
1365
+ // Get all active managers (for monitoring)
1366
+ getActiveManagers() {
1367
+ return new Map(this.managers);
1368
+ }
921
1369
  };
922
1370
 
923
- // __tests__/suite.ts
1371
+ // src/__tests__/suite.ts
924
1372
  import {
925
- ModelType as ModelType2,
926
- createUniqueUuid as createUniqueUuid3,
927
- logger as logger7
1373
+ ModelType as ModelType3,
1374
+ createUniqueUuid as createUniqueUuid6,
1375
+ logger as logger10
928
1376
  } from "@elizaos/core";
929
1377
 
930
- // __tests__/test-utils.ts
1378
+ // src/__tests__/test-utils.ts
931
1379
  var TEST_IMAGE_URL = "https://github.com/elizaOS/awesome-eliza/blob/main/assets/eliza-logo.jpg?raw=true";
932
1380
  var TEST_IMAGE = {
933
1381
  id: "mock-image-id",
@@ -940,9 +1388,276 @@ var TEST_IMAGE = {
940
1388
  alt_text: "mock image"
941
1389
  };
942
1390
 
943
- // __tests__/suite.ts
1391
+ // src/__tests__/e2e/scenarios.ts
1392
+ import { logger as logger9, createUniqueUuid as createUniqueUuid5 } from "@elizaos/core";
1393
+ var farcasterE2EScenarios = [
1394
+ {
1395
+ name: "Farcaster Plugin - Agent Introduction",
1396
+ async fn(runtime) {
1397
+ var _a;
1398
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
1399
+ if (!service) {
1400
+ throw new Error("Farcaster service not initialized");
1401
+ }
1402
+ const postService = service.getPostService(runtime.agentId);
1403
+ if (!postService) {
1404
+ throw new Error("PostService not available");
1405
+ }
1406
+ const introText = `Hello Farcaster! I'm ${runtime.character.name}, an AI agent powered by ElizaOS. Looking forward to connecting with you all! \u{1F916}`;
1407
+ const cast = await postService.createPost({
1408
+ agentId: runtime.agentId,
1409
+ roomId: createUniqueUuid5(runtime, "farcaster-timeline"),
1410
+ text: introText
1411
+ });
1412
+ if (!cast || !cast.id || !cast.text || !((_a = cast.metadata) == null ? void 0 : _a.castHash)) {
1413
+ throw new Error("Failed to create introduction cast");
1414
+ }
1415
+ logger9.info(`Posted introduction cast: ${cast.metadata.castHash}`);
1416
+ const manager = service.getActiveManagers().get(runtime.agentId);
1417
+ if (!manager) {
1418
+ throw new Error("Manager not found for agent");
1419
+ }
1420
+ const fid = parseInt(runtime.getSetting("FARCASTER_FID"));
1421
+ const profile = await manager.client.getProfile(fid);
1422
+ if (!profile || profile.fid !== fid) {
1423
+ throw new Error("Profile fetch failed or FID mismatch");
1424
+ }
1425
+ logger9.info(`Agent profile verified: @${profile.username} (FID: ${profile.fid})`);
1426
+ }
1427
+ },
1428
+ {
1429
+ name: "Farcaster Plugin - Timeline Monitoring",
1430
+ async fn(runtime) {
1431
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
1432
+ if (!service) {
1433
+ throw new Error("Farcaster service not initialized");
1434
+ }
1435
+ const postService = service.getPostService(runtime.agentId);
1436
+ if (!postService) {
1437
+ throw new Error("PostService not available");
1438
+ }
1439
+ const casts = await postService.getPosts({
1440
+ agentId: runtime.agentId,
1441
+ limit: 10
1442
+ });
1443
+ if (!Array.isArray(casts)) {
1444
+ throw new Error("getPosts did not return an array");
1445
+ }
1446
+ logger9.info(`Found ${casts.length} casts in timeline`);
1447
+ if (casts.length > 0) {
1448
+ const firstCast = casts[0];
1449
+ if (!firstCast.id || !firstCast.username || !firstCast.text) {
1450
+ throw new Error("Cast missing required fields");
1451
+ }
1452
+ logger9.info(`Latest cast by @${firstCast.username}: ${firstCast.text.substring(0, 50)}...`);
1453
+ }
1454
+ const mentions = await postService.getMentions(runtime.agentId, { limit: 5 });
1455
+ if (!Array.isArray(mentions)) {
1456
+ throw new Error("getMentions did not return an array");
1457
+ }
1458
+ logger9.info(`Found ${mentions.length} mentions`);
1459
+ }
1460
+ },
1461
+ {
1462
+ name: "Farcaster Plugin - Message Send and Retrieve",
1463
+ async fn(runtime) {
1464
+ var _a;
1465
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
1466
+ if (!service) {
1467
+ throw new Error("Farcaster service not initialized");
1468
+ }
1469
+ const messageService = service.getMessageService(runtime.agentId);
1470
+ if (!messageService) {
1471
+ throw new Error("MessageService not available");
1472
+ }
1473
+ const roomId = createUniqueUuid5(runtime, "test-conversation");
1474
+ const message = await messageService.sendMessage({
1475
+ agentId: runtime.agentId,
1476
+ roomId,
1477
+ text: "Testing message send and retrieve with ElizaOS Farcaster plugin! \u{1F9EA}",
1478
+ type: "CAST" /* CAST */
1479
+ });
1480
+ if (!message || !message.id || !((_a = message.metadata) == null ? void 0 : _a.castHash)) {
1481
+ throw new Error("Failed to send message or missing metadata");
1482
+ }
1483
+ logger9.info(`Sent cast with hash: ${message.metadata.castHash}`);
1484
+ const castHash = message.metadata.castHash;
1485
+ const retrieved = await messageService.getMessage(castHash, runtime.agentId);
1486
+ if (!retrieved || retrieved.text !== message.text) {
1487
+ throw new Error("Failed to retrieve message or content mismatch");
1488
+ }
1489
+ logger9.info("Successfully retrieved message by hash");
1490
+ }
1491
+ },
1492
+ {
1493
+ name: "Farcaster Plugin - Reply Threading",
1494
+ async fn(runtime) {
1495
+ var _a, _b;
1496
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
1497
+ if (!service) {
1498
+ throw new Error("Farcaster service not initialized");
1499
+ }
1500
+ const messageService = service.getMessageService(runtime.agentId);
1501
+ const postService = service.getPostService(runtime.agentId);
1502
+ if (!messageService || !postService) {
1503
+ throw new Error("Services not available");
1504
+ }
1505
+ const originalCast = await postService.createPost({
1506
+ agentId: runtime.agentId,
1507
+ roomId: createUniqueUuid5(runtime, "reply-test"),
1508
+ text: "This is a test cast for reply threading \u{1F9F5}"
1509
+ });
1510
+ if (!originalCast || !((_a = originalCast.metadata) == null ? void 0 : _a.castHash)) {
1511
+ throw new Error("Failed to create original cast");
1512
+ }
1513
+ const reply = await messageService.sendMessage({
1514
+ agentId: runtime.agentId,
1515
+ roomId: originalCast.roomId,
1516
+ text: "This is a test reply maintaining thread context! \u{1F4AC}",
1517
+ type: "REPLY",
1518
+ replyToId: originalCast.metadata.castHash,
1519
+ metadata: {
1520
+ parentHash: originalCast.metadata.castHash
1521
+ }
1522
+ });
1523
+ if (!reply || !reply.inReplyTo || !((_b = reply.metadata) == null ? void 0 : _b.castHash)) {
1524
+ throw new Error("Failed to create reply or missing thread context");
1525
+ }
1526
+ logger9.info(`Created reply ${reply.metadata.castHash} to ${originalCast.metadata.castHash}`);
1527
+ }
1528
+ },
1529
+ {
1530
+ name: "Farcaster Plugin - Action Execution",
1531
+ async fn(runtime) {
1532
+ const { sendCastAction: sendCastAction2 } = await import("./sendCast-OW6DBKQB.js");
1533
+ const mockMessage = {
1534
+ id: createUniqueUuid5(runtime, "test-message"),
1535
+ agentId: runtime.agentId,
1536
+ roomId: createUniqueUuid5(runtime, "test-room"),
1537
+ entityId: runtime.agentId,
1538
+ content: {
1539
+ text: "Can you post about the ElizaOS framework on Farcaster?"
1540
+ },
1541
+ createdAt: Date.now()
1542
+ };
1543
+ const shouldExecute = await sendCastAction2.validate(runtime, mockMessage);
1544
+ if (!shouldExecute) {
1545
+ throw new Error("SEND_CAST action validation failed");
1546
+ }
1547
+ const result = await sendCastAction2.handler(runtime, mockMessage);
1548
+ if (!result) {
1549
+ throw new Error("SEND_CAST action execution failed");
1550
+ }
1551
+ logger9.info("Successfully validated and executed SEND_CAST action");
1552
+ }
1553
+ },
1554
+ {
1555
+ name: "Farcaster Plugin - Provider Context",
1556
+ async fn(runtime) {
1557
+ var _a, _b;
1558
+ const { farcasterProfileProvider: farcasterProfileProvider2 } = await import("./profileProvider-TNRU42OO.js");
1559
+ const { farcasterTimelineProvider: farcasterTimelineProvider2 } = await import("./timelineProvider-GPRPFEVJ.js");
1560
+ const mockMessage = {
1561
+ id: createUniqueUuid5(runtime, "test-message"),
1562
+ agentId: runtime.agentId,
1563
+ roomId: createUniqueUuid5(runtime, "test-room"),
1564
+ entityId: runtime.agentId,
1565
+ content: { text: "test" },
1566
+ createdAt: Date.now()
1567
+ };
1568
+ const profileContext = await farcasterProfileProvider2.get(runtime, mockMessage, { values: [], data: {}, text: "" });
1569
+ if (!profileContext || !profileContext.text || ((_a = profileContext.data) == null ? void 0 : _a.available) === void 0) {
1570
+ throw new Error("Profile provider returned invalid context");
1571
+ }
1572
+ logger9.info(`Profile provider: ${profileContext.text}`);
1573
+ const timelineContext = await farcasterTimelineProvider2.get(runtime, mockMessage, { values: [], data: {}, text: "" });
1574
+ if (!timelineContext || !timelineContext.text || ((_b = timelineContext.data) == null ? void 0 : _b.available) === void 0) {
1575
+ throw new Error("Timeline provider returned invalid context");
1576
+ }
1577
+ logger9.info(`Timeline provider: ${timelineContext.text}`);
1578
+ }
1579
+ },
1580
+ {
1581
+ name: "Farcaster Plugin - Rate Limit Handling",
1582
+ async fn(runtime) {
1583
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
1584
+ if (!service) {
1585
+ throw new Error("Farcaster service not initialized");
1586
+ }
1587
+ const messageService = service.getMessageService(runtime.agentId);
1588
+ if (!messageService) {
1589
+ throw new Error("MessageService not available");
1590
+ }
1591
+ const promises = [];
1592
+ for (let i = 0; i < 3; i++) {
1593
+ promises.push(
1594
+ messageService.sendMessage({
1595
+ agentId: runtime.agentId,
1596
+ roomId: createUniqueUuid5(runtime, "rate-limit-test"),
1597
+ text: `Rate limit test message ${i + 1}`,
1598
+ type: "CAST" /* CAST */
1599
+ }).catch((error) => {
1600
+ logger9.warn(`Expected rate limit error: ${error.message}`);
1601
+ return null;
1602
+ })
1603
+ );
1604
+ }
1605
+ const results = await Promise.all(promises);
1606
+ const successfulSends = results.filter((r) => r !== null);
1607
+ if (successfulSends.length === 0) {
1608
+ throw new Error("All messages failed - check if rate limiting is too strict");
1609
+ }
1610
+ logger9.info(`Successfully sent ${successfulSends.length} out of ${promises.length} messages`);
1611
+ }
1612
+ },
1613
+ {
1614
+ name: "Farcaster Plugin - Service Health Check",
1615
+ async fn(runtime) {
1616
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
1617
+ if (!service) {
1618
+ throw new Error("Farcaster service not initialized");
1619
+ }
1620
+ const health = await service.healthCheck();
1621
+ if (!health || health.healthy === void 0 || !health.details) {
1622
+ throw new Error("Health check returned invalid data");
1623
+ }
1624
+ logger9.info(`Service health: ${health.healthy ? "Healthy" : "Unhealthy"}`);
1625
+ logger9.info(`Active managers: ${health.details.activeManagers}`);
1626
+ if (!health.healthy) {
1627
+ logger9.warn("Service reported unhealthy status:", health.details);
1628
+ }
1629
+ }
1630
+ },
1631
+ {
1632
+ name: "Farcaster Plugin - Should Send a Real Cast",
1633
+ async fn(runtime) {
1634
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
1635
+ if (!service) {
1636
+ throw new Error("FarcasterService not found");
1637
+ }
1638
+ const postService = service.getPostService(runtime.agentId);
1639
+ if (!postService) {
1640
+ throw new Error("PostService not available");
1641
+ }
1642
+ const uniqueMessage = `This is a real E2E test cast from ElizaOS! ID: ${createUniqueUuid5(runtime, "e2e-cast")}`;
1643
+ logger9.info(`Attempting to post cast: "${uniqueMessage}"`);
1644
+ const cast = await postService.createPost({
1645
+ agentId: runtime.agentId,
1646
+ roomId: createUniqueUuid5(runtime, "farcaster-e2e-test"),
1647
+ text: uniqueMessage
1648
+ });
1649
+ if (!cast || !cast.id) {
1650
+ throw new Error("E2E test failed to create a real cast.");
1651
+ }
1652
+ logger9.success(`Successfully posted E2E test cast with ID: ${cast.id}`);
1653
+ }
1654
+ }
1655
+ ];
1656
+
1657
+ // src/__tests__/suite.ts
944
1658
  var FarcasterTestSuite = class {
945
- name = "farcaster";
1659
+ name = "Farcaster Plugin Tests";
1660
+ description = "Test suite for Farcaster plugin functionality";
946
1661
  manager = null;
947
1662
  tests;
948
1663
  /**
@@ -950,23 +1665,76 @@ var FarcasterTestSuite = class {
950
1665
  * Initializes an array of test functions to be executed.
951
1666
  */
952
1667
  constructor() {
953
- this.tests = [
954
- {
955
- name: "Initialize Farcaster Client",
956
- fn: this.testInitializingClient.bind(this)
957
- },
958
- { name: "Fetch Profile", fn: this.testFetchProfile.bind(this) },
959
- {
960
- name: "Fetch Timeline",
961
- fn: this.testFetchTimeline.bind(this)
962
- },
963
- { name: "Post Cast", fn: this.testPostCast.bind(this) },
964
- { name: "Post Cast With Image", fn: this.testPostImageCast.bind(this) },
965
- {
966
- name: "Handle Cast Response",
967
- fn: this.testHandleCastResponse.bind(this)
1668
+ const hasRealCredentials = !!(process.env.FARCASTER_FID && process.env.FARCASTER_SIGNER_UUID && process.env.FARCASTER_NEYNAR_API_KEY);
1669
+ logger10.info("=== Farcaster Test Suite Configuration ===");
1670
+ logger10.info(`FID: ${process.env.FARCASTER_FID ? "\u2713 Found" : "\u2717 Missing"}`);
1671
+ logger10.info(`Signer UUID: ${process.env.FARCASTER_SIGNER_UUID ? "\u2713 Found" : "\u2717 Missing"}`);
1672
+ logger10.info(`API Key: ${process.env.FARCASTER_NEYNAR_API_KEY ? "\u2713 Found" : "\u2717 Missing"}`);
1673
+ logger10.info(`Dry Run: ${process.env.FARCASTER_DRY_RUN || "not set (defaults to false)"}`);
1674
+ logger10.info("=========================================");
1675
+ if (hasRealCredentials) {
1676
+ logger10.success("\u2705 Running with real Farcaster credentials");
1677
+ this.tests = farcasterE2EScenarios;
1678
+ } else {
1679
+ logger10.warn("\u26A0\uFE0F Farcaster credentials not found in environment variables");
1680
+ logger10.warn("\u26A0\uFE0F Tests will run in mock mode");
1681
+ logger10.warn("\u26A0\uFE0F To run real tests, set FARCASTER_FID, FARCASTER_SIGNER_UUID, and FARCASTER_NEYNAR_API_KEY");
1682
+ this.tests = [
1683
+ {
1684
+ name: "Mock: Check Farcaster Configuration",
1685
+ fn: this.testMockConfiguration.bind(this)
1686
+ },
1687
+ {
1688
+ name: "Mock: Service Initialization",
1689
+ fn: this.testMockServiceInit.bind(this)
1690
+ }
1691
+ ];
1692
+ }
1693
+ }
1694
+ /**
1695
+ * Test that checks if Farcaster is properly configured
1696
+ */
1697
+ async testMockConfiguration(runtime) {
1698
+ logger10.info("Running mock configuration test");
1699
+ const fid = runtime.getSetting("FARCASTER_FID");
1700
+ const signerUuid = runtime.getSetting("FARCASTER_SIGNER_UUID");
1701
+ const apiKey = runtime.getSetting("FARCASTER_NEYNAR_API_KEY");
1702
+ logger10.info("Runtime settings check:");
1703
+ logger10.info(`- FID from runtime: ${fid ? "Found" : "Not found"}`);
1704
+ logger10.info(`- Signer UUID from runtime: ${signerUuid ? "Found" : "Not found"}`);
1705
+ logger10.info(`- API Key from runtime: ${apiKey ? "Found" : "Not found"}`);
1706
+ if (!fid || !signerUuid || !apiKey) {
1707
+ logger10.info("Farcaster not configured - this is expected in mock mode");
1708
+ logger10.info("To enable real tests, configure the following:");
1709
+ logger10.info("- FARCASTER_FID: Your Farcaster ID");
1710
+ logger10.info("- FARCASTER_SIGNER_UUID: Neynar signer UUID");
1711
+ logger10.info("- FARCASTER_NEYNAR_API_KEY: Neynar API key");
1712
+ }
1713
+ }
1714
+ /**
1715
+ * Test service initialization without real credentials
1716
+ */
1717
+ async testMockServiceInit(runtime) {
1718
+ logger10.info("Running mock service initialization test");
1719
+ try {
1720
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
1721
+ if (!service) {
1722
+ logger10.info("Farcaster service not available - this is expected without credentials");
1723
+ return;
1724
+ }
1725
+ logger10.info("Farcaster service is registered but may not be fully initialized");
1726
+ if (typeof service.getMessageService === "function") {
1727
+ logger10.info("\u2713 getMessageService method exists");
1728
+ }
1729
+ if (typeof service.getPostService === "function") {
1730
+ logger10.info("\u2713 getPostService method exists");
1731
+ }
1732
+ if (typeof service.healthCheck === "function") {
1733
+ logger10.info("\u2713 healthCheck method exists");
968
1734
  }
969
- ];
1735
+ } catch (error) {
1736
+ logger10.info("Service initialization check completed");
1737
+ }
970
1738
  }
971
1739
  /**
972
1740
  * Asynchronously initializes the Farcaster client for the provided agent runtime.
@@ -982,7 +1750,7 @@ var FarcasterTestSuite = class {
982
1750
  }
983
1751
  this.manager = service.managers.get(runtime.agentId);
984
1752
  if (this.manager) {
985
- logger7.debug("FarcasterAgentManager initialized successfully.");
1753
+ logger10.debug("FarcasterAgentManager initialized successfully.");
986
1754
  } else {
987
1755
  throw new Error("FarcasterAgentManager failed to initialize.");
988
1756
  }
@@ -1009,7 +1777,7 @@ var FarcasterTestSuite = class {
1009
1777
  if (!profile || !profile.fid) {
1010
1778
  throw new Error("Profile fetch failed.");
1011
1779
  }
1012
- logger7.log("Successfully fetched Farcaster profile:", profile);
1780
+ logger10.log("Successfully fetched Farcaster profile:", profile);
1013
1781
  } catch (error) {
1014
1782
  throw new Error(`Error fetching Farcaster profile: ${error}`);
1015
1783
  }
@@ -1035,7 +1803,7 @@ var FarcasterTestSuite = class {
1035
1803
  if (!result.timeline || result.timeline.length === 0) {
1036
1804
  throw new Error("No casts in timeline.");
1037
1805
  }
1038
- logger7.log(`Successfully fetched ${result.timeline.length} casts from timeline.`);
1806
+ logger10.log(`Successfully fetched ${result.timeline.length} casts from timeline.`);
1039
1807
  } catch (error) {
1040
1808
  throw new Error(`Error fetching timeline: ${error}`);
1041
1809
  }
@@ -1059,7 +1827,7 @@ var FarcasterTestSuite = class {
1059
1827
  if (!result || result.length === 0) {
1060
1828
  throw new Error("Cast posting failed.");
1061
1829
  }
1062
- logger7.success("Successfully posted a test cast.");
1830
+ logger10.success("Successfully posted a test cast.");
1063
1831
  } catch (error) {
1064
1832
  throw new Error(`Error posting a cast: ${error}`);
1065
1833
  }
@@ -1087,7 +1855,7 @@ var FarcasterTestSuite = class {
1087
1855
  if (!result || result.length === 0) {
1088
1856
  throw new Error("Cast with image posting failed.");
1089
1857
  }
1090
- logger7.success("Successfully posted a test cast with image.");
1858
+ logger10.success("Successfully posted a test cast with image.");
1091
1859
  } catch (error) {
1092
1860
  throw new Error(`Error posting a cast with image: ${error}`);
1093
1861
  }
@@ -1115,15 +1883,15 @@ var FarcasterTestSuite = class {
1115
1883
  },
1116
1884
  timestamp: /* @__PURE__ */ new Date()
1117
1885
  };
1118
- const memoryId = createUniqueUuid3(runtime, testCast.hash);
1886
+ const memoryId = createUniqueUuid6(runtime, testCast.hash);
1119
1887
  const memory = {
1120
1888
  id: memoryId,
1121
1889
  agentId: runtime.agentId,
1122
1890
  content: {
1123
1891
  text: testCast.text
1124
1892
  },
1125
- entityId: createUniqueUuid3(runtime, String(testCast.authorFid)),
1126
- roomId: createUniqueUuid3(runtime, "test-room"),
1893
+ entityId: createUniqueUuid6(runtime, String(testCast.authorFid)),
1894
+ roomId: createUniqueUuid6(runtime, "test-room"),
1127
1895
  createdAt: testCast.timestamp.getTime()
1128
1896
  };
1129
1897
  runtime.emitEvent("farcaster.mention_received", {
@@ -1132,7 +1900,7 @@ var FarcasterTestSuite = class {
1132
1900
  cast: testCast,
1133
1901
  source: "farcaster"
1134
1902
  });
1135
- logger7.success("Successfully simulated cast response handling");
1903
+ logger10.success("Successfully simulated cast response handling");
1136
1904
  } catch (error) {
1137
1905
  throw new Error(`Error handling cast response: ${error}`);
1138
1906
  }
@@ -1146,18 +1914,313 @@ var FarcasterTestSuite = class {
1146
1914
  */
1147
1915
  async generateRandomCastContent(runtime, context = "general") {
1148
1916
  const prompt = `Generate a short, interesting cast about ${context} (max 280 chars).`;
1149
- const result = await runtime.useModel(ModelType2.TEXT_SMALL, {
1917
+ const result = await runtime.useModel(ModelType3.TEXT_SMALL, {
1150
1918
  prompt
1151
1919
  });
1152
1920
  return result.substring(0, 280);
1153
1921
  }
1922
+ /**
1923
+ * Tests the MessageService functionality
1924
+ *
1925
+ * @param {IAgentRuntime} runtime - The runtime environment.
1926
+ * @returns {Promise<void>} A promise that resolves when the test is complete.
1927
+ */
1928
+ async testMessageService(runtime) {
1929
+ try {
1930
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
1931
+ if (!service) {
1932
+ throw new Error("Farcaster service not found");
1933
+ }
1934
+ const messageService = service.getMessageService(runtime.agentId);
1935
+ if (!messageService) {
1936
+ throw new Error("MessageService not initialized");
1937
+ }
1938
+ const messages = await messageService.getMessages({
1939
+ agentId: runtime.agentId,
1940
+ limit: 5
1941
+ });
1942
+ logger10.log(`Retrieved ${messages.length} messages from MessageService`);
1943
+ const testText = await this.generateRandomCastContent(runtime, "message_service_test");
1944
+ const message = await messageService.sendMessage({
1945
+ agentId: runtime.agentId,
1946
+ roomId: createUniqueUuid6(runtime, "test-room"),
1947
+ text: testText,
1948
+ type: "CAST" /* CAST */
1949
+ });
1950
+ if (!message || !message.id) {
1951
+ throw new Error("Failed to send message via MessageService");
1952
+ }
1953
+ logger10.success("MessageService test completed successfully");
1954
+ } catch (error) {
1955
+ throw new Error(`Error testing MessageService: ${error}`);
1956
+ }
1957
+ }
1958
+ /**
1959
+ * Tests the PostService functionality
1960
+ *
1961
+ * @param {IAgentRuntime} runtime - The runtime environment.
1962
+ * @returns {Promise<void>} A promise that resolves when the test is complete.
1963
+ */
1964
+ async testPostService(runtime) {
1965
+ try {
1966
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
1967
+ if (!service) {
1968
+ throw new Error("Farcaster service not found");
1969
+ }
1970
+ const castService = service.getCastService(runtime.agentId);
1971
+ if (!castService) {
1972
+ throw new Error("CastService not initialized");
1973
+ }
1974
+ const casts = await castService.getCasts({
1975
+ agentId: runtime.agentId,
1976
+ limit: 5
1977
+ });
1978
+ logger10.log(`Retrieved ${casts.length} casts from CastService`);
1979
+ const testText = await this.generateRandomCastContent(runtime, "cast_service_test");
1980
+ const cast = await castService.createCast({
1981
+ agentId: runtime.agentId,
1982
+ roomId: createUniqueUuid6(runtime, "test-room"),
1983
+ text: testText
1984
+ });
1985
+ if (!cast || !cast.id) {
1986
+ throw new Error("Failed to create cast via CastService");
1987
+ }
1988
+ logger10.success("CastService test completed successfully");
1989
+ } catch (error) {
1990
+ throw new Error(`Error testing PostService: ${error}`);
1991
+ }
1992
+ }
1993
+ /**
1994
+ * Tests real account posting functionality
1995
+ *
1996
+ * @param {IAgentRuntime} runtime - The runtime environment.
1997
+ * @returns {Promise<void>} A promise that resolves when the test is complete.
1998
+ */
1999
+ async testRealAccountPosting(runtime) {
2000
+ var _a;
2001
+ try {
2002
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
2003
+ if (!service) {
2004
+ throw new Error("Farcaster service not found");
2005
+ }
2006
+ const postService = service.getPostService(runtime.agentId);
2007
+ if (!postService) {
2008
+ throw new Error("PostService not initialized");
2009
+ }
2010
+ const testPosts = [
2011
+ "Testing ElizaOS Farcaster integration! \u{1F680} #ElizaOS",
2012
+ "AI agents are the future of social media engagement \u{1F916}",
2013
+ "Building amazing things with the ElizaOS framework \u{1F4BB}"
2014
+ ];
2015
+ for (const text of testPosts) {
2016
+ const post = await postService.createPost({
2017
+ agentId: runtime.agentId,
2018
+ roomId: createUniqueUuid6(runtime, "real-test"),
2019
+ text
2020
+ });
2021
+ if (!post || !post.id || !((_a = post.metadata) == null ? void 0 : _a.castHash)) {
2022
+ throw new Error("Failed to create real post");
2023
+ }
2024
+ logger10.success(`Posted real cast: ${post.metadata.castHash}`);
2025
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
2026
+ }
2027
+ logger10.success("Real account posting test completed successfully");
2028
+ } catch (error) {
2029
+ throw new Error(`Error testing real account posting: ${error}`);
2030
+ }
2031
+ }
2032
+ /**
2033
+ * Tests real account interactions (mentions, replies, etc)
2034
+ *
2035
+ * @param {IAgentRuntime} runtime - The runtime environment.
2036
+ * @returns {Promise<void>} A promise that resolves when the test is complete.
2037
+ */
2038
+ async testRealAccountInteractions(runtime) {
2039
+ var _a, _b;
2040
+ try {
2041
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
2042
+ if (!service) {
2043
+ throw new Error("Farcaster service not found");
2044
+ }
2045
+ const postService = service.getPostService(runtime.agentId);
2046
+ const messageService = service.getMessageService(runtime.agentId);
2047
+ if (!postService || !messageService) {
2048
+ throw new Error("Services not initialized");
2049
+ }
2050
+ const mentions = await postService.getMentions(runtime.agentId, { limit: 10 });
2051
+ logger10.log(`Found ${mentions.length} mentions`);
2052
+ const timeline = await postService.getPosts({
2053
+ agentId: runtime.agentId,
2054
+ limit: 20
2055
+ });
2056
+ logger10.log(`Found ${timeline.length} timeline posts`);
2057
+ if (timeline.length > 0) {
2058
+ const targetPost = timeline[0];
2059
+ if ((_a = targetPost.metadata) == null ? void 0 : _a.castHash) {
2060
+ const reply = await messageService.sendMessage({
2061
+ agentId: runtime.agentId,
2062
+ roomId: targetPost.roomId,
2063
+ text: "Great post! Testing real interactions with ElizaOS \u{1F389}",
2064
+ type: "REPLY" /* REPLY */,
2065
+ replyToId: targetPost.metadata.castHash,
2066
+ metadata: {
2067
+ parentHash: targetPost.metadata.castHash
2068
+ }
2069
+ });
2070
+ if (reply && ((_b = reply.metadata) == null ? void 0 : _b.castHash)) {
2071
+ logger10.success(`Replied to cast with: ${reply.metadata.castHash}`);
2072
+ }
2073
+ }
2074
+ }
2075
+ logger10.success("Real account interactions test completed successfully");
2076
+ } catch (error) {
2077
+ throw new Error(`Error testing real account interactions: ${error}`);
2078
+ }
2079
+ }
2080
+ /**
2081
+ * Tests message metadata tracking functionality
2082
+ *
2083
+ * @param {IAgentRuntime} runtime - The runtime environment.
2084
+ * @returns {Promise<void>} A promise that resolves when the test is complete.
2085
+ */
2086
+ async testMessageMetadataTracking(runtime) {
2087
+ var _a, _b;
2088
+ try {
2089
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
2090
+ if (!service) {
2091
+ throw new Error("Farcaster service not found");
2092
+ }
2093
+ const messageService = service.getMessageService(runtime.agentId);
2094
+ if (!messageService) {
2095
+ throw new Error("MessageService not initialized");
2096
+ }
2097
+ const testMessage = await messageService.sendMessage({
2098
+ agentId: runtime.agentId,
2099
+ roomId: createUniqueUuid6(runtime, "metadata-test"),
2100
+ text: "Testing metadata tracking with ElizaOS",
2101
+ type: "CAST" /* CAST */
2102
+ });
2103
+ if (!testMessage || !((_a = testMessage.metadata) == null ? void 0 : _a.castHash)) {
2104
+ throw new Error("Failed to send test message");
2105
+ }
2106
+ const castHash = testMessage.metadata.castHash;
2107
+ logger10.log(`Sent message with cast hash: ${castHash}`);
2108
+ const retrievedMessage = await messageService.getMessage(castHash, runtime.agentId);
2109
+ if (!retrievedMessage) {
2110
+ throw new Error("Failed to retrieve message by hash");
2111
+ }
2112
+ if (((_b = retrievedMessage.metadata) == null ? void 0 : _b.castHash) !== castHash) {
2113
+ throw new Error("Metadata mismatch in retrieved message");
2114
+ }
2115
+ logger10.success("Message metadata tracking test completed successfully");
2116
+ } catch (error) {
2117
+ throw new Error(`Error testing message metadata tracking: ${error}`);
2118
+ }
2119
+ }
2120
+ };
2121
+
2122
+ // src/actions/replyCast.ts
2123
+ import {
2124
+ logger as logger11
2125
+ } from "@elizaos/core";
2126
+ var replyCastAction = {
2127
+ name: "REPLY_TO_CAST",
2128
+ description: "Replies to a cast on Farcaster",
2129
+ examples: [
2130
+ [
2131
+ {
2132
+ name: "user",
2133
+ content: { text: "Someone asked about ElizaOS on Farcaster, can you reply?" }
2134
+ },
2135
+ {
2136
+ name: "assistant",
2137
+ content: {
2138
+ text: "I'll reply to their question about ElizaOS.",
2139
+ actions: ["REPLY_TO_CAST"]
2140
+ }
2141
+ }
2142
+ ],
2143
+ [
2144
+ {
2145
+ name: "user",
2146
+ content: { text: "Reply to that cast and thank them for the feedback" }
2147
+ },
2148
+ {
2149
+ name: "assistant",
2150
+ content: {
2151
+ text: "I'll reply with a thank you message.",
2152
+ actions: ["REPLY_TO_CAST"]
2153
+ }
2154
+ }
2155
+ ]
2156
+ ],
2157
+ validate: async (runtime, message) => {
2158
+ var _a;
2159
+ const text = ((_a = message.content.text) == null ? void 0 : _a.toLowerCase()) || "";
2160
+ const keywords = ["reply", "respond", "answer", "comment"];
2161
+ const hasKeyword = keywords.some((keyword) => text.includes(keyword));
2162
+ const hasParentCast = !!(message.content.metadata && message.content.metadata.parentCastHash);
2163
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
2164
+ const isServiceAvailable = !!(service == null ? void 0 : service.getMessageService(runtime.agentId));
2165
+ return hasKeyword && (hasParentCast || isServiceAvailable);
2166
+ },
2167
+ handler: async (runtime, message, state) => {
2168
+ var _a;
2169
+ try {
2170
+ const service = runtime.getService(FARCASTER_SERVICE_NAME);
2171
+ const messageService = service == null ? void 0 : service.getMessageService(runtime.agentId);
2172
+ if (!messageService) {
2173
+ logger11.error("[REPLY_TO_CAST] MessageService not available");
2174
+ return false;
2175
+ }
2176
+ const parentCastHash = ((_a = message.content.metadata) == null ? void 0 : _a.parentCastHash) || (state == null ? void 0 : state.parentCastHash);
2177
+ if (!parentCastHash) {
2178
+ logger11.error("[REPLY_TO_CAST] No parent cast to reply to");
2179
+ return false;
2180
+ }
2181
+ let replyContent = "";
2182
+ if (state == null ? void 0 : state.replyContent) {
2183
+ replyContent = state.replyContent;
2184
+ } else {
2185
+ const prompt = `Based on this request: "${message.content.text}", generate a helpful and engaging reply for a Farcaster cast (max 320 characters).`;
2186
+ const response = await runtime.useModel("text_large", { prompt });
2187
+ replyContent = typeof response === "string" ? response : response.text || "";
2188
+ }
2189
+ if (replyContent.length > 320) {
2190
+ replyContent = replyContent.substring(0, 317) + "...";
2191
+ }
2192
+ const reply = await messageService.sendMessage({
2193
+ agentId: runtime.agentId,
2194
+ roomId: message.roomId,
2195
+ text: replyContent,
2196
+ type: "REPLY" /* REPLY */,
2197
+ replyToId: parentCastHash,
2198
+ metadata: {
2199
+ parentHash: parentCastHash
2200
+ }
2201
+ });
2202
+ logger11.info(`[REPLY_TO_CAST] Successfully replied to cast: ${reply.id}`);
2203
+ return true;
2204
+ } catch (error) {
2205
+ logger11.error("[REPLY_TO_CAST] Error replying to cast:", error);
2206
+ return false;
2207
+ }
2208
+ }
1154
2209
  };
1155
2210
 
2211
+ // src/actions/index.ts
2212
+ var farcasterActions = [sendCastAction, replyCastAction];
2213
+
2214
+ // src/providers/index.ts
2215
+ var farcasterProviders = [farcasterProfileProvider, farcasterTimelineProvider];
2216
+
1156
2217
  // src/index.ts
1157
2218
  var farcasterPlugin = {
1158
2219
  name: "farcaster",
1159
- description: "Farcaster client plugin",
2220
+ description: "Farcaster client plugin for sending and receiving casts",
1160
2221
  services: [FarcasterService],
2222
+ actions: farcasterActions,
2223
+ providers: farcasterProviders,
1161
2224
  tests: [new FarcasterTestSuite()]
1162
2225
  };
1163
2226
  var index_default = farcasterPlugin;