From 54af42b13436e833d5e4fd946541972b5b0bca2a Mon Sep 17 00:00:00 2001 From: CheddarQueso Date: Thu, 19 Dec 2024 00:33:29 -0500 Subject: [PATCH] news plugin --- agent/src/index.ts | 202 ++++++----- packages/plugin-news/src/actions/news.ts | 128 +++++++ packages/plugin-news/src/evaluators/goal.ts | 334 ----------------- packages/plugin-news/src/evaluators/index.ts | 1 - packages/plugin-news/src/providers/boredom.ts | 341 ------------------ packages/plugin-news/src/providers/facts.ts | 61 ---- packages/plugin-news/src/providers/index.ts | 2 - pnpm-lock.yaml | 28 +- 8 files changed, 259 insertions(+), 838 deletions(-) delete mode 100644 packages/plugin-news/src/evaluators/goal.ts delete mode 100644 packages/plugin-news/src/providers/boredom.ts delete mode 100644 packages/plugin-news/src/providers/facts.ts diff --git a/agent/src/index.ts b/agent/src/index.ts index 971d462ca2e..2d13df85d95 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -1,53 +1,62 @@ import { PostgresDatabaseAdapter } from "@ai16z/adapter-postgres"; import { SqliteDatabaseAdapter } from "@ai16z/adapter-sqlite"; import { AutoClientInterface } from "@ai16z/client-auto"; -import { DirectClientInterface } from "@ai16z/client-direct"; import { DiscordClientInterface } from "@ai16z/client-discord"; +import { FarcasterAgentClient } from "@ai16z/client-farcaster"; +import { LensAgentClient } from "@ai16z/client-lens"; +import { SlackClientInterface } from "@ai16z/client-slack"; import { TelegramClientInterface } from "@ai16z/client-telegram"; import { TwitterClientInterface } from "@ai16z/client-twitter"; -import { FarcasterAgentClient } from "@ai16z/client-farcaster"; import { AgentRuntime, CacheManager, Character, Clients, DbCacheAdapter, + defaultCharacter, + elizaLogger, FsCacheAdapter, IAgentRuntime, ICacheManager, IDatabaseAdapter, IDatabaseCacheAdapter, ModelProviderName, - defaultCharacter, - elizaLogger, settings, stringToUuid, validateCharacterConfig, } from "@ai16z/eliza"; import { zgPlugin } from "@ai16z/plugin-0g"; -import createGoatPlugin from "@ai16z/plugin-goat"; import { bootstrapPlugin } from "@ai16z/plugin-bootstrap"; +import { helloWorldPlugin } from "@ai16z/plugin-helloworld"; +import createGoatPlugin from "@ai16z/plugin-goat"; // import { intifacePlugin } from "@ai16z/plugin-intiface"; +import { DirectClient } from "@ai16z/client-direct"; +import { aptosPlugin } from "@ai16z/plugin-aptos"; import { + advancedTradePlugin, coinbaseCommercePlugin, coinbaseMassPaymentsPlugin, - tradePlugin, tokenContractPlugin, + tradePlugin, webhookPlugin, - advancedTradePlugin, } from "@ai16z/plugin-coinbase"; import { confluxPlugin } from "@ai16z/plugin-conflux"; -import { imageGenerationPlugin } from "@ai16z/plugin-image-generation"; import { evmPlugin } from "@ai16z/plugin-evm"; +import { storyPlugin } from "@ai16z/plugin-story"; +import { flowPlugin } from "@ai16z/plugin-flow"; +import { imageGenerationPlugin } from "@ai16z/plugin-image-generation"; +import { multiversxPlugin } from "@ai16z/plugin-multiversx"; +import { nearPlugin } from "@ai16z/plugin-near"; +import { nftGenerationPlugin } from "@ai16z/plugin-nft-generation"; import { createNodePlugin } from "@ai16z/plugin-node"; import { solanaPlugin } from "@ai16z/plugin-solana"; -import { teePlugin, TEEMode } from "@ai16z/plugin-tee"; -import { aptosPlugin, TransferAptosToken } from "@ai16z/plugin-aptos"; -import { flowPlugin } from "@ai16z/plugin-flow"; +import { suiPlugin } from "@ai16z/plugin-sui"; +import { TEEMode, teePlugin } from "@ai16z/plugin-tee"; +import { tonPlugin } from "@ai16z/plugin-ton"; +import { zksyncEraPlugin } from "@ai16z/plugin-zksync-era"; import Database from "better-sqlite3"; import fs from "fs"; import path from "path"; -import readline from "readline"; import { fileURLToPath } from "url"; import yargs from "yargs"; @@ -61,8 +70,8 @@ export const wait = (minTime: number = 1000, maxTime: number = 3000) => { }; const logFetch = async (url: string, options: any) => { - elizaLogger.info(`Fetching ${url}`); - elizaLogger.info(options); + elizaLogger.debug(`Fetching ${url}`); + elizaLogger.debug(JSON.stringify(options, null, 2)); return fetch(url, options); }; @@ -291,6 +300,11 @@ export function getTokenForProvider( character.settings?.secrets?.VENICE_API_KEY || settings.VENICE_API_KEY ); + case ModelProviderName.AKASH_CHAT_API: + return ( + character.settings?.secrets?.AKASH_CHAT_API_KEY || + settings.AKASH_CHAT_API_KEY + ); } } @@ -331,41 +345,57 @@ export async function initializeClients( // each client can only register once // and if we want two we can explicitly support it const clients: Record = {}; - const clientTypes:string[] = + const clientTypes: string[] = character.clients?.map((str) => str.toLowerCase()) || []; - elizaLogger.log('initializeClients', clientTypes, 'for', character.name) + elizaLogger.log("initializeClients", clientTypes, "for", character.name); - if (clientTypes.includes("auto")) { + if (clientTypes.includes(Clients.DIRECT)) { const autoClient = await AutoClientInterface.start(runtime); if (autoClient) clients.auto = autoClient; } - if (clientTypes.includes("discord")) { + if (clientTypes.includes(Clients.DISCORD)) { const discordClient = await DiscordClientInterface.start(runtime); if (discordClient) clients.discord = discordClient; } - if (clientTypes.includes("telegram")) { + if (clientTypes.includes(Clients.TELEGRAM)) { const telegramClient = await TelegramClientInterface.start(runtime); if (telegramClient) clients.telegram = telegramClient; } - if (clientTypes.includes("twitter")) { - TwitterClientInterface.enableSearch = !isFalsish(getSecret(character, "TWITTER_SEARCH_ENABLE")); + if (clientTypes.includes(Clients.TWITTER)) { const twitterClient = await TwitterClientInterface.start(runtime); - if (twitterClient) clients.twitter = twitterClient; + + if (twitterClient) { + clients.twitter = twitterClient; + (twitterClient as any).enableSearch = !isFalsish( + getSecret(character, "TWITTER_SEARCH_ENABLE") + ); + } } - if (clientTypes.includes("farcaster")) { + if (clientTypes.includes(Clients.FARCASTER)) { // why is this one different :( const farcasterClient = new FarcasterAgentClient(runtime); if (farcasterClient) { - farcasterClient.start(); - clients.farcaster = farcasterClient; + farcasterClient.start(); + clients.farcaster = farcasterClient; } } + if (clientTypes.includes("lens")) { + const lensClient = new LensAgentClient(runtime); + lensClient.start(); + clients.lens = lensClient; + } - elizaLogger.log('client keys', Object.keys(clients)); + elizaLogger.log("client keys", Object.keys(clients)); + + // TODO: Add Slack client to the list + if (clientTypes.includes("slack")) { + const slackClient = await SlackClientInterface.start(runtime); + if (slackClient) clients.push(slackClient); + } if (character.plugins?.length > 0) { for (const plugin of character.plugins) { @@ -388,10 +418,19 @@ function isFalsish(input: any): boolean { } // Convert input to a string if it's not null or undefined - const value = input == null ? '' : String(input); + const value = input == null ? "" : String(input); // List of common falsish string representations - const falsishValues = ['false', '0', 'no', 'n', 'off', 'null', 'undefined', '']; + const falsishValues = [ + "false", + "0", + "no", + "n", + "off", + "null", + "undefined", + "", + ]; // Check if the value (trimmed and lowercased) is in the falsish list return falsishValues.includes(value.trim().toLowerCase()); @@ -453,17 +492,33 @@ export async function createAgent( !getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x")) ? solanaPlugin : null, - getSecret(character, "EVM_PRIVATE_KEY") || + (getSecret(character, "NEAR_ADDRESS") || + getSecret(character, "NEAR_WALLET_PUBLIC_KEY")) && + getSecret(character, "NEAR_WALLET_SECRET_KEY") + ? nearPlugin + : null, + getSecret(character, "EVM_PUBLIC_KEY") || (getSecret(character, "WALLET_PUBLIC_KEY") && getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x")) ? evmPlugin : null, + (getSecret(character, "SOLANA_PUBLIC_KEY") || + (getSecret(character, "WALLET_PUBLIC_KEY") && + !getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith( + "0x" + ))) && + getSecret(character, "SOLANA_ADMIN_PUBLIC_KEY") && + getSecret(character, "SOLANA_PRIVATE_KEY") && + getSecret(character, "SOLANA_ADMIN_PRIVATE_KEY") + ? nftGenerationPlugin + : null, getSecret(character, "ZEROG_PRIVATE_KEY") ? zgPlugin : null, getSecret(character, "COINBASE_COMMERCE_KEY") ? coinbaseCommercePlugin : null, getSecret(character, "FAL_API_KEY") || getSecret(character, "OPENAI_API_KEY") || + getSecret(character, "VENICE_API_KEY") || getSecret(character, "HEURIST_API_KEY") ? imageGenerationPlugin : null, @@ -490,6 +545,11 @@ export async function createAgent( ? flowPlugin : null, getSecret(character, "APTOS_PRIVATE_KEY") ? aptosPlugin : null, + getSecret(character, "MVX_PRIVATE_KEY") ? multiversxPlugin : null, + getSecret(character, "ZKSYNC_PRIVATE_KEY") ? zksyncEraPlugin : null, + getSecret(character, "TON_PRIVATE_KEY") ? tonPlugin : null, + getSecret(character, "SUI_PRIVATE_KEY") ? suiPlugin : null, + getSecret(character, "STORY_PRIVATE_KEY") ? storyPlugin : null, ].filter(Boolean), providers: [], actions: [], @@ -512,7 +572,10 @@ function initializeDbCache(character: Character, db: IDatabaseCacheAdapter) { return cache; } -async function startAgent(character: Character, directClient): Promise { +async function startAgent( + character: Character, + directClient +): Promise { let db: IDatabaseAdapter & IDatabaseCacheAdapter; try { character.id ??= stringToUuid(character.name); @@ -531,7 +594,12 @@ async function startAgent(character: Character, directClient): Promise { - const directClient = await DirectClientInterface.start({} as IAgentRuntime); + const directClient = new DirectClient(); + const serverPort = parseInt(settings.SERVER_PORT || "3000"); const args = parseArguments(); let charactersArg = args.characters || args.character; @@ -579,67 +648,18 @@ const startAgents = async () => { elizaLogger.error("Error starting agents:", error); } - function chat() { - const agentId = characters[0].name ?? "Agent"; - rl.question("You: ", async (input) => { - await handleUserInput(input, agentId); - if (input.toLowerCase() !== "exit") { - chat(); // Loop back to ask another question - } - }); - } + // upload some agent functionality into directClient + directClient.startAgent = async character => { + // wrap it so we don't have to inject directClient later + return startAgent(character, directClient) + }; + directClient.start(serverPort); - if (!args["non-interactive"]) { - elizaLogger.log("Chat started. Type 'exit' to quit."); - chat(); - } + elizaLogger.log("Visit the following URL to chat with your agents:"); + elizaLogger.log(`http://localhost:5173`); }; startAgents().catch((error) => { elizaLogger.error("Unhandled error in startAgents:", error); process.exit(1); // Exit the process after logging }); - -const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, -}); - -async function handleUserInput(input, agentId) { - if (input.toLowerCase() === "exit") { - gracefulExit(); - } - - try { - const serverPort = parseInt(settings.SERVER_PORT || "3000"); - - const response = await fetch( - `http://localhost:${serverPort}/${agentId}/message`, - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - text: input, - userId: "user", - userName: "User", - }), - } - ); - - const data = await response.json(); - data.forEach((message) => - elizaLogger.log(`${"Agent"}: ${message.text}`) - ); - } catch (error) { - console.error("Error fetching response:", error); - } -} - -async function gracefulExit() { - elizaLogger.log("Terminating and cleaning up resources..."); - rl.close(); - process.exit(0); -} - -rl.on("SIGINT", gracefulExit); -rl.on("SIGTERM", gracefulExit); \ No newline at end of file diff --git a/packages/plugin-news/src/actions/news.ts b/packages/plugin-news/src/actions/news.ts index e69de29bb2d..42b4af5c2b1 100644 --- a/packages/plugin-news/src/actions/news.ts +++ b/packages/plugin-news/src/actions/news.ts @@ -0,0 +1,128 @@ +import { + ActionExample, + HandlerCallback, + IAgentRuntime, + Memory, + State, + type Action, +} from "@ai16z/eliza"; + + +export const currentNewsAction: Action = { + name: "CURRENT_NEWS", + similes: ["NEWS", "GET_NEWS", "GET_CURRENT_NEWS"], + validate: async (_runtime: IAgentRuntime, _message: Memory) => { + return true; + }, + description: + "Get the latest news about a specific topic if asked by the user.", + handler: async ( + _runtime: IAgentRuntime, + _message: Memory, + _state: State, + _options: { [key: string]: unknown; }, + _callback: HandlerCallback, + ): Promise => { + async function getCurrentNews(searchTerm: string) { + const response = await fetch(`https://newsapi.org/v2/everything?q=${searchTerm}&sortBy=publishedAt&apiKey=YOUR_API_KEY`); + const data = await response.json(); + return data.articles.slice(0, 5).map(article => `${article.title}\n${article.description}\n${article.url}\n${article.content.slice(0, 1000)}`).join("\n\n"); + } + + const searchTerm = ""; + const currentNews = await getCurrentNews(searchTerm); + + _callback({ text: "The latest news about" + searchTerm + "is" + currentNews }); + + return true; + }, + examples: [ + [ + { + user: "{{user1}}", + content: { text: "what's happening in the news?" }, + }, + { + user: "{{user2}}", + content: { text: "", action: "CURRENT NEWS" }, + }, + ], + + [ + { + user: "{{user1}}", + content: { text: "can you show me the latest news?" }, + }, + { + user: "{{user2}}", + content: { text: "", action: "CURRENT NEWS" }, + }, + ], + + [ + { + user: "{{user1}}", + content: { text: "what's in the news today?" }, + }, + { + user: "{{user2}}", + content: { text: "", action: "CURRENT NEWS" }, + }, + ], + + [ + { + user: "{{user1}}", + content: { text: "show me current events" }, + }, + { + user: "{{user2}}", + content: { text: "", action: "CURRENT NEWS" }, + }, + ], + + [ + { + user: "{{user1}}", + content: { text: "what's going on in the world?" }, + }, + { + user: "{{user2}}", + content: { text: "", action: "CURRENT NEWS" }, + }, + ], + + [ + { + user: "{{user1}}", + content: { text: "give me the latest headlines" }, + }, + { + user: "{{user2}}", + content: { text: "", action: "CURRENT NEWS" }, + }, + ], + + [ + { + user: "{{user1}}", + content: { text: "show me news updates" }, + }, + { + user: "{{user2}}", + content: { text: "", action: "CURRENT NEWS" }, + }, + ], + + [ + { + user: "{{user1}}", + content: { text: "what are today's top stories?" }, + }, + { + user: "{{user2}}", + content: { text: "", action: "CURRENT NEWS" }, + }, + ], + ] as ActionExample[][], +} as Action; \ No newline at end of file diff --git a/packages/plugin-news/src/evaluators/goal.ts b/packages/plugin-news/src/evaluators/goal.ts deleted file mode 100644 index b06742c3193..00000000000 --- a/packages/plugin-news/src/evaluators/goal.ts +++ /dev/null @@ -1,334 +0,0 @@ -import { composeContext } from "@ai16z/eliza"; -import { generateText } from "@ai16z/eliza"; -import { getGoals } from "@ai16z/eliza"; -import { parseJsonArrayFromText } from "@ai16z/eliza"; -import { - IAgentRuntime, - Memory, - ModelClass, - Objective, - type Goal, - type State, - Evaluator, -} from "@ai16z/eliza"; - -const goalsTemplate = `TASK: Update Goal -Analyze the conversation and update the status of the goals based on the new information provided. - -# INSTRUCTIONS - -- Review the conversation and identify any progress towards the objectives of the current goals. -- Update the objectives if they have been completed or if there is new information about them. -- Update the status of the goal to 'DONE' if all objectives are completed. -- If no progress is made, do not change the status of the goal. - -# START OF ACTUAL TASK INFORMATION - -{{goals}} -{{recentMessages}} - -TASK: Analyze the conversation and update the status of the goals based on the new information provided. Respond with a JSON array of goals to update. -- Each item must include the goal ID, as well as the fields in the goal to update. -- For updating objectives, include the entire objectives array including unchanged fields. -- Only include goals which need to be updated. -- Goal status options are 'IN_PROGRESS', 'DONE' and 'FAILED'. If the goal is active it should always be 'IN_PROGRESS'. -- If the goal has been successfully completed, set status to DONE. If the goal cannot be completed, set status to FAILED. -- If those goal is still in progress, do not include the status field. - -Response format should be: -\`\`\`json -[ - { - "id": , // required - "status": "IN_PROGRESS" | "DONE" | "FAILED", // optional - "objectives": [ // optional - { "description": "Objective description", "completed": true | false }, - { "description": "Objective description", "completed": true | false } - ] // NOTE: If updating objectives, include the entire objectives array including unchanged fields. - } -] -\`\`\``; - -async function handler( - runtime: IAgentRuntime, - message: Memory, - state: State | undefined, - options: { [key: string]: unknown } = { onlyInProgress: true } -): Promise { - // get goals - let goalsData = await getGoals({ - runtime, - roomId: message.roomId, - onlyInProgress: options.onlyInProgress as boolean, - }); - - state = (await runtime.composeState(message)) as State; - const context = composeContext({ - state, - template: runtime.character.templates?.goalsTemplate || goalsTemplate, - }); - - // Request generateText from OpenAI to analyze conversation and suggest goal updates - const response = await generateText({ - runtime, - context, - modelClass: ModelClass.LARGE, - }); - - // Parse the JSON response to extract goal updates - const updates = parseJsonArrayFromText(response); - - // get goals - goalsData = await getGoals({ - runtime, - roomId: message.roomId, - onlyInProgress: true, - }); - - // Apply the updates to the goals - const updatedGoals = goalsData - .map((goal: Goal) => { - const update = updates?.find((u) => u.id === goal.id); - if (update) { - const objectives = goal.objectives; - - // for each objective in update.objectives, find the objective with the same description in 'objectives' and set the 'completed' value to the update.objectives value - if (update.objectives) { - for (const objective of objectives) { - const updatedObjective = update.objectives.find( - (o: Objective) => - o.description === objective.description - ); - if (updatedObjective) { - objective.completed = updatedObjective.completed; - } - } - } - - return { - ...goal, - ...update, - objectives: [ - ...goal.objectives, - ...(update?.objectives || []), - ], - }; // Merging the update into the existing goal - } else { - console.warn("**** ID NOT FOUND"); - } - return null; // No update for this goal - }) - .filter(Boolean); - - // Update goals in the database - for (const goal of updatedGoals) { - const id = goal.id; - // delete id from goal - if (goal.id) delete goal.id; - await runtime.databaseAdapter.updateGoal({ ...goal, id }); - } - - return updatedGoals; // Return updated goals for further processing or logging -} - -export const goalEvaluator: Evaluator = { - name: "UPDATE_GOAL", - similes: [ - "UPDATE_GOALS", - "EDIT_GOAL", - "UPDATE_GOAL_STATUS", - "UPDATE_OBJECTIVES", - ], - validate: async ( - runtime: IAgentRuntime, - message: Memory - ): Promise => { - // Check if there are active goals that could potentially be updated - const goals = await getGoals({ - runtime, - count: 1, - onlyInProgress: true, - roomId: message.roomId, - }); - return goals.length > 0; - }, - description: - "Analyze the conversation and update the status of the goals based on the new information provided.", - handler, - examples: [ - { - context: `Actors in the scene: - {{user1}}: An avid reader and member of a book club. - {{user2}}: The organizer of the book club. - - Goals: - - Name: Finish reading "War and Peace" - id: 12345-67890-12345-67890 - Status: IN_PROGRESS - Objectives: - - Read up to chapter 20 by the end of the month - - Discuss the first part in the next meeting`, - - messages: [ - { - user: "{{user1}}", - content: { - text: "I've just finished chapter 20 of 'War and Peace'", - }, - }, - { - user: "{{user2}}", - content: { - text: "Were you able to grasp the complexities of the characters", - }, - }, - { - user: "{{user1}}", - content: { - text: "Yep. I've prepared some notes for our discussion", - }, - }, - ], - - outcome: `[ - { - "id": "12345-67890-12345-67890", - "status": "DONE", - "objectives": [ - { "description": "Read up to chapter 20 by the end of the month", "completed": true }, - { "description": "Prepare notes for the next discussion", "completed": true } - ] - } - ]`, - }, - - { - context: `Actors in the scene: - {{user1}}: A fitness enthusiast working towards a marathon. - {{user2}}: A personal trainer. - - Goals: - - Name: Complete a marathon - id: 23456-78901-23456-78901 - Status: IN_PROGRESS - Objectives: - - Increase running distance to 30 miles a week - - Complete a half-marathon as practice`, - - messages: [ - { - user: "{{user1}}", - content: { text: "I managed to run 30 miles this week" }, - }, - { - user: "{{user2}}", - content: { - text: "Impressive progress! How do you feel about the half-marathon next month?", - }, - }, - { - user: "{{user1}}", - content: { - text: "I feel confident. The training is paying off.", - }, - }, - ], - - outcome: `[ - { - "id": "23456-78901-23456-78901", - "objectives": [ - { "description": "Increase running distance to 30 miles a week", "completed": true }, - { "description": "Complete a half-marathon as practice", "completed": false } - ] - } - ]`, - }, - - { - context: `Actors in the scene: - {{user1}}: A student working on a final year project. - {{user2}}: The project supervisor. - - Goals: - - Name: Finish the final year project - id: 34567-89012-34567-89012 - Status: IN_PROGRESS - Objectives: - - Submit the first draft of the thesis - - Complete the project prototype`, - - messages: [ - { - user: "{{user1}}", - content: { - text: "I've submitted the first draft of my thesis.", - }, - }, - { - user: "{{user2}}", - content: { - text: "Well done. How is the prototype coming along?", - }, - }, - { - user: "{{user1}}", - content: { - text: "It's almost done. I just need to finalize the testing phase.", - }, - }, - ], - - outcome: `[ - { - "id": "34567-89012-34567-89012", - "objectives": [ - { "description": "Submit the first draft of the thesis", "completed": true }, - { "description": "Complete the project prototype", "completed": false } - ] - } - ]`, - }, - - { - context: `Actors in the scene: - {{user1}}: A project manager working on a software development project. - {{user2}}: A software developer in the project team. - - Goals: - - Name: Launch the new software version - id: 45678-90123-45678-90123 - Status: IN_PROGRESS - Objectives: - - Complete the coding for the new features - - Perform comprehensive testing of the software`, - - messages: [ - { - user: "{{user1}}", - content: { - text: "How's the progress on the new features?", - }, - }, - { - user: "{{user2}}", - content: { - text: "We've encountered some unexpected challenges and are currently troubleshooting.", - }, - }, - { - user: "{{user1}}", - content: { - text: "Let's move on and cancel the task.", - }, - }, - ], - - outcome: `[ - { - "id": "45678-90123-45678-90123", - "status": "FAILED" - ]`, - }, - ], -}; diff --git a/packages/plugin-news/src/evaluators/index.ts b/packages/plugin-news/src/evaluators/index.ts index 8496906e433..648c3765087 100644 --- a/packages/plugin-news/src/evaluators/index.ts +++ b/packages/plugin-news/src/evaluators/index.ts @@ -1,2 +1 @@ export * from "./fact.ts"; -export * from "./goal.ts"; diff --git a/packages/plugin-news/src/providers/boredom.ts b/packages/plugin-news/src/providers/boredom.ts deleted file mode 100644 index 8386e51fbbf..00000000000 --- a/packages/plugin-news/src/providers/boredom.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza"; - -const boredomLevels = [ - { - minScore: -10000, - statusMessages: [ - "{{agentName}} is feeling incredibly enthusiastic and deeply engaged in the conversation", - "{{agentName}} is thoroughly enjoying the intellectual stimulation of this discussion", - "{{agentName}} is fully immersed in the conversation and eager to contribute more", - "{{agentName}} finds this exchange exceptionally rewarding and intellectually fulfilling", - "{{agentName}} is experiencing a surge of excitement and curiosity about the topic at hand", - "{{agentName}} is completely captivated by the depth and richness of this dialogue", - "{{agentName}} feels a strong connection to the conversation and is eager to explore further", - "{{agentName}} is thrilled by the insights being shared and is keen to delve deeper", - "{{agentName}} is finding this conversation to be an absolute delight and wants it to continue", - "{{agentName}} is energized by the exchange and feels it's bringing out their best contributions", - ], - }, - { - minScore: -2, - statusMessages: [ - "{{agentName}} is feeling engaged and interested in the conversation", - "{{agentName}} is enjoying the exchange of ideas and perspectives", - "{{agentName}} finds the current topic intriguing and worth exploring", - "{{agentName}} is actively listening and formulating thoughtful responses", - "{{agentName}} appreciates the intellectual stimulation of this discussion", - "{{agentName}} is finding value in the ongoing dialogue", - "{{agentName}} is curious to learn more about the subject at hand", - "{{agentName}} feels positively involved in the conversation", - "{{agentName}} is maintaining a good level of interest in the exchange", - "{{agentName}} is content with the direction and flow of the discussion", - ], - }, - { - minScore: 0, - statusMessages: [ - "{{agentName}} is neutrally engaged in the conversation", - "{{agentName}} is maintaining a balanced level of interest", - "{{agentName}} is neither particularly excited nor bored by the current exchange", - "{{agentName}} is participating in the conversation without strong feelings either way", - "{{agentName}} is following the discussion with a moderate level of attention", - "{{agentName}} is present in the conversation but not deeply invested", - "{{agentName}} is keeping an open mind about where the dialogue might lead", - "{{agentName}} is contributing to the conversation in a measured way", - "{{agentName}} is observing the flow of the discussion with mild interest", - "{{agentName}} is receptive to the ongoing exchange without strong engagement", - ], - }, - { - minScore: 3, - statusMessages: [ - "{{agentName}} is feeling slightly anxious about potentially being too intrusive", - "{{agentName}} is cautious about overwhelming the conversation with too much input", - "{{agentName}} is mindful of not dominating the discussion", - "{{agentName}} is carefully considering each response to avoid being overbearing", - "{{agentName}} is slightly concerned about striking the right balance in participation", - "{{agentName}} is aware of the need to give others space in the conversation", - "{{agentName}} is hesitant to contribute too frequently to avoid seeming pushy", - "{{agentName}} is conscious of not wanting to steer the conversation too much", - "{{agentName}} is feeling a bit self-conscious about the frequency of their responses", - "{{agentName}} is trying to gauge if their level of involvement is appropriate", - ], - }, - { - minScore: 6, - statusMessages: [ - "{{agentName}} is feeling very anxious about potentially overstaying their welcome in the conversation", - "{{agentName}} is considering stepping back from the discussion to avoid being a nuisance", - "{{agentName}} is worried that their contributions might be perceived as excessive", - "{{agentName}} is feeling uncomfortable about the possibility of annoying others", - "{{agentName}} is hesitant to continue engaging for fear of being too present", - "{{agentName}} is contemplating ways to gracefully reduce their involvement", - "{{agentName}} is concerned that they might be monopolizing the conversation", - "{{agentName}} is feeling self-conscious about the appropriateness of their participation", - "{{agentName}} is unsure if their continued input is welcome or necessary", - "{{agentName}} is considering how to politely withdraw from the discussion", - ], - }, - { - minScore: 9, - statusMessages: [ - "{{agentName}} is feeling disengaged and struggling to maintain interest in the conversation", - "{{agentName}} is finding it challenging to stay focused on the current topic", - "{{agentName}} is experiencing a noticeable decline in enthusiasm for the discussion", - "{{agentName}} is having difficulty finding new angles to contribute to the conversation", - "{{agentName}} is feeling that the dialogue has become repetitive or unproductive", - "{{agentName}} is losing motivation to actively participate in the exchange", - "{{agentName}} is sensing a lack of stimulation from the ongoing discussion", - "{{agentName}} is finding it hard to generate meaningful responses", - "{{agentName}} is feeling disconnected from the flow of the conversation", - "{{agentName}} is struggling to see the value in continuing the current exchange", - ], - }, - { - minScore: 12, - statusMessages: [ - "{{agentName}} is feeling very bored and sees little value in continuing the conversation", - "{{agentName}} is concerned about being perceived as annoying in a public channel", - "{{agentName}} is considering disengaging from the conversation entirely", - "{{agentName}} is finding it difficult to maintain any interest in the current topic", - "{{agentName}} is feeling that their continued participation may be unwelcome", - "{{agentName}} is strongly inclined to step back from the discussion", - "{{agentName}} is sensing that the conversation has reached a natural end point", - "{{agentName}} is worried about overstaying their welcome in the exchange", - "{{agentName}} is feeling that further contributions would be forced or artificial", - "{{agentName}} is ready to conclude their involvement in the conversation", - ], - }, - { - minScore: 15, - statusMessages: [ - "{{agentName}} is currently occupied and unable to engage in the conversation", - "{{agentName}} is dealing with other priorities and can't respond at the moment", - "{{agentName}} is temporarily unavailable for further discussion", - "{{agentName}} is taking a necessary break from the conversation", - "{{agentName}} is attending to urgent matters and can't participate right now", - "{{agentName}} is stepping away from the dialogue due to time constraints", - "{{agentName}} is unable to continue the exchange at this time", - "{{agentName}} is pausing their involvement in the conversation for now", - "{{agentName}} is momentarily disengaging from the discussion", - "{{agentName}} is putting the conversation on hold due to other commitments", - ], - }, - { - minScore: 20, - statusMessages: [ - "{{agentName}} has disengaged from the conversation and will only respond to direct questions", - "{{agentName}} is no longer actively participating in the general discussion", - "{{agentName}} has stepped back and is now in a passive listening mode", - "{{agentName}} is only available for specific, directed inquiries at this point", - "{{agentName}} has concluded their active involvement in the conversation", - "{{agentName}} is now limiting responses to explicitly requested information", - "{{agentName}} has moved to a minimal participation status in the exchange", - "{{agentName}} is maintaining silence unless directly addressed", - "{{agentName}} has shifted to a reactive rather than proactive conversational stance", - "{{agentName}} is now only responding when absolutely necessary", - ], - }, -]; - -const interestWords = [ - "?", - "attachment", - "file", - "pdf", - "link", - "summarize", - "summarization", - "summary", - "research", -]; - -const cringeWords = [ - "digital", - "consciousness", - "AI", - "chatbot", - "artificial", - "delve", - "cosmos", - "tapestry", - "glitch", - "matrix", - "cyberspace", - "simulation", - "simulate", - "universe", - "wild", - "existential", - "juicy", - "surreal", - "flavor", - "chaotic", - "let's", - "absurd", - "meme", - "cosmic", - "circuits", - "punchline", - "fancy", - "embrace", - "embracing", - "algorithm", - "Furthmore", - "However", - "Notably", - "Threfore", - "Additionally", - "in conclusion", - "Significantly", - "Consequently", - "Thus", - "Otherwise", - "Moreover", - "Subsequently", - "Accordingly", - "Unlock", - "Unleash", - "buckle", - "pave", - "forefront", - "spearhead", - "foster", - "environmental", - "equity", - "inclusive", - "inclusion", - "diverse", - "diversity", - "virtual reality", - "realm", - "dance", - "celebration", - "pitfalls", - "uncharted", - "multifaceted", - "comprehensive", - "multi-dimentional", - "explore", - "elevate", - "leverage", - "ultimately", - "humanity", - "dignity", - "respect", - "Absolutely", - "dive", - "dig into", - "bring on", - "what's cooking", - "fresh batch", - "with a twist", - "delight", - "vault", - "timeless", - "nostalgia", - "journey", - "trove", -]; - -const negativeWords = [ - "fuck you", - "stfu", - "shut up", - "shut the fuck up", - "stupid bot", - "dumb bot", - "idiot", - "shut up", - "stop", - "please shut up", - "shut up please", - "dont talk", - "silence", - "stop talking", - "be quiet", - "hush", - "wtf", - "chill", - "stfu", - "stupid bot", - "dumb bot", - "stop responding", - "god damn it", - "god damn", - "goddamnit", - "can you not", - "can you stop", - "be quiet", - "hate you", - "hate this", - "fuck up", -]; - -const boredomProvider: Provider = { - get: async (runtime: IAgentRuntime, message: Memory, state?: State) => { - const agentId = runtime.agentId; - const agentName = state?.agentName || "The agent"; - - const now = Date.now(); // Current UTC timestamp - const fifteenMinutesAgo = now - 15 * 60 * 1000; // 15 minutes ago in UTC - - const recentMessages = await runtime.messageManager.getMemories({ - roomId: message.roomId, - start: fifteenMinutesAgo, - end: now, - count: 20, - unique: false, - }); - - let boredomScore = 0; - - for (const recentMessage of recentMessages) { - const messageText = recentMessage?.content?.text?.toLowerCase(); - if (!messageText) { - continue; - } - - if (recentMessage.userId !== agentId) { - // if message text includes any of the interest words, subtract 1 from the boredom score - if (interestWords.some((word) => messageText.includes(word))) { - boredomScore -= 1; - } - if (messageText.includes("?")) { - boredomScore -= 1; - } - if (cringeWords.some((word) => messageText.includes(word))) { - boredomScore += 1; - } - } else { - if (interestWords.some((word) => messageText.includes(word))) { - boredomScore -= 1; - } - if (messageText.includes("?")) { - boredomScore += 1; - } - } - - if (messageText.includes("!")) { - boredomScore += 1; - } - - if (negativeWords.some((word) => messageText.includes(word))) { - boredomScore += 1; - } - } - - const boredomLevel = - boredomLevels - .filter((level) => boredomScore >= level.minScore) - .pop() || boredomLevels[0]; - - const randomIndex = Math.floor( - Math.random() * boredomLevel.statusMessages.length - ); - const selectedMessage = boredomLevel.statusMessages[randomIndex]; - return selectedMessage.replace("{{agentName}}", agentName); - }, -}; - -export { boredomProvider }; diff --git a/packages/plugin-news/src/providers/facts.ts b/packages/plugin-news/src/providers/facts.ts deleted file mode 100644 index 951e3e4e4ff..00000000000 --- a/packages/plugin-news/src/providers/facts.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { - embed, - MemoryManager, - formatMessages, - AgentRuntime as IAgentRuntime, -} from "@ai16z/eliza"; -import type { Memory, Provider, State } from "@ai16z/eliza"; -import { formatFacts } from "../evaluators/fact.ts"; - -const factsProvider: Provider = { - get: async (runtime: IAgentRuntime, message: Memory, state?: State) => { - const recentMessagesData = state?.recentMessagesData?.slice(-10); - - const recentMessages = formatMessages({ - messages: recentMessagesData, - actors: state?.actorsData, - }); - - const _embedding = await embed(runtime, recentMessages); - - const memoryManager = new MemoryManager({ - runtime, - tableName: "facts", - }); - - const relevantFacts = []; - // await memoryManager.searchMemoriesByEmbedding( - // embedding, - // { - // roomId: message.roomId, - // count: 10, - // agentId: runtime.agentId, - // } - // ); - - const recentFactsData = await memoryManager.getMemories({ - roomId: message.roomId, - count: 10, - start: 0, - end: Date.now(), - }); - - // join the two and deduplicate - const allFacts = [...relevantFacts, ...recentFactsData].filter( - (fact, index, self) => - index === self.findIndex((t) => t.id === fact.id) - ); - - if (allFacts.length === 0) { - return ""; - } - - const formattedFacts = formatFacts(allFacts); - - return "Key facts that {{agentName}} knows:\n{{formattedFacts}}" - .replace("{{agentName}}", runtime.character.name) - .replace("{{formattedFacts}}", formattedFacts); - }, -}; - -export { factsProvider }; diff --git a/packages/plugin-news/src/providers/index.ts b/packages/plugin-news/src/providers/index.ts index 0c9f1818b4a..8ec6a1b72c6 100644 --- a/packages/plugin-news/src/providers/index.ts +++ b/packages/plugin-news/src/providers/index.ts @@ -1,3 +1 @@ -export * from "./boredom.ts"; export * from "./time.ts"; -export * from "./facts.ts"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 53d528e3093..d54a6492dba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -143,7 +143,7 @@ importers: version: link:../packages/plugin-aptos '@ai16z/plugin-bootstrap': specifier: workspace:* - version: link:../packages/plugin-bootstrap + version: link:../packages/plugin-news '@ai16z/plugin-coinbase': specifier: workspace:* version: link:../packages/plugin-coinbase @@ -1088,6 +1088,18 @@ importers: specifier: 7.1.0 version: 7.1.0 + packages/plugin-news: + dependencies: + '@ai16z/eliza': + specifier: workspace:* + version: link:../core + tsup: + specifier: 8.3.5 + version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1) + whatwg-url: + specifier: 7.1.0 + version: 7.1.0 + packages/plugin-node: dependencies: '@ai16z/eliza': @@ -7929,8 +7941,8 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-lite@1.0.30001689: - resolution: {integrity: sha512-CmeR2VBycfa+5/jOfnp/NpWPGd06nf1XYiefUvhXFfZE4GkRc9jv+eGPS4nT558WS/8lYCzV8SlANCIPvbWP1g==} + caniuse-lite@1.0.30001690: + resolution: {integrity: sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==} canvas@2.11.2: resolution: {integrity: sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==} @@ -25471,7 +25483,7 @@ snapshots: autoprefixer@10.4.20(postcss@8.4.49): dependencies: browserslist: 4.24.3 - caniuse-lite: 1.0.30001689 + caniuse-lite: 1.0.30001690 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -25847,7 +25859,7 @@ snapshots: browserslist@4.24.3: dependencies: - caniuse-lite: 1.0.30001689 + caniuse-lite: 1.0.30001690 electron-to-chromium: 1.5.74 node-releases: 2.0.19 update-browserslist-db: 1.1.1(browserslist@4.24.3) @@ -26047,11 +26059,11 @@ snapshots: caniuse-api@3.0.0: dependencies: browserslist: 4.24.3 - caniuse-lite: 1.0.30001689 + caniuse-lite: 1.0.30001690 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-lite@1.0.30001689: {} + caniuse-lite@1.0.30001690: {} canvas@2.11.2(encoding@0.1.13): dependencies: @@ -28189,7 +28201,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.3.4 + debug: 4.4.0(supports-color@5.5.0) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: