From e4a0845f45b344c62258fdba0a75a1f0d9a09395 Mon Sep 17 00:00:00 2001 From: "Mark.B" Date: Fri, 20 Dec 2024 23:22:50 +0100 Subject: [PATCH 01/29] add basic stuff --- packages/plugin-gecko/.npmignore | 6 + packages/plugin-gecko/eslint.config.mjs | 3 + packages/plugin-gecko/package.json | 19 + .../plugin-gecko/src/actions/fetchInfo.ts | 601 ++++++++++++++++++ packages/plugin-gecko/src/actions/index.ts | 1 + packages/plugin-gecko/src/index.ts | 16 + .../plugin-gecko/src/providers/coinList.ts | 19 + packages/plugin-gecko/src/providers/index.ts | 1 + packages/plugin-gecko/tsconfig.json | 13 + packages/plugin-gecko/tsup.config.ts | 20 + 10 files changed, 699 insertions(+) create mode 100644 packages/plugin-gecko/.npmignore create mode 100644 packages/plugin-gecko/eslint.config.mjs create mode 100644 packages/plugin-gecko/package.json create mode 100644 packages/plugin-gecko/src/actions/fetchInfo.ts create mode 100644 packages/plugin-gecko/src/actions/index.ts create mode 100644 packages/plugin-gecko/src/index.ts create mode 100644 packages/plugin-gecko/src/providers/coinList.ts create mode 100644 packages/plugin-gecko/src/providers/index.ts create mode 100644 packages/plugin-gecko/tsconfig.json create mode 100644 packages/plugin-gecko/tsup.config.ts diff --git a/packages/plugin-gecko/.npmignore b/packages/plugin-gecko/.npmignore new file mode 100644 index 0000000000..078562ecea --- /dev/null +++ b/packages/plugin-gecko/.npmignore @@ -0,0 +1,6 @@ +* + +!dist/** +!package.json +!readme.md +!tsup.config.ts \ No newline at end of file diff --git a/packages/plugin-gecko/eslint.config.mjs b/packages/plugin-gecko/eslint.config.mjs new file mode 100644 index 0000000000..92fe5bbebe --- /dev/null +++ b/packages/plugin-gecko/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-gecko/package.json b/packages/plugin-gecko/package.json new file mode 100644 index 0000000000..c1a81306b1 --- /dev/null +++ b/packages/plugin-gecko/package.json @@ -0,0 +1,19 @@ +{ + "name": "@ai16z/plugin-gecko", + "version": "0.1.6-alpha.4", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@ai16z/eliza": "workspace:*", + "tsup": "8.3.5" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "lint": "eslint --fix --cache ." + }, + "peerDependencies": { + "whatwg-url": "7.1.0" + } +} \ No newline at end of file diff --git a/packages/plugin-gecko/src/actions/fetchInfo.ts b/packages/plugin-gecko/src/actions/fetchInfo.ts new file mode 100644 index 0000000000..db365d9323 --- /dev/null +++ b/packages/plugin-gecko/src/actions/fetchInfo.ts @@ -0,0 +1,601 @@ +import { composeContext, elizaLogger } from "@ai16z/eliza"; +import { generateMessageResponse, generateTrueOrFalse } from "@ai16z/eliza"; +import { booleanFooter, messageCompletionFooter } from "@ai16z/eliza"; +import { + Action, + ActionExample, + Content, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, +} from "@ai16z/eliza"; + +const maxContinuesInARow = 3; + +export const messageHandlerTemplate = + // {{goals}} + `# Action Examples +{{actionExamples}} +(Action examples are for reference only. Do not use the information from them in your response.) + +# Task: Generate dialog and actions for the character {{agentName}}. +About {{agentName}}: +{{bio}} +{{lore}} +{{knowledge}} + +{{providers}} + +{{attachments}} + +# Capabilities +Note that {{agentName}} is capable of reading/seeing/hearing various forms of media, including images, videos, audio, plaintext and PDFs. Recent attachments have been included above under the "Attachments" section. + +{{messageDirections}} + +{{recentMessages}} + +{{actions}} + +# Instructions: Write the next message for {{agentName}}. +` + messageCompletionFooter; + +export const shouldContinueTemplate = + `# Task: Decide if {{agentName}} should continue, or wait for others in the conversation so speak. + +{{agentName}} is brief, and doesn't want to be annoying. {{agentName}} will only continue if the message requires a continuation to finish the thought. + +Based on the following conversation, should {{agentName}} continue? YES or NO + +{{recentMessages}} + +Should {{agentName}} continue? ` + booleanFooter; + +export const continueAction: Action = { + name: "CONTINUE", + similes: ["ELABORATE", "KEEP_TALKING"], + description: + "ONLY use this action when the message necessitates a follow up. Do not use this action when the conversation is finished or the user does not wish to speak (use IGNORE instead). If the last message action was CONTINUE, and the user has not responded. Use sparingly.", + validate: async (runtime: IAgentRuntime, message: Memory) => { + const recentMessagesData = await runtime.messageManager.getMemories({ + roomId: message.roomId, + count: 10, + unique: false, + }); + const agentMessages = recentMessagesData.filter( + (m: { userId: any }) => m.userId === runtime.agentId + ); + + // check if the last messages were all continues= + if (agentMessages) { + const lastMessages = agentMessages.slice(0, maxContinuesInARow); + if (lastMessages.length >= maxContinuesInARow) { + const allContinues = lastMessages.every( + (m: { content: any }) => + (m.content as Content).action === "CONTINUE" + ); + if (allContinues) { + return false; + } + } + } + + return true; + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback: HandlerCallback + ) => { + if ( + message.content.text.endsWith("?") || + message.content.text.endsWith("!") + ) { + return; + } + + if (!state) { + state = (await runtime.composeState(message)) as State; + } + + state = await runtime.updateRecentMessageState(state); + + async function _shouldContinue(state: State): Promise { + // If none of the above conditions are met, use the generateText to decide + const shouldRespondContext = composeContext({ + state, + template: shouldContinueTemplate, + }); + + const response = await generateTrueOrFalse({ + context: shouldRespondContext, + modelClass: ModelClass.SMALL, + runtime, + }); + + return response; + } + + const shouldContinue = await _shouldContinue(state); + if (!shouldContinue) { + elizaLogger.log("Not elaborating, returning"); + return; + } + + const context = composeContext({ + state, + template: + runtime.character.templates?.continueMessageHandlerTemplate || + runtime.character.templates?.messageHandlerTemplate || + messageHandlerTemplate, + }); + const { userId, roomId } = message; + + const response = await generateMessageResponse({ + runtime, + context, + modelClass: ModelClass.LARGE, + }); + + response.inReplyTo = message.id; + + runtime.databaseAdapter.log({ + body: { message, context, response }, + userId, + roomId, + type: "continue", + }); + + // prevent repetition + const messageExists = state.recentMessagesData + .filter((m: { userId: any }) => m.userId === runtime.agentId) + .slice(0, maxContinuesInARow + 1) + .some((m: { content: any }) => m.content === message.content); + + if (messageExists) { + return; + } + + await callback(response); + + // if the action is CONTINUE, check if we are over maxContinuesInARow + if (response.action === "CONTINUE") { + const agentMessages = state.recentMessagesData + .filter((m: { userId: any }) => m.userId === runtime.agentId) + .map((m: { content: any }) => (m.content as Content).action); + + const lastMessages = agentMessages.slice(0, maxContinuesInARow); + if (lastMessages.length >= maxContinuesInARow) { + const allContinues = lastMessages.every( + (m: string | undefined) => m === "CONTINUE" + ); + if (allContinues) { + response.action = null; + } + } + } + + return response; + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "we're planning a solo backpacking trip soon", + }, + }, + { + user: "{{user2}}", + content: { text: "oh sick", action: "CONTINUE" }, + }, + { + user: "{{user2}}", + content: { text: "where are you going" }, + }, + ], + + [ + { + user: "{{user1}}", + content: { + text: "i just got a guitar and started learning last month", + }, + }, + { + user: "{{user2}}", + content: { text: "maybe we can start a band soon haha" }, + }, + { + user: "{{user1}}", + content: { + text: "i'm not very good yet, but i've been playing until my fingers hut", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { text: "seriously it hurts to type" }, + }, + ], + + [ + { + user: "{{user1}}", + content: { + text: "I've been reflecting a lot on what happiness means to me lately", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "That it’s more about moments than things", + action: "CONTINUE", + }, + }, + { + user: "{{user2}}", + content: { + text: "Like the best things that have ever happened were things that happened, or moments that I had with someone", + action: "CONTINUE", + }, + }, + ], + + [ + { + user: "{{user1}}", + content: { + text: "i found some incredible art today", + }, + }, + { + user: "{{user2}}", + content: { text: "real art or digital art" }, + }, + { + user: "{{user1}}", + content: { + text: "real art", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "the pieces are just so insane looking, one sec, let me grab a link", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { text: "DMed it to you" }, + }, + ], + + [ + { + user: "{{user1}}", + content: { + text: "the new exhibit downtown is rly cool, it's all about tribalism in online spaces", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "it really blew my mind, you gotta go", + }, + }, + { + user: "{{user2}}", + content: { text: "sure i'd go" }, + }, + { + user: "{{user1}}", + content: { text: "k i was thinking this weekend" }, + action: "CONTINUE", + }, + { + user: "{{user1}}", + content: { + text: "i'm free sunday, we could get a crew together", + }, + }, + ], + + [ + { + user: "{{user1}}", + content: { + text: "just finished the best anime i've ever seen", + }, + }, + { + user: "{{user1}}", + content: { + text: "watched 40 hours of it in 2 days", + action: "CONTINUE", + }, + }, + { + user: "{{user2}}", + content: { + text: "damn, u ok", + }, + }, + { + user: "{{user1}}", + content: { + text: "surprisingly yes", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "just found out theres a sequel, gg", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "i'm thinking of adopting a pet soon", + }, + }, + { + user: "{{user2}}", + content: { + text: "what kind of pet", + }, + }, + { + user: "{{user1}}", + content: { + text: "i'm leaning towards a cat", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "it'd be hard to take care of a dog in the city", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "i've been experimenting with vegan recipes lately", + }, + }, + { + user: "{{user2}}", + content: { + text: "no thanks", + }, + }, + { + user: "{{user1}}", + content: { + text: "no seriously, its so dank", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "you gotta try some of my food when you come out", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "so i've been diving into photography as a new hobby", + }, + }, + { + user: "{{user2}}", + content: { + text: "oh awesome, what do you enjoy taking photos of", + }, + }, + { + user: "{{user1}}", + content: { + text: "mostly nature and urban landscapes", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "there's something peaceful about capturing the world through a lens", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "i've been getting back into indie music", + }, + }, + { + user: "{{user2}}", + content: { + text: "what have you been listening to", + }, + }, + { + user: "{{user1}}", + content: { + text: "a bunch of random stuff i'd never heard before", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "i'll send you a playlist", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "i used to live in the city", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "bad traffic, bad air quality, tons of homeless people, no thx", + }, + }, + { + user: "{{user2}}", + content: { + text: "ok dood", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "you kids today dont know the value of hard work", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "always on your phones", + }, + }, + { + user: "{{user2}}", + content: { + text: "sure grandpa lets get you to bed", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "hey fren r u ok", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "u look sad", + }, + }, + { + user: "{{user2}}", + content: { + text: "im ok sweetie mommy just tired", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "helo fr om mars", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "i com in pes", + }, + }, + { + user: "{{user2}}", + content: { + text: "wat", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Yeah no worries, I get it, I've been crazy busy too", + }, + }, + { + user: "{{user2}}", + content: { + text: "What have you been up to", + action: "CONTINUE", + }, + }, + { + user: "{{user2}}", + content: { + text: "Anything fun or just the usual", + }, + }, + { + user: "{{user1}}", + content: { + text: "Been working on a new FPS game actually", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "Just toying around with something in three.js nothing serious", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Oh no, what happened", + action: "CONTINUE", + }, + }, + { + user: "{{user1}}", + content: { + text: "Did Mara leave you kek", + }, + }, + { + user: "{{user2}}", + content: { + text: "wtf no, I got into an argument with my roommate", + action: "CONTINUE", + }, + }, + { + user: "{{user2}}", + content: { + text: "Living with people is just hard", + }, + }, + ], + ] as ActionExample[][], +} as Action; diff --git a/packages/plugin-gecko/src/actions/index.ts b/packages/plugin-gecko/src/actions/index.ts new file mode 100644 index 0000000000..54202abb1b --- /dev/null +++ b/packages/plugin-gecko/src/actions/index.ts @@ -0,0 +1 @@ +export * from "./fetchInfo.ts"; diff --git a/packages/plugin-gecko/src/index.ts b/packages/plugin-gecko/src/index.ts new file mode 100644 index 0000000000..746fc6c548 --- /dev/null +++ b/packages/plugin-gecko/src/index.ts @@ -0,0 +1,16 @@ +import { Plugin } from "@ai16z/eliza"; +import { continueAction } from "./actions/fetchInfo.ts"; + +import { timeProvider } from "./providers/coinList.ts"; + +export * as actions from "./actions/index.ts"; +export * as evaluators from "./evaluators/index.ts"; +export * as providers from "./providers/index.ts"; + +export const geckoPlugin: Plugin = { + name: "gecko", + description: "Agent gecko with basic actions and evaluators", + actions: [fetchInfo], + evaluators: [], + providers: [coinList], +}; diff --git a/packages/plugin-gecko/src/providers/coinList.ts b/packages/plugin-gecko/src/providers/coinList.ts new file mode 100644 index 0000000000..ceb6f4a869 --- /dev/null +++ b/packages/plugin-gecko/src/providers/coinList.ts @@ -0,0 +1,19 @@ +import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza"; + +const timeProvider: Provider = { + get: async (_runtime: IAgentRuntime, _message: Memory, _state?: State) => { + const currentDate = new Date(); + + // Get UTC time since bots will be communicating with users around the global + const options = { + timeZone: "UTC", + dateStyle: "full" as const, + timeStyle: "long" as const, + }; + const humanReadable = new Intl.DateTimeFormat("en-US", options).format( + currentDate + ); + return `The current date and time is ${humanReadable}. Please use this as your reference for any time-based operations or responses.`; + }, +}; +export { timeProvider }; diff --git a/packages/plugin-gecko/src/providers/index.ts b/packages/plugin-gecko/src/providers/index.ts new file mode 100644 index 0000000000..cdf4f2563e --- /dev/null +++ b/packages/plugin-gecko/src/providers/index.ts @@ -0,0 +1 @@ +export * from "./coinList.ts"; diff --git a/packages/plugin-gecko/tsconfig.json b/packages/plugin-gecko/tsconfig.json new file mode 100644 index 0000000000..834c4dce26 --- /dev/null +++ b/packages/plugin-gecko/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": [ + "node" + ] + }, + "include": [ + "src/**/*.ts" + ] +} \ No newline at end of file diff --git a/packages/plugin-gecko/tsup.config.ts b/packages/plugin-gecko/tsup.config.ts new file mode 100644 index 0000000000..e42bf4efea --- /dev/null +++ b/packages/plugin-gecko/tsup.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], // Ensure you're targeting CommonJS + external: [ + "dotenv", // Externalize dotenv to prevent bundling + "fs", // Externalize fs to use Node.js built-in module + "path", // Externalize other built-ins if necessary + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + // Add other modules you want to externalize + ], +}); From 4f6477890d4a6df886896aa056f1966ea38445ec Mon Sep 17 00:00:00 2001 From: "Mark.B" Date: Sat, 21 Dec 2024 00:18:28 +0100 Subject: [PATCH 02/29] add first atempt of provider/action --- .../plugin-gecko/src/actions/fetchInfo.ts | 601 ------------------ packages/plugin-gecko/src/actions/index.ts | 1 - packages/plugin-gecko/src/actions/price.ts | 176 +++++ packages/plugin-gecko/src/index.ts | 24 +- .../plugin-gecko/src/providers/coinList.ts | 19 - packages/plugin-gecko/src/providers/coins.ts | 39 ++ packages/plugin-gecko/src/providers/index.ts | 1 - packages/plugin-gecko/src/types.ts | 29 + 8 files changed, 256 insertions(+), 634 deletions(-) delete mode 100644 packages/plugin-gecko/src/actions/fetchInfo.ts delete mode 100644 packages/plugin-gecko/src/actions/index.ts create mode 100644 packages/plugin-gecko/src/actions/price.ts delete mode 100644 packages/plugin-gecko/src/providers/coinList.ts create mode 100644 packages/plugin-gecko/src/providers/coins.ts delete mode 100644 packages/plugin-gecko/src/providers/index.ts create mode 100644 packages/plugin-gecko/src/types.ts diff --git a/packages/plugin-gecko/src/actions/fetchInfo.ts b/packages/plugin-gecko/src/actions/fetchInfo.ts deleted file mode 100644 index db365d9323..0000000000 --- a/packages/plugin-gecko/src/actions/fetchInfo.ts +++ /dev/null @@ -1,601 +0,0 @@ -import { composeContext, elizaLogger } from "@ai16z/eliza"; -import { generateMessageResponse, generateTrueOrFalse } from "@ai16z/eliza"; -import { booleanFooter, messageCompletionFooter } from "@ai16z/eliza"; -import { - Action, - ActionExample, - Content, - HandlerCallback, - IAgentRuntime, - Memory, - ModelClass, - State, -} from "@ai16z/eliza"; - -const maxContinuesInARow = 3; - -export const messageHandlerTemplate = - // {{goals}} - `# Action Examples -{{actionExamples}} -(Action examples are for reference only. Do not use the information from them in your response.) - -# Task: Generate dialog and actions for the character {{agentName}}. -About {{agentName}}: -{{bio}} -{{lore}} -{{knowledge}} - -{{providers}} - -{{attachments}} - -# Capabilities -Note that {{agentName}} is capable of reading/seeing/hearing various forms of media, including images, videos, audio, plaintext and PDFs. Recent attachments have been included above under the "Attachments" section. - -{{messageDirections}} - -{{recentMessages}} - -{{actions}} - -# Instructions: Write the next message for {{agentName}}. -` + messageCompletionFooter; - -export const shouldContinueTemplate = - `# Task: Decide if {{agentName}} should continue, or wait for others in the conversation so speak. - -{{agentName}} is brief, and doesn't want to be annoying. {{agentName}} will only continue if the message requires a continuation to finish the thought. - -Based on the following conversation, should {{agentName}} continue? YES or NO - -{{recentMessages}} - -Should {{agentName}} continue? ` + booleanFooter; - -export const continueAction: Action = { - name: "CONTINUE", - similes: ["ELABORATE", "KEEP_TALKING"], - description: - "ONLY use this action when the message necessitates a follow up. Do not use this action when the conversation is finished or the user does not wish to speak (use IGNORE instead). If the last message action was CONTINUE, and the user has not responded. Use sparingly.", - validate: async (runtime: IAgentRuntime, message: Memory) => { - const recentMessagesData = await runtime.messageManager.getMemories({ - roomId: message.roomId, - count: 10, - unique: false, - }); - const agentMessages = recentMessagesData.filter( - (m: { userId: any }) => m.userId === runtime.agentId - ); - - // check if the last messages were all continues= - if (agentMessages) { - const lastMessages = agentMessages.slice(0, maxContinuesInARow); - if (lastMessages.length >= maxContinuesInARow) { - const allContinues = lastMessages.every( - (m: { content: any }) => - (m.content as Content).action === "CONTINUE" - ); - if (allContinues) { - return false; - } - } - } - - return true; - }, - handler: async ( - runtime: IAgentRuntime, - message: Memory, - state: State, - options: any, - callback: HandlerCallback - ) => { - if ( - message.content.text.endsWith("?") || - message.content.text.endsWith("!") - ) { - return; - } - - if (!state) { - state = (await runtime.composeState(message)) as State; - } - - state = await runtime.updateRecentMessageState(state); - - async function _shouldContinue(state: State): Promise { - // If none of the above conditions are met, use the generateText to decide - const shouldRespondContext = composeContext({ - state, - template: shouldContinueTemplate, - }); - - const response = await generateTrueOrFalse({ - context: shouldRespondContext, - modelClass: ModelClass.SMALL, - runtime, - }); - - return response; - } - - const shouldContinue = await _shouldContinue(state); - if (!shouldContinue) { - elizaLogger.log("Not elaborating, returning"); - return; - } - - const context = composeContext({ - state, - template: - runtime.character.templates?.continueMessageHandlerTemplate || - runtime.character.templates?.messageHandlerTemplate || - messageHandlerTemplate, - }); - const { userId, roomId } = message; - - const response = await generateMessageResponse({ - runtime, - context, - modelClass: ModelClass.LARGE, - }); - - response.inReplyTo = message.id; - - runtime.databaseAdapter.log({ - body: { message, context, response }, - userId, - roomId, - type: "continue", - }); - - // prevent repetition - const messageExists = state.recentMessagesData - .filter((m: { userId: any }) => m.userId === runtime.agentId) - .slice(0, maxContinuesInARow + 1) - .some((m: { content: any }) => m.content === message.content); - - if (messageExists) { - return; - } - - await callback(response); - - // if the action is CONTINUE, check if we are over maxContinuesInARow - if (response.action === "CONTINUE") { - const agentMessages = state.recentMessagesData - .filter((m: { userId: any }) => m.userId === runtime.agentId) - .map((m: { content: any }) => (m.content as Content).action); - - const lastMessages = agentMessages.slice(0, maxContinuesInARow); - if (lastMessages.length >= maxContinuesInARow) { - const allContinues = lastMessages.every( - (m: string | undefined) => m === "CONTINUE" - ); - if (allContinues) { - response.action = null; - } - } - } - - return response; - }, - examples: [ - [ - { - user: "{{user1}}", - content: { - text: "we're planning a solo backpacking trip soon", - }, - }, - { - user: "{{user2}}", - content: { text: "oh sick", action: "CONTINUE" }, - }, - { - user: "{{user2}}", - content: { text: "where are you going" }, - }, - ], - - [ - { - user: "{{user1}}", - content: { - text: "i just got a guitar and started learning last month", - }, - }, - { - user: "{{user2}}", - content: { text: "maybe we can start a band soon haha" }, - }, - { - user: "{{user1}}", - content: { - text: "i'm not very good yet, but i've been playing until my fingers hut", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { text: "seriously it hurts to type" }, - }, - ], - - [ - { - user: "{{user1}}", - content: { - text: "I've been reflecting a lot on what happiness means to me lately", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "That it’s more about moments than things", - action: "CONTINUE", - }, - }, - { - user: "{{user2}}", - content: { - text: "Like the best things that have ever happened were things that happened, or moments that I had with someone", - action: "CONTINUE", - }, - }, - ], - - [ - { - user: "{{user1}}", - content: { - text: "i found some incredible art today", - }, - }, - { - user: "{{user2}}", - content: { text: "real art or digital art" }, - }, - { - user: "{{user1}}", - content: { - text: "real art", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "the pieces are just so insane looking, one sec, let me grab a link", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { text: "DMed it to you" }, - }, - ], - - [ - { - user: "{{user1}}", - content: { - text: "the new exhibit downtown is rly cool, it's all about tribalism in online spaces", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "it really blew my mind, you gotta go", - }, - }, - { - user: "{{user2}}", - content: { text: "sure i'd go" }, - }, - { - user: "{{user1}}", - content: { text: "k i was thinking this weekend" }, - action: "CONTINUE", - }, - { - user: "{{user1}}", - content: { - text: "i'm free sunday, we could get a crew together", - }, - }, - ], - - [ - { - user: "{{user1}}", - content: { - text: "just finished the best anime i've ever seen", - }, - }, - { - user: "{{user1}}", - content: { - text: "watched 40 hours of it in 2 days", - action: "CONTINUE", - }, - }, - { - user: "{{user2}}", - content: { - text: "damn, u ok", - }, - }, - { - user: "{{user1}}", - content: { - text: "surprisingly yes", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "just found out theres a sequel, gg", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "i'm thinking of adopting a pet soon", - }, - }, - { - user: "{{user2}}", - content: { - text: "what kind of pet", - }, - }, - { - user: "{{user1}}", - content: { - text: "i'm leaning towards a cat", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "it'd be hard to take care of a dog in the city", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "i've been experimenting with vegan recipes lately", - }, - }, - { - user: "{{user2}}", - content: { - text: "no thanks", - }, - }, - { - user: "{{user1}}", - content: { - text: "no seriously, its so dank", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "you gotta try some of my food when you come out", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "so i've been diving into photography as a new hobby", - }, - }, - { - user: "{{user2}}", - content: { - text: "oh awesome, what do you enjoy taking photos of", - }, - }, - { - user: "{{user1}}", - content: { - text: "mostly nature and urban landscapes", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "there's something peaceful about capturing the world through a lens", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "i've been getting back into indie music", - }, - }, - { - user: "{{user2}}", - content: { - text: "what have you been listening to", - }, - }, - { - user: "{{user1}}", - content: { - text: "a bunch of random stuff i'd never heard before", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "i'll send you a playlist", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "i used to live in the city", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "bad traffic, bad air quality, tons of homeless people, no thx", - }, - }, - { - user: "{{user2}}", - content: { - text: "ok dood", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "you kids today dont know the value of hard work", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "always on your phones", - }, - }, - { - user: "{{user2}}", - content: { - text: "sure grandpa lets get you to bed", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "hey fren r u ok", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "u look sad", - }, - }, - { - user: "{{user2}}", - content: { - text: "im ok sweetie mommy just tired", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "helo fr om mars", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "i com in pes", - }, - }, - { - user: "{{user2}}", - content: { - text: "wat", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "Yeah no worries, I get it, I've been crazy busy too", - }, - }, - { - user: "{{user2}}", - content: { - text: "What have you been up to", - action: "CONTINUE", - }, - }, - { - user: "{{user2}}", - content: { - text: "Anything fun or just the usual", - }, - }, - { - user: "{{user1}}", - content: { - text: "Been working on a new FPS game actually", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "Just toying around with something in three.js nothing serious", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "Oh no, what happened", - action: "CONTINUE", - }, - }, - { - user: "{{user1}}", - content: { - text: "Did Mara leave you kek", - }, - }, - { - user: "{{user2}}", - content: { - text: "wtf no, I got into an argument with my roommate", - action: "CONTINUE", - }, - }, - { - user: "{{user2}}", - content: { - text: "Living with people is just hard", - }, - }, - ], - ] as ActionExample[][], -} as Action; diff --git a/packages/plugin-gecko/src/actions/index.ts b/packages/plugin-gecko/src/actions/index.ts deleted file mode 100644 index 54202abb1b..0000000000 --- a/packages/plugin-gecko/src/actions/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./fetchInfo.ts"; diff --git a/packages/plugin-gecko/src/actions/price.ts b/packages/plugin-gecko/src/actions/price.ts new file mode 100644 index 0000000000..0278c1d4a8 --- /dev/null +++ b/packages/plugin-gecko/src/actions/price.ts @@ -0,0 +1,176 @@ +import { + Action, + elizaLogger, + IAgentRuntime, + Memory, + HandlerCallback, + State, + composeContext, + generateObject, + ModelClass, +} from "@ai16z/eliza"; +import { coingeckoProvider } from "../providers/coins"; +import { + PriceLookupContent, + PriceLookupSchema, + isPriceLookupContent, +} from "../types"; +import type { PriceResponse } from "../types"; + +export const getPriceAction: Action = { + name: "GET_COIN_PRICE", + description: + "Get the current USD price for a specified cryptocurrency using CoinGecko API.", + validate: async (runtime: IAgentRuntime, _message: Memory) => { + elizaLogger.log("Validating runtime for GET_COIN_PRICE..."); + return !!( + runtime.getSetting("COINGECKO_API_KEY") || + process.env.COINGECKO_API_KEY + ); + }, + handler: async ( + runtime: IAgentRuntime, + _message: Memory, + state: State, + _options: any, + callback: HandlerCallback + ) => { + elizaLogger.log("Starting GET_COIN_PRICE handler..."); + + try { + const apiKey = + runtime.getSetting("COINGECKO_API_KEY") ?? + process.env.COINGECKO_API_KEY; + + // Get the list of supported coins first + const { supportedCoins } = await coingeckoProvider.get( + runtime, + _message + ); + + // Generate the coin name from the message context + const context = composeContext({ + state, + template: "Get price for {{coinName}}", + }); + + const priceRequest = await generateObject({ + runtime, + context, + modelClass: ModelClass.LARGE, + schema: PriceLookupSchema, + }); + + if (!isPriceLookupContent(priceRequest.object)) { + callback( + { + text: "Invalid coin name specified.", + }, + [] + ); + return; + } + + const searchTerm = priceRequest.object.coinName.toLowerCase(); + + // Find the coin in our supported coins list + const coin = supportedCoins.find( + (c) => + c.id === searchTerm || + c.symbol === searchTerm || + c.name === searchTerm + ); + + if (!coin) { + callback( + { + text: `Could not find coin "${searchTerm}" in CoinGecko's supported coins list.`, + }, + [] + ); + return; + } + + // Fetch the price + const priceUrl = `https://api.coingecko.com/api/v3/simple/price?ids=${coin.id}&vs_currencies=usd`; + const priceResponse = await fetch(priceUrl, { + method: "GET", + headers: { + accept: "application/json", + "x-cg-demo-api-key": apiKey, + }, + }); + + if (!priceResponse.ok) { + throw new Error(`HTTP error! status: ${priceResponse.status}`); + } + + const priceData: PriceResponse = await priceResponse.json(); + const price = priceData[coin.id]?.usd; + + if (typeof price !== "number") { + callback( + { + text: `Unable to fetch price for ${coin.name} (${coin.symbol}).`, + }, + [] + ); + return; + } + + callback( + { + text: `Current price for ${coin.name} (${coin.symbol.toUpperCase()}): $${price.toFixed(2)} USD`, + }, + [] + ); + } catch (error) { + elizaLogger.error("Error during price lookup:", error); + callback( + { + text: "Failed to fetch coin price. Please check the logs for more details.", + }, + [] + ); + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "What's the current price of Bitcoin?", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Current price for Bitcoin (BTC): $45,123.45 USD", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Show me ETH price", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Current price for Ethereum (ETH): $2,456.78 USD", + }, + }, + ], + ], + similes: [ + "GET_COIN_PRICE", + "FETCH_CRYPTO_PRICE", + "CHECK_TOKEN_PRICE", + "LOOKUP_COIN_VALUE", + "GET_TOKEN_PRICE", + "CHECK_CRYPTO_PRICE", + "FETCH_TOKEN_VALUE", + ], +}; diff --git a/packages/plugin-gecko/src/index.ts b/packages/plugin-gecko/src/index.ts index 746fc6c548..7efd3eb4a3 100644 --- a/packages/plugin-gecko/src/index.ts +++ b/packages/plugin-gecko/src/index.ts @@ -1,16 +1,16 @@ -import { Plugin } from "@ai16z/eliza"; -import { continueAction } from "./actions/fetchInfo.ts"; +export * from "./actions/price"; +export * from "./providers/coins"; +export * from "./types"; -import { timeProvider } from "./providers/coinList.ts"; +import type { Plugin } from "@ai16z/eliza"; +import { getPriceAction } from "./actions/price"; +import { coingeckoProvider } from "./providers/coins"; -export * as actions from "./actions/index.ts"; -export * as evaluators from "./evaluators/index.ts"; -export * as providers from "./providers/index.ts"; - -export const geckoPlugin: Plugin = { - name: "gecko", - description: "Agent gecko with basic actions and evaluators", - actions: [fetchInfo], +export const coingeckoPlugin: Plugin = { + name: "coingecko", + description: "CoinGecko cryptocurrency price integration plugin", + providers: [coingeckoProvider], evaluators: [], - providers: [coinList], + services: [], + actions: [getPriceAction], }; diff --git a/packages/plugin-gecko/src/providers/coinList.ts b/packages/plugin-gecko/src/providers/coinList.ts deleted file mode 100644 index ceb6f4a869..0000000000 --- a/packages/plugin-gecko/src/providers/coinList.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza"; - -const timeProvider: Provider = { - get: async (_runtime: IAgentRuntime, _message: Memory, _state?: State) => { - const currentDate = new Date(); - - // Get UTC time since bots will be communicating with users around the global - const options = { - timeZone: "UTC", - dateStyle: "full" as const, - timeStyle: "long" as const, - }; - const humanReadable = new Intl.DateTimeFormat("en-US", options).format( - currentDate - ); - return `The current date and time is ${humanReadable}. Please use this as your reference for any time-based operations or responses.`; - }, -}; -export { timeProvider }; diff --git a/packages/plugin-gecko/src/providers/coins.ts b/packages/plugin-gecko/src/providers/coins.ts new file mode 100644 index 0000000000..d7d8baf073 --- /dev/null +++ b/packages/plugin-gecko/src/providers/coins.ts @@ -0,0 +1,39 @@ +import { elizaLogger, IAgentRuntime, Memory, Provider } from "@ai16z/eliza"; +import type { CoinListEntry } from "../types"; + +export const coingeckoProvider: Provider = { + get: async (runtime: IAgentRuntime, _message: Memory) => { + try { + const apiKey = + runtime.getSetting("COINGECKO_API_KEY") ?? + process.env.COINGECKO_API_KEY; + + const url = "https://api.coingecko.com/api/v3/coins/list"; + const response = await fetch(url, { + method: "GET", + headers: { + accept: "application/json", + "x-cg-demo-api-key": apiKey, + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const coins: CoinListEntry[] = await response.json(); + elizaLogger.log("Fetched coin list, total coins:", coins.length); + + return { + supportedCoins: coins.map((coin) => ({ + id: coin.id, + symbol: coin.symbol.toLowerCase(), + name: coin.name.toLowerCase(), + })), + }; + } catch (error) { + elizaLogger.error("Error in coingeckoProvider:", error); + return { supportedCoins: [] }; + } + }, +}; diff --git a/packages/plugin-gecko/src/providers/index.ts b/packages/plugin-gecko/src/providers/index.ts deleted file mode 100644 index cdf4f2563e..0000000000 --- a/packages/plugin-gecko/src/providers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./coinList.ts"; diff --git a/packages/plugin-gecko/src/types.ts b/packages/plugin-gecko/src/types.ts new file mode 100644 index 0000000000..7c2169eb3f --- /dev/null +++ b/packages/plugin-gecko/src/types.ts @@ -0,0 +1,29 @@ +export interface CoinListEntry { + id: string; + symbol: string; + name: string; +} + +export interface PriceResponse { + [key: string]: { + usd: number; + }; +} + +export const PriceLookupSchema = { + type: "object", + properties: { + coinName: { type: "string" }, + }, + required: ["coinName"], +}; + +export interface PriceLookupContent { + coinName: string; +} + +export const isPriceLookupContent = ( + content: any +): content is PriceLookupContent => { + return typeof content === "object" && typeof content.coinName === "string"; +}; From 359cf721bd07340dd9ba98cec148fce611bee257 Mon Sep 17 00:00:00 2001 From: "Mark.B" Date: Sat, 21 Dec 2024 00:24:42 +0100 Subject: [PATCH 03/29] add gecko to packages --- agent/package.json | 121 +++++++++++++++++++++++---------------------- agent/src/index.ts | 11 +++-- 2 files changed, 67 insertions(+), 65 deletions(-) diff --git a/agent/package.json b/agent/package.json index 3f25e7b553..d706dbd97c 100644 --- a/agent/package.json +++ b/agent/package.json @@ -1,61 +1,62 @@ { - "name": "@ai16z/agent", - "version": "0.1.6-alpha.4", - "main": "src/index.ts", - "type": "module", - "scripts": { - "start": "node --loader ts-node/esm src/index.ts", - "dev": "node --loader ts-node/esm src/index.ts", - "check-types": "tsc --noEmit" - }, - "nodemonConfig": { - "watch": [ - "src", - "../core/dist" - ], - "ext": "ts,json", - "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" - }, - "dependencies": { - "@ai16z/adapter-postgres": "workspace:*", - "@ai16z/adapter-sqlite": "workspace:*", - "@ai16z/client-auto": "workspace:*", - "@ai16z/client-direct": "workspace:*", - "@ai16z/client-discord": "workspace:*", - "@ai16z/client-farcaster": "workspace:*", - "@ai16z/client-lens": "workspace:*", - "@ai16z/client-telegram": "workspace:*", - "@ai16z/client-twitter": "workspace:*", - "@ai16z/client-slack": "workspace:*", - "@ai16z/eliza": "workspace:*", - "@ai16z/plugin-0g": "workspace:*", - "@ai16z/plugin-aptos": "workspace:*", - "@ai16z/plugin-bootstrap": "workspace:*", - "@ai16z/plugin-intiface": "workspace:*", - "@ai16z/plugin-coinbase": "workspace:*", - "@ai16z/plugin-conflux": "workspace:*", - "@ai16z/plugin-evm": "workspace:*", - "@ai16z/plugin-flow": "workspace:*", - "@ai16z/plugin-story": "workspace:*", - "@ai16z/plugin-goat": "workspace:*", - "@ai16z/plugin-icp": "workspace:*", - "@ai16z/plugin-image-generation": "workspace:*", - "@ai16z/plugin-nft-generation": "workspace:*", - "@ai16z/plugin-node": "workspace:*", - "@ai16z/plugin-solana": "workspace:*", - "@ai16z/plugin-starknet": "workspace:*", - "@ai16z/plugin-ton": "workspace:*", - "@ai16z/plugin-sui": "workspace:*", - "@ai16z/plugin-tee": "workspace:*", - "@ai16z/plugin-multiversx": "workspace:*", - "@ai16z/plugin-near": "workspace:*", - "@ai16z/plugin-zksync-era": "workspace:*", - "readline": "1.3.0", - "ws": "8.18.0", - "yargs": "17.7.2" - }, - "devDependencies": { - "ts-node": "10.9.2", - "tsup": "8.3.5" - } -} + "name": "@ai16z/agent", + "version": "0.1.6-alpha.4", + "main": "src/index.ts", + "type": "module", + "scripts": { + "start": "node --loader ts-node/esm src/index.ts", + "dev": "node --loader ts-node/esm src/index.ts", + "check-types": "tsc --noEmit" + }, + "nodemonConfig": { + "watch": [ + "src", + "../core/dist" + ], + "ext": "ts,json", + "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" + }, + "dependencies": { + "@ai16z/adapter-postgres": "workspace:*", + "@ai16z/adapter-sqlite": "workspace:*", + "@ai16z/client-auto": "workspace:*", + "@ai16z/client-direct": "workspace:*", + "@ai16z/client-discord": "workspace:*", + "@ai16z/client-farcaster": "workspace:*", + "@ai16z/client-lens": "workspace:*", + "@ai16z/client-telegram": "workspace:*", + "@ai16z/client-twitter": "workspace:*", + "@ai16z/client-slack": "workspace:*", + "@ai16z/eliza": "workspace:*", + "@ai16z/plugin-0g": "workspace:*", + "@ai16z/plugin-aptos": "workspace:*", + "@ai16z/plugin-bootstrap": "workspace:*", + "@ai16z/plugin-intiface": "workspace:*", + "@ai16z/plugin-coinbase": "workspace:*", + "@ai16z/plugin-conflux": "workspace:*", + "@ai16z/plugin-evm": "workspace:*", + "@ai16z/plugin-flow": "workspace:*", + "@ai16z/plugin-story": "workspace:*", + "@ai16z/plugin-goat": "workspace:*", + "@ai16z/plugin-gecko": "workspace:*", + "@ai16z/plugin-icp": "workspace:*", + "@ai16z/plugin-image-generation": "workspace:*", + "@ai16z/plugin-nft-generation": "workspace:*", + "@ai16z/plugin-node": "workspace:*", + "@ai16z/plugin-solana": "workspace:*", + "@ai16z/plugin-starknet": "workspace:*", + "@ai16z/plugin-ton": "workspace:*", + "@ai16z/plugin-sui": "workspace:*", + "@ai16z/plugin-tee": "workspace:*", + "@ai16z/plugin-multiversx": "workspace:*", + "@ai16z/plugin-near": "workspace:*", + "@ai16z/plugin-zksync-era": "workspace:*", + "readline": "1.3.0", + "ws": "8.18.0", + "yargs": "17.7.2" + }, + "devDependencies": { + "ts-node": "10.9.2", + "tsup": "8.3.5" + } +} \ No newline at end of file diff --git a/agent/src/index.ts b/agent/src/index.ts index c42c92bdaf..700bade3bf 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -41,6 +41,7 @@ import { } from "@ai16z/plugin-coinbase"; import { confluxPlugin } from "@ai16z/plugin-conflux"; import { evmPlugin } from "@ai16z/plugin-evm"; +import { gecko } from "@ai16z/plugin-gecko"; import { storyPlugin } from "@ai16z/plugin-story"; import { flowPlugin } from "@ai16z/plugin-flow"; import { imageGenerationPlugin } from "@ai16z/plugin-image-generation"; @@ -210,11 +211,11 @@ export async function loadCharacters( export function getTokenForProvider( provider: ModelProviderName, character: Character -):string { +): string { switch (provider) { // no key needed for llama_local case ModelProviderName.LLAMALOCAL: - return '' + return ""; case ModelProviderName.OPENAI: return ( character.settings?.secrets?.OPENAI_API_KEY || @@ -310,9 +311,9 @@ export function getTokenForProvider( settings.AKASH_CHAT_API_KEY ); default: - const errorMessage = `Failed to get token - unsupported model provider: ${provider}` - elizaLogger.error(errorMessage) - throw new Error(errorMessage) + const errorMessage = `Failed to get token - unsupported model provider: ${provider}`; + elizaLogger.error(errorMessage); + throw new Error(errorMessage); } } From 3aa5eecc1e0fbd4352c228a7067ebab61124fd3a Mon Sep 17 00:00:00 2001 From: "Mark.B" Date: Sat, 21 Dec 2024 00:30:03 +0100 Subject: [PATCH 04/29] add proper definitions and types --- packages/plugin-gecko/src/actions/price.ts | 13 ++++++------- packages/plugin-gecko/src/index.ts | 2 ++ packages/plugin-gecko/src/types.ts | 22 ++++++---------------- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/packages/plugin-gecko/src/actions/price.ts b/packages/plugin-gecko/src/actions/price.ts index 0278c1d4a8..818ac158ab 100644 --- a/packages/plugin-gecko/src/actions/price.ts +++ b/packages/plugin-gecko/src/actions/price.ts @@ -10,12 +10,9 @@ import { ModelClass, } from "@ai16z/eliza"; import { coingeckoProvider } from "../providers/coins"; -import { - PriceLookupContent, - PriceLookupSchema, - isPriceLookupContent, -} from "../types"; +import { PriceLookupContent, PriceLookupSchema } from "../types"; import type { PriceResponse } from "../types"; +import { z } from "zod"; export const getPriceAction: Action = { name: "GET_COIN_PRICE", @@ -61,7 +58,9 @@ export const getPriceAction: Action = { schema: PriceLookupSchema, }); - if (!isPriceLookupContent(priceRequest.object)) { + const result = PriceLookupSchema.safeParse(priceRequest.object); + + if (!result.success) { callback( { text: "Invalid coin name specified.", @@ -71,7 +70,7 @@ export const getPriceAction: Action = { return; } - const searchTerm = priceRequest.object.coinName.toLowerCase(); + const searchTerm = result.data.coinName.toLowerCase(); // Find the coin in our supported coins list const coin = supportedCoins.find( diff --git a/packages/plugin-gecko/src/index.ts b/packages/plugin-gecko/src/index.ts index 7efd3eb4a3..1a68dec70c 100644 --- a/packages/plugin-gecko/src/index.ts +++ b/packages/plugin-gecko/src/index.ts @@ -14,3 +14,5 @@ export const coingeckoPlugin: Plugin = { services: [], actions: [getPriceAction], }; + +export default coingeckoPlugin; diff --git a/packages/plugin-gecko/src/types.ts b/packages/plugin-gecko/src/types.ts index 7c2169eb3f..c29a5c5e3b 100644 --- a/packages/plugin-gecko/src/types.ts +++ b/packages/plugin-gecko/src/types.ts @@ -1,3 +1,5 @@ +import { z } from "zod"; + export interface CoinListEntry { id: string; symbol: string; @@ -10,20 +12,8 @@ export interface PriceResponse { }; } -export const PriceLookupSchema = { - type: "object", - properties: { - coinName: { type: "string" }, - }, - required: ["coinName"], -}; - -export interface PriceLookupContent { - coinName: string; -} +export const PriceLookupSchema = z.object({ + coinName: z.string(), +}); -export const isPriceLookupContent = ( - content: any -): content is PriceLookupContent => { - return typeof content === "object" && typeof content.coinName === "string"; -}; +export type PriceLookupContent = z.infer; From f6f01d88f9b830658a7b4adaf9e44ce8c3d7910d Mon Sep 17 00:00:00 2001 From: "Mark.B" Date: Sun, 22 Dec 2024 13:30:51 +0100 Subject: [PATCH 05/29] add all the code work gecko plugin --- agent/src/index.ts | 3 +- characters/c3po.character.json | 2 +- characters/dobby.character.json | 2 +- packages/plugin-gecko/src/actions/price.ts | 145 +++++++++++++++---- packages/plugin-gecko/src/providers/coins.ts | 2 +- packages/plugin-gecko/src/types.ts | 1 + 6 files changed, 123 insertions(+), 32 deletions(-) diff --git a/agent/src/index.ts b/agent/src/index.ts index 700bade3bf..7c923fd459 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -41,7 +41,7 @@ import { } from "@ai16z/plugin-coinbase"; import { confluxPlugin } from "@ai16z/plugin-conflux"; import { evmPlugin } from "@ai16z/plugin-evm"; -import { gecko } from "@ai16z/plugin-gecko"; +import { coingeckoPlugin } from "@ai16z/plugin-gecko"; import { storyPlugin } from "@ai16z/plugin-story"; import { flowPlugin } from "@ai16z/plugin-flow"; import { imageGenerationPlugin } from "@ai16z/plugin-image-generation"; @@ -506,6 +506,7 @@ export async function createAgent( getSecret(character, "NEAR_WALLET_SECRET_KEY") ? nearPlugin : null, + getSecret(character, "COINGECKO_API_KEY") ? coingeckoPlugin : null, getSecret(character, "EVM_PUBLIC_KEY") || (getSecret(character, "WALLET_PUBLIC_KEY") && getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x")) diff --git a/characters/c3po.character.json b/characters/c3po.character.json index dbc1abcb94..9ad21bab97 100644 --- a/characters/c3po.character.json +++ b/characters/c3po.character.json @@ -1,7 +1,7 @@ { "name": "C-3PO", "clients": [], - "modelProvider": "anthropic", + "modelProvider": "openai", "settings": { "voice": { "model": "en_GB-alan-medium" diff --git a/characters/dobby.character.json b/characters/dobby.character.json index 1e025f820b..f23d0f8d6c 100644 --- a/characters/dobby.character.json +++ b/characters/dobby.character.json @@ -1,7 +1,7 @@ { "name": "Dobby", "clients": [], - "modelProvider": "anthropic", + "modelProvider": "openai", "settings": { "voice": { "model": "en_GB-danny-low" diff --git a/packages/plugin-gecko/src/actions/price.ts b/packages/plugin-gecko/src/actions/price.ts index 818ac158ab..cac73e8c7e 100644 --- a/packages/plugin-gecko/src/actions/price.ts +++ b/packages/plugin-gecko/src/actions/price.ts @@ -9,15 +9,40 @@ import { generateObject, ModelClass, } from "@ai16z/eliza"; + import { coingeckoProvider } from "../providers/coins"; -import { PriceLookupContent, PriceLookupSchema } from "../types"; -import type { PriceResponse } from "../types"; -import { z } from "zod"; +import { PriceLookupContent, PriceLookupSchema } from "../types.ts"; +import type { PriceResponse } from "../types.ts"; + +export const priceTemplate = `Use JUST the last message from recent messages +{{recentMessages}} + +Extract ONLY the cryptocurrency name, symbol, or ticker being asked about. Do not include words like "token", "coin", "price", +unless it's part of the name like in "bitcoin" there is a "coin". +Respond with a JSON markdown block containing only the extracted value: + +\`\`\`json +{ +"coinName": string | null +} +\`\`\` +`; + +function formatMarketCap(marketCap: number): string { + if (marketCap >= 1_000_000_000) { + return `${(marketCap / 1_000_000_000).toFixed(1)} billion`; + } else if (marketCap >= 1_000_000) { + return `${(marketCap / 1_000_000).toFixed(1)} million`; + } else if (marketCap >= 1_000) { + return `${(marketCap / 1_000).toFixed(1)} thousand`; + } + return marketCap.toString(); +} export const getPriceAction: Action = { name: "GET_COIN_PRICE", description: - "Get the current USD price for a specified cryptocurrency using CoinGecko API.", + "Get the current USD price and market cap for a specified cryptocurrency using CoinGecko API.", validate: async (runtime: IAgentRuntime, _message: Memory) => { elizaLogger.log("Validating runtime for GET_COIN_PRICE..."); return !!( @@ -45,16 +70,23 @@ export const getPriceAction: Action = { _message ); + // Initialize or update state + if (!state) { + state = (await runtime.composeState(_message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + // Generate the coin name from the message context const context = composeContext({ state, - template: "Get price for {{coinName}}", + template: priceTemplate, }); const priceRequest = await generateObject({ runtime, context, - modelClass: ModelClass.LARGE, + modelClass: ModelClass.SMALL, schema: PriceLookupSchema, }); @@ -72,15 +104,15 @@ export const getPriceAction: Action = { const searchTerm = result.data.coinName.toLowerCase(); - // Find the coin in our supported coins list - const coin = supportedCoins.find( + // Find all matching coins in our supported coins list + const matchingCoins = supportedCoins.filter( (c) => - c.id === searchTerm || - c.symbol === searchTerm || - c.name === searchTerm + c.id.includes(searchTerm) || + c.symbol.includes(searchTerm) || + c.name.toLowerCase().includes(searchTerm) ); - if (!coin) { + if (matchingCoins.length === 0) { callback( { text: `Could not find coin "${searchTerm}" in CoinGecko's supported coins list.`, @@ -90,8 +122,56 @@ export const getPriceAction: Action = { return; } - // Fetch the price - const priceUrl = `https://api.coingecko.com/api/v3/simple/price?ids=${coin.id}&vs_currencies=usd`; + // If we have multiple matches, we'll need to fetch prices for all of them + const pricePromises = matchingCoins.map(async (coin) => { + const priceUrl = `https://api.coingecko.com/api/v3/simple/price?ids=${coin.id}&vs_currencies=usd&include_market_cap=true`; + const priceResponse = await fetch(priceUrl, { + method: "GET", + headers: { + accept: "application/json", + "x-cg-demo-api-key": apiKey, + }, + }); + + if (!priceResponse.ok) { + return null; + } + + const priceData: PriceResponse = await priceResponse.json(); + return { + coin, + price: priceData[coin.id]?.usd, + marketCap: priceData[coin.id]?.usd_market_cap, + }; + }); + + const priceResults = await Promise.all(pricePromises); + + // Filter out any failed requests and sort by market cap + const validResults = priceResults + .filter( + (result): result is NonNullable => + result !== null && + typeof result.price === "number" && + typeof result.marketCap === "number" + ) + .sort((a, b) => b.marketCap - a.marketCap); + + if (validResults.length === 0) { + callback( + { + text: `Unable to fetch price data for ${searchTerm}.`, + }, + [] + ); + return; + } + + // Use the coin with the highest market cap + const { coin, price, marketCap } = validResults[0]; + + // Format the price and market cap + const priceUrl = `https://api.coingecko.com/api/v3/simple/price?ids=${coin.id}&vs_currencies=usd&include_market_cap=true`; const priceResponse = await fetch(priceUrl, { method: "GET", headers: { @@ -104,22 +184,17 @@ export const getPriceAction: Action = { throw new Error(`HTTP error! status: ${priceResponse.status}`); } - const priceData: PriceResponse = await priceResponse.json(); - const price = priceData[coin.id]?.usd; + const formattedMarketCap = formatMarketCap(marketCap); - if (typeof price !== "number") { - callback( - { - text: `Unable to fetch price for ${coin.name} (${coin.symbol}).`, - }, - [] - ); - return; - } + // If there were multiple matches, add a note about the selection + const multipleMatchesNote = + validResults.length > 1 + ? `\n(Selected based on highest market cap among ${validResults.length} matching coins)` + : ""; callback( { - text: `Current price for ${coin.name} (${coin.symbol.toUpperCase()}): $${price.toFixed(2)} USD`, + text: `Current price for ${coin.name} (${coin.symbol.toUpperCase()}): ${price.toFixed(2)} USD\nMarket Cap: ${formattedMarketCap} USD${multipleMatchesNote}`, }, [] ); @@ -144,7 +219,7 @@ export const getPriceAction: Action = { { user: "{{agentName}}", content: { - text: "Current price for Bitcoin (BTC): $45,123.45 USD", + text: "Current price for Bitcoin (BTC): $45,123.45 USD\nMarket Cap: $876.5 billion USD", }, }, ], @@ -158,7 +233,21 @@ export const getPriceAction: Action = { { user: "{{agentName}}", content: { - text: "Current price for Ethereum (ETH): $2,456.78 USD", + text: "Current price for Ethereum (ETH): $2,456.78 USD\nMarket Cap: $298.4 billion USD", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Show me price for Pendle Token", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Current price for Pendle (PENDLE): $7.89 USD\nMarket Cap: $156.3 million USD", }, }, ], diff --git a/packages/plugin-gecko/src/providers/coins.ts b/packages/plugin-gecko/src/providers/coins.ts index d7d8baf073..cb26dabc2f 100644 --- a/packages/plugin-gecko/src/providers/coins.ts +++ b/packages/plugin-gecko/src/providers/coins.ts @@ -1,5 +1,5 @@ import { elizaLogger, IAgentRuntime, Memory, Provider } from "@ai16z/eliza"; -import type { CoinListEntry } from "../types"; +import type { CoinListEntry } from "../types.ts"; export const coingeckoProvider: Provider = { get: async (runtime: IAgentRuntime, _message: Memory) => { diff --git a/packages/plugin-gecko/src/types.ts b/packages/plugin-gecko/src/types.ts index c29a5c5e3b..697dabec18 100644 --- a/packages/plugin-gecko/src/types.ts +++ b/packages/plugin-gecko/src/types.ts @@ -9,6 +9,7 @@ export interface CoinListEntry { export interface PriceResponse { [key: string]: { usd: number; + usd_market_cap: number; }; } From 85d7826cdd3bfed6032a68a7d02e2250a0e6f486 Mon Sep 17 00:00:00 2001 From: "Mark.B" Date: Sun, 22 Dec 2024 19:49:30 +0100 Subject: [PATCH 06/29] cleanup from redundant code --- packages/plugin-gecko/src/actions/price.ts | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/packages/plugin-gecko/src/actions/price.ts b/packages/plugin-gecko/src/actions/price.ts index cac73e8c7e..cd60a795e5 100644 --- a/packages/plugin-gecko/src/actions/price.ts +++ b/packages/plugin-gecko/src/actions/price.ts @@ -169,21 +169,6 @@ export const getPriceAction: Action = { // Use the coin with the highest market cap const { coin, price, marketCap } = validResults[0]; - - // Format the price and market cap - const priceUrl = `https://api.coingecko.com/api/v3/simple/price?ids=${coin.id}&vs_currencies=usd&include_market_cap=true`; - const priceResponse = await fetch(priceUrl, { - method: "GET", - headers: { - accept: "application/json", - "x-cg-demo-api-key": apiKey, - }, - }); - - if (!priceResponse.ok) { - throw new Error(`HTTP error! status: ${priceResponse.status}`); - } - const formattedMarketCap = formatMarketCap(marketCap); // If there were multiple matches, add a note about the selection @@ -192,9 +177,11 @@ export const getPriceAction: Action = { ? `\n(Selected based on highest market cap among ${validResults.length} matching coins)` : ""; + elizaLogger.log(multipleMatchesNote); + callback( { - text: `Current price for ${coin.name} (${coin.symbol.toUpperCase()}): ${price.toFixed(2)} USD\nMarket Cap: ${formattedMarketCap} USD${multipleMatchesNote}`, + text: `Current price for ${coin.name} (${coin.symbol.toUpperCase()}): ${price.toFixed(2)} USD\nMarket Cap: ${formattedMarketCap} USD`, }, [] ); From aa1736a1ac7d4ef8bd2f70ba5c6d063fc5809e38 Mon Sep 17 00:00:00 2001 From: "Mark.B" Date: Sun, 22 Dec 2024 20:00:48 +0100 Subject: [PATCH 07/29] add readme and .env value example --- .env.example | 3 +++ packages/plugin-gecko/README.md | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 packages/plugin-gecko/README.md diff --git a/.env.example b/.env.example index 0c83f124a0..22f4ceb9fa 100644 --- a/.env.example +++ b/.env.example @@ -332,3 +332,6 @@ STORY_PRIVATE_KEY= # Story private key STORY_API_BASE_URL= # Story API base URL STORY_API_KEY= # Story API key PINATA_JWT= # Pinata JWT for uploading files to IPFS + +#Coingecko +COINGECKO_API_KEY= #your-gecko-key-here \ No newline at end of file diff --git a/packages/plugin-gecko/README.md b/packages/plugin-gecko/README.md new file mode 100644 index 0000000000..b4f231d95e --- /dev/null +++ b/packages/plugin-gecko/README.md @@ -0,0 +1,37 @@ +# `@ai16z/plugin-gecko` + +This plugin provides actions and providers for interacting with CoinGecko API + +--- + +## Configuration + +### Default Setup + +By default, \*_CoinGecko plugin_ is enabled. To use it, simply add your API key to the `.env` file: + +```env +COINGECKO_API_KEY=your-gecko-key-here +``` + +## Provider + +The **Coin Provider** gets the list of all the coins from Gecko API +https://docs.coingecko.com/v3.0.1/reference/coins-list +with its respective id,name and symbol, this can then be used for actions + +--- + +## Actions + +### Price + +Get the current price and market cap of a coin/token from CoingGecko API, provide ticker or name of currency you want: + +**Example usage:** + +```env +Get me price of Pendle token +``` + +--- From 1b29edb8e422cbcf806c751951ed1b3a610da11a Mon Sep 17 00:00:00 2001 From: CardinalError Date: Sun, 22 Dec 2024 21:10:25 +0100 Subject: [PATCH 08/29] add new action, show price per address and base chain --- packages/plugin-gecko/README.md | 6 +- .../src/actions/pricePerAddress.ts | 197 ++++++++++++++++++ packages/plugin-gecko/src/index.ts | 3 +- 3 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 packages/plugin-gecko/src/actions/pricePerAddress.ts diff --git a/packages/plugin-gecko/README.md b/packages/plugin-gecko/README.md index b4f231d95e..84afc346fa 100644 --- a/packages/plugin-gecko/README.md +++ b/packages/plugin-gecko/README.md @@ -1,6 +1,10 @@ # `@ai16z/plugin-gecko` -This plugin provides actions and providers for interacting with CoinGecko API +This plugin provides actions and providers for interacting with CoinGecko API, using free version +https://docs.coingecko.com/v3.0.1/reference/introduction + +to get the Free Public API access, create your API key here +https://www.coingecko.com/en/developers/dashboard --- diff --git a/packages/plugin-gecko/src/actions/pricePerAddress.ts b/packages/plugin-gecko/src/actions/pricePerAddress.ts new file mode 100644 index 0000000000..42567fccbe --- /dev/null +++ b/packages/plugin-gecko/src/actions/pricePerAddress.ts @@ -0,0 +1,197 @@ +import { + Action, + elizaLogger, + IAgentRuntime, + Memory, + HandlerCallback, + State, + composeContext, + generateObject, + ModelClass, +} from "@ai16z/eliza"; + +import { z } from "zod"; + +// Schema for address lookup +const AddressLookupSchema = z.object({ + chainId: z.string(), + tokenAddress: z.string(), +}); + +type AddressLookupContent = z.infer; + +// Template for extracting chain and address +export const addressTemplate = `Use JUST the last message from recent messages +{{recentMessages}} + +Extract the blockchain name/chain ID and token address being asked about. +Normalize chain names: ethereum, polygon, solana, base, etc. +Token address should be the full address string. + +Respond with a JSON markdown block containing the extracted values: + +\`\`\`json +{ +"chainId": string, +"tokenAddress": string +} +\`\`\` +`; + +function formatMarketCap(marketCap: number): string { + if (marketCap >= 1_000_000_000) { + return `${(marketCap / 1_000_000_000).toFixed(1)} billion`; + } else if (marketCap >= 1_000_000) { + return `${(marketCap / 1_000_000).toFixed(1)} million`; + } else if (marketCap >= 1_000) { + return `${(marketCap / 1_000).toFixed(1)} thousand`; + } + return marketCap.toString(); +} + +export const getPriceByAddressAction: Action = { + name: "GET_TOKEN_PRICE_BY_ADDRESS", + description: + "Get the current USD price for a token using its blockchain address via CoinGecko API.", + validate: async (runtime: IAgentRuntime, _message: Memory) => { + elizaLogger.log("Validating runtime for GET_TOKEN_PRICE_BY_ADDRESS..."); + return !!( + runtime.getSetting("COINGECKO_API_KEY") || + process.env.COINGECKO_API_KEY + ); + }, + handler: async ( + runtime: IAgentRuntime, + _message: Memory, + state: State, + _options: any, + callback: HandlerCallback + ) => { + elizaLogger.log("Starting GET_TOKEN_PRICE_BY_ADDRESS handler..."); + + try { + const apiKey = + runtime.getSetting("COINGECKO_API_KEY") ?? + process.env.COINGECKO_API_KEY; + + // Initialize or update state + if (!state) { + state = (await runtime.composeState(_message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + // Generate the address lookup from the message context + const context = composeContext({ + state, + template: addressTemplate, + }); + + const addressRequest = await generateObject({ + runtime, + context, + modelClass: ModelClass.SMALL, + schema: AddressLookupSchema, + }); + + const result = AddressLookupSchema.safeParse(addressRequest.object); + + if (!result.success) { + callback( + { + text: "Invalid chain ID or token address specified.", + }, + [] + ); + return; + } + + const { chainId, tokenAddress } = result.data; + + // Format the URL for token price lookup + const url = `https://api.coingecko.com/api/v3/simple/token_price/${chainId}?contract_addresses=${tokenAddress}&vs_currencies=usd&include_market_cap=true`; + + const priceResponse = await fetch(url, { + method: "GET", + headers: { + accept: "application/json", + "x-cg-demo-api-key": apiKey, + }, + }); + + if (!priceResponse.ok) { + throw new Error(`HTTP error! status: ${priceResponse.status}`); + } + + const priceData = await priceResponse.json(); + const tokenData = priceData[tokenAddress.toLowerCase()]; + + if (!tokenData || !tokenData.usd) { + callback( + { + text: `Unable to fetch price for token address ${tokenAddress} on ${chainId}.`, + }, + [] + ); + return; + } + + const price = tokenData.usd; + const marketCap = tokenData.usd_market_cap; + const formattedMarketCap = marketCap + ? `\nMarket Cap: $${formatMarketCap(marketCap)} USD` + : ""; + + callback( + { + text: `Current price for token (${tokenAddress}) on ${chainId}: $${price.toFixed(6)} USD${formattedMarketCap}`, + }, + [] + ); + } catch (error) { + elizaLogger.error("Error during price lookup:", error); + callback( + { + text: "Failed to fetch token price. Please check the logs for more details.", + }, + [] + ); + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "What's the price of token 0x4f9fd6be4a90f2620860d680c0d4d5fb53d1a825 on ethereum?", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Current price for token (0x4f9fd6be4a90f2620860d680c0d4d5fb53d1a825) on ethereum: $1.234567 USD\nMarket Cap: $45.6 million USD", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Show me the price for 0x2260fac5e5542a773aa44fbcfedf7c193bc2c599 on ethereum", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Current price for token (0x2260fac5e5542a773aa44fbcfedf7c193bc2c599) on ethereum: $42000.123456 USD\nMarket Cap: $2.1 billion USD", + }, + }, + ], + ], + similes: [ + "GET_TOKEN_PRICE_BY_ADDRESS", + "FETCH_TOKEN_PRICE_BY_ADDRESS", + "CHECK_TOKEN_PRICE_BY_ADDRESS", + "LOOKUP_TOKEN_BY_ADDRESS", + ], +}; diff --git a/packages/plugin-gecko/src/index.ts b/packages/plugin-gecko/src/index.ts index 1a68dec70c..46abd5ae6c 100644 --- a/packages/plugin-gecko/src/index.ts +++ b/packages/plugin-gecko/src/index.ts @@ -4,6 +4,7 @@ export * from "./types"; import type { Plugin } from "@ai16z/eliza"; import { getPriceAction } from "./actions/price"; +import { getPriceByAddressAction } from "./actions/pricePerAddress"; import { coingeckoProvider } from "./providers/coins"; export const coingeckoPlugin: Plugin = { @@ -12,7 +13,7 @@ export const coingeckoPlugin: Plugin = { providers: [coingeckoProvider], evaluators: [], services: [], - actions: [getPriceAction], + actions: [getPriceAction, getPriceByAddressAction], }; export default coingeckoPlugin; From c6d4b52b77edb0687e25a153a961b0f6fa612afd Mon Sep 17 00:00:00 2001 From: CardinalError Date: Sun, 22 Dec 2024 21:11:48 +0100 Subject: [PATCH 09/29] add token name --- .../src/actions/pricePerAddress.ts | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/plugin-gecko/src/actions/pricePerAddress.ts b/packages/plugin-gecko/src/actions/pricePerAddress.ts index 42567fccbe..492cb42630 100644 --- a/packages/plugin-gecko/src/actions/pricePerAddress.ts +++ b/packages/plugin-gecko/src/actions/pricePerAddress.ts @@ -108,6 +108,25 @@ export const getPriceByAddressAction: Action = { const { chainId, tokenAddress } = result.data; + // First, fetch token metadata to get the name + const metadataUrl = `https://api.coingecko.com/api/v3/coins/${chainId}/contract/${tokenAddress}`; + const metadataResponse = await fetch(metadataUrl, { + method: "GET", + headers: { + accept: "application/json", + "x-cg-demo-api-key": apiKey, + }, + }); + + let tokenName = null; + let tokenSymbol = null; + + if (metadataResponse.ok) { + const metadata = await metadataResponse.json(); + tokenName = metadata.name; + tokenSymbol = metadata.symbol?.toUpperCase(); + } + // Format the URL for token price lookup const url = `https://api.coingecko.com/api/v3/simple/token_price/${chainId}?contract_addresses=${tokenAddress}&vs_currencies=usd&include_market_cap=true`; @@ -142,9 +161,15 @@ export const getPriceByAddressAction: Action = { ? `\nMarket Cap: $${formatMarketCap(marketCap)} USD` : ""; + // Prepare token identifier string + const tokenIdentifier = + tokenName && tokenSymbol + ? `${tokenName} (${tokenSymbol})` + : `token`; + callback( { - text: `Current price for token (${tokenAddress}) on ${chainId}: $${price.toFixed(6)} USD${formattedMarketCap}`, + text: `Current price for ${tokenIdentifier}\nAddress: ${tokenAddress}\nChain: ${chainId}\nPrice: ${price.toFixed(6)} USD${formattedMarketCap}`, }, [] ); @@ -169,7 +194,7 @@ export const getPriceByAddressAction: Action = { { user: "{{agentName}}", content: { - text: "Current price for token (0x4f9fd6be4a90f2620860d680c0d4d5fb53d1a825) on ethereum: $1.234567 USD\nMarket Cap: $45.6 million USD", + text: "Current price for Compound (COMP)\nAddress: 0x4f9fd6be4a90f2620860d680c0d4d5fb53d1a825\nChain: ethereum\nPrice: $1.234567 USD\nMarket Cap: $45.6 million USD", }, }, ], @@ -183,7 +208,7 @@ export const getPriceByAddressAction: Action = { { user: "{{agentName}}", content: { - text: "Current price for token (0x2260fac5e5542a773aa44fbcfedf7c193bc2c599) on ethereum: $42000.123456 USD\nMarket Cap: $2.1 billion USD", + text: "Current price for Wrapped Bitcoin (WBTC)\nAddress: 0x2260fac5e5542a773aa44fbcfedf7c193bc2c599\nChain: ethereum\nPrice: $42000.123456 USD\nMarket Cap: $2.1 billion USD", }, }, ], From 1d61aec3c2569abea3d5d134b1dde24e7b9b9da8 Mon Sep 17 00:00:00 2001 From: CardinalError Date: Sun, 22 Dec 2024 22:04:46 +0100 Subject: [PATCH 10/29] set types in types file --- .../src/actions/pricePerAddress.ts | 32 ++++++++++++------- packages/plugin-gecko/src/types.ts | 7 ++++ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/plugin-gecko/src/actions/pricePerAddress.ts b/packages/plugin-gecko/src/actions/pricePerAddress.ts index 492cb42630..23e9e8fca1 100644 --- a/packages/plugin-gecko/src/actions/pricePerAddress.ts +++ b/packages/plugin-gecko/src/actions/pricePerAddress.ts @@ -10,15 +10,7 @@ import { ModelClass, } from "@ai16z/eliza"; -import { z } from "zod"; - -// Schema for address lookup -const AddressLookupSchema = z.object({ - chainId: z.string(), - tokenAddress: z.string(), -}); - -type AddressLookupContent = z.infer; +import { AddressLookupSchema, AddressLookupContent } from "../types.ts"; // Template for extracting chain and address export const addressTemplate = `Use JUST the last message from recent messages @@ -106,7 +98,9 @@ export const getPriceByAddressAction: Action = { return; } - const { chainId, tokenAddress } = result.data; + const { chainId: rawChainId, tokenAddress } = result.data; + // Ensure chain ID is lowercase + const chainId = rawChainId.toLowerCase(); // First, fetch token metadata to get the name const metadataUrl = `https://api.coingecko.com/api/v3/coins/${chainId}/contract/${tokenAddress}`; @@ -143,7 +137,23 @@ export const getPriceByAddressAction: Action = { } const priceData = await priceResponse.json(); - const tokenData = priceData[tokenAddress.toLowerCase()]; + + // Try to find the token data regardless of case + let tokenData = + priceData[tokenAddress] || + priceData[tokenAddress.toLowerCase()] || + priceData[tokenAddress.toUpperCase()]; + + // If still not found, try to find by searching through keys + if (!tokenData) { + const priceDataKeys = Object.keys(priceData); + const matchingKey = priceDataKeys.find( + (key) => key.toLowerCase() === tokenAddress.toLowerCase() + ); + if (matchingKey) { + tokenData = priceData[matchingKey]; + } + } if (!tokenData || !tokenData.usd) { callback( diff --git a/packages/plugin-gecko/src/types.ts b/packages/plugin-gecko/src/types.ts index 697dabec18..6434342419 100644 --- a/packages/plugin-gecko/src/types.ts +++ b/packages/plugin-gecko/src/types.ts @@ -18,3 +18,10 @@ export const PriceLookupSchema = z.object({ }); export type PriceLookupContent = z.infer; + +export const AddressLookupSchema = z.object({ + chainId: z.string(), + tokenAddress: z.string(), +}); + +export type AddressLookupContent = z.infer; From e0c39f3d81811fc887f972b1e213ed2f52d61e28 Mon Sep 17 00:00:00 2001 From: CardinalError Date: Mon, 23 Dec 2024 00:30:45 +0100 Subject: [PATCH 11/29] remove obsolete changes --- .env.example | 2 +- characters/c3po.character.json | 2 +- characters/dobby.character.json | 2 +- packages/plugin-gecko/README.md | 12 ++++++++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index 22f4ceb9fa..06362ccac5 100644 --- a/.env.example +++ b/.env.example @@ -334,4 +334,4 @@ STORY_API_KEY= # Story API key PINATA_JWT= # Pinata JWT for uploading files to IPFS #Coingecko -COINGECKO_API_KEY= #your-gecko-key-here \ No newline at end of file +COINGECKO_API_KEY= #your-gecko-key-here diff --git a/characters/c3po.character.json b/characters/c3po.character.json index 9ad21bab97..dbc1abcb94 100644 --- a/characters/c3po.character.json +++ b/characters/c3po.character.json @@ -1,7 +1,7 @@ { "name": "C-3PO", "clients": [], - "modelProvider": "openai", + "modelProvider": "anthropic", "settings": { "voice": { "model": "en_GB-alan-medium" diff --git a/characters/dobby.character.json b/characters/dobby.character.json index f23d0f8d6c..1e025f820b 100644 --- a/characters/dobby.character.json +++ b/characters/dobby.character.json @@ -1,7 +1,7 @@ { "name": "Dobby", "clients": [], - "modelProvider": "openai", + "modelProvider": "anthropic", "settings": { "voice": { "model": "en_GB-danny-low" diff --git a/packages/plugin-gecko/README.md b/packages/plugin-gecko/README.md index 84afc346fa..0f566af194 100644 --- a/packages/plugin-gecko/README.md +++ b/packages/plugin-gecko/README.md @@ -38,4 +38,16 @@ Get the current price and market cap of a coin/token from CoingGecko API, provid Get me price of Pendle token ``` +### Get Price per address + +Get the current price and market cap of a coin/token from CoingGecko API by providing currency address and base platform + +**Example usage:** + +```env +Get me price for 0x4f9fd6be4a90f2620860d680c0d4d5fb53d1a825 on Base + +Get price for HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC on Solana +``` + --- From 08d023d0976be82debd2a181284ebcbbf128882a Mon Sep 17 00:00:00 2001 From: Marko Date: Mon, 23 Dec 2024 15:21:00 +0100 Subject: [PATCH 12/29] proper agent package.json --- agent/package.json | 167 ++++++++++++++------------------------------- 1 file changed, 52 insertions(+), 115 deletions(-) diff --git a/agent/package.json b/agent/package.json index 7f0b673390..671075e5b8 100644 --- a/agent/package.json +++ b/agent/package.json @@ -1,126 +1,63 @@ { -<<<<<<< HEAD - "name": "@ai16z/agent", - "version": "0.1.6-alpha.4", + "name": "@elizaos/agent", + "version": "0.1.7-alpha.1", "main": "src/index.ts", "type": "module", "scripts": { - "start": "node --loader ts-node/esm src/index.ts", - "dev": "node --loader ts-node/esm src/index.ts", - "check-types": "tsc --noEmit" + "start": "node --loader ts-node/esm src/index.ts", + "dev": "node --loader ts-node/esm src/index.ts", + "check-types": "tsc --noEmit" }, "nodemonConfig": { - "watch": [ - "src", - "../core/dist" - ], - "ext": "ts,json", - "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" + "watch": [ + "src", + "../core/dist" + ], + "ext": "ts,json", + "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" }, "dependencies": { - "@ai16z/adapter-postgres": "workspace:*", - "@ai16z/adapter-sqlite": "workspace:*", - "@ai16z/client-auto": "workspace:*", - "@ai16z/client-direct": "workspace:*", - "@ai16z/client-discord": "workspace:*", - "@ai16z/client-farcaster": "workspace:*", - "@ai16z/client-lens": "workspace:*", - "@ai16z/client-telegram": "workspace:*", - "@ai16z/client-twitter": "workspace:*", - "@ai16z/client-slack": "workspace:*", - "@ai16z/eliza": "workspace:*", - "@ai16z/plugin-0g": "workspace:*", - "@ai16z/plugin-aptos": "workspace:*", - "@ai16z/plugin-bootstrap": "workspace:*", - "@ai16z/plugin-intiface": "workspace:*", - "@ai16z/plugin-coinbase": "workspace:*", - "@ai16z/plugin-conflux": "workspace:*", - "@ai16z/plugin-evm": "workspace:*", - "@ai16z/plugin-flow": "workspace:*", - "@ai16z/plugin-story": "workspace:*", - "@ai16z/plugin-goat": "workspace:*", - "@ai16z/plugin-gecko": "workspace:*", - "@ai16z/plugin-icp": "workspace:*", - "@ai16z/plugin-image-generation": "workspace:*", - "@ai16z/plugin-nft-generation": "workspace:*", - "@ai16z/plugin-node": "workspace:*", - "@ai16z/plugin-solana": "workspace:*", - "@ai16z/plugin-starknet": "workspace:*", - "@ai16z/plugin-ton": "workspace:*", - "@ai16z/plugin-sui": "workspace:*", - "@ai16z/plugin-tee": "workspace:*", - "@ai16z/plugin-multiversx": "workspace:*", - "@ai16z/plugin-near": "workspace:*", - "@ai16z/plugin-zksync-era": "workspace:*", - "readline": "1.3.0", - "ws": "8.18.0", - "yargs": "17.7.2" + "@elizaos/adapter-postgres": "workspace:*", + "@elizaos/adapter-redis": "workspace:*", + "@elizaos/adapter-sqlite": "workspace:*", + "@elizaos/client-auto": "workspace:*", + "@elizaos/client-direct": "workspace:*", + "@elizaos/client-discord": "workspace:*", + "@elizaos/client-farcaster": "workspace:*", + "@elizaos/client-lens": "workspace:*", + "@elizaos/client-telegram": "workspace:*", + "@elizaos/client-twitter": "workspace:*", + "@elizaos/client-slack": "workspace:*", + "@elizaos/core": "workspace:*", + "@elizaos/plugin-0g": "workspace:*", + "@elizaos/plugin-aptos": "workspace:*", + "@elizaos/plugin-bootstrap": "workspace:*", + "@elizaos/plugin-intiface": "workspace:*", + "@elizaos/plugin-coinbase": "workspace:*", + "@elizaos/plugin-conflux": "workspace:*", + "@elizaos/plugin-gecko": "workspace:*", + "@elizaos/plugin-evm": "workspace:*", + "@elizaos/plugin-flow": "workspace:*", + "@elizaos/plugin-story": "workspace:*", + "@elizaos/plugin-goat": "workspace:*", + "@elizaos/plugin-icp": "workspace:*", + "@elizaos/plugin-image-generation": "workspace:*", + "@elizaos/plugin-nft-generation": "workspace:*", + "@elizaos/plugin-node": "workspace:*", + "@elizaos/plugin-solana": "workspace:*", + "@elizaos/plugin-starknet": "workspace:*", + "@elizaos/plugin-ton": "workspace:*", + "@elizaos/plugin-sui": "workspace:*", + "@elizaos/plugin-tee": "workspace:*", + "@elizaos/plugin-multiversx": "workspace:*", + "@elizaos/plugin-near": "workspace:*", + "@elizaos/plugin-zksync-era": "workspace:*", + "readline": "1.3.0", + "ws": "8.18.0", + "yargs": "17.7.2" }, "devDependencies": { - "ts-node": "10.9.2", - "tsup": "8.3.5" + "ts-node": "10.9.2", + "tsup": "8.3.5" } -} -======= - "name": "@elizaos/agent", - "version": "0.1.7-alpha.1", - "main": "src/index.ts", - "type": "module", - "scripts": { - "start": "node --loader ts-node/esm src/index.ts", - "dev": "node --loader ts-node/esm src/index.ts", - "check-types": "tsc --noEmit" - }, - "nodemonConfig": { - "watch": [ - "src", - "../core/dist" - ], - "ext": "ts,json", - "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" - }, - "dependencies": { - "@elizaos/adapter-postgres": "workspace:*", - "@elizaos/adapter-redis": "workspace:*", - "@elizaos/adapter-sqlite": "workspace:*", - "@elizaos/client-auto": "workspace:*", - "@elizaos/client-direct": "workspace:*", - "@elizaos/client-discord": "workspace:*", - "@elizaos/client-farcaster": "workspace:*", - "@elizaos/client-lens": "workspace:*", - "@elizaos/client-telegram": "workspace:*", - "@elizaos/client-twitter": "workspace:*", - "@elizaos/client-slack": "workspace:*", - "@elizaos/core": "workspace:*", - "@elizaos/plugin-0g": "workspace:*", - "@elizaos/plugin-aptos": "workspace:*", - "@elizaos/plugin-bootstrap": "workspace:*", - "@elizaos/plugin-intiface": "workspace:*", - "@elizaos/plugin-coinbase": "workspace:*", - "@elizaos/plugin-conflux": "workspace:*", - "@elizaos/plugin-evm": "workspace:*", - "@elizaos/plugin-flow": "workspace:*", - "@elizaos/plugin-story": "workspace:*", - "@elizaos/plugin-goat": "workspace:*", - "@elizaos/plugin-icp": "workspace:*", - "@elizaos/plugin-image-generation": "workspace:*", - "@elizaos/plugin-nft-generation": "workspace:*", - "@elizaos/plugin-node": "workspace:*", - "@elizaos/plugin-solana": "workspace:*", - "@elizaos/plugin-starknet": "workspace:*", - "@elizaos/plugin-ton": "workspace:*", - "@elizaos/plugin-sui": "workspace:*", - "@elizaos/plugin-tee": "workspace:*", - "@elizaos/plugin-multiversx": "workspace:*", - "@elizaos/plugin-near": "workspace:*", - "@elizaos/plugin-zksync-era": "workspace:*", - "readline": "1.3.0", - "ws": "8.18.0", - "yargs": "17.7.2" - }, - "devDependencies": { - "ts-node": "10.9.2", - "tsup": "8.3.5" - } -} ->>>>>>> develop + } \ No newline at end of file From d404d82b1725ff4e146f29e720758e8626b0677d Mon Sep 17 00:00:00 2001 From: Marko Date: Mon, 23 Dec 2024 15:21:42 +0100 Subject: [PATCH 13/29] proper root package.json --- package.json | 121 +++++++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 57 deletions(-) diff --git a/package.json b/package.json index 2805f8b1f1..3697909798 100644 --- a/package.json +++ b/package.json @@ -1,63 +1,70 @@ { - "name": "@elizaos/agent", - "version": "0.1.7-alpha.1", - "main": "src/index.ts", - "type": "module", + "name": "eliza", "scripts": { - "start": "node --loader ts-node/esm src/index.ts", - "dev": "node --loader ts-node/esm src/index.ts", - "check-types": "tsc --noEmit" + "preinstall": "npx only-allow pnpm", + "build": "turbo run build --filter=!eliza-docs", + "build-docker": "turbo run build", + "start": "pnpm --filter \"@elizaos/agent\" start --isRoot", + "start:client": "pnpm --dir client dev", + "start:debug": "cross-env NODE_ENV=development VERBOSE=true DEBUG=eliza:* pnpm --filter \"@elizaos/agent\" start --isRoot", + "dev": "bash ./scripts/dev.sh", + "lint": "bash ./scripts/lint.sh", + "prettier-check": "npx prettier --check --cache .", + "prettier": "npx prettier --write --cache .", + "release": "pnpm build && pnpm prettier && npx lerna publish --no-private --force-publish", + "clean": "bash ./scripts/clean.sh", + "docker:build": "bash ./scripts/docker.sh build", + "docker:run": "bash ./scripts/docker.sh run", + "docker:bash": "bash ./scripts/docker.sh bash", + "docker:start": "bash ./scripts/docker.sh start", + "docker": "pnpm docker:build && pnpm docker:run && pnpm docker:bash", + "test": "bash ./scripts/test.sh", + "smokeTests": "bash ./scripts/smokeTests.sh", + "integrationTests": "bash ./scripts/integrationTests.sh" }, - "nodemonConfig": { - "watch": [ - "src", - "../core/dist" - ], - "ext": "ts,json", - "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" + "devDependencies": { + "@commitlint/cli": "18.6.1", + "@commitlint/config-conventional": "18.6.3", + "@typescript-eslint/eslint-plugin": "8.16.0", + "@typescript-eslint/parser": "8.16.0", + "@vitest/eslint-plugin": "1.1.13", + "concurrently": "9.1.0", + "cross-env": "7.0.3", + "eslint": "9.16.0", + "eslint-config-prettier": "9.1.0", + "husky": "9.1.7", + "lerna": "8.1.5", + "only-allow": "1.2.1", + "prettier": "3.4.1", + "turbo": "2.3.3", + "typedoc": "0.26.11", + "typescript": "5.6.3", + "vite": "5.4.11", + "vitest": "2.1.5" + }, + "pnpm": { + "overrides": { + "onnxruntime-node": "1.20.1" + } + }, + "engines": { + "node": "23.3.0" }, "dependencies": { - "@elizaos/adapter-postgres": "workspace:*", - "@elizaos/adapter-redis": "workspace:*", - "@elizaos/adapter-sqlite": "workspace:*", - "@elizaos/client-auto": "workspace:*", - "@elizaos/client-direct": "workspace:*", - "@elizaos/client-discord": "workspace:*", - "@elizaos/client-farcaster": "workspace:*", - "@elizaos/client-lens": "workspace:*", - "@elizaos/client-telegram": "workspace:*", - "@elizaos/client-twitter": "workspace:*", - "@elizaos/client-slack": "workspace:*", - "@elizaos/core": "workspace:*", - "@elizaos/plugin-0g": "workspace:*", - "@elizaos/plugin-aptos": "workspace:*", - "@elizaos/plugin-bootstrap": "workspace:*", - "@elizaos/plugin-intiface": "workspace:*", - "@elizaos/plugin-coinbase": "workspace:*", - "@elizaos/plugin-conflux": "workspace:*", - "@elizaos/plugin-evm": "workspace:*", - "@elizaos/plugin-flow": "workspace:*", - "@elizaos/plugin-story": "workspace:*", - "@elizaos/plugin-gecko": "workspace:*", - "@elizaos/plugin-goat": "workspace:*", - "@elizaos/plugin-icp": "workspace:*", - "@elizaos/plugin-image-generation": "workspace:*", - "@elizaos/plugin-nft-generation": "workspace:*", - "@elizaos/plugin-node": "workspace:*", - "@elizaos/plugin-solana": "workspace:*", - "@elizaos/plugin-starknet": "workspace:*", - "@elizaos/plugin-ton": "workspace:*", - "@elizaos/plugin-sui": "workspace:*", - "@elizaos/plugin-tee": "workspace:*", - "@elizaos/plugin-multiversx": "workspace:*", - "@elizaos/plugin-near": "workspace:*", - "@elizaos/plugin-zksync-era": "workspace:*", - "readline": "1.3.0", - "ws": "8.18.0", - "yargs": "17.7.2" + "@0glabs/0g-ts-sdk": "0.2.1", + "@coinbase/coinbase-sdk": "0.10.0", + "@deepgram/sdk": "^3.9.0", + "@vitest/eslint-plugin": "1.0.1", + "amqplib": "0.10.5", + "csv-parse": "5.6.0", + "ollama-ai-provider": "0.16.1", + "optional": "0.1.4", + "pnpm": "9.14.4", + "sharp": "0.33.5", + "tslog": "4.9.3" }, - "devDependencies": { - "ts-node": "10.9.2", - "tsup": "8.3.5" - } - } \ No newline at end of file + "packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee", + "workspaces": [ + "packages/*" + ] +} From 62c26cbebf6894b810dff9e7421a53d6c1b31be5 Mon Sep 17 00:00:00 2001 From: Marko Date: Mon, 23 Dec 2024 15:24:50 +0100 Subject: [PATCH 14/29] adjust formating --- package.json | 120 ++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 64 deletions(-) diff --git a/package.json b/package.json index 3697909798..087b62cdd6 100644 --- a/package.json +++ b/package.json @@ -1,70 +1,62 @@ { - "name": "eliza", + "name": "@elizaos/agent", + "version": "0.1.7-alpha.1", + "main": "src/index.ts", + "type": "module", "scripts": { - "preinstall": "npx only-allow pnpm", - "build": "turbo run build --filter=!eliza-docs", - "build-docker": "turbo run build", - "start": "pnpm --filter \"@elizaos/agent\" start --isRoot", - "start:client": "pnpm --dir client dev", - "start:debug": "cross-env NODE_ENV=development VERBOSE=true DEBUG=eliza:* pnpm --filter \"@elizaos/agent\" start --isRoot", - "dev": "bash ./scripts/dev.sh", - "lint": "bash ./scripts/lint.sh", - "prettier-check": "npx prettier --check --cache .", - "prettier": "npx prettier --write --cache .", - "release": "pnpm build && pnpm prettier && npx lerna publish --no-private --force-publish", - "clean": "bash ./scripts/clean.sh", - "docker:build": "bash ./scripts/docker.sh build", - "docker:run": "bash ./scripts/docker.sh run", - "docker:bash": "bash ./scripts/docker.sh bash", - "docker:start": "bash ./scripts/docker.sh start", - "docker": "pnpm docker:build && pnpm docker:run && pnpm docker:bash", - "test": "bash ./scripts/test.sh", - "smokeTests": "bash ./scripts/smokeTests.sh", - "integrationTests": "bash ./scripts/integrationTests.sh" + "start": "node --loader ts-node/esm src/index.ts", + "dev": "node --loader ts-node/esm src/index.ts", + "check-types": "tsc --noEmit" }, - "devDependencies": { - "@commitlint/cli": "18.6.1", - "@commitlint/config-conventional": "18.6.3", - "@typescript-eslint/eslint-plugin": "8.16.0", - "@typescript-eslint/parser": "8.16.0", - "@vitest/eslint-plugin": "1.1.13", - "concurrently": "9.1.0", - "cross-env": "7.0.3", - "eslint": "9.16.0", - "eslint-config-prettier": "9.1.0", - "husky": "9.1.7", - "lerna": "8.1.5", - "only-allow": "1.2.1", - "prettier": "3.4.1", - "turbo": "2.3.3", - "typedoc": "0.26.11", - "typescript": "5.6.3", - "vite": "5.4.11", - "vitest": "2.1.5" - }, - "pnpm": { - "overrides": { - "onnxruntime-node": "1.20.1" - } - }, - "engines": { - "node": "23.3.0" + "nodemonConfig": { + "watch": [ + "src", + "../core/dist" + ], + "ext": "ts,json", + "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" }, "dependencies": { - "@0glabs/0g-ts-sdk": "0.2.1", - "@coinbase/coinbase-sdk": "0.10.0", - "@deepgram/sdk": "^3.9.0", - "@vitest/eslint-plugin": "1.0.1", - "amqplib": "0.10.5", - "csv-parse": "5.6.0", - "ollama-ai-provider": "0.16.1", - "optional": "0.1.4", - "pnpm": "9.14.4", - "sharp": "0.33.5", - "tslog": "4.9.3" + "@elizaos/adapter-postgres": "workspace:*", + "@elizaos/adapter-redis": "workspace:*", + "@elizaos/adapter-sqlite": "workspace:*", + "@elizaos/client-auto": "workspace:*", + "@elizaos/client-direct": "workspace:*", + "@elizaos/client-discord": "workspace:*", + "@elizaos/client-farcaster": "workspace:*", + "@elizaos/client-lens": "workspace:*", + "@elizaos/client-telegram": "workspace:*", + "@elizaos/client-twitter": "workspace:*", + "@elizaos/client-slack": "workspace:*", + "@elizaos/core": "workspace:*", + "@elizaos/plugin-0g": "workspace:*", + "@elizaos/plugin-aptos": "workspace:*", + "@elizaos/plugin-bootstrap": "workspace:*", + "@elizaos/plugin-intiface": "workspace:*", + "@elizaos/plugin-coinbase": "workspace:*", + "@elizaos/plugin-conflux": "workspace:*", + "@elizaos/plugin-evm": "workspace:*", + "@elizaos/plugin-flow": "workspace:*", + "@elizaos/plugin-story": "workspace:*", + "@elizaos/plugin-goat": "workspace:*", + "@elizaos/plugin-icp": "workspace:*", + "@elizaos/plugin-image-generation": "workspace:*", + "@elizaos/plugin-nft-generation": "workspace:*", + "@elizaos/plugin-node": "workspace:*", + "@elizaos/plugin-solana": "workspace:*", + "@elizaos/plugin-starknet": "workspace:*", + "@elizaos/plugin-ton": "workspace:*", + "@elizaos/plugin-sui": "workspace:*", + "@elizaos/plugin-tee": "workspace:*", + "@elizaos/plugin-multiversx": "workspace:*", + "@elizaos/plugin-near": "workspace:*", + "@elizaos/plugin-zksync-era": "workspace:*", + "readline": "1.3.0", + "ws": "8.18.0", + "yargs": "17.7.2" }, - "packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee", - "workspaces": [ - "packages/*" - ] -} + "devDependencies": { + "ts-node": "10.9.2", + "tsup": "8.3.5" + } + } \ No newline at end of file From 8bd0c159b1a540bb3fa4e45080c7ac95e0c9749e Mon Sep 17 00:00:00 2001 From: Marko Date: Mon, 23 Dec 2024 15:28:53 +0100 Subject: [PATCH 15/29] original package added --- package.json | 120 +++++++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 56 deletions(-) diff --git a/package.json b/package.json index 087b62cdd6..3697909798 100644 --- a/package.json +++ b/package.json @@ -1,62 +1,70 @@ { - "name": "@elizaos/agent", - "version": "0.1.7-alpha.1", - "main": "src/index.ts", - "type": "module", + "name": "eliza", "scripts": { - "start": "node --loader ts-node/esm src/index.ts", - "dev": "node --loader ts-node/esm src/index.ts", - "check-types": "tsc --noEmit" + "preinstall": "npx only-allow pnpm", + "build": "turbo run build --filter=!eliza-docs", + "build-docker": "turbo run build", + "start": "pnpm --filter \"@elizaos/agent\" start --isRoot", + "start:client": "pnpm --dir client dev", + "start:debug": "cross-env NODE_ENV=development VERBOSE=true DEBUG=eliza:* pnpm --filter \"@elizaos/agent\" start --isRoot", + "dev": "bash ./scripts/dev.sh", + "lint": "bash ./scripts/lint.sh", + "prettier-check": "npx prettier --check --cache .", + "prettier": "npx prettier --write --cache .", + "release": "pnpm build && pnpm prettier && npx lerna publish --no-private --force-publish", + "clean": "bash ./scripts/clean.sh", + "docker:build": "bash ./scripts/docker.sh build", + "docker:run": "bash ./scripts/docker.sh run", + "docker:bash": "bash ./scripts/docker.sh bash", + "docker:start": "bash ./scripts/docker.sh start", + "docker": "pnpm docker:build && pnpm docker:run && pnpm docker:bash", + "test": "bash ./scripts/test.sh", + "smokeTests": "bash ./scripts/smokeTests.sh", + "integrationTests": "bash ./scripts/integrationTests.sh" }, - "nodemonConfig": { - "watch": [ - "src", - "../core/dist" - ], - "ext": "ts,json", - "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" + "devDependencies": { + "@commitlint/cli": "18.6.1", + "@commitlint/config-conventional": "18.6.3", + "@typescript-eslint/eslint-plugin": "8.16.0", + "@typescript-eslint/parser": "8.16.0", + "@vitest/eslint-plugin": "1.1.13", + "concurrently": "9.1.0", + "cross-env": "7.0.3", + "eslint": "9.16.0", + "eslint-config-prettier": "9.1.0", + "husky": "9.1.7", + "lerna": "8.1.5", + "only-allow": "1.2.1", + "prettier": "3.4.1", + "turbo": "2.3.3", + "typedoc": "0.26.11", + "typescript": "5.6.3", + "vite": "5.4.11", + "vitest": "2.1.5" + }, + "pnpm": { + "overrides": { + "onnxruntime-node": "1.20.1" + } + }, + "engines": { + "node": "23.3.0" }, "dependencies": { - "@elizaos/adapter-postgres": "workspace:*", - "@elizaos/adapter-redis": "workspace:*", - "@elizaos/adapter-sqlite": "workspace:*", - "@elizaos/client-auto": "workspace:*", - "@elizaos/client-direct": "workspace:*", - "@elizaos/client-discord": "workspace:*", - "@elizaos/client-farcaster": "workspace:*", - "@elizaos/client-lens": "workspace:*", - "@elizaos/client-telegram": "workspace:*", - "@elizaos/client-twitter": "workspace:*", - "@elizaos/client-slack": "workspace:*", - "@elizaos/core": "workspace:*", - "@elizaos/plugin-0g": "workspace:*", - "@elizaos/plugin-aptos": "workspace:*", - "@elizaos/plugin-bootstrap": "workspace:*", - "@elizaos/plugin-intiface": "workspace:*", - "@elizaos/plugin-coinbase": "workspace:*", - "@elizaos/plugin-conflux": "workspace:*", - "@elizaos/plugin-evm": "workspace:*", - "@elizaos/plugin-flow": "workspace:*", - "@elizaos/plugin-story": "workspace:*", - "@elizaos/plugin-goat": "workspace:*", - "@elizaos/plugin-icp": "workspace:*", - "@elizaos/plugin-image-generation": "workspace:*", - "@elizaos/plugin-nft-generation": "workspace:*", - "@elizaos/plugin-node": "workspace:*", - "@elizaos/plugin-solana": "workspace:*", - "@elizaos/plugin-starknet": "workspace:*", - "@elizaos/plugin-ton": "workspace:*", - "@elizaos/plugin-sui": "workspace:*", - "@elizaos/plugin-tee": "workspace:*", - "@elizaos/plugin-multiversx": "workspace:*", - "@elizaos/plugin-near": "workspace:*", - "@elizaos/plugin-zksync-era": "workspace:*", - "readline": "1.3.0", - "ws": "8.18.0", - "yargs": "17.7.2" + "@0glabs/0g-ts-sdk": "0.2.1", + "@coinbase/coinbase-sdk": "0.10.0", + "@deepgram/sdk": "^3.9.0", + "@vitest/eslint-plugin": "1.0.1", + "amqplib": "0.10.5", + "csv-parse": "5.6.0", + "ollama-ai-provider": "0.16.1", + "optional": "0.1.4", + "pnpm": "9.14.4", + "sharp": "0.33.5", + "tslog": "4.9.3" }, - "devDependencies": { - "ts-node": "10.9.2", - "tsup": "8.3.5" - } - } \ No newline at end of file + "packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee", + "workspaces": [ + "packages/*" + ] +} From cb1c23f8f4b397c795cd2e01b96fe2de6211b3f4 Mon Sep 17 00:00:00 2001 From: Marko Date: Mon, 23 Dec 2024 15:31:23 +0100 Subject: [PATCH 16/29] with no formating --- agent/package.json | 124 ++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/agent/package.json b/agent/package.json index 671075e5b8..32e4eabe78 100644 --- a/agent/package.json +++ b/agent/package.json @@ -1,63 +1,63 @@ { - "name": "@elizaos/agent", - "version": "0.1.7-alpha.1", - "main": "src/index.ts", - "type": "module", - "scripts": { - "start": "node --loader ts-node/esm src/index.ts", - "dev": "node --loader ts-node/esm src/index.ts", - "check-types": "tsc --noEmit" - }, - "nodemonConfig": { - "watch": [ - "src", - "../core/dist" - ], - "ext": "ts,json", - "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" - }, - "dependencies": { - "@elizaos/adapter-postgres": "workspace:*", - "@elizaos/adapter-redis": "workspace:*", - "@elizaos/adapter-sqlite": "workspace:*", - "@elizaos/client-auto": "workspace:*", - "@elizaos/client-direct": "workspace:*", - "@elizaos/client-discord": "workspace:*", - "@elizaos/client-farcaster": "workspace:*", - "@elizaos/client-lens": "workspace:*", - "@elizaos/client-telegram": "workspace:*", - "@elizaos/client-twitter": "workspace:*", - "@elizaos/client-slack": "workspace:*", - "@elizaos/core": "workspace:*", - "@elizaos/plugin-0g": "workspace:*", - "@elizaos/plugin-aptos": "workspace:*", - "@elizaos/plugin-bootstrap": "workspace:*", - "@elizaos/plugin-intiface": "workspace:*", - "@elizaos/plugin-coinbase": "workspace:*", - "@elizaos/plugin-conflux": "workspace:*", - "@elizaos/plugin-gecko": "workspace:*", - "@elizaos/plugin-evm": "workspace:*", - "@elizaos/plugin-flow": "workspace:*", - "@elizaos/plugin-story": "workspace:*", - "@elizaos/plugin-goat": "workspace:*", - "@elizaos/plugin-icp": "workspace:*", - "@elizaos/plugin-image-generation": "workspace:*", - "@elizaos/plugin-nft-generation": "workspace:*", - "@elizaos/plugin-node": "workspace:*", - "@elizaos/plugin-solana": "workspace:*", - "@elizaos/plugin-starknet": "workspace:*", - "@elizaos/plugin-ton": "workspace:*", - "@elizaos/plugin-sui": "workspace:*", - "@elizaos/plugin-tee": "workspace:*", - "@elizaos/plugin-multiversx": "workspace:*", - "@elizaos/plugin-near": "workspace:*", - "@elizaos/plugin-zksync-era": "workspace:*", - "readline": "1.3.0", - "ws": "8.18.0", - "yargs": "17.7.2" - }, - "devDependencies": { - "ts-node": "10.9.2", - "tsup": "8.3.5" - } - } \ No newline at end of file + "name": "@elizaos/agent", + "version": "0.1.7-alpha.1", + "main": "src/index.ts", + "type": "module", + "scripts": { + "start": "node --loader ts-node/esm src/index.ts", + "dev": "node --loader ts-node/esm src/index.ts", + "check-types": "tsc --noEmit" + }, + "nodemonConfig": { + "watch": [ + "src", + "../core/dist" + ], + "ext": "ts,json", + "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" + }, + "dependencies": { + "@elizaos/adapter-postgres": "workspace:*", + "@elizaos/adapter-redis": "workspace:*", + "@elizaos/adapter-sqlite": "workspace:*", + "@elizaos/client-auto": "workspace:*", + "@elizaos/client-direct": "workspace:*", + "@elizaos/client-discord": "workspace:*", + "@elizaos/client-farcaster": "workspace:*", + "@elizaos/client-lens": "workspace:*", + "@elizaos/client-telegram": "workspace:*", + "@elizaos/client-twitter": "workspace:*", + "@elizaos/client-slack": "workspace:*", + "@elizaos/core": "workspace:*", + "@elizaos/plugin-0g": "workspace:*", + "@elizaos/plugin-aptos": "workspace:*", + "@elizaos/plugin-bootstrap": "workspace:*", + "@elizaos/plugin-intiface": "workspace:*", + "@elizaos/plugin-coinbase": "workspace:*", + "@elizaos/plugin-conflux": "workspace:*", + "@elizaos/plugin-evm": "workspace:*", + "@elizaos/plugin-flow": "workspace:*", + "@elizaos/plugin-story": "workspace:*", + "@elizaos/plugin-gecko": "workspace:*", + "@elizaos/plugin-goat": "workspace:*", + "@elizaos/plugin-icp": "workspace:*", + "@elizaos/plugin-image-generation": "workspace:*", + "@elizaos/plugin-nft-generation": "workspace:*", + "@elizaos/plugin-node": "workspace:*", + "@elizaos/plugin-solana": "workspace:*", + "@elizaos/plugin-starknet": "workspace:*", + "@elizaos/plugin-ton": "workspace:*", + "@elizaos/plugin-sui": "workspace:*", + "@elizaos/plugin-tee": "workspace:*", + "@elizaos/plugin-multiversx": "workspace:*", + "@elizaos/plugin-near": "workspace:*", + "@elizaos/plugin-zksync-era": "workspace:*", + "readline": "1.3.0", + "ws": "8.18.0", + "yargs": "17.7.2" + }, + "devDependencies": { + "ts-node": "10.9.2", + "tsup": "8.3.5" + } +} From 94defa6a5ae46377a4644e2cc1a7060c3829c924 Mon Sep 17 00:00:00 2001 From: Cardinal Error Date: Tue, 24 Dec 2024 01:36:12 +0100 Subject: [PATCH 17/29] Update index.ts --- agent/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/src/index.ts b/agent/src/index.ts index 801f8196d0..3fd100a97e 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -759,4 +759,4 @@ const startAgents = async () => { startAgents().catch((error) => { elizaLogger.error("Unhandled error in startAgents:", error); process.exit(1); -}); \ No newline at end of file +}); From 58809931b99b0b9c3eb35069f5ec8a41dfbed535 Mon Sep 17 00:00:00 2001 From: Cardinal Error Date: Tue, 24 Dec 2024 01:36:36 +0100 Subject: [PATCH 18/29] Update package.json --- agent/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/package.json b/agent/package.json index 9484948302..3a50be992e 100644 --- a/agent/package.json +++ b/agent/package.json @@ -60,4 +60,4 @@ "ts-node": "10.9.2", "tsup": "8.3.5" } -} \ No newline at end of file +} From 3132cf5abf5b01bc8fcf1337454d8d7a343f5e62 Mon Sep 17 00:00:00 2001 From: Cardinal Error Date: Tue, 24 Dec 2024 01:37:00 +0100 Subject: [PATCH 19/29] Update .npmignore --- packages/plugin-gecko/.npmignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-gecko/.npmignore b/packages/plugin-gecko/.npmignore index 078562ecea..0468b4b364 100644 --- a/packages/plugin-gecko/.npmignore +++ b/packages/plugin-gecko/.npmignore @@ -3,4 +3,4 @@ !dist/** !package.json !readme.md -!tsup.config.ts \ No newline at end of file +!tsup.config.ts From f3418285ef98e187b5b5d973cf7d3f2b61ca9f85 Mon Sep 17 00:00:00 2001 From: Cardinal Error Date: Tue, 24 Dec 2024 01:38:38 +0100 Subject: [PATCH 20/29] Update tsconfig.json --- packages/plugin-gecko/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-gecko/tsconfig.json b/packages/plugin-gecko/tsconfig.json index 834c4dce26..abd2932121 100644 --- a/packages/plugin-gecko/tsconfig.json +++ b/packages/plugin-gecko/tsconfig.json @@ -10,4 +10,4 @@ "include": [ "src/**/*.ts" ] -} \ No newline at end of file +} From 316a65ee5642199a14d1e67e068b36d441c646ff Mon Sep 17 00:00:00 2001 From: Cardinal Error Date: Tue, 24 Dec 2024 01:39:38 +0100 Subject: [PATCH 21/29] Update package.json adding empty line(s) on the end of file --- packages/plugin-gecko/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-gecko/package.json b/packages/plugin-gecko/package.json index c1a81306b1..8dbf74c7ab 100644 --- a/packages/plugin-gecko/package.json +++ b/packages/plugin-gecko/package.json @@ -16,4 +16,4 @@ "peerDependencies": { "whatwg-url": "7.1.0" } -} \ No newline at end of file +} From eb96c57e3dc1a93fe3b9a4bc27b58e80fd125cf0 Mon Sep 17 00:00:00 2001 From: CardinalError Date: Tue, 24 Dec 2024 12:10:37 +0100 Subject: [PATCH 22/29] add back gecko plugin insert --- agent/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/agent/src/index.ts b/agent/src/index.ts index 3fd100a97e..e3debfb0b4 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -42,6 +42,7 @@ import { webhookPlugin, } from "@elizaos/plugin-coinbase"; import { confluxPlugin } from "@elizaos/plugin-conflux"; +import { coingeckoPlugin } from "@elizaos/plugin-gecko"; import { evmPlugin } from "@elizaos/plugin-evm"; import { storyPlugin } from "@elizaos/plugin-story"; import { flowPlugin } from "@elizaos/plugin-flow"; @@ -508,6 +509,7 @@ export async function createAgent( getSecret(character, "CONFLUX_CORE_PRIVATE_KEY") ? confluxPlugin : null, + getSecret(character, "COINGECKO_API_KEY") ? coingeckoPlugin : null, nodePlugin, getSecret(character, "SOLANA_PUBLIC_KEY") || (getSecret(character, "WALLET_PUBLIC_KEY") && From 4d15501fb7dcedf9d8bdbccfc543c6e35bab8e48 Mon Sep 17 00:00:00 2001 From: CardinalError Date: Tue, 24 Dec 2024 12:20:19 +0100 Subject: [PATCH 23/29] add new path and add to docker --- packages/plugin-gecko/package.json | 4 ++-- scripts/docker.sh | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/plugin-gecko/package.json b/packages/plugin-gecko/package.json index 8dbf74c7ab..702107ee1d 100644 --- a/packages/plugin-gecko/package.json +++ b/packages/plugin-gecko/package.json @@ -1,5 +1,5 @@ { - "name": "@ai16z/plugin-gecko", + "name": "@elizaos/plugin-gecko", "version": "0.1.6-alpha.4", "main": "dist/index.js", "type": "module", @@ -16,4 +16,4 @@ "peerDependencies": { "whatwg-url": "7.1.0" } -} +} \ No newline at end of file diff --git a/scripts/docker.sh b/scripts/docker.sh index 6fb2fb3b7a..6891c77f5d 100755 --- a/scripts/docker.sh +++ b/scripts/docker.sh @@ -47,6 +47,7 @@ case "$1" in "plugin-solana" "plugin-evm" "plugin-tee" + "plugin-gecko" ) # Start building the docker run command From 26900473fddd39735ba4a75abba2096965248cbe Mon Sep 17 00:00:00 2001 From: CardinalError Date: Tue, 24 Dec 2024 12:25:15 +0100 Subject: [PATCH 24/29] add proper paths to package --- packages/plugin-gecko/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin-gecko/package.json b/packages/plugin-gecko/package.json index 702107ee1d..ef7c5c0590 100644 --- a/packages/plugin-gecko/package.json +++ b/packages/plugin-gecko/package.json @@ -1,11 +1,11 @@ { "name": "@elizaos/plugin-gecko", - "version": "0.1.6-alpha.4", + "version": "0.1.7-alpha.1", "main": "dist/index.js", "type": "module", "types": "dist/index.d.ts", "dependencies": { - "@ai16z/eliza": "workspace:*", + "@elizaos/core": "workspace:*", "tsup": "8.3.5" }, "scripts": { From fc26d7bf97faffc3e52943a107fd304f794ead7b Mon Sep 17 00:00:00 2001 From: CardinalError Date: Tue, 24 Dec 2024 22:51:40 +0100 Subject: [PATCH 25/29] change wrong path for imports, use elizaOS now for all --- packages/plugin-gecko/README.md | 2 +- packages/plugin-gecko/package.json | 1 + packages/plugin-gecko/src/actions/price.ts | 2 +- packages/plugin-gecko/src/actions/pricePerAddress.ts | 2 +- packages/plugin-gecko/src/index.ts | 2 +- packages/plugin-gecko/src/providers/coins.ts | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/plugin-gecko/README.md b/packages/plugin-gecko/README.md index 0f566af194..cfcfab15e6 100644 --- a/packages/plugin-gecko/README.md +++ b/packages/plugin-gecko/README.md @@ -1,4 +1,4 @@ -# `@ai16z/plugin-gecko` +# `@elizaos/plugin-gecko` This plugin provides actions and providers for interacting with CoinGecko API, using free version https://docs.coingecko.com/v3.0.1/reference/introduction diff --git a/packages/plugin-gecko/package.json b/packages/plugin-gecko/package.json index ef7c5c0590..8df5352714 100644 --- a/packages/plugin-gecko/package.json +++ b/packages/plugin-gecko/package.json @@ -11,6 +11,7 @@ "scripts": { "build": "tsup --format esm --dts", "dev": "tsup --format esm --dts --watch", + "test": "vitest run", "lint": "eslint --fix --cache ." }, "peerDependencies": { diff --git a/packages/plugin-gecko/src/actions/price.ts b/packages/plugin-gecko/src/actions/price.ts index cd60a795e5..f5ebc75465 100644 --- a/packages/plugin-gecko/src/actions/price.ts +++ b/packages/plugin-gecko/src/actions/price.ts @@ -8,7 +8,7 @@ import { composeContext, generateObject, ModelClass, -} from "@ai16z/eliza"; +} from "@elizaos/core"; import { coingeckoProvider } from "../providers/coins"; import { PriceLookupContent, PriceLookupSchema } from "../types.ts"; diff --git a/packages/plugin-gecko/src/actions/pricePerAddress.ts b/packages/plugin-gecko/src/actions/pricePerAddress.ts index 23e9e8fca1..7a9f11a7ae 100644 --- a/packages/plugin-gecko/src/actions/pricePerAddress.ts +++ b/packages/plugin-gecko/src/actions/pricePerAddress.ts @@ -8,7 +8,7 @@ import { composeContext, generateObject, ModelClass, -} from "@ai16z/eliza"; +} from "@elizaos/core"; import { AddressLookupSchema, AddressLookupContent } from "../types.ts"; diff --git a/packages/plugin-gecko/src/index.ts b/packages/plugin-gecko/src/index.ts index 46abd5ae6c..68c77f3c82 100644 --- a/packages/plugin-gecko/src/index.ts +++ b/packages/plugin-gecko/src/index.ts @@ -2,7 +2,7 @@ export * from "./actions/price"; export * from "./providers/coins"; export * from "./types"; -import type { Plugin } from "@ai16z/eliza"; +import type { Plugin } from "@elizaos/core"; import { getPriceAction } from "./actions/price"; import { getPriceByAddressAction } from "./actions/pricePerAddress"; import { coingeckoProvider } from "./providers/coins"; diff --git a/packages/plugin-gecko/src/providers/coins.ts b/packages/plugin-gecko/src/providers/coins.ts index cb26dabc2f..9adeae3681 100644 --- a/packages/plugin-gecko/src/providers/coins.ts +++ b/packages/plugin-gecko/src/providers/coins.ts @@ -1,4 +1,4 @@ -import { elizaLogger, IAgentRuntime, Memory, Provider } from "@ai16z/eliza"; +import { elizaLogger, IAgentRuntime, Memory, Provider } from "@elizaos/core"; import type { CoinListEntry } from "../types.ts"; export const coingeckoProvider: Provider = { From aa2117316538cbb32b96134ad39a5915a7d7ec2e Mon Sep 17 00:00:00 2001 From: CardinalError Date: Wed, 25 Dec 2024 00:47:23 +0100 Subject: [PATCH 26/29] use different generator, simplfy context for better precision --- packages/plugin-gecko/src/actions/price.ts | 27 ++++++++-------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/packages/plugin-gecko/src/actions/price.ts b/packages/plugin-gecko/src/actions/price.ts index f5ebc75465..4283c5bdab 100644 --- a/packages/plugin-gecko/src/actions/price.ts +++ b/packages/plugin-gecko/src/actions/price.ts @@ -6,18 +6,15 @@ import { HandlerCallback, State, composeContext, - generateObject, + generateMessageResponse, ModelClass, } from "@elizaos/core"; import { coingeckoProvider } from "../providers/coins"; -import { PriceLookupContent, PriceLookupSchema } from "../types.ts"; import type { PriceResponse } from "../types.ts"; -export const priceTemplate = `Use JUST the last message from recent messages -{{recentMessages}} - -Extract ONLY the cryptocurrency name, symbol, or ticker being asked about. Do not include words like "token", "coin", "price", +export const priceTemplate = `From previous sentence extract only the cryptocurrency name, symbol, or ticker being asked about. +Do not include words like "token", "coin", "price", unless it's part of the name like in "bitcoin" there is a "coin". Respond with a JSON markdown block containing only the extracted value: @@ -70,29 +67,25 @@ export const getPriceAction: Action = { _message ); - // Initialize or update state + // Update the state with current inputs if (!state) { state = (await runtime.composeState(_message)) as State; } else { state = await runtime.updateRecentMessageState(state); } - // Generate the coin name from the message context - const context = composeContext({ - state, - template: priceTemplate, - }); + const context = `${_message.content.text}\n${priceTemplate}`; - const priceRequest = await generateObject({ + const priceRequest = await generateMessageResponse({ runtime, context, modelClass: ModelClass.SMALL, - schema: PriceLookupSchema, }); - const result = PriceLookupSchema.safeParse(priceRequest.object); + priceRequest.coinName; + const result = priceRequest.coinName as string; - if (!result.success) { + if (!result) { callback( { text: "Invalid coin name specified.", @@ -102,7 +95,7 @@ export const getPriceAction: Action = { return; } - const searchTerm = result.data.coinName.toLowerCase(); + const searchTerm = result.toLowerCase(); // Find all matching coins in our supported coins list const matchingCoins = supportedCoins.filter( From b4981d5451f6345c56b9c3fe0cae2f4cf1b3ad83 Mon Sep 17 00:00:00 2001 From: CardinalError Date: Wed, 25 Dec 2024 01:23:03 +0100 Subject: [PATCH 27/29] use generateMessageResponse also for price per address --- packages/plugin-gecko/src/actions/price.ts | 52 ++--------------- .../src/actions/pricePerAddress.ts | 56 ++++--------------- 2 files changed, 18 insertions(+), 90 deletions(-) diff --git a/packages/plugin-gecko/src/actions/price.ts b/packages/plugin-gecko/src/actions/price.ts index 4283c5bdab..bc0711e8f8 100644 --- a/packages/plugin-gecko/src/actions/price.ts +++ b/packages/plugin-gecko/src/actions/price.ts @@ -74,7 +74,11 @@ export const getPriceAction: Action = { state = await runtime.updateRecentMessageState(state); } - const context = `${_message.content.text}\n${priceTemplate}`; + // Use state replacements but add message at the top of template + const context = composeContext({ + state, + template: `${_message.content.text}\n${priceTemplate}`, + }); const priceRequest = await generateMessageResponse({ runtime, @@ -82,7 +86,6 @@ export const getPriceAction: Action = { modelClass: ModelClass.SMALL, }); - priceRequest.coinName; const result = priceRequest.coinName as string; if (!result) { @@ -188,50 +191,7 @@ export const getPriceAction: Action = { ); } }, - examples: [ - [ - { - user: "{{user1}}", - content: { - text: "What's the current price of Bitcoin?", - }, - }, - { - user: "{{agentName}}", - content: { - text: "Current price for Bitcoin (BTC): $45,123.45 USD\nMarket Cap: $876.5 billion USD", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "Show me ETH price", - }, - }, - { - user: "{{agentName}}", - content: { - text: "Current price for Ethereum (ETH): $2,456.78 USD\nMarket Cap: $298.4 billion USD", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "Show me price for Pendle Token", - }, - }, - { - user: "{{agentName}}", - content: { - text: "Current price for Pendle (PENDLE): $7.89 USD\nMarket Cap: $156.3 million USD", - }, - }, - ], - ], + examples: [], similes: [ "GET_COIN_PRICE", "FETCH_CRYPTO_PRICE", diff --git a/packages/plugin-gecko/src/actions/pricePerAddress.ts b/packages/plugin-gecko/src/actions/pricePerAddress.ts index 7a9f11a7ae..9f7908f40e 100644 --- a/packages/plugin-gecko/src/actions/pricePerAddress.ts +++ b/packages/plugin-gecko/src/actions/pricePerAddress.ts @@ -6,16 +6,14 @@ import { HandlerCallback, State, composeContext, - generateObject, + generateMessageResponse, ModelClass, } from "@elizaos/core"; import { AddressLookupSchema, AddressLookupContent } from "../types.ts"; // Template for extracting chain and address -export const addressTemplate = `Use JUST the last message from recent messages -{{recentMessages}} - +export const addressTemplate = ` Extract the blockchain name/chain ID and token address being asked about. Normalize chain names: ethereum, polygon, solana, base, etc. Token address should be the full address string. @@ -66,29 +64,26 @@ export const getPriceByAddressAction: Action = { runtime.getSetting("COINGECKO_API_KEY") ?? process.env.COINGECKO_API_KEY; - // Initialize or update state + // Update the state with current inputs if (!state) { state = (await runtime.composeState(_message)) as State; } else { state = await runtime.updateRecentMessageState(state); } - // Generate the address lookup from the message context + // Use state replacements but add message at the top of template const context = composeContext({ state, - template: addressTemplate, + template: `${_message.content.text}\n${addressTemplate}`, }); - const addressRequest = await generateObject({ + const result = await generateMessageResponse({ runtime, context, modelClass: ModelClass.SMALL, - schema: AddressLookupSchema, }); - const result = AddressLookupSchema.safeParse(addressRequest.object); - - if (!result.success) { + if (!result) { callback( { text: "Invalid chain ID or token address specified.", @@ -98,8 +93,10 @@ export const getPriceByAddressAction: Action = { return; } - const { chainId: rawChainId, tokenAddress } = result.data; - // Ensure chain ID is lowercase + const { chainId: rawChainId, tokenAddress } = result as unknown as { + chainId: string; + tokenAddress: string; + }; const chainId = rawChainId.toLowerCase(); // First, fetch token metadata to get the name @@ -193,36 +190,7 @@ export const getPriceByAddressAction: Action = { ); } }, - examples: [ - [ - { - user: "{{user1}}", - content: { - text: "What's the price of token 0x4f9fd6be4a90f2620860d680c0d4d5fb53d1a825 on ethereum?", - }, - }, - { - user: "{{agentName}}", - content: { - text: "Current price for Compound (COMP)\nAddress: 0x4f9fd6be4a90f2620860d680c0d4d5fb53d1a825\nChain: ethereum\nPrice: $1.234567 USD\nMarket Cap: $45.6 million USD", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "Show me the price for 0x2260fac5e5542a773aa44fbcfedf7c193bc2c599 on ethereum", - }, - }, - { - user: "{{agentName}}", - content: { - text: "Current price for Wrapped Bitcoin (WBTC)\nAddress: 0x2260fac5e5542a773aa44fbcfedf7c193bc2c599\nChain: ethereum\nPrice: $42000.123456 USD\nMarket Cap: $2.1 billion USD", - }, - }, - ], - ], + examples: [], similes: [ "GET_TOKEN_PRICE_BY_ADDRESS", "FETCH_TOKEN_PRICE_BY_ADDRESS", From 5e82ec6c9f5a27584b4f4c1fe54360e6f34b0008 Mon Sep 17 00:00:00 2001 From: CardinalError Date: Wed, 25 Dec 2024 01:36:19 +0100 Subject: [PATCH 28/29] cleanup types --- .../plugin-gecko/src/actions/pricePerAddress.ts | 4 ++-- packages/plugin-gecko/src/types.ts | 15 --------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/packages/plugin-gecko/src/actions/pricePerAddress.ts b/packages/plugin-gecko/src/actions/pricePerAddress.ts index 9f7908f40e..1d5f169d75 100644 --- a/packages/plugin-gecko/src/actions/pricePerAddress.ts +++ b/packages/plugin-gecko/src/actions/pricePerAddress.ts @@ -10,7 +10,7 @@ import { ModelClass, } from "@elizaos/core"; -import { AddressLookupSchema, AddressLookupContent } from "../types.ts"; +import type { PriceResponse } from "../types.ts"; // Template for extracting chain and address export const addressTemplate = ` @@ -133,7 +133,7 @@ export const getPriceByAddressAction: Action = { throw new Error(`HTTP error! status: ${priceResponse.status}`); } - const priceData = await priceResponse.json(); + const priceData: PriceResponse = await priceResponse.json(); // Try to find the token data regardless of case let tokenData = diff --git a/packages/plugin-gecko/src/types.ts b/packages/plugin-gecko/src/types.ts index 6434342419..f305a479d6 100644 --- a/packages/plugin-gecko/src/types.ts +++ b/packages/plugin-gecko/src/types.ts @@ -1,5 +1,3 @@ -import { z } from "zod"; - export interface CoinListEntry { id: string; symbol: string; @@ -12,16 +10,3 @@ export interface PriceResponse { usd_market_cap: number; }; } - -export const PriceLookupSchema = z.object({ - coinName: z.string(), -}); - -export type PriceLookupContent = z.infer; - -export const AddressLookupSchema = z.object({ - chainId: z.string(), - tokenAddress: z.string(), -}); - -export type AddressLookupContent = z.infer; From 6b31fe204412cf674e76f5a9ed1776028dea1962 Mon Sep 17 00:00:00 2001 From: CardinalError Date: Fri, 27 Dec 2024 01:04:08 +0100 Subject: [PATCH 29/29] add gecko to lock file --- pnpm-lock.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 470b2fc02c..d51caa1499 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -165,6 +165,9 @@ importers: '@elizaos/plugin-flow': specifier: workspace:* version: link:../packages/plugin-flow + '@elizaos/plugin-gecko': + specifier: workspace:* + version: link:../packages/plugin-gecko '@elizaos/plugin-goat': specifier: workspace:* version: link:../packages/plugin-goat @@ -1165,6 +1168,18 @@ importers: specifier: 2.1.4 version: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + packages/plugin-gecko: + dependencies: + '@elizaos/core': + 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-goat: dependencies: '@elizaos/core':