From 0cef0a0a018dbdff498e3f6617b85607639e88b6 Mon Sep 17 00:00:00 2001 From: Ocenka Date: Fri, 31 Jan 2025 13:45:35 +0000 Subject: [PATCH 01/24] typo index.ts --- packages/plugin-cosmos/src/templates/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-cosmos/src/templates/index.ts b/packages/plugin-cosmos/src/templates/index.ts index e9c82de73d6..074a8e51897 100644 --- a/packages/plugin-cosmos/src/templates/index.ts +++ b/packages/plugin-cosmos/src/templates/index.ts @@ -26,7 +26,7 @@ Respond with a JSON markdown block containing only the extracted values. All fie "chainName": string // The chain name. \`\`\` -Example reponse for the input: "Make transfer 0.0001 OM to mantra1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf on mantrachaintestnet2", the response should be: +Example response for the input: "Make transfer 0.0001 OM to mantra1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf on mantrachaintestnet2", the response should be: \`\`\`json { "symbol": "OM", From ddf145a6575d36a540bb532bfe1ad824bb4f9a36 Mon Sep 17 00:00:00 2001 From: Ocenka Date: Fri, 31 Jan 2025 13:46:22 +0000 Subject: [PATCH 02/24] fix typo api.ts --- packages/plugin-story/src/types/api.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin-story/src/types/api.ts b/packages/plugin-story/src/types/api.ts index 2f22adaa030..6187a55285f 100644 --- a/packages/plugin-story/src/types/api.ts +++ b/packages/plugin-story/src/types/api.ts @@ -29,7 +29,7 @@ export enum RESOURCE_TYPE { LATEST_TRANSACTIONS = "transactions/latest", } -export enum RESPOURCE_REPONSE_TYPE { +export enum RESPOURCE_RESPONSE_TYPE { LICENSE_TOKEN = "LICENSETOKEN", // new version LICENSE_TEMPLATES = "LICENSETEMPLATE", // new version LICENSE_TERMS = "LICENSETERM", // new version @@ -556,4 +556,4 @@ export type LicenseTerms = { licenseTemplate: Address; blockNumber: string; blockTime: string; -}; \ No newline at end of file +}; From 413383ac63bdaf5c83ce002d55d3e4c1b749e3f2 Mon Sep 17 00:00:00 2001 From: Ocenka Date: Fri, 31 Jan 2025 13:47:23 +0000 Subject: [PATCH 03/24] fix typo GoplusSecurityService.ts --- packages/plugin-goplus/src/services/GoplusSecurityService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-goplus/src/services/GoplusSecurityService.ts b/packages/plugin-goplus/src/services/GoplusSecurityService.ts index 581f9f2f2e5..0621b0dce0a 100644 --- a/packages/plugin-goplus/src/services/GoplusSecurityService.ts +++ b/packages/plugin-goplus/src/services/GoplusSecurityService.ts @@ -80,7 +80,7 @@ export class GoplusSecurityService extends Service implements IGoplusSecuritySer checkResult = await goPlusManage.dappSecurityAndPhishingSite(obj.url); break; default: - throw new Error("type is invaild") + throw new Error("type is invalid") } elizaLogger.log("checkResult text", checkResult); From 908198be040e3690eb6588d0de97820e134c144d Mon Sep 17 00:00:00 2001 From: Ocenka Date: Fri, 31 Jan 2025 13:48:18 +0000 Subject: [PATCH 04/24] fix typo README.md --- packages/plugin-email/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-email/README.md b/packages/plugin-email/README.md index 3748c7ba65e..8372ebc9964 100644 --- a/packages/plugin-email/README.md +++ b/packages/plugin-email/README.md @@ -18,7 +18,7 @@ The following settings will be declared on your environment variable or inside y ## IMAP Section - `EMAIL_INCOMING_SERVICE`: "imap" -- `EMAIL_INCOMING_HOST`: IMAP Hostname or IP to conenct to +- `EMAIL_INCOMING_HOST`: IMAP Hostname or IP to connect to - `EMAIL_INCOMING_PORT`: the port to connect to (defaults to 993) - `EMAIL_INCOMING_USER`: Username - `EMAIL_INCOMING_PASS`: Password From cc4f5e956771565c93c5ff489ea5003163ada953 Mon Sep 17 00:00:00 2001 From: alexpaden Date: Fri, 31 Jan 2025 15:23:15 -0700 Subject: [PATCH 05/24] save imageUrls for outbound tweets/messages interactions.ts handles inbound utils.ts handles outbound --- packages/client-twitter/src/utils.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/client-twitter/src/utils.ts b/packages/client-twitter/src/utils.ts index f62564bef1b..0c64a59d231 100644 --- a/packages/client-twitter/src/utils.ts +++ b/packages/client-twitter/src/utils.ts @@ -83,6 +83,7 @@ export async function buildConversationThread( text: currentTweet.text, source: "twitter", url: currentTweet.permanentUrl, + imageUrls: currentTweet.photos.map((p) => p.url) || [], inReplyTo: currentTweet.inReplyToStatusId ? stringToUuid( currentTweet.inReplyToStatusId + @@ -278,6 +279,7 @@ export async function sendTweet( text: tweet.text, source: "twitter", url: tweet.permanentUrl, + imageUrls: tweet.photos.map((p) => p.url) || [], inReplyTo: tweet.inReplyToStatusId ? stringToUuid( tweet.inReplyToStatusId + "-" + client.runtime.agentId From fe21a0206608ac3ad115ffc97329546f994e4206 Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Sat, 1 Feb 2025 10:48:11 +0800 Subject: [PATCH 06/24] remove duplicated plugins --- agent/package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/agent/package.json b/agent/package.json index 4d2e88e48b6..7a2bfc75587 100644 --- a/agent/package.json +++ b/agent/package.json @@ -66,9 +66,7 @@ "@elizaos/plugin-icp": "workspace:*", "@elizaos/plugin-initia": "workspace:*", "@elizaos/plugin-image-generation": "workspace:*", - "@elizaos/plugin-intiface": "workspace:*", "@elizaos/plugin-lens-network": "workspace:*", - "@elizaos/plugin-letzai": "workspace:*", "@elizaos/plugin-lit": "workspace:*", "@elizaos/plugin-massa": "workspace:*", "@elizaos/plugin-mind-network": "workspace:*", From e53e69f92a8b935b5f03771410b03d43c6282cc7 Mon Sep 17 00:00:00 2001 From: Ocenka Date: Sat, 1 Feb 2025 11:34:23 +0000 Subject: [PATCH 07/24] Update api.ts --- packages/plugin-story/src/types/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-story/src/types/api.ts b/packages/plugin-story/src/types/api.ts index 6187a55285f..6d1d9fc95a1 100644 --- a/packages/plugin-story/src/types/api.ts +++ b/packages/plugin-story/src/types/api.ts @@ -29,7 +29,7 @@ export enum RESOURCE_TYPE { LATEST_TRANSACTIONS = "transactions/latest", } -export enum RESPOURCE_RESPONSE_TYPE { +export enum RESOURCE_RESPONSE_TYPE { LICENSE_TOKEN = "LICENSETOKEN", // new version LICENSE_TEMPLATES = "LICENSETEMPLATE", // new version LICENSE_TERMS = "LICENSETERM", // new version From dd8fa10132e4384b0172c5096ad89850c613ebb6 Mon Sep 17 00:00:00 2001 From: Joshua <64296537+HashWarlock@users.noreply.github.com> Date: Sat, 1 Feb 2025 13:39:43 -0500 Subject: [PATCH 08/24] fix: upgrade openai and vercel ai packages to fix o1 errors --- packages/core/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index d5fdfe8f186..d55ef41c1d3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -67,12 +67,12 @@ "@ai-sdk/google-vertex": "0.0.43", "@ai-sdk/groq": "0.0.3", "@ai-sdk/mistral": "1.0.9", - "@ai-sdk/openai": "1.0.5", + "@ai-sdk/openai": "1.1.9", "@ai-sdk/amazon-bedrock": "1.1.0", "@fal-ai/client": "1.2.0", "@tavily/core": "^0.0.2", "@types/uuid": "10.0.0", - "ai": "3.4.33", + "ai": "4.1.16", "anthropic-vertex-ai": "1.0.2", "dotenv": "16.4.5", "fastembed": "1.14.1", @@ -84,7 +84,7 @@ "js-tiktoken": "1.0.15", "langchain": "0.3.6", "ollama-ai-provider": "0.16.1", - "openai": "4.73.0", + "openai": "4.82.0", "pino": "^9.6.0", "pino-pretty": "^13.0.0", "tinyld": "1.3.4", From 9bf304d03c731e56d39205a638e42892b31b897d Mon Sep 17 00:00:00 2001 From: comfsrt <155266597+comfsrt@users.noreply.github.com> Date: Sun, 2 Feb 2025 18:02:11 +0100 Subject: [PATCH 09/24] Update chat_2024-12-07.md --- .../Discord/collaborations/3d-ai-tv/chat_2024-12-07.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/community/Discord/collaborations/3d-ai-tv/chat_2024-12-07.md b/docs/community/Discord/collaborations/3d-ai-tv/chat_2024-12-07.md index a41aa77f3de..062f542cb93 100644 --- a/docs/community/Discord/collaborations/3d-ai-tv/chat_2024-12-07.md +++ b/docs/community/Discord/collaborations/3d-ai-tv/chat_2024-12-07.md @@ -15,7 +15,7 @@ The conversation focused on integrating @bigdookie's artwork as bumpers in their - Do we need video producers? Why is it complicated for comfy stuff to be fast-paced? (asked by [boom](09:56)) - What are the next steps in establishing a Creative Studio and bidding on projects? How does budget influence project success? (asked by [whobody, boom](10:27)) - How will the open-source approach help us? How can Banodoco handle bids on their end? (asked by [boom (10:00)]) -- Can we prompt an engineer to help the story arch or main punchlines for AI-assisted writing? How does it come together with human and AI collaboration in filmmaking? (asked by [boom] (10:05)) +- Can we prompt an engineer to help the story arc or main punchlines for AI-assisted writing? How does it come together with human and AI collaboration in filmmaking? (asked by [boom] (10:05)) ## Who Helped Who From 42ac7a8c9ad896a38292df64fa1e19b91f3f6eb3 Mon Sep 17 00:00:00 2001 From: comfsrt <155266597+comfsrt@users.noreply.github.com> Date: Sun, 2 Feb 2025 18:02:35 +0100 Subject: [PATCH 10/24] Update chat_2024-10-27.md --- docs/community/Discord/development/coders/chat_2024-10-27.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/community/Discord/development/coders/chat_2024-10-27.md b/docs/community/Discord/development/coders/chat_2024-10-27.md index 5020d493c06..7589eb8ad96 100644 --- a/docs/community/Discord/development/coders/chat_2024-10-27.md +++ b/docs/community/Discord/development/coders/chat_2024-10-27.md @@ -2,7 +2,7 @@ ## Summary -In the chat, Cyfer785 sought assistance for creating a frontend interface that would display AI-generated content in a retro style with live scrolling text, reminiscent of Claude's capabilities but tailored to their own AI pipe output. DegenSpartan and Poe engaged in the conversation, suggesting that Cyfer785 was essentially attempting to replicate features from existing projects like Infinite Backrooms and Claude without adding original value. The discussion highlighted a divergence of interests as Cyfer785's vision did not align with what DegenSpartan and Poe were willing or able to provide, leading to the conclusion that they were not suitable collaborators for this project. Despite some initial enthusiasm from other participants like astr0x., who humorously claimed a share of non-existent profits, the technical focus remained on Cyfer785's request for a unique AI interface development. +In the chat, Cyfer785 sought assistance for creating a frontend interface that would display AI-generated content in a retro style with live scrolling text, reminiscent of Claude's capabilities but tailored to their own AI pipe output. DegenSpartan and Poe engaged in the conversation, suggesting that Cyfer785 was essentially attempting to replicate features from existing projects like Infinite Backrooms and Claude without adding original value. The discussion highlighted a divergence of interests as Cyfer785's vision did not align with what DegenSpartan and Poe were willing or able to provide, leading to the conclusion that they were not suitable collaborators for this project. Despite some initial enthusiasm from other participants like astr0x, who humorously claimed a share of non-existent profits, the technical focus remained on Cyfer785's request for a unique AI interface development. ## FAQ From 074a0a14662604edd6145e2f942a3750babe53b6 Mon Sep 17 00:00:00 2001 From: AIFlow_ML Date: Mon, 3 Feb 2025 03:54:03 +0700 Subject: [PATCH 11/24] Fixed all the issues and added biome --- packages/plugin-allora/biome.json | 41 +++++++++++++++++++ packages/plugin-allora/package.json | 12 +++++- .../plugin-allora/src/actions/getInference.ts | 13 +++--- .../plugin-allora/src/providers/topics.ts | 4 +- 4 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 packages/plugin-allora/biome.json diff --git a/packages/plugin-allora/biome.json b/packages/plugin-allora/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-allora/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-allora/package.json b/packages/plugin-allora/package.json index 6dee6303b49..754cf4e8813 100644 --- a/packages/plugin-allora/package.json +++ b/packages/plugin-allora/package.json @@ -5,16 +5,24 @@ "type": "module", "types": "dist/index.d.ts", "dependencies": { - "@alloralabs/allora-sdk": "0.0.4", "@elizaos/core": "workspace:*", "node-cache": "5.1.2", "vitest": "2.1.8", "@alloralabs/allora-sdk": "^0.1.0" }, + "devDependencies": { + "@biomejs/biome": "1.9.4", + "tsup": "8.3.5", + "vitest": "2.1.8" + }, "scripts": { "build": "tsup --format esm --dts", "dev": "tsup --format esm --dts --watch", - "test": "vitest run" + "test": "vitest run", + "lint": "biome lint .", + "lint:fix": "biome check --apply .", + "format": "biome format .", + "format:fix": "biome format --write ." }, "peerDependencies": { "whatwg-url": "7.1.0" diff --git a/packages/plugin-allora/src/actions/getInference.ts b/packages/plugin-allora/src/actions/getInference.ts index d875aa35994..9b1c7acb823 100644 --- a/packages/plugin-allora/src/actions/getInference.ts +++ b/packages/plugin-allora/src/actions/getInference.ts @@ -36,22 +36,23 @@ export const getInferenceAction: Action = { runtime: IAgentRuntime, message: Memory, state: State, - options: { [key: string]: unknown }, + _options: { [key: string]: unknown }, callback: HandlerCallback ): Promise => { // Initialize or update state - if (!state) { - state = (await runtime.composeState(message)) as State; + let currentState = state; + if (!currentState) { + currentState = (await runtime.composeState(message)) as State; } else { - state = await runtime.updateRecentMessageState(state); + currentState = await runtime.updateRecentMessageState(currentState); } // Get Allora topics information from the provider - state.alloraTopics = await topicsProvider.get(runtime, message, state); + currentState.alloraTopics = await topicsProvider.get(runtime, message, currentState); // Compose context for extracting the inference fields const inferenceTopicContext = composeContext({ - state, + state: currentState, template: getInferenceTemplate, }); diff --git a/packages/plugin-allora/src/providers/topics.ts b/packages/plugin-allora/src/providers/topics.ts index 6dd72da36ac..2288c3f22e1 100644 --- a/packages/plugin-allora/src/providers/topics.ts +++ b/packages/plugin-allora/src/providers/topics.ts @@ -23,14 +23,14 @@ export class TopicsProvider implements Provider { const alloraTopics = await this.getAlloraTopics(runtime); // Format the topics into a string to be added to the prompt context - let output = `Allora Network Topics: \n`; + let output = 'Allora Network Topics: \n'; for (const topic of alloraTopics) { output += `Topic Name: ${topic.topic_name}\n`; output += `Topic Description: ${topic.description}\n`; output += `Topic ID: ${topic.topic_id}\n`; output += `Topic is Active: ${topic.is_active}\n`; output += `Topic Updated At: ${topic.updated_at}\n`; - output += `\n`; + output += '\n'; } return output; From b788b9dd0ff19a1fef447bdf997c067d4c921b20 Mon Sep 17 00:00:00 2001 From: AIFlow_ML Date: Mon, 3 Feb 2025 04:11:01 +0700 Subject: [PATCH 12/24] Fixed multiple issues and aded biome. --- packages/plugin-akash/biome.json | 41 +++++++++++++++++++ packages/plugin-akash/package.json | 9 ++-- .../src/actions/closeDeployment.ts | 2 +- .../src/actions/createCertificate.ts | 6 +-- .../src/actions/createDeployment.ts | 4 +- .../src/actions/getDeploymentApi.ts | 12 +++--- .../src/actions/getDeploymentStatus.ts | 2 +- .../plugin-akash/src/actions/getGPUPricing.ts | 12 +++--- .../plugin-akash/src/actions/getManifest.ts | 8 ++-- .../src/actions/getProvidersList.ts | 4 +- packages/plugin-akash/src/error/error.ts | 3 +- packages/plugin-akash/src/index.ts | 2 +- packages/plugin-akash/src/runtime_inspect.ts | 4 +- 13 files changed, 75 insertions(+), 34 deletions(-) create mode 100644 packages/plugin-akash/biome.json diff --git a/packages/plugin-akash/biome.json b/packages/plugin-akash/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-akash/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-akash/package.json b/packages/plugin-akash/package.json index 8da2ca91a7c..40bac98c74c 100644 --- a/packages/plugin-akash/package.json +++ b/packages/plugin-akash/package.json @@ -9,7 +9,10 @@ "build": "tsup", "dev": "tsup --watch", "clean": "rm -rf dist", - "lint:fix": "eslint . --fix", + "lint": "biome lint .", + "lint:fix": "biome check --apply .", + "format": "biome format .", + "format:fix": "biome format --write .", "test": "vitest", "test:watch": "vitest watch", "test:coverage": "vitest run --coverage", @@ -32,15 +35,13 @@ "ora": "^8.0.1" }, "devDependencies": { + "@biomejs/biome": "1.9.4", "@types/dotenv": "^8.2.0", "@types/jest": "^29.5.11", "@types/js-yaml": "^4.0.9", "@types/node": "^20.10.5", - "@typescript-eslint/eslint-plugin": "^6.15.0", - "@typescript-eslint/parser": "^6.15.0", "@vitest/coverage-v8": "^0.34.6", "@vitest/ui": "^0.34.6", - "eslint": "^9.16.0", "tsup": "^8.0.1", "typescript": "^5.3.3", "vite": "^5.0.10", diff --git a/packages/plugin-akash/src/actions/closeDeployment.ts b/packages/plugin-akash/src/actions/closeDeployment.ts index 47c7e17a64b..1b6b9a9fc6d 100644 --- a/packages/plugin-akash/src/actions/closeDeployment.ts +++ b/packages/plugin-akash/src/actions/closeDeployment.ts @@ -311,7 +311,7 @@ export const closeDeploymentAction: Action = { handler: async ( runtime: IAgentRuntime, message: Memory, - state: State | undefined, + _state: State | undefined, _options: { [key: string]: unknown } = {}, callback?: HandlerCallback ): Promise => { diff --git a/packages/plugin-akash/src/actions/createCertificate.ts b/packages/plugin-akash/src/actions/createCertificate.ts index 6e026596629..801d0e9863e 100644 --- a/packages/plugin-akash/src/actions/createCertificate.ts +++ b/packages/plugin-akash/src/actions/createCertificate.ts @@ -8,8 +8,8 @@ import type { CertificatePem } from "@akashnetwork/akashjs/build/certificates/ce import { getAkashTypeRegistry } from "@akashnetwork/akashjs/build/stargate"; import { validateAkashConfig } from "../environment"; import { AkashError, AkashErrorCode, withRetry } from "../error/error"; -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; import { Registry } from "@cosmjs/proto-signing"; import type { SigningStargateClient as AkashSigningStargateClient } from "@akashnetwork/akashjs/node_modules/@cosmjs/stargate"; import { getCertificatePath } from "../utils/paths"; @@ -271,7 +271,7 @@ export const createCertificateAction: Action = { handler: async ( runtime: IAgentRuntime, message: Memory, - state: State | undefined, + _state: State | undefined, options: { callback?: HandlerCallback } = {} ): Promise => { const actionId = Date.now().toString(); diff --git a/packages/plugin-akash/src/actions/createDeployment.ts b/packages/plugin-akash/src/actions/createDeployment.ts index 2032961fe44..d21cecd416c 100644 --- a/packages/plugin-akash/src/actions/createDeployment.ts +++ b/packages/plugin-akash/src/actions/createDeployment.ts @@ -13,8 +13,8 @@ import { DirectSecp256k1HdWallet, Registry } from "@cosmjs/proto-signing"; import { SigningStargateClient } from "@cosmjs/stargate"; import { validateAkashConfig } from "../environment"; import { AkashError, AkashErrorCode, withRetry } from "../error/error"; -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; import { getCertificatePath, getDefaultSDLPath } from "../utils/paths"; // import { fileURLToPath } from 'url'; import { inspectRuntime, isPluginLoaded } from "../runtime_inspect"; diff --git a/packages/plugin-akash/src/actions/getDeploymentApi.ts b/packages/plugin-akash/src/actions/getDeploymentApi.ts index 503be32530e..fc46ac9ed30 100644 --- a/packages/plugin-akash/src/actions/getDeploymentApi.ts +++ b/packages/plugin-akash/src/actions/getDeploymentApi.ts @@ -3,8 +3,8 @@ import type { IAgentRuntime, Memory, State, HandlerCallback, Content, ActionExam import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; import { validateAkashConfig } from "../environment"; import { AkashError, AkashErrorCode } from "../error/error"; -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; import { getDeploymentsPath } from "../utils/paths"; export interface DeploymentInfo { @@ -48,7 +48,7 @@ async function fetchWithRetry(url: string, options: RequestInit, retries = 3, de }); if (i < retries - 1) { - await sleep(delay * Math.pow(2, i)); // Exponential backoff + await sleep(delay * (2 ** i)); // Exponential backoff continue; } @@ -63,7 +63,7 @@ async function fetchWithRetry(url: string, options: RequestInit, retries = 3, de elizaLogger.warn(`API request error (attempt ${i + 1}/${retries})`, { error: error instanceof Error ? error.message : String(error) }); - await sleep(delay * Math.pow(2, i)); + await sleep(delay * (2 ** i)); } } throw new AkashError( @@ -336,7 +336,7 @@ export const getDeploymentApiAction: Action = { } as ActionExample ]], - validate: async (runtime: IAgentRuntime, message: Memory): Promise => { + validate: async (_runtime: IAgentRuntime, message: Memory): Promise => { elizaLogger.debug("Validating get deployments request", { message }); try { const params = message.content as Partial; @@ -381,7 +381,7 @@ export const getDeploymentApiAction: Action = { handler: async ( runtime: IAgentRuntime, message: Memory, - state: State | undefined, + _state: State | undefined, _options: { [key: string]: unknown } = {}, callback?: HandlerCallback ): Promise => { diff --git a/packages/plugin-akash/src/actions/getDeploymentStatus.ts b/packages/plugin-akash/src/actions/getDeploymentStatus.ts index b927a8961df..2dfd2abae5a 100644 --- a/packages/plugin-akash/src/actions/getDeploymentStatus.ts +++ b/packages/plugin-akash/src/actions/getDeploymentStatus.ts @@ -143,7 +143,7 @@ export const getDeploymentStatusAction: Action = { handler: async ( runtime: IAgentRuntime, message: Memory, - state: State | undefined, + _state: State | undefined, _options: { [key: string]: unknown } = {}, callback?: HandlerCallback ): Promise => { diff --git a/packages/plugin-akash/src/actions/getGPUPricing.ts b/packages/plugin-akash/src/actions/getGPUPricing.ts index a3a4073a2ea..395fa5796e2 100644 --- a/packages/plugin-akash/src/actions/getGPUPricing.ts +++ b/packages/plugin-akash/src/actions/getGPUPricing.ts @@ -58,23 +58,23 @@ export const getGPUPricingAction: Action = { } as ActionExample ]], - validate: async (runtime: IAgentRuntime, message: Memory): Promise => { + validate: async (_runtime: IAgentRuntime, message: Memory): Promise => { elizaLogger.debug("Validating GPU pricing request", { message }); try { const params = message.content as Partial; // Validate CPU if provided - if (params.cpu !== undefined && (isNaN(params.cpu) || params.cpu <= 0)) { + if (params.cpu !== undefined && (Number.isNaN(params.cpu) || params.cpu <= 0)) { throw new GPUPricingError("CPU units must be a positive number", "INVALID_CPU"); } // Validate memory if provided - if (params.memory !== undefined && (isNaN(params.memory) || params.memory <= 0)) { + if (params.memory !== undefined && (Number.isNaN(params.memory) || params.memory <= 0)) { throw new GPUPricingError("Memory must be a positive number", "INVALID_MEMORY"); } // Validate storage if provided - if (params.storage !== undefined && (isNaN(params.storage) || params.storage <= 0)) { + if (params.storage !== undefined && (Number.isNaN(params.storage) || params.storage <= 0)) { throw new GPUPricingError("Storage must be a positive number", "INVALID_STORAGE"); } @@ -91,9 +91,9 @@ export const getGPUPricingAction: Action = { }, handler: async ( - runtime: IAgentRuntime, + _runtime: IAgentRuntime, message: Memory, - state: State | undefined, + _state: State | undefined, _options: { [key: string]: unknown; } = {}, callback?: HandlerCallback ): Promise => { diff --git a/packages/plugin-akash/src/actions/getManifest.ts b/packages/plugin-akash/src/actions/getManifest.ts index 099ae0f412d..5760617d262 100644 --- a/packages/plugin-akash/src/actions/getManifest.ts +++ b/packages/plugin-akash/src/actions/getManifest.ts @@ -3,8 +3,8 @@ import type { IAgentRuntime, Memory, State, HandlerCallback, Content, ActionExam import { SDL } from "@akashnetwork/akashjs/build/sdl"; import { validateAkashConfig } from "../environment"; import { AkashError, AkashErrorCode } from "../error/error"; -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; import yaml from 'js-yaml'; // import { getAkashTypeRegistry } from "@akashnetwork/akashjs/build/stargate"; import { getDefaultSDLPath } from "../utils/paths"; @@ -70,7 +70,7 @@ const loadSDLFromFile = (filePath: string): string => { // If we get here, none of the paths worked throw new AkashError( - `SDL file not found in any of the possible locations`, + 'SDL file not found in any of the possible locations', AkashErrorCode.VALIDATION_SDL_FAILED, { filePath, @@ -185,7 +185,7 @@ export const getManifestAction: Action = { handler: async ( runtime: IAgentRuntime, message: Memory, - state: State | undefined, + _state: State | undefined, _options: { [key: string]: unknown; } = {}, callback?: HandlerCallback ): Promise => { diff --git a/packages/plugin-akash/src/actions/getProvidersList.ts b/packages/plugin-akash/src/actions/getProvidersList.ts index 8a01783fd27..e8449b82e55 100644 --- a/packages/plugin-akash/src/actions/getProvidersList.ts +++ b/packages/plugin-akash/src/actions/getProvidersList.ts @@ -162,7 +162,7 @@ export const getProvidersListAction: Action = { } as ActionExample ]], - validate: async (runtime: IAgentRuntime, message: Memory): Promise => { + validate: async (_runtime: IAgentRuntime, message: Memory): Promise => { elizaLogger.debug("Validating get providers list request", { message }); try { const params = message.content as Partial; @@ -210,7 +210,7 @@ export const getProvidersListAction: Action = { handler: async ( runtime: IAgentRuntime, message: Memory, - state: State | undefined, + _state: State | undefined, _options: { [key: string]: unknown; } = {}, callback?: HandlerCallback ): Promise => { diff --git a/packages/plugin-akash/src/error/error.ts b/packages/plugin-akash/src/error/error.ts index 0ddbdc603ee..9b6adeed193 100644 --- a/packages/plugin-akash/src/error/error.ts +++ b/packages/plugin-akash/src/error/error.ts @@ -1,4 +1,3 @@ - export enum AkashErrorCategory { WALLET = 'WALLET', DEPLOYMENT = 'DEPLOYMENT', @@ -117,7 +116,7 @@ export async function withRetry( } catch (error) { lastError = error as Error; if (i < maxRetries - 1) { - await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i))); + await new Promise(resolve => setTimeout(resolve, delay * (2 ** i))); } } } diff --git a/packages/plugin-akash/src/index.ts b/packages/plugin-akash/src/index.ts index fdd7f59f84d..5ff80a4aca3 100644 --- a/packages/plugin-akash/src/index.ts +++ b/packages/plugin-akash/src/index.ts @@ -1,4 +1,4 @@ -import { Plugin} from "@elizaos/core"; +import type { Plugin} from "@elizaos/core"; import chalk from 'chalk'; import Table from 'cli-table3'; import ora from 'ora'; diff --git a/packages/plugin-akash/src/runtime_inspect.ts b/packages/plugin-akash/src/runtime_inspect.ts index 25b5aee39fd..985b6d0d466 100644 --- a/packages/plugin-akash/src/runtime_inspect.ts +++ b/packages/plugin-akash/src/runtime_inspect.ts @@ -56,7 +56,7 @@ export function isPluginLoaded(runtime: IAgentRuntime, pluginName: string): bool // Check plugins array const plugins = (runtime as any).plugins as Plugin[]; if (!plugins) { - elizaLogger.warn(`No plugins array found in runtime`); + elizaLogger.warn('No plugins array found in runtime'); return false; } @@ -70,7 +70,7 @@ export function isPluginLoaded(runtime: IAgentRuntime, pluginName: string): bool // Check if actions are registered const actions = (runtime as any).actions as Action[]; if (!actions || !actions.length) { - elizaLogger.warn(`No actions found in runtime`); + elizaLogger.warn('No actions found in runtime'); return false; } From d7f83bce0b9e53b73bb71bd396101a7098f92b1a Mon Sep 17 00:00:00 2001 From: AIFlow_ML Date: Mon, 3 Feb 2025 04:20:38 +0700 Subject: [PATCH 13/24] Fixed the typing and added biome --- packages/plugin-agentkit/biome.json | 41 ++++++++++++++++++++++++ packages/plugin-agentkit/package.json | 7 +++- packages/plugin-agentkit/src/actions.ts | 6 ++-- packages/plugin-agentkit/src/provider.ts | 7 ++-- 4 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 packages/plugin-agentkit/biome.json diff --git a/packages/plugin-agentkit/biome.json b/packages/plugin-agentkit/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-agentkit/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-agentkit/package.json b/packages/plugin-agentkit/package.json index 19a716a51ed..12b633ddc39 100644 --- a/packages/plugin-agentkit/package.json +++ b/packages/plugin-agentkit/package.json @@ -12,6 +12,7 @@ "tsup": "8.3.5" }, "devDependencies": { + "@biomejs/biome": "1.9.4", "vitest": "^1.0.0" }, "scripts": { @@ -19,6 +20,10 @@ "dev": "tsup --format esm --dts --watch", "test": "vitest run", "test:watch": "vitest watch", - "test:coverage": "vitest run --coverage" + "test:coverage": "vitest run --coverage", + "lint": "biome lint .", + "lint:fix": "biome check --apply .", + "format": "biome format .", + "format:fix": "biome format --write ." } } diff --git a/packages/plugin-agentkit/src/actions.ts b/packages/plugin-agentkit/src/actions.ts index 7bf3827c51c..b08c65f927e 100644 --- a/packages/plugin-agentkit/src/actions.ts +++ b/packages/plugin-agentkit/src/actions.ts @@ -37,7 +37,7 @@ export async function getAgentKitActions({ runtime: IAgentRuntime, message: Memory, state: State | undefined, - options?: Record, + _options?: Record, callback?: HandlerCallback ): Promise => { try { @@ -93,7 +93,7 @@ export async function getAgentKitActions({ async function executeToolAction( tool: Tool, - parameters: any, + parameters: unknown, client: CdpAgentkit ): Promise { const toolkit = new CdpToolkit(client); @@ -107,7 +107,7 @@ async function executeToolAction( return await selectedTool.call(parameters); } -function composeParameterContext(tool: any, state: State): string { +function composeParameterContext(tool: Tool, state: State): string { const contextTemplate = `{{recentMessages}} Given the recent messages, extract the following information for the action "${tool.name}": diff --git a/packages/plugin-agentkit/src/provider.ts b/packages/plugin-agentkit/src/provider.ts index f55719e2c14..038a9c0143d 100644 --- a/packages/plugin-agentkit/src/provider.ts +++ b/packages/plugin-agentkit/src/provider.ts @@ -1,6 +1,6 @@ import type { Provider, IAgentRuntime } from "@elizaos/core"; import { CdpAgentkit } from "@coinbase/cdp-agentkit-core"; -import * as fs from "fs"; +import * as fs from "node:fs"; const WALLET_DATA_FILE = "wallet_data.txt"; @@ -46,10 +46,11 @@ export async function getClient(): Promise { } export const walletProvider: Provider = { - async get(runtime: IAgentRuntime): Promise { + async get(_runtime: IAgentRuntime): Promise { try { const client = await getClient(); - const address = (await (client as any).wallet.addresses)[0].id; + // Access wallet addresses using type assertion based on the known structure + const address = (client as unknown as { wallet: { addresses: Array<{ id: string }> } }).wallet.addresses[0].id; return `AgentKit Wallet Address: ${address}`; } catch (error) { console.error("Error in AgentKit provider:", error); From ebe6c14b539abf946f0080998eff50ec42a41059 Mon Sep 17 00:00:00 2001 From: AIFlow_ML Date: Mon, 3 Feb 2025 04:52:09 +0700 Subject: [PATCH 14/24] fixed all the issues but deployTokenAction.ts for the ANY and the result need probaly a refactoring. --- packages/plugin-abstract/biome.json | 41 +++++++++++++++++++ packages/plugin-abstract/eslint.config.mjs | 3 -- packages/plugin-abstract/package.json | 6 ++- .../src/actions/deployTokenAction.ts | 16 ++++---- .../src/actions/getBalanceAction.ts | 19 +++++---- .../src/actions/transferAction.ts | 40 ++++++++++++++---- 6 files changed, 96 insertions(+), 29 deletions(-) create mode 100644 packages/plugin-abstract/biome.json delete mode 100644 packages/plugin-abstract/eslint.config.mjs diff --git a/packages/plugin-abstract/biome.json b/packages/plugin-abstract/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-abstract/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-abstract/eslint.config.mjs b/packages/plugin-abstract/eslint.config.mjs deleted file mode 100644 index 92fe5bbebef..00000000000 --- a/packages/plugin-abstract/eslint.config.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import eslintGlobalConfig from "../../eslint.config.mjs"; - -export default [...eslintGlobalConfig]; diff --git a/packages/plugin-abstract/package.json b/packages/plugin-abstract/package.json index 4795f922ca6..65a97d495e5 100644 --- a/packages/plugin-abstract/package.json +++ b/packages/plugin-abstract/package.json @@ -25,7 +25,10 @@ "viem": "2.22.2" }, "scripts": { - "lint": "eslint --fix --cache .", + "lint": "biome lint .", + "lint:fix": "biome check --apply .", + "format": "biome format .", + "format:fix": "biome format --write .", "build": "tsup --format esm --no-dts", "dev": "tsup --format esm --no-dts --watch", "test": "vitest run", @@ -33,6 +36,7 @@ "test:coverage": "vitest run --coverage" }, "devDependencies": { + "@biomejs/biome": "1.9.4", "tsup": "8.3.5", "typescript": "4.9", "vitest": "^1.0.0" diff --git a/packages/plugin-abstract/src/actions/deployTokenAction.ts b/packages/plugin-abstract/src/actions/deployTokenAction.ts index e06a22fbf8b..83c30946a26 100644 --- a/packages/plugin-abstract/src/actions/deployTokenAction.ts +++ b/packages/plugin-abstract/src/actions/deployTokenAction.ts @@ -99,15 +99,17 @@ export const deployTokenAction: Action = { ): Promise => { elizaLogger.log("Starting Abstract DEPLOY_TOKEN handler..."); - if (!state) { - state = (await runtime.composeState(message)) as State; - } else { - state = await runtime.updateRecentMessageState(state); - } + // Initialize or update state + let currentState = state; + if (!currentState) { + currentState = (await runtime.composeState(message)) as State; + } else { + currentState = await runtime.updateRecentMessageState(currentState); + } - state.currentMessage = `${state.recentMessagesData[1].content.text}`; + currentState.currentMessage = `${currentState.recentMessagesData[1].content.text}`; const deployContext = composeContext({ - state, + state: currentState, template: deployTemplate, }); diff --git a/packages/plugin-abstract/src/actions/getBalanceAction.ts b/packages/plugin-abstract/src/actions/getBalanceAction.ts index 9b4c68ecd00..602fe375676 100644 --- a/packages/plugin-abstract/src/actions/getBalanceAction.ts +++ b/packages/plugin-abstract/src/actions/getBalanceAction.ts @@ -76,7 +76,7 @@ export const getBalanceAction: Action = { "BALANCE_CHECK", "TOKEN_BALANCE", ], - validate: async (runtime: IAgentRuntime, message: Memory) => { + validate: async (runtime: IAgentRuntime, _message: Memory) => { await validateAbstractConfig(runtime); return true; }, @@ -90,17 +90,18 @@ export const getBalanceAction: Action = { ): Promise => { elizaLogger.log("Starting Abstract GET_BALANCE handler..."); - // Initialize or update state - if (!state) { - state = (await runtime.composeState(message)) as State; - } else { - state = await runtime.updateRecentMessageState(state); - } + // Initialize or update state + let currentState = state; + if (!currentState) { + currentState = (await runtime.composeState(message)) as State; + } else { + currentState = await runtime.updateRecentMessageState(currentState); + } // Compose balance context - state.currentMessage = `${state.recentMessagesData[1].content.text}`; + currentState.currentMessage = `${currentState.recentMessagesData[1].content.text}`; const balanceContext = composeContext({ - state, + state: currentState, template: balanceTemplate, }); diff --git a/packages/plugin-abstract/src/actions/transferAction.ts b/packages/plugin-abstract/src/actions/transferAction.ts index a11eeef8102..4cc3f996cc3 100644 --- a/packages/plugin-abstract/src/actions/transferAction.ts +++ b/packages/plugin-abstract/src/actions/transferAction.ts @@ -26,6 +26,27 @@ import { getTokenByName, } from "../utils/viemHelpers"; +// Define types for Abstract client +interface AbstractTransactionRequest { + chain: typeof abstractTestnet; + to: string; + value: bigint; + kzg: undefined; +} + +interface AbstractContractRequest { + chain: typeof abstractTestnet; + address: string; + abi: typeof erc20Abi; + functionName: string; + args: [string, bigint]; +} + +interface AbstractClient { + sendTransaction: (request: AbstractTransactionRequest) => Promise; + writeContract: (request: AbstractContractRequest) => Promise; +} + const TransferSchema = z.object({ tokenAddress: z.string().optional().nullable(), recipient: z.string(), @@ -107,17 +128,18 @@ export const transferAction: Action = { ): Promise => { elizaLogger.log("Starting Abstract SEND_TOKEN handler..."); - // Initialize or update state - if (!state) { - state = (await runtime.composeState(message)) as State; - } else { - state = await runtime.updateRecentMessageState(state); - } + // Initialize or update state + let currentState = state; + if (!currentState) { + currentState = (await runtime.composeState(message)) as State; + } else { + currentState = await runtime.updateRecentMessageState(currentState); + } // Compose transfer context - state.currentMessage = `${state.recentMessagesData[1].content.text}`; + currentState.currentMessage = `${currentState.recentMessagesData[1].content.text}`; const transferContext = composeContext({ - state, + state: currentState, template: transferTemplate, }); @@ -204,7 +226,7 @@ export const transferAction: Action = { const abstractClient = (await createAbstractClient({ chain: abstractTestnet, signer: account, - })) as any; // biome-ignore lint/suspicious/noExplicitAny: type being exported as never + })) as AbstractClient; if (isEthTransfer) { hash = await abstractClient.sendTransaction({ From 9822f49d62026658b77f1ac85b0669a2a3d8e9c8 Mon Sep 17 00:00:00 2001 From: AIFlow_ML Date: Mon, 3 Feb 2025 05:02:21 +0700 Subject: [PATCH 15/24] Fixed all the issues and added biome --- packages/plugin-3d-generation/biome.json | 41 ++++++++++++++++++++++ packages/plugin-3d-generation/package.json | 7 +++- packages/plugin-3d-generation/src/index.ts | 10 +++--- 3 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 packages/plugin-3d-generation/biome.json diff --git a/packages/plugin-3d-generation/biome.json b/packages/plugin-3d-generation/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-3d-generation/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-3d-generation/package.json b/packages/plugin-3d-generation/package.json index cd3e821b0ad..85e57b61212 100644 --- a/packages/plugin-3d-generation/package.json +++ b/packages/plugin-3d-generation/package.json @@ -24,12 +24,17 @@ "whatwg-url": "7.1.0" }, "devDependencies": { + "@biomejs/biome": "1.5.3", "vitest": "^2.1.5" }, "scripts": { "build": "tsup --format esm --dts", "dev": "tsup --format esm --dts --watch", - "test": "vitest run" + "test": "vitest run", + "lint": "biome check src/", + "lint:fix": "biome check --apply src/", + "format": "biome format src/", + "format:fix": "biome format --write src/" }, "peerDependencies": { "whatwg-url": "7.1.0" diff --git a/packages/plugin-3d-generation/src/index.ts b/packages/plugin-3d-generation/src/index.ts index f0d2bb2e5db..b6b516bee19 100644 --- a/packages/plugin-3d-generation/src/index.ts +++ b/packages/plugin-3d-generation/src/index.ts @@ -10,10 +10,10 @@ import type { import { fal } from "@fal-ai/client"; import { FAL_CONSTANTS } from "./constants"; -import * as fs from "fs"; -import { Buffer } from "buffer"; -import * as path from "path"; -import * as process from "process"; +import * as fs from "node:fs"; +import { Buffer } from "node:buffer"; +import * as path from "node:path"; +import * as process from "node:process"; const generate3D = async (prompt: string, runtime: IAgentRuntime) => { process.env["FAL_KEY"] = @@ -84,7 +84,7 @@ const ThreeDGeneration: Action = { runtime: IAgentRuntime, message: Memory, _state: State, - _options: any, + _options: Record, callback: HandlerCallback ) => { elizaLogger.log("3D generation request:", message); From 329cc14ea3a8465ebf0fe26df9711dc0a6919c9f Mon Sep 17 00:00:00 2001 From: AIFlow_ML Date: Mon, 3 Feb 2025 05:29:51 +0700 Subject: [PATCH 16/24] Fixed all the issues and added Biome --- packages/plugin-0x/biome.json | 41 ++++++++++++++ packages/plugin-0x/package.json | 13 ++++- packages/plugin-0x/src/EVMtokenRegistry.ts | 6 +-- .../src/actions/getIndicativePrice.ts | 30 +++++------ packages/plugin-0x/src/actions/getQuote.ts | 54 +++++++++---------- packages/plugin-0x/src/actions/swap.ts | 29 +++++----- packages/plugin-0x/src/constants.ts | 2 +- .../src/hooks.ts/useGetWalletClient.ts | 4 +- packages/plugin-0x/src/index.ts | 2 +- 9 files changed, 115 insertions(+), 66 deletions(-) create mode 100644 packages/plugin-0x/biome.json diff --git a/packages/plugin-0x/biome.json b/packages/plugin-0x/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-0x/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-0x/package.json b/packages/plugin-0x/package.json index 517c3f96fee..2949450152e 100644 --- a/packages/plugin-0x/package.json +++ b/packages/plugin-0x/package.json @@ -21,13 +21,22 @@ "scripts": { "build": "tsup --format esm --dts", "dev": "tsup --format esm --dts --watch", - "test": "vitest run" + "test": "vitest run", + "lint": "biome check src/", + "lint:fix": "biome check --apply src/", + "format": "biome format src/", + "format:fix": "biome format --write src/" }, "dependencies": { + "@elizaos/core": "workspace:*", + "tsup": "^8.0.1", + "whatwg-url": "7.1.0", "@0x/swap-ts-sdk": "2.1.1" }, "devDependencies": { - "tsup": "^8.0.1" + "tsup": "^8.0.1", + "@biomejs/biome": "1.5.3", + "vitest": "^2.1.5" }, "peerDependencies": { "@elizaos/core": "workspace:*", diff --git a/packages/plugin-0x/src/EVMtokenRegistry.ts b/packages/plugin-0x/src/EVMtokenRegistry.ts index 51a674b941d..39075f71a5a 100644 --- a/packages/plugin-0x/src/EVMtokenRegistry.ts +++ b/packages/plugin-0x/src/EVMtokenRegistry.ts @@ -1,9 +1,9 @@ import { elizaLogger } from "@elizaos/core"; import { Chains, - TokenMetadata, - TrustWalletGithubJson, - TrustWalletTokenMetadata, + type TokenMetadata, + type TrustWalletGithubJson, + type TrustWalletTokenMetadata, } from "./types"; import { NATIVE_TOKENS } from "./constants"; diff --git a/packages/plugin-0x/src/actions/getIndicativePrice.ts b/packages/plugin-0x/src/actions/getIndicativePrice.ts index b73ceee4ca8..7a9a469d46c 100644 --- a/packages/plugin-0x/src/actions/getIndicativePrice.ts +++ b/packages/plugin-0x/src/actions/getIndicativePrice.ts @@ -1,9 +1,9 @@ import { - Action, - IAgentRuntime, - Memory, - State, - HandlerCallback, + type Action, + type IAgentRuntime, + type Memory, + type State, + type HandlerCallback, elizaLogger, composeContext, ModelClass, @@ -13,7 +13,7 @@ import { import { createClientV2 } from "@0x/swap-ts-sdk"; import { getIndicativePriceTemplate } from "../templates"; import { z } from "zod"; -import { Chains, GetIndicativePriceResponse, PriceInquiry } from "../types"; +import { Chains, type GetIndicativePriceResponse, type PriceInquiry } from "../types"; import { parseUnits } from "viem"; import { CHAIN_NAMES, ZX_MEMORY } from "../constants"; import { EVMTokenRegistry } from "../EVMtokenRegistry"; @@ -45,17 +45,17 @@ export const getIndicativePrice: Action = { runtime: IAgentRuntime, message: Memory, state: State, - options: Record, + _options: Record, callback: HandlerCallback ) => { const supportedChains = Object.keys(Chains).join(" | "); - state = !state + const localState = !state ? await runtime.composeState(message, { supportedChains }) : await runtime.updateRecentMessageState(state); const context = composeContext({ - state, + state: localState, template: getIndicativePriceTemplate, }); @@ -86,7 +86,7 @@ export const getIndicativePrice: Action = { text: `Unsupported chain: ${chain}. Supported chains are: ${Object.keys( Chains ) - .filter((k) => isNaN(Number(k))) + .filter((k) => !Number.isNaN(Number(k))) .join(", ")}`, }); return; @@ -148,10 +148,10 @@ export const getIndicativePrice: Action = { // Format amounts to human-readable numbers const buyAmount = Number(price.buyAmount) / - Math.pow(10, buyTokenMetadata.decimals); + (10 ** buyTokenMetadata.decimals); const sellAmount = Number(price.sellAmount) / - Math.pow(10, sellTokenMetadata.decimals); + (10 ** sellTokenMetadata.decimals); await storePriceInquiryToMemory(runtime, message, { sellTokenObject: sellTokenMetadata, @@ -163,13 +163,13 @@ export const getIndicativePrice: Action = { // Updated formatted response to include chain const formattedResponse = [ - `💱 Swap Details:`, - `────────────────`, + "💱 Swap Details:", + "────────────────", `📤 Sell: ${sellAmount.toFixed(4)} ${sellTokenMetadata.symbol}`, `📥 Buy: ${buyAmount.toFixed(4)} ${buyTokenMetadata.symbol}`, `📊 Rate: 1 ${sellTokenMetadata.symbol} = ${(buyAmount / sellAmount).toFixed(4)} ${buyTokenMetadata.symbol}`, `🔗 Chain: ${CHAIN_NAMES[chainId]}`, - `────────────────`, + "────────────────", `💫 Happy with the price? Type 'quote' to continue`, ].join("\n"); diff --git a/packages/plugin-0x/src/actions/getQuote.ts b/packages/plugin-0x/src/actions/getQuote.ts index 9d50beb94d1..d4df553fe71 100644 --- a/packages/plugin-0x/src/actions/getQuote.ts +++ b/packages/plugin-0x/src/actions/getQuote.ts @@ -1,13 +1,13 @@ import { - Action, - IAgentRuntime, - Memory, - State, - HandlerCallback, + type Action, + type IAgentRuntime, + type Memory, + type State, + type HandlerCallback, elizaLogger, MemoryManager, } from "@elizaos/core"; -import { GetQuoteResponse, PriceInquiry, Quote } from "../types"; +import type { GetQuoteResponse, PriceInquiry, Quote } from "../types"; import { formatTokenAmount } from "../utils"; import { CHAIN_NAMES, NATIVE_TOKENS, ZX_MEMORY } from "../constants"; import { createClientV2 } from "@0x/swap-ts-sdk"; @@ -25,8 +25,8 @@ export const getQuote: Action = { handler: async ( runtime: IAgentRuntime, message: Memory, - state: State, - options: Record, + _state: State, + _options: Record, callback: HandlerCallback ) => { const latestPriceInquiry = await retrieveLatestPriceInquiry( @@ -89,7 +89,7 @@ export const getQuote: Action = { const warnings = []; if (quote.issues?.balance) { warnings.push( - `⚠️ Warnings:`, + "⚠️ Warnings:", ` • Insufficient balance (Have ${formatTokenAmount( quote.issues.balance.actual, quote.issues.balance.token, @@ -99,8 +99,8 @@ export const getQuote: Action = { } const formattedResponse = [ - `🎯 Firm Quote Details:`, - `────────────────`, + "🎯 Firm Quote Details:", + "────────────────", // Basic swap details (same as price) `📤 Sell: ${formatTokenAmount( quote.sellAmount, @@ -125,7 +125,7 @@ export const getQuote: Action = { )}`, // Fee breakdown - `💰 Fees Breakdown:`, + "💰 Fees Breakdown:", ` • 0x Protocol Fee: ${formatTokenAmount( quote.fees.zeroExFee?.amount, quote.fees.zeroExFee?.token, @@ -153,8 +153,8 @@ export const getQuote: Action = { ...(warnings.length > 0 ? warnings : []), - `────────────────`, - `💫 Ready to execute? Type 'execute' to continue`, + "────────────────", + "💫 Ready to execute? Type 'execute' to continue", ] .filter(Boolean) .join("\n"); @@ -223,20 +223,20 @@ export const getQuote: Action = { ], }; -const formatTime = (time: string) => { - const expirationDate = new Date(parseInt(time) * 1000); +// const formatTime = (time: string) => { +// const expirationDate = new Date(parseInt(time) * 1000); - // Format: "Mar 15, 2:30 PM" - const formattedTime = expirationDate.toLocaleString(undefined, { - month: "short", - day: "numeric", - hour: "numeric", - minute: "2-digit", - hour12: true, - }); +// // Format: "Mar 15, 2:30 PM" +// const formattedTime = expirationDate.toLocaleString(undefined, { +// month: "short", +// day: "numeric", +// hour: "numeric", +// minute: "2-digit", +// hour12: true, +// }); - return `${formattedTime}`; -}; +// return `${formattedTime}`; +// }; export const retrieveLatestPriceInquiry = async ( runtime: IAgentRuntime, @@ -260,7 +260,7 @@ export const retrieveLatestPriceInquiry = async ( } return null; } catch (error) { - elizaLogger.error(`Failed to retrieve price inquiry: ${error.message}`); + elizaLogger.error("Failed to retrieve price inquiry:", error.message); return null; } }; diff --git a/packages/plugin-0x/src/actions/swap.ts b/packages/plugin-0x/src/actions/swap.ts index 17da2721440..2183d8be3d9 100644 --- a/packages/plugin-0x/src/actions/swap.ts +++ b/packages/plugin-0x/src/actions/swap.ts @@ -1,16 +1,16 @@ import { - Action, - IAgentRuntime, - Memory, - State, - HandlerCallback, + type Action, + type IAgentRuntime, + type Memory, + type State, + type HandlerCallback, elizaLogger, MemoryManager, } from "@elizaos/core"; -import { Hex, numberToHex, concat } from "viem"; +import { type Hex, numberToHex, concat } from "viem"; import { CHAIN_EXPLORERS, ZX_MEMORY } from "../constants"; import { getWalletClient } from "../hooks.ts/useGetWalletClient"; -import { Quote } from "../types"; +import type { Quote } from "../types"; export const swap: Action = { name: "EXECUTE_SWAP_0X", @@ -31,8 +31,8 @@ export const swap: Action = { handler: async ( runtime: IAgentRuntime, message: Memory, - state: State, - options: Record, + _state: State, + _options: Record, callback: HandlerCallback ) => { const latestQuote = await retrieveLatestQuote(runtime, message); @@ -99,13 +99,12 @@ export const swap: Action = { content: { hash: txHash, status: "success" }, }); return true; - } else { - callback({ - text: `❌ Swap failed! Check transaction: ${CHAIN_EXPLORERS[chainId]}/tx/${txHash}`, - content: { hash: txHash, status: "failed" }, - }); - return false; } + callback({ + text: `❌ Swap failed! Check transaction: ${CHAIN_EXPLORERS[chainId]}/tx/${txHash}`, + content: { hash: txHash, status: "failed" }, + }); + return false; } catch (error) { elizaLogger.error("Swap execution failed:", error); callback({ diff --git a/packages/plugin-0x/src/constants.ts b/packages/plugin-0x/src/constants.ts index f51220a229a..f161bbb0729 100644 --- a/packages/plugin-0x/src/constants.ts +++ b/packages/plugin-0x/src/constants.ts @@ -1,4 +1,4 @@ -import { Chains, TokenMetadata } from "./types"; +import { Chains, type TokenMetadata } from "./types"; export const ZX_MEMORY = { price: { diff --git a/packages/plugin-0x/src/hooks.ts/useGetWalletClient.ts b/packages/plugin-0x/src/hooks.ts/useGetWalletClient.ts index 5bc7238bb3b..25516a3808d 100644 --- a/packages/plugin-0x/src/hooks.ts/useGetWalletClient.ts +++ b/packages/plugin-0x/src/hooks.ts/useGetWalletClient.ts @@ -3,8 +3,8 @@ import { http, publicActions, createTestClient, - WalletClient, - PublicClient, + type WalletClient, + type PublicClient, walletActions, } from "viem"; diff --git a/packages/plugin-0x/src/index.ts b/packages/plugin-0x/src/index.ts index f7f493eae20..a8fd1471137 100644 --- a/packages/plugin-0x/src/index.ts +++ b/packages/plugin-0x/src/index.ts @@ -1,4 +1,4 @@ -import { Plugin } from "@elizaos/core"; +import type { Plugin } from "@elizaos/core"; import { getIndicativePrice } from "./actions/getIndicativePrice"; import { getQuote } from "./actions/getQuote"; import { swap } from "./actions/swap"; From 625338be384dff50fae567da1acad791b1733ab0 Mon Sep 17 00:00:00 2001 From: AIFlow_ML Date: Mon, 3 Feb 2025 05:48:34 +0700 Subject: [PATCH 17/24] Fixed all the issues and added biome. Only issues still in place in upload.ts i had to add an any to overcome the issue on the line 370 const flowContract = getFlowContract(runtime.getSetting(ZEROG_FLOW_ADDRESS), signer as any); --- packages/plugin-0g/biome.json | 41 ++++++++++++++++++++++++ packages/plugin-0g/eslint.config.mjs | 3 -- packages/plugin-0g/package.json | 6 +++- packages/plugin-0g/src/actions/upload.ts | 26 ++++++++------- packages/plugin-0g/src/utils/security.ts | 4 +-- 5 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 packages/plugin-0g/biome.json delete mode 100644 packages/plugin-0g/eslint.config.mjs diff --git a/packages/plugin-0g/biome.json b/packages/plugin-0g/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-0g/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-0g/eslint.config.mjs b/packages/plugin-0g/eslint.config.mjs deleted file mode 100644 index 92fe5bbebef..00000000000 --- a/packages/plugin-0g/eslint.config.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import eslintGlobalConfig from "../../eslint.config.mjs"; - -export default [...eslintGlobalConfig]; diff --git a/packages/plugin-0g/package.json b/packages/plugin-0g/package.json index 8fddc8a82bc..89b4ca1f2d1 100644 --- a/packages/plugin-0g/package.json +++ b/packages/plugin-0g/package.json @@ -25,12 +25,16 @@ "tsup": "8.3.5" }, "devDependencies": { + "@biomejs/biome": "1.5.3", "vitest": "^1.2.1" }, "scripts": { "build": "tsup --format esm --dts", "dev": "tsup --format esm --dts --watch", "test": "vitest run", - "lint": "eslint --fix --cache ." + "lint": "biome check src/", + "lint:fix": "biome check --apply src/", + "format": "biome format src/", + "format:fix": "biome format --write src/" } } diff --git a/packages/plugin-0g/src/actions/upload.ts b/packages/plugin-0g/src/actions/upload.ts index 23615831800..639da61a140 100644 --- a/packages/plugin-0g/src/actions/upload.ts +++ b/packages/plugin-0g/src/actions/upload.ts @@ -11,9 +11,9 @@ import { elizaLogger, } from "@elizaos/core"; import { Indexer, ZgFile, getFlowContract } from "@0glabs/0g-ts-sdk"; -import { ethers } from "ethers"; +import { ethers, Wallet } from "ethers"; import { composeContext } from "@elizaos/core"; -import { promises as fs } from "fs"; +import { promises as fs, type Stats } from "node:fs"; import { FileSecurityValidator } from "../utils/security"; import { logSecurityEvent, monitorUpload, monitorFileValidation, monitorCleanup } from '../utils/monitoring'; import { uploadTemplate } from "../templates/upload"; @@ -24,10 +24,10 @@ export interface UploadContent extends Content { function isUploadContent( _runtime: IAgentRuntime, - content: any + content: unknown ): content is UploadContent { elizaLogger.debug("Validating upload content", { content }); - return typeof content.filePath === "string"; + return typeof content === "object" && content !== null && "filePath" in content && typeof (content as UploadContent).filePath === "string"; } export const zgUpload: Action = { @@ -82,7 +82,7 @@ export const zgUpload: Action = { }; // Validate config values - if (isNaN(config.maxFileSize) || config.maxFileSize <= 0) { + if (Number.isNaN(config.maxFileSize) || config.maxFileSize <= 0) { elizaLogger.error("Invalid ZEROG_MAX_FILE_SIZE setting", { value: runtime.getSetting("ZEROG_MAX_FILE_SIZE"), messageId: message.id @@ -117,7 +117,7 @@ export const zgUpload: Action = { runtime: IAgentRuntime, message: Memory, state: State, - _options: any, + _options: Record, callback: HandlerCallback ) => { elizaLogger.info("ZG_UPLOAD action started", { @@ -131,18 +131,20 @@ export const zgUpload: Action = { try { // Update state if needed - if (!state) { + // Initialize or update state + let currentState = state; + if (!currentState) { elizaLogger.debug("No state provided, composing new state"); - state = (await runtime.composeState(message)) as State; + currentState = (await runtime.composeState(message)) as State; } else { elizaLogger.debug("Updating existing state"); - state = await runtime.updateRecentMessageState(state); + currentState = await runtime.updateRecentMessageState(currentState); } // Compose upload context elizaLogger.debug("Composing upload context"); const uploadContext = composeContext({ - state, + state: currentState, template: uploadTemplate, }); @@ -307,7 +309,7 @@ export const zgUpload: Action = { // Start upload monitoring const startTime = Date.now(); - let fileStats; + let fileStats: Stats; try { fileStats = await fs.stat(sanitizedPath); elizaLogger.debug("File stats retrieved", { @@ -365,7 +367,7 @@ export const zgUpload: Action = { const provider = new ethers.JsonRpcProvider(runtime.getSetting("ZEROG_EVM_RPC")); const signer = new ethers.Wallet(runtime.getSetting("ZEROG_PRIVATE_KEY"), provider); const indexer = new Indexer(runtime.getSetting("ZEROG_INDEXER_RPC")); - const flowContract = getFlowContract(runtime.getSetting("ZEROG_FLOW_ADDRESS"), signer); + const flowContract = getFlowContract(runtime.getSetting("ZEROG_FLOW_ADDRESS"), signer as any); // Upload file to ZeroG elizaLogger.info("Starting file upload to ZeroG", { diff --git a/packages/plugin-0g/src/utils/security.ts b/packages/plugin-0g/src/utils/security.ts index 2f84af5dc25..6b2e3df898f 100644 --- a/packages/plugin-0g/src/utils/security.ts +++ b/packages/plugin-0g/src/utils/security.ts @@ -1,5 +1,5 @@ -import { promises as fs } from 'fs'; -import path from 'path'; +import { promises as fs } from 'node:fs'; +import path from 'node:path'; export interface SecurityConfig { maxFileSize: number; From 40931b48bdc4037ee9356f50da9676854c93772d Mon Sep 17 00:00:00 2001 From: AIFlow_ML Date: Mon, 3 Feb 2025 05:59:47 +0700 Subject: [PATCH 18/24] Added biome to - plugin-zksync-era - plugin-zilliqa - plugin-zerion - plugin-whatsapp --- packages/plugin-whatsapp/biome.json | 41 ++++++++++++++++++++ packages/plugin-whatsapp/package.json | 7 +++- packages/plugin-zerion/biome.json | 41 ++++++++++++++++++++ packages/plugin-zerion/eslint.config.mjs | 3 -- packages/plugin-zerion/package.json | 6 ++- packages/plugin-zilliqa/biome.json | 41 ++++++++++++++++++++ packages/plugin-zilliqa/package.json | 9 ++++- packages/plugin-zksync-era/biome.json | 41 ++++++++++++++++++++ packages/plugin-zksync-era/eslint.config.mjs | 3 -- packages/plugin-zksync-era/package.json | 8 +++- 10 files changed, 190 insertions(+), 10 deletions(-) create mode 100644 packages/plugin-whatsapp/biome.json create mode 100644 packages/plugin-zerion/biome.json delete mode 100644 packages/plugin-zerion/eslint.config.mjs create mode 100644 packages/plugin-zilliqa/biome.json create mode 100644 packages/plugin-zksync-era/biome.json delete mode 100644 packages/plugin-zksync-era/eslint.config.mjs diff --git a/packages/plugin-whatsapp/biome.json b/packages/plugin-whatsapp/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-whatsapp/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-whatsapp/package.json b/packages/plugin-whatsapp/package.json index 13853dc3c14..0520cb7a9bc 100644 --- a/packages/plugin-whatsapp/package.json +++ b/packages/plugin-whatsapp/package.json @@ -23,13 +23,18 @@ "build": "tsup --format esm --dts", "dev": "tsup --format esm --dts --watch", "test": "vitest run", - "coverage": "vitest run --coverage" + "coverage": "vitest run --coverage", + "lint": "biome check src/", + "lint:fix": "biome check --apply src/", + "format": "biome format src/", + "format:fix": "biome format --write src/" }, "dependencies": { "@elizaos/core": "workspace:*", "axios": "1.7.8" }, "devDependencies": { + "@biomejs/biome": "1.5.3", "@types/node": "20.17.9", "@typescript-eslint/eslint-plugin": "8.16.0", "@typescript-eslint/parser": "8.16.0", diff --git a/packages/plugin-zerion/biome.json b/packages/plugin-zerion/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-zerion/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-zerion/eslint.config.mjs b/packages/plugin-zerion/eslint.config.mjs deleted file mode 100644 index 92fe5bbebef..00000000000 --- a/packages/plugin-zerion/eslint.config.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import eslintGlobalConfig from "../../eslint.config.mjs"; - -export default [...eslintGlobalConfig]; diff --git a/packages/plugin-zerion/package.json b/packages/plugin-zerion/package.json index e4dc7d34803..6d668a0a138 100644 --- a/packages/plugin-zerion/package.json +++ b/packages/plugin-zerion/package.json @@ -8,11 +8,15 @@ "@elizaos/core": "workspace:*" }, "devDependencies": { + "@biomejs/biome": "1.5.3", "tsup": "^8.3.5" }, "scripts": { "build": "tsup --format esm --dts", "dev": "tsup --format esm --dts --watch", - "lint": "eslint --fix --cache ." + "lint": "biome check src/", + "lint:fix": "biome check --apply src/", + "format": "biome format src/", + "format:fix": "biome format --write src/" } } diff --git a/packages/plugin-zilliqa/biome.json b/packages/plugin-zilliqa/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-zilliqa/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-zilliqa/package.json b/packages/plugin-zilliqa/package.json index b83ac6845b8..ed4c74e6279 100644 --- a/packages/plugin-zilliqa/package.json +++ b/packages/plugin-zilliqa/package.json @@ -16,9 +16,16 @@ "@zilliqa-js/zilliqa": "^3.5.0", "tsup": "8.3.5" }, + "devDependencies": { + "@biomejs/biome": "1.5.3" + }, "scripts": { "build": "tsup --format esm --dts", - "dev": "tsup --format esm --dts --watch" + "dev": "tsup --format esm --dts --watch", + "lint": "biome check src/", + "lint:fix": "biome check --apply src/", + "format": "biome format src/", + "format:fix": "biome format --write src/" }, "peerDependencies": { "whatwg-url": "7.1.0" diff --git a/packages/plugin-zksync-era/biome.json b/packages/plugin-zksync-era/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-zksync-era/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-zksync-era/eslint.config.mjs b/packages/plugin-zksync-era/eslint.config.mjs deleted file mode 100644 index 92fe5bbebef..00000000000 --- a/packages/plugin-zksync-era/eslint.config.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import eslintGlobalConfig from "../../eslint.config.mjs"; - -export default [...eslintGlobalConfig]; diff --git a/packages/plugin-zksync-era/package.json b/packages/plugin-zksync-era/package.json index 3ef16373690..da568e5fdbe 100644 --- a/packages/plugin-zksync-era/package.json +++ b/packages/plugin-zksync-era/package.json @@ -23,9 +23,15 @@ "tsup": "^8.3.5", "viem": "2.22.2" }, + "devDependencies": { + "@biomejs/biome": "1.5.3" + }, "scripts": { "build": "tsup --format esm --dts", - "lint": "eslint --fix --cache ." + "lint": "biome check src/", + "lint:fix": "biome check --apply src/", + "format": "biome format src/", + "format:fix": "biome format --write src/" }, "peerDependencies": { "whatwg-url": "7.1.0" From 247ccdae8e2b6c14f789606153c94d8717b61ca2 Mon Sep 17 00:00:00 2001 From: AIFlow_ML Date: Mon, 3 Feb 2025 06:10:41 +0700 Subject: [PATCH 19/24] Add Biome linting and formatting configuration to the following plugins: - plugin-web-search - plugin-video-generation - plugin-udio - plugin-twitter --- packages/plugin-twitter/biome.json | 41 +++++++++++++++++++ packages/plugin-twitter/eslint.config.mjs | 3 -- packages/plugin-twitter/package.json | 6 ++- packages/plugin-udio/biome.json | 41 +++++++++++++++++++ packages/plugin-udio/eslint.config.mjs | 3 -- packages/plugin-udio/package.json | 13 ++++-- packages/plugin-video-generation/biome.json | 41 +++++++++++++++++++ packages/plugin-video-generation/package.json | 10 ++++- packages/plugin-web-search/biome.json | 41 +++++++++++++++++++ packages/plugin-web-search/eslint.config.mjs | 3 -- packages/plugin-web-search/package.json | 8 +++- 11 files changed, 195 insertions(+), 15 deletions(-) create mode 100644 packages/plugin-twitter/biome.json delete mode 100644 packages/plugin-twitter/eslint.config.mjs create mode 100644 packages/plugin-udio/biome.json delete mode 100644 packages/plugin-udio/eslint.config.mjs create mode 100644 packages/plugin-video-generation/biome.json create mode 100644 packages/plugin-web-search/biome.json delete mode 100644 packages/plugin-web-search/eslint.config.mjs diff --git a/packages/plugin-twitter/biome.json b/packages/plugin-twitter/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-twitter/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-twitter/eslint.config.mjs b/packages/plugin-twitter/eslint.config.mjs deleted file mode 100644 index 92fe5bbebef..00000000000 --- a/packages/plugin-twitter/eslint.config.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import eslintGlobalConfig from "../../eslint.config.mjs"; - -export default [...eslintGlobalConfig]; diff --git a/packages/plugin-twitter/package.json b/packages/plugin-twitter/package.json index 09cbeb222a7..a6b181a3d95 100644 --- a/packages/plugin-twitter/package.json +++ b/packages/plugin-twitter/package.json @@ -24,6 +24,7 @@ "tsup": "8.3.5" }, "devDependencies": { + "@biomejs/biome": "1.5.3", "vitest": "^1.0.0" }, "scripts": { @@ -31,6 +32,9 @@ "dev": "tsup --format esm --dts --watch", "test": "vitest run", "test:watch": "vitest", - "lint": "eslint --fix --cache ." + "lint": "biome check src/", + "lint:fix": "biome check --apply src/", + "format": "biome format src/", + "format:fix": "biome format --write src/" } } diff --git a/packages/plugin-udio/biome.json b/packages/plugin-udio/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-udio/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-udio/eslint.config.mjs b/packages/plugin-udio/eslint.config.mjs deleted file mode 100644 index 92fe5bbebef..00000000000 --- a/packages/plugin-udio/eslint.config.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import eslintGlobalConfig from "../../eslint.config.mjs"; - -export default [...eslintGlobalConfig]; diff --git a/packages/plugin-udio/package.json b/packages/plugin-udio/package.json index 12ba10cb4fe..994fda5b366 100644 --- a/packages/plugin-udio/package.json +++ b/packages/plugin-udio/package.json @@ -3,19 +3,26 @@ "version": "0.1.9", "description": "Suno AI Music Generation Plugin for Eliza", "main": "dist/index.js", + "type": "module", "types": "dist/index.d.ts", "scripts": { - "build": "tsup", + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "lint": "biome check src/", + "lint:fix": "biome check --apply src/", + "format": "biome format src/", + "format:fix": "biome format --write src/", "test": "jest" }, "dependencies": { - "@elizaos/core": "^0.1.0" + "@elizaos/core": "workspace:*" }, "devDependencies": { + "@biomejs/biome": "1.5.3", "typescript": "^5.0.0", "@types/node": "^16.0.0", "jest": "^27.0.0", "@types/jest": "^27.0.0", - "tsup": "^7.2.0" + "tsup": "^8.3.5" } } diff --git a/packages/plugin-video-generation/biome.json b/packages/plugin-video-generation/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-video-generation/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-video-generation/package.json b/packages/plugin-video-generation/package.json index 8656816e84d..78626b94f12 100644 --- a/packages/plugin-video-generation/package.json +++ b/packages/plugin-video-generation/package.json @@ -22,9 +22,17 @@ "@elizaos/core": "workspace:*", "tsup": "8.3.5" }, + "devDependencies": { + "@biomejs/biome": "1.5.3", + "tsup": "^8.3.5" + }, "scripts": { "build": "tsup --format esm --dts", - "dev": "tsup --format esm --dts --watch" + "dev": "tsup --format esm --dts --watch", + "lint": "biome check src/", + "lint:fix": "biome check --apply src/", + "format": "biome format src/", + "format:fix": "biome format --write src/" }, "peerDependencies": { "whatwg-url": "7.1.0" diff --git a/packages/plugin-web-search/biome.json b/packages/plugin-web-search/biome.json new file mode 100644 index 00000000000..818716a6219 --- /dev/null +++ b/packages/plugin-web-search/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedVariables": "error" + }, + "suspicious": { + "noExplicitAny": "error" + }, + "style": { + "useConst": "error", + "useImportType": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "es5" + } + }, + "files": { + "ignore": [ + "dist/**/*", + "extra/**/*", + "node_modules/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/plugin-web-search/eslint.config.mjs b/packages/plugin-web-search/eslint.config.mjs deleted file mode 100644 index 92fe5bbebef..00000000000 --- a/packages/plugin-web-search/eslint.config.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import eslintGlobalConfig from "../../eslint.config.mjs"; - -export default [...eslintGlobalConfig]; diff --git a/packages/plugin-web-search/package.json b/packages/plugin-web-search/package.json index d72a50372b7..5e73a372310 100644 --- a/packages/plugin-web-search/package.json +++ b/packages/plugin-web-search/package.json @@ -24,10 +24,16 @@ "tsup": "8.3.5", "js-tiktoken": "1.0.15" }, + "devDependencies": { + "@biomejs/biome": "1.5.3" + }, "scripts": { "build": "tsup --format esm --dts", "dev": "tsup --format esm --dts --watch", - "lint": "eslint --fix --cache ." + "lint": "biome check src/", + "lint:fix": "biome check --apply src/", + "format": "biome format src/", + "format:fix": "biome format --write src/" }, "peerDependencies": { "whatwg-url": "7.1.0" From 45e58e9faf6e41ff17a5f4c92fbf44d969c3cdca Mon Sep 17 00:00:00 2001 From: Shakker Nerd <165377636+shakkernerd@users.noreply.github.com> Date: Sun, 2 Feb 2025 23:15:19 +0000 Subject: [PATCH 20/24] chore: remove multiple tsup package --- packages/plugin-0x/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/plugin-0x/package.json b/packages/plugin-0x/package.json index 2949450152e..975b84a391b 100644 --- a/packages/plugin-0x/package.json +++ b/packages/plugin-0x/package.json @@ -29,7 +29,6 @@ }, "dependencies": { "@elizaos/core": "workspace:*", - "tsup": "^8.0.1", "whatwg-url": "7.1.0", "@0x/swap-ts-sdk": "2.1.1" }, From d0bc2f97c5ec46d799fdbc9cde2f633e21e905ed Mon Sep 17 00:00:00 2001 From: Demirix Date: Mon, 3 Feb 2025 00:44:14 +0100 Subject: [PATCH 21/24] feat (chore): plugin-coinmarketcap (#3134) * plugin-coinmarketcap: vitest config * plugin-coinmarketcap: package json * plugin-coinmarketcap: test setup * plugin-coinmarketcap: get price tests * plugin-coinmarketcap: get price service tests --------- Co-authored-by: Shakker Nerd <165377636+shakkernerd@users.noreply.github.com> --- .../actions/getPrice.service.test.ts | 151 +++++++++++ .../__tests__/actions/getPrice.test.ts | 234 ++++++++++++++++++ .../plugin-coinmarketcap/__tests__/setup.ts | 10 + packages/plugin-coinmarketcap/package.json | 5 +- .../plugin-coinmarketcap/vitest.config.ts | 16 ++ 5 files changed, 415 insertions(+), 1 deletion(-) create mode 100644 packages/plugin-coinmarketcap/__tests__/actions/getPrice.service.test.ts create mode 100644 packages/plugin-coinmarketcap/__tests__/actions/getPrice.test.ts create mode 100644 packages/plugin-coinmarketcap/__tests__/setup.ts create mode 100644 packages/plugin-coinmarketcap/vitest.config.ts diff --git a/packages/plugin-coinmarketcap/__tests__/actions/getPrice.service.test.ts b/packages/plugin-coinmarketcap/__tests__/actions/getPrice.service.test.ts new file mode 100644 index 00000000000..e695eea392d --- /dev/null +++ b/packages/plugin-coinmarketcap/__tests__/actions/getPrice.service.test.ts @@ -0,0 +1,151 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import axios from 'axios'; +import { createPriceService } from '../../src/actions/getPrice/service'; + +vi.mock('axios'); + +describe('PriceService', () => { + const API_KEY = 'test-api-key'; + let priceService: ReturnType; + + beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(axios.create).mockReturnValue(axios); + priceService = createPriceService(API_KEY); + }); + + it('should create axios instance with correct config', () => { + expect(axios.create).toHaveBeenCalledWith({ + baseURL: 'https://pro-api.coinmarketcap.com/v1', + headers: { + 'X-CMC_PRO_API_KEY': API_KEY, + 'Accept': 'application/json' + } + }); + }); + + it('should normalize symbol and currency', async () => { + const mockResponse = { + data: { + data: { + BTC: { + quote: { + USD: { + price: 50000, + market_cap: 1000000000000, + volume_24h: 30000000000, + percent_change_24h: 2.5 + } + } + } + } + } + }; + + vi.mocked(axios.get).mockResolvedValueOnce(mockResponse); + + await priceService.getPrice(' btc ', ' usd '); + + expect(axios.get).toHaveBeenCalledWith( + '/cryptocurrency/quotes/latest', + expect.objectContaining({ + params: { + symbol: 'BTC', + convert: 'USD' + } + }) + ); + }); + + it('should return formatted price data', async () => { + const mockResponse = { + data: { + data: { + BTC: { + quote: { + USD: { + price: 50000, + market_cap: 1000000000000, + volume_24h: 30000000000, + percent_change_24h: 2.5 + } + } + } + } + } + }; + + vi.mocked(axios.get).mockResolvedValueOnce(mockResponse); + + const result = await priceService.getPrice('BTC', 'USD'); + + expect(result).toEqual({ + price: 50000, + marketCap: 1000000000000, + volume24h: 30000000000, + percentChange24h: 2.5 + }); + }); + + it('should handle missing symbol data', async () => { + const mockResponse = { + data: { + data: {} + } + }; + + vi.mocked(axios.get).mockResolvedValueOnce(mockResponse); + + await expect(priceService.getPrice('INVALID', 'USD')) + .rejects + .toThrow('No data found for symbol: INVALID'); + }); + + it('should handle missing quote data', async () => { + const mockResponse = { + data: { + data: { + BTC: { + quote: {} + } + } + } + }; + + vi.mocked(axios.get).mockResolvedValueOnce(mockResponse); + + await expect(priceService.getPrice('BTC', 'INVALID')) + .rejects + .toThrow('No quote data found for currency: INVALID'); + }); + + it('should handle API errors', async () => { + const errorMessage = 'API rate limit exceeded'; + const apiError = new Error(errorMessage); + Object.assign(apiError, { + isAxiosError: true, + response: { + data: { + status: { + error_message: errorMessage + } + } + } + }); + + vi.mocked(axios.get).mockRejectedValueOnce(apiError); + + await expect(priceService.getPrice('BTC', 'USD')) + .rejects + .toThrow(`${errorMessage}`); + }); + + it('should handle non-axios errors', async () => { + const error = new Error('Network error'); + vi.mocked(axios.get).mockRejectedValueOnce(error); + + await expect(priceService.getPrice('BTC', 'USD')) + .rejects + .toThrow('Network error'); + }); +}); diff --git a/packages/plugin-coinmarketcap/__tests__/actions/getPrice.test.ts b/packages/plugin-coinmarketcap/__tests__/actions/getPrice.test.ts new file mode 100644 index 00000000000..f737c282c41 --- /dev/null +++ b/packages/plugin-coinmarketcap/__tests__/actions/getPrice.test.ts @@ -0,0 +1,234 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { elizaLogger, ModelClass, generateObjectDeprecated, composeContext } from '@elizaos/core'; +import getPriceAction from '../../src/actions/getPrice'; +import axios from 'axios'; +import * as environment from '../../src/environment'; + +vi.mock('axios'); +vi.mock('@elizaos/core', () => ({ + elizaLogger: { + log: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + info: vi.fn(), + success: vi.fn(), + }, + generateObjectDeprecated: vi.fn(), + composeContext: vi.fn(), + ModelClass: { SMALL: 'SMALL' } +})); +vi.mock('../../src/environment', () => ({ + validateCoinMarketCapConfig: vi.fn() +})); + +describe('getPrice action', () => { + const mockRuntime = { + composeState: vi.fn(), + updateRecentMessageState: vi.fn(), + getPluginConfig: vi.fn(), + }; + + const mockMessage = {}; + const mockState = {}; + const mockCallback = vi.fn(); + const mockConfig = { + COINMARKETCAP_API_KEY: 'test-api-key' + }; + + beforeEach(() => { + vi.clearAllMocks(); + + // Mock environment validation + vi.mocked(environment.validateCoinMarketCapConfig).mockResolvedValue(mockConfig); + + // Mock runtime functions + mockRuntime.composeState.mockResolvedValue(mockState); + mockRuntime.updateRecentMessageState.mockResolvedValue(mockState); + mockRuntime.getPluginConfig.mockResolvedValue({ + apiKey: 'test-api-key' + }); + + // Mock axios create + vi.mocked(axios.create).mockReturnValue(axios); + + // Mock the core functions + vi.mocked(elizaLogger.log).mockImplementation(() => {}); + vi.mocked(elizaLogger.error).mockImplementation(() => {}); + vi.mocked(elizaLogger.success).mockImplementation(() => {}); + vi.mocked(composeContext).mockReturnValue({}); + }); + + it('should validate coinmarketcap config', async () => { + await getPriceAction.validate(mockRuntime, mockMessage); + expect(environment.validateCoinMarketCapConfig).toHaveBeenCalledWith(mockRuntime); + }); + + it('should fetch and format price data', async () => { + const mockResponse = { + data: { + data: { + BTC: { + quote: { + USD: { + price: 50000, + market_cap: 1000000000000, + volume_24h: 30000000000, + percent_change_24h: 2.5 + } + } + } + } + } + }; + + vi.mocked(axios.get).mockResolvedValueOnce(mockResponse); + + // Mock the content generation + vi.mocked(generateObjectDeprecated).mockResolvedValueOnce({ + symbol: 'BTC', + currency: 'USD' + }); + + await getPriceAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(axios.get).toHaveBeenCalledWith( + '/cryptocurrency/quotes/latest', + expect.objectContaining({ + params: { + symbol: 'BTC', + convert: 'USD' + } + }) + ); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('50000 USD'), + content: expect.objectContaining({ + symbol: 'BTC', + currency: 'USD', + price: 50000, + marketCap: 1000000000000, + volume24h: 30000000000, + percentChange24h: 2.5 + }) + })); + }); + + it('should handle invalid symbol', async () => { + const mockResponse = { + data: { + data: {} + } + }; + + vi.mocked(axios.get).mockResolvedValueOnce(mockResponse); + + // Mock the content generation + vi.mocked(generateObjectDeprecated).mockResolvedValueOnce({ + symbol: 'INVALID', + currency: 'USD' + }); + + await getPriceAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('No data found for symbol'), + content: expect.objectContaining({ + error: expect.stringContaining('No data found for symbol') + }) + })); + }); + + it('should handle invalid currency', async () => { + const mockResponse = { + data: { + data: { + BTC: { + quote: {} + } + } + } + }; + + vi.mocked(axios.get).mockResolvedValueOnce(mockResponse); + + // Mock the content generation + vi.mocked(generateObjectDeprecated).mockResolvedValueOnce({ + symbol: 'BTC', + currency: 'INVALID' + }); + + await getPriceAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('No quote data found for currency'), + content: expect.objectContaining({ + error: expect.stringContaining('No quote data found for currency') + }) + })); + }); + + it('should handle API errors gracefully', async () => { + vi.mocked(axios.get).mockRejectedValueOnce(new Error('API Error')); + + // Mock the content generation + vi.mocked(generateObjectDeprecated).mockResolvedValueOnce({ + symbol: 'BTC', + currency: 'USD' + }); + + await getPriceAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('API Error'), + content: expect.objectContaining({ + error: expect.stringContaining('API Error') + }) + })); + }); + + it('should handle rate limit errors', async () => { + const errorMessage = 'Rate limit exceeded'; + const rateLimitError = new Error(`API Error: ${errorMessage}`); + Object.assign(rateLimitError, { + isAxiosError: true, + response: { + data: { + status: { + error_message: errorMessage + } + } + } + }); + vi.mocked(axios.get).mockRejectedValueOnce(rateLimitError); + + // Mock the content generation + vi.mocked(generateObjectDeprecated).mockResolvedValueOnce({ + symbol: 'BTC', + currency: 'USD' + }); + + await getPriceAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith({ + text: `Error fetching price: API Error: ${errorMessage}`, + content: { error: `API Error: ${errorMessage}` } + }); + }); + + it('should handle invalid content generation', async () => { + // Mock invalid content generation + vi.mocked(generateObjectDeprecated).mockResolvedValueOnce({ + invalidField: 'invalid' + }); + + await getPriceAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Invalid price check content'), + content: expect.objectContaining({ + error: expect.stringContaining('Invalid price check content') + }) + })); + }); +}); diff --git a/packages/plugin-coinmarketcap/__tests__/setup.ts b/packages/plugin-coinmarketcap/__tests__/setup.ts new file mode 100644 index 00000000000..bbc49909c16 --- /dev/null +++ b/packages/plugin-coinmarketcap/__tests__/setup.ts @@ -0,0 +1,10 @@ +import { vi } from 'vitest'; + +// Mock console methods +global.console = { + ...console, + log: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + info: vi.fn() +}; diff --git a/packages/plugin-coinmarketcap/package.json b/packages/plugin-coinmarketcap/package.json index 47f46660068..cf504b6840f 100644 --- a/packages/plugin-coinmarketcap/package.json +++ b/packages/plugin-coinmarketcap/package.json @@ -20,6 +20,9 @@ "lint": "biome lint .", "lint:fix": "biome check --apply .", "format": "biome format .", - "format:fix": "biome format --write ." + "format:fix": "biome format --write .", + "test": "vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage" } } diff --git a/packages/plugin-coinmarketcap/vitest.config.ts b/packages/plugin-coinmarketcap/vitest.config.ts new file mode 100644 index 00000000000..5c5066f7c54 --- /dev/null +++ b/packages/plugin-coinmarketcap/vitest.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + setupFiles: ['__tests__/setup.ts'], + include: ['__tests__/**/*.test.ts'], + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html'], + include: ['src/**/*.ts'], + exclude: ['**/*.d.ts', '**/*.test.ts', '**/examples.ts', '**/template.ts'] + } + } +}); From 773eeaddc89e2400ed334a5ad792f382906c083d Mon Sep 17 00:00:00 2001 From: Demirix Date: Mon, 3 Feb 2025 00:46:58 +0100 Subject: [PATCH 22/24] feat (chore): plugin-coingecko test config and coverage (#3124) * plugin-coingecko: package json * plugin-coingecko: vitest config * plugin-coingecko: get price tests * plugin-coingecko: test setup * plugin-coingecko: get trending tests * plugin-coingecko: top gainers losers tests * plugin-coingecko: get market tests --------- Co-authored-by: Shakker Nerd <165377636+shakkernerd@users.noreply.github.com> --- .../__tests__/actions/getMarkets.test.ts | 281 ++++++++++++++++++ .../__tests__/actions/getPrice.test.ts | 208 +++++++++++++ .../actions/getTopGainersLosers.test.ts | 251 ++++++++++++++++ .../__tests__/actions/getTrending.test.ts | 220 ++++++++++++++ packages/plugin-coingecko/__tests__/setup.ts | 20 ++ packages/plugin-coingecko/package.json | 6 +- packages/plugin-coingecko/vitest.config.ts | 10 + 7 files changed, 995 insertions(+), 1 deletion(-) create mode 100644 packages/plugin-coingecko/__tests__/actions/getMarkets.test.ts create mode 100644 packages/plugin-coingecko/__tests__/actions/getPrice.test.ts create mode 100644 packages/plugin-coingecko/__tests__/actions/getTopGainersLosers.test.ts create mode 100644 packages/plugin-coingecko/__tests__/actions/getTrending.test.ts create mode 100644 packages/plugin-coingecko/__tests__/setup.ts create mode 100644 packages/plugin-coingecko/vitest.config.ts diff --git a/packages/plugin-coingecko/__tests__/actions/getMarkets.test.ts b/packages/plugin-coingecko/__tests__/actions/getMarkets.test.ts new file mode 100644 index 00000000000..d6c937e2b20 --- /dev/null +++ b/packages/plugin-coingecko/__tests__/actions/getMarkets.test.ts @@ -0,0 +1,281 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { elizaLogger, ModelClass, generateObject, composeContext } from '@elizaos/core'; +import getMarketsAction, { formatCategory } from '../../src/actions/getMarkets'; +import axios from 'axios'; +import * as environment from '../../src/environment'; +import * as categoriesProvider from '../../src/providers/categoriesProvider'; + +vi.mock('axios'); +vi.mock('@elizaos/core', () => ({ + elizaLogger: { + log: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + info: vi.fn(), + success: vi.fn(), + }, + generateObject: vi.fn(), + composeContext: vi.fn(), + ModelClass: { LARGE: 'LARGE', SMALL: 'SMALL' } +})); +vi.mock('../../src/environment', () => ({ + validateCoingeckoConfig: vi.fn(), + getApiConfig: vi.fn() +})); +vi.mock('../../src/providers/categoriesProvider'); + +describe('getMarkets action', () => { + const mockRuntime = { + composeState: vi.fn(), + updateRecentMessageState: vi.fn(), + getPluginConfig: vi.fn(), + }; + + const mockMessage = {}; + const mockState = {}; + const mockCallback = vi.fn(); + const mockConfig = { + COINGECKO_API_KEY: 'test-api-key', + COINGECKO_PRO_API_KEY: null + }; + + const mockCategories = [ + { category_id: 'defi', name: 'DeFi' }, + { category_id: 'nft', name: 'NFT' } + ]; + + beforeEach(() => { + vi.clearAllMocks(); + + // Mock environment validation + vi.mocked(environment.validateCoingeckoConfig).mockResolvedValue(mockConfig); + vi.mocked(environment.getApiConfig).mockReturnValue({ + baseUrl: 'https://api.coingecko.com/api/v3', + apiKey: 'test-api-key', + headerKey: 'x-cg-demo-api-key' + }); + + // Mock categories provider + vi.mocked(categoriesProvider.getCategoriesData).mockResolvedValue(mockCategories); + + // Mock runtime functions + mockRuntime.composeState.mockResolvedValue(mockState); + mockRuntime.updateRecentMessageState.mockResolvedValue(mockState); + mockRuntime.getPluginConfig.mockResolvedValue({ + apiKey: 'test-api-key', + baseUrl: 'https://api.coingecko.com/api/v3' + }); + + // Mock the core functions + vi.mocked(elizaLogger.log).mockImplementation(() => {}); + vi.mocked(elizaLogger.error).mockImplementation(() => {}); + vi.mocked(elizaLogger.success).mockImplementation(() => {}); + vi.mocked(composeContext).mockReturnValue({}); + }); + + describe('formatCategory', () => { + it('should return undefined for undefined input', () => { + expect(formatCategory(undefined, mockCategories)).toBeUndefined(); + }); + + it('should find exact match by category_id', () => { + expect(formatCategory('defi', mockCategories)).toBe('defi'); + }); + + it('should find match by name', () => { + expect(formatCategory('DeFi', mockCategories)).toBe('defi'); + }); + + it('should find partial match', () => { + expect(formatCategory('nf', mockCategories)).toBe('nft'); + }); + + it('should return undefined for no match', () => { + expect(formatCategory('invalid-category', mockCategories)).toBeUndefined(); + }); + }); + + it('should validate coingecko config', async () => { + await getMarketsAction.validate(mockRuntime, mockMessage); + expect(environment.validateCoingeckoConfig).toHaveBeenCalledWith(mockRuntime); + }); + + it('should fetch and format market data', async () => { + const mockResponse = { + data: [ + { + id: 'bitcoin', + symbol: 'btc', + name: 'Bitcoin', + image: 'image_url', + current_price: 50000, + market_cap: 1000000000000, + market_cap_rank: 1, + fully_diluted_valuation: 1100000000000, + total_volume: 30000000000, + high_24h: 51000, + low_24h: 49000, + price_change_24h: 1000, + price_change_percentage_24h: 2, + market_cap_change_24h: 20000000000, + market_cap_change_percentage_24h: 2, + circulating_supply: 19000000, + total_supply: 21000000, + max_supply: 21000000, + ath: 69000, + ath_change_percentage: -27.5, + ath_date: '2021-11-10T14:24:11.849Z', + atl: 67.81, + atl_change_percentage: 73623.12, + atl_date: '2013-07-06T00:00:00.000Z', + last_updated: '2024-01-31T23:00:00.000Z' + } + ] + }; + + vi.mocked(axios.get).mockResolvedValueOnce(mockResponse); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + vs_currency: 'usd', + category: 'defi', + order: 'market_cap_desc', + per_page: 20, + page: 1, + sparkline: false + }, + modelClass: ModelClass.SMALL + }); + + await getMarketsAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(axios.get).toHaveBeenCalledWith( + 'https://api.coingecko.com/api/v3/coins/markets', + expect.objectContaining({ + params: { + vs_currency: 'usd', + category: 'defi', + order: 'market_cap_desc', + per_page: 20, + page: 1, + sparkline: false + } + }) + ); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Bitcoin (BTC)'), + content: expect.objectContaining({ + markets: expect.arrayContaining([ + expect.objectContaining({ + name: 'Bitcoin', + symbol: 'BTC', + marketCapRank: 1, + currentPrice: 50000 + }) + ]) + }) + })); + }); + + it('should handle invalid category', async () => { + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + vs_currency: 'usd', + category: 'invalid-category', + order: 'market_cap_desc', + per_page: 20, + page: 1, + sparkline: false + }, + modelClass: ModelClass.SMALL + }); + + await getMarketsAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Invalid category'), + error: expect.objectContaining({ + message: expect.stringContaining('Invalid category') + }) + })); + }); + + it('should handle API errors gracefully', async () => { + vi.mocked(axios.get).mockRejectedValueOnce(new Error('API Error')); + + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + vs_currency: 'usd', + order: 'market_cap_desc', + per_page: 20, + page: 1, + sparkline: false + }, + modelClass: ModelClass.SMALL + }); + + await getMarketsAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Error fetching market data'), + error: expect.objectContaining({ + message: expect.stringContaining('API Error') + }) + })); + }); + + it('should handle rate limit errors', async () => { + const rateLimitError = new Error('Rate limit exceeded'); + Object.assign(rateLimitError, { + response: { status: 429 } + }); + vi.mocked(axios.get).mockRejectedValueOnce(rateLimitError); + + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + vs_currency: 'usd', + order: 'market_cap_desc', + per_page: 20, + page: 1, + sparkline: false + }, + modelClass: ModelClass.SMALL + }); + + await getMarketsAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Rate limit exceeded'), + error: expect.objectContaining({ + message: expect.stringContaining('Rate limit exceeded'), + statusCode: 429 + }) + })); + }); + + it('should handle empty response data', async () => { + vi.mocked(axios.get).mockResolvedValueOnce({ data: [] }); + + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + vs_currency: 'usd', + order: 'market_cap_desc', + per_page: 20, + page: 1, + sparkline: false + }, + modelClass: ModelClass.SMALL + }); + + await getMarketsAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('No market data received'), + error: expect.objectContaining({ + message: expect.stringContaining('No market data received') + }) + })); + }); +}); diff --git a/packages/plugin-coingecko/__tests__/actions/getPrice.test.ts b/packages/plugin-coingecko/__tests__/actions/getPrice.test.ts new file mode 100644 index 00000000000..3c371be397f --- /dev/null +++ b/packages/plugin-coingecko/__tests__/actions/getPrice.test.ts @@ -0,0 +1,208 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { elizaLogger, ModelClass, generateObject, composeContext } from '@elizaos/core'; +import getPriceAction from '../../src/actions/getPrice'; +import axios from 'axios'; +import * as environment from '../../src/environment'; +import * as coinsProvider from '../../src/providers/coinsProvider'; + +vi.mock('axios'); +vi.mock('@elizaos/core', () => ({ + elizaLogger: { + log: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + info: vi.fn(), + success: vi.fn(), + }, + generateObject: vi.fn(), + composeContext: vi.fn(), + ModelClass: { LARGE: 'LARGE' } +})); +vi.mock('../../src/environment', () => ({ + validateCoingeckoConfig: vi.fn(), + getApiConfig: vi.fn() +})); +vi.mock('../../src/providers/coinsProvider'); + +describe('getPrice action', () => { + const mockRuntime = { + composeState: vi.fn(), + updateRecentMessageState: vi.fn(), + getPluginConfig: vi.fn(), + }; + + const mockMessage = {}; + const mockState = {}; + const mockCallback = vi.fn(); + const mockConfig = { + COINGECKO_API_KEY: 'test-api-key', + COINGECKO_PRO_API_KEY: null + }; + + beforeEach(() => { + vi.clearAllMocks(); + + // Mock environment validation + vi.mocked(environment.validateCoingeckoConfig).mockResolvedValue(mockConfig); + vi.mocked(environment.getApiConfig).mockReturnValue({ + baseUrl: 'https://api.coingecko.com/api/v3', + apiKey: 'test-api-key', + headerKey: 'x-cg-demo-api-key' + }); + + // Mock runtime functions + mockRuntime.composeState.mockResolvedValue(mockState); + mockRuntime.updateRecentMessageState.mockResolvedValue(mockState); + mockRuntime.getPluginConfig.mockResolvedValue({ + apiKey: 'test-api-key', + baseUrl: 'https://api.coingecko.com/api/v3' + }); + + // Mock the core functions + vi.mocked(elizaLogger.log).mockImplementation(() => {}); + vi.mocked(elizaLogger.error).mockImplementation(() => {}); + vi.mocked(elizaLogger.success).mockImplementation(() => {}); + vi.mocked(composeContext).mockReturnValue({}); + }); + + it('should validate coingecko config', async () => { + await getPriceAction.validate(mockRuntime, mockMessage); + expect(environment.validateCoingeckoConfig).toHaveBeenCalledWith(mockRuntime); + }); + + it('should fetch and format price data for a single coin', async () => { + const mockPriceResponse = { + data: { + bitcoin: { + usd: 50000, + eur: 42000 + } + } + }; + + const mockCoinsData = [{ + id: 'bitcoin', + name: 'Bitcoin', + symbol: 'btc' + }]; + + vi.mocked(axios.get).mockResolvedValueOnce(mockPriceResponse); + vi.mocked(coinsProvider.getCoinsData).mockResolvedValueOnce(mockCoinsData); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + coinIds: 'bitcoin', + currency: ['usd', 'eur'], + include_market_cap: false, + include_24hr_vol: false, + include_24hr_change: false, + include_last_updated_at: false + }, + modelClass: ModelClass.LARGE + }); + + await getPriceAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(axios.get).toHaveBeenCalledWith( + 'https://api.coingecko.com/api/v3/simple/price', + expect.any(Object) + ); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Bitcoin (BTC)') + })); + }); + + it('should handle API errors gracefully', async () => { + vi.mocked(axios.get).mockRejectedValueOnce(new Error('API Error')); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + coinIds: 'invalid-coin', + currency: ['usd'], + include_market_cap: false, + include_24hr_vol: false, + include_24hr_change: false, + include_last_updated_at: false + }, + modelClass: ModelClass.LARGE + }); + + await getPriceAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + content: expect.objectContaining({ + error: expect.stringContaining('API Error') + }) + })); + }); + + it('should handle empty response data', async () => { + vi.mocked(axios.get).mockResolvedValueOnce({ data: {} }); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + coinIds: 'non-existent-coin', + currency: ['usd'], + include_market_cap: false, + include_24hr_vol: false, + include_24hr_change: false, + include_last_updated_at: false + }, + modelClass: ModelClass.LARGE + }); + + await getPriceAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + content: expect.objectContaining({ + error: expect.stringContaining('No price data available') + }) + })); + }); + + it('should include additional market data when requested', async () => { + const mockPriceResponse = { + data: { + ethereum: { + usd: 3000, + usd_market_cap: 350000000000, + usd_24h_vol: 20000000000, + usd_24h_change: 5.5, + last_updated_at: 1643673600 + } + } + }; + + const mockCoinsData = [{ + id: 'ethereum', + name: 'Ethereum', + symbol: 'eth' + }]; + + vi.mocked(axios.get).mockResolvedValueOnce(mockPriceResponse); + vi.mocked(coinsProvider.getCoinsData).mockResolvedValueOnce(mockCoinsData); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + coinIds: 'ethereum', + currency: ['usd'], + include_market_cap: true, + include_24hr_vol: true, + include_24hr_change: true, + include_last_updated_at: true + }, + modelClass: ModelClass.LARGE + }); + + await getPriceAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Market Cap') + })); + }); +}); diff --git a/packages/plugin-coingecko/__tests__/actions/getTopGainersLosers.test.ts b/packages/plugin-coingecko/__tests__/actions/getTopGainersLosers.test.ts new file mode 100644 index 00000000000..3854e593353 --- /dev/null +++ b/packages/plugin-coingecko/__tests__/actions/getTopGainersLosers.test.ts @@ -0,0 +1,251 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { elizaLogger, ModelClass, generateObject, composeContext } from '@elizaos/core'; +import getTopGainersLosersAction from '../../src/actions/getTopGainersLosers'; +import axios from 'axios'; +import * as environment from '../../src/environment'; + +vi.mock('axios'); +vi.mock('@elizaos/core', () => ({ + elizaLogger: { + log: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + info: vi.fn(), + success: vi.fn(), + }, + generateObject: vi.fn(), + composeContext: vi.fn(), + ModelClass: { LARGE: 'LARGE' } +})); +vi.mock('../../src/environment', () => ({ + validateCoingeckoConfig: vi.fn(), + getApiConfig: vi.fn() +})); + +describe('getTopGainersLosers action', () => { + const mockRuntime = { + composeState: vi.fn(), + updateRecentMessageState: vi.fn(), + getPluginConfig: vi.fn(), + }; + + const mockMessage = {}; + const mockState = {}; + const mockCallback = vi.fn(); + const mockConfig = { + COINGECKO_API_KEY: 'test-api-key', + COINGECKO_PRO_API_KEY: null + }; + + beforeEach(() => { + vi.clearAllMocks(); + + // Mock environment validation + vi.mocked(environment.validateCoingeckoConfig).mockResolvedValue(mockConfig); + vi.mocked(environment.getApiConfig).mockReturnValue({ + baseUrl: 'https://api.coingecko.com/api/v3', + apiKey: 'test-api-key', + headerKey: 'x-cg-demo-api-key' + }); + + // Mock runtime functions + mockRuntime.composeState.mockResolvedValue(mockState); + mockRuntime.updateRecentMessageState.mockResolvedValue(mockState); + mockRuntime.getPluginConfig.mockResolvedValue({ + apiKey: 'test-api-key', + baseUrl: 'https://api.coingecko.com/api/v3' + }); + + // Mock the core functions + vi.mocked(elizaLogger.log).mockImplementation(() => {}); + vi.mocked(elizaLogger.error).mockImplementation(() => {}); + vi.mocked(elizaLogger.success).mockImplementation(() => {}); + vi.mocked(composeContext).mockReturnValue({}); + }); + + it('should validate coingecko config', async () => { + await getTopGainersLosersAction.validate(mockRuntime, mockMessage); + expect(environment.validateCoingeckoConfig).toHaveBeenCalledWith(mockRuntime); + }); + + it('should fetch and format top gainers and losers data', async () => { + const mockResponse = { + data: { + top_gainers: [ + { + id: 'bitcoin', + symbol: 'btc', + name: 'Bitcoin', + image: 'image_url', + market_cap_rank: 1, + usd: 50000, + usd_24h_vol: 30000000000, + usd_24h_change: 5.5 + } + ], + top_losers: [ + { + id: 'ethereum', + symbol: 'eth', + name: 'Ethereum', + image: 'image_url', + market_cap_rank: 2, + usd: 2500, + usd_24h_vol: 20000000000, + usd_24h_change: -3.2 + } + ] + } + }; + + vi.mocked(axios.get).mockResolvedValueOnce(mockResponse); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + vs_currency: 'usd', + duration: '24h', + top_coins: '1000' + }, + modelClass: ModelClass.LARGE + }); + + await getTopGainersLosersAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(axios.get).toHaveBeenCalledWith( + 'https://api.coingecko.com/api/v3/coins/top_gainers_losers', + expect.objectContaining({ + params: { + vs_currency: 'usd', + duration: '24h', + top_coins: '1000' + } + }) + ); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Bitcoin (BTC)'), + content: expect.objectContaining({ + data: expect.objectContaining({ + top_gainers: expect.arrayContaining([ + expect.objectContaining({ + name: 'Bitcoin', + symbol: 'btc', + usd_24h_change: 5.5 + }) + ]), + top_losers: expect.arrayContaining([ + expect.objectContaining({ + name: 'Ethereum', + symbol: 'eth', + usd_24h_change: -3.2 + }) + ]) + }) + }) + })); + }); + + it('should handle API errors gracefully', async () => { + vi.mocked(axios.get).mockRejectedValueOnce(new Error('API Error')); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + vs_currency: 'usd', + duration: '24h', + top_coins: '1000' + }, + modelClass: ModelClass.LARGE + }); + + await getTopGainersLosersAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Error fetching top gainers/losers data'), + content: expect.objectContaining({ + error: expect.stringContaining('API Error') + }) + })); + }); + + it('should handle rate limit errors', async () => { + const rateLimitError = new Error('Rate limit exceeded'); + Object.assign(rateLimitError, { + response: { status: 429 } + }); + vi.mocked(axios.get).mockRejectedValueOnce(rateLimitError); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + vs_currency: 'usd', + duration: '24h', + top_coins: '1000' + }, + modelClass: ModelClass.LARGE + }); + + await getTopGainersLosersAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Rate limit exceeded'), + content: expect.objectContaining({ + error: expect.stringContaining('Rate limit exceeded'), + statusCode: 429 + }) + })); + }); + + it('should handle pro plan requirement errors', async () => { + const proPlanError = new Error('Pro plan required'); + Object.assign(proPlanError, { + response: { status: 403 } + }); + vi.mocked(axios.get).mockRejectedValueOnce(proPlanError); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + vs_currency: 'usd', + duration: '24h', + top_coins: '1000' + }, + modelClass: ModelClass.LARGE + }); + + await getTopGainersLosersAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('requires a CoinGecko Pro API key'), + content: expect.objectContaining({ + error: expect.stringContaining('Pro plan required'), + statusCode: 403, + requiresProPlan: true + }) + })); + }); + + it('should handle empty response data', async () => { + vi.mocked(axios.get).mockResolvedValueOnce({ data: null }); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + vs_currency: 'usd', + duration: '24h', + top_coins: '1000' + }, + modelClass: ModelClass.LARGE + }); + + await getTopGainersLosersAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('No data received'), + content: expect.objectContaining({ + error: expect.stringContaining('No data received') + }) + })); + }); +}); diff --git a/packages/plugin-coingecko/__tests__/actions/getTrending.test.ts b/packages/plugin-coingecko/__tests__/actions/getTrending.test.ts new file mode 100644 index 00000000000..32b51f36aaa --- /dev/null +++ b/packages/plugin-coingecko/__tests__/actions/getTrending.test.ts @@ -0,0 +1,220 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { elizaLogger, ModelClass, generateObject, composeContext } from '@elizaos/core'; +import getTrendingAction from '../../src/actions/getTrending'; +import axios from 'axios'; +import * as environment from '../../src/environment'; + +vi.mock('axios'); +vi.mock('@elizaos/core', () => ({ + elizaLogger: { + log: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + info: vi.fn(), + success: vi.fn(), + }, + generateObject: vi.fn(), + composeContext: vi.fn(), + ModelClass: { LARGE: 'LARGE' } +})); +vi.mock('../../src/environment', () => ({ + validateCoingeckoConfig: vi.fn(), + getApiConfig: vi.fn() +})); + +describe('getTrending action', () => { + const mockRuntime = { + composeState: vi.fn(), + updateRecentMessageState: vi.fn(), + getPluginConfig: vi.fn(), + }; + + const mockMessage = {}; + const mockState = {}; + const mockCallback = vi.fn(); + const mockConfig = { + COINGECKO_API_KEY: 'test-api-key', + COINGECKO_PRO_API_KEY: null + }; + + beforeEach(() => { + vi.clearAllMocks(); + + // Mock environment validation + vi.mocked(environment.validateCoingeckoConfig).mockResolvedValue(mockConfig); + vi.mocked(environment.getApiConfig).mockReturnValue({ + baseUrl: 'https://api.coingecko.com/api/v3', + apiKey: 'test-api-key', + headerKey: 'x-cg-demo-api-key' + }); + + // Mock runtime functions + mockRuntime.composeState.mockResolvedValue(mockState); + mockRuntime.updateRecentMessageState.mockResolvedValue(mockState); + mockRuntime.getPluginConfig.mockResolvedValue({ + apiKey: 'test-api-key', + baseUrl: 'https://api.coingecko.com/api/v3' + }); + + // Mock the core functions + vi.mocked(elizaLogger.log).mockImplementation(() => {}); + vi.mocked(elizaLogger.error).mockImplementation(() => {}); + vi.mocked(elizaLogger.success).mockImplementation(() => {}); + vi.mocked(composeContext).mockReturnValue({}); + }); + + it('should validate coingecko config', async () => { + await getTrendingAction.validate(mockRuntime, mockMessage); + expect(environment.validateCoingeckoConfig).toHaveBeenCalledWith(mockRuntime); + }); + + it('should fetch and format trending data', async () => { + const mockTrendingResponse = { + data: { + coins: [ + { + item: { + id: 'bitcoin', + name: 'Bitcoin', + symbol: 'btc', + market_cap_rank: 1, + thumb: 'thumb_url', + large: 'large_url' + } + } + ], + nfts: [ + { + id: 'bored-ape', + name: 'Bored Ape Yacht Club', + symbol: 'BAYC', + thumb: 'thumb_url' + } + ], + categories: [ + { + id: 'defi', + name: 'DeFi' + } + ], + exchanges: [], + icos: [] + } + }; + + vi.mocked(axios.get).mockResolvedValueOnce(mockTrendingResponse); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + include_nfts: true, + include_categories: true + }, + modelClass: ModelClass.LARGE + }); + + await getTrendingAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(axios.get).toHaveBeenCalledWith( + 'https://api.coingecko.com/api/v3/search/trending', + expect.any(Object) + ); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Bitcoin (BTC)'), + content: expect.objectContaining({ + trending: expect.objectContaining({ + coins: expect.arrayContaining([ + expect.objectContaining({ + name: 'Bitcoin', + symbol: 'BTC', + marketCapRank: 1 + }) + ]), + nfts: expect.arrayContaining([ + expect.objectContaining({ + name: 'Bored Ape Yacht Club', + symbol: 'BAYC' + }) + ]), + categories: expect.arrayContaining([ + expect.objectContaining({ + name: 'DeFi' + }) + ]) + }) + }) + })); + }); + + it('should handle API errors gracefully', async () => { + vi.mocked(axios.get).mockRejectedValueOnce(new Error('API Error')); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + include_nfts: true, + include_categories: true + }, + modelClass: ModelClass.LARGE + }); + + await getTrendingAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Error fetching trending data'), + content: expect.objectContaining({ + error: expect.stringContaining('API Error') + }) + })); + }); + + it('should handle rate limit errors', async () => { + const rateLimitError = new Error('Rate limit exceeded'); + Object.assign(rateLimitError, { + response: { status: 429 } + }); + vi.mocked(axios.get).mockRejectedValueOnce(rateLimitError); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + include_nfts: true, + include_categories: true + }, + modelClass: ModelClass.LARGE + }); + + await getTrendingAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Rate limit exceeded'), + content: expect.objectContaining({ + error: expect.stringContaining('Rate limit exceeded'), + statusCode: 429 + }) + })); + }); + + it('should handle empty response data', async () => { + vi.mocked(axios.get).mockResolvedValueOnce({ data: null }); + + // Mock the content generation + vi.mocked(generateObject).mockResolvedValueOnce({ + object: { + include_nfts: true, + include_categories: true + }, + modelClass: ModelClass.LARGE + }); + + await getTrendingAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback); + + expect(mockCallback).toHaveBeenCalledWith(expect.objectContaining({ + text: expect.stringContaining('Error fetching trending data'), + content: expect.objectContaining({ + error: expect.stringContaining('No data received') + }) + })); + }); +}); diff --git a/packages/plugin-coingecko/__tests__/setup.ts b/packages/plugin-coingecko/__tests__/setup.ts new file mode 100644 index 00000000000..ba8257dbe39 --- /dev/null +++ b/packages/plugin-coingecko/__tests__/setup.ts @@ -0,0 +1,20 @@ +import { vi } from 'vitest'; +import { elizaLogger } from '@elizaos/core'; + +// Mock elizaLogger +vi.mock('@elizaos/core', () => ({ + elizaLogger: { + log: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + info: vi.fn(), + generateObject: vi.fn(), + } +})); + +// Mock fetch +global.fetch = vi.fn(); + +beforeEach(() => { + vi.clearAllMocks(); +}); diff --git a/packages/plugin-coingecko/package.json b/packages/plugin-coingecko/package.json index 1283821cb26..b5086ec15af 100644 --- a/packages/plugin-coingecko/package.json +++ b/packages/plugin-coingecko/package.json @@ -10,12 +10,16 @@ "tsup": "^8.3.5" }, "devDependencies": { - "@biomejs/biome": "1.9.4" + "@biomejs/biome": "1.9.4", + "@vitest/coverage-v8": "^1.2.2", + "vitest": "^1.2.2" }, "scripts": { "build": "tsup --format esm --dts", "dev": "tsup --format esm --dts --watch", "test": "vitest run", + "test:watch": "vitest watch", + "test:coverage": "vitest run --coverage", "clean": "rm -rf dist", "lint": "biome lint .", "lint:fix": "biome check --apply .", diff --git a/packages/plugin-coingecko/vitest.config.ts b/packages/plugin-coingecko/vitest.config.ts new file mode 100644 index 00000000000..419efc958f9 --- /dev/null +++ b/packages/plugin-coingecko/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + setupFiles: ['./__tests__/setup.ts'], + include: ['**/__tests__/**/*.test.ts'], + } +}); From 9fe3bc552c254ccde33fa4b07bcac57f7a6048ff Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Mon, 3 Feb 2025 13:04:40 +0800 Subject: [PATCH 23/24] update provider-utils --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 00d43be54d4..05a1c67f865 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "@polkadot/types-codec": "10.13.1", "@polkadot/keyring": "12.6.2", "@ai-sdk/provider": "1.0.6", - "@ai-sdk/provider-utils": "2.1.2", + "@ai-sdk/provider-utils": "2.1.6", "cookie": "0.7.0", "bs58": "5.0.0", "@coral-xyz/anchor": "0.28.0" From adc87b87633b0d599a095b2d871a522bd7fd4e31 Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Mon, 3 Feb 2025 13:40:58 +0800 Subject: [PATCH 24/24] extract attribute from raw text instead of normalized json --- packages/core/src/parsing.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/parsing.ts b/packages/core/src/parsing.ts index ebe4f614403..ffdc7f096ce 100644 --- a/packages/core/src/parsing.ts +++ b/packages/core/src/parsing.ts @@ -152,7 +152,7 @@ export function parseJSONObjectFromText( } catch (e) { console.error("Error parsing JSON:", e); console.error("Text is not JSON", text); - return extractAttributes(parsingText); + return extractAttributes(text); } } else { const objectPattern = /{[\s\S]*?}/; @@ -165,7 +165,7 @@ export function parseJSONObjectFromText( } catch (e) { console.error("Error parsing JSON:", e); console.error("Text is not JSON", text); - return extractAttributes(parsingText); + return extractAttributes(text); } } }