diff --git a/.env.example b/.env.example index 31adb83e379..60e2e94c241 100644 --- a/.env.example +++ b/.env.example @@ -88,8 +88,11 @@ TWITTER_TARGET_USERS= # Comma separated list of Twitter user names to TWITTER_RETRY_LIMIT= # Maximum retry attempts for Twitter login TWITTER_SPACES_ENABLE=false # Enable or disable Twitter Spaces logic -XAI_API_KEY= -XAI_MODEL= +# CONFIGURATION FOR APPROVING TWEETS BEFORE IT GETS POSTED +TWITTER_APPROVAL_DISCORD_CHANNEL_ID= # Channel ID for the Discord bot to listen and send approval messages +TWITTER_APPROVAL_DISCORD_BOT_TOKEN= # Discord bot token (this could be a different bot token from DISCORD_API_TOKEN) +TWITTER_APPROVAL_ENABLED= # Enable or disable Twitter approval logic #Default is false +TWITTER_APPROVAL_CHECK_INTERVAL=60000 # Default: 60 seconds # Post Interval Settings (in minutes) POST_INTERVAL_MIN= # Default: 90 @@ -103,7 +106,6 @@ MAX_ACTIONS_PROCESSING=1 # Maximum number of actions (e.g., retweets, likes) to ACTION_TIMELINE_TYPE=foryou # Type of timeline to interact with. Options: "foryou" or "following". Default: "foryou" # Feature Flags -IMAGE_GEN= # Set to TRUE to enable image generation USE_OPENAI_EMBEDDING= # Set to TRUE for OpenAI/1536, leave blank for local USE_OLLAMA_EMBEDDING= # Set to TRUE for OLLAMA/1024, leave blank for local @@ -268,6 +270,9 @@ CHARITY_ADDRESS_ETH=0x750EF1D7a0b4Ab1c97B7A623D7917CcEb5ea779C CHARITY_ADDRESS_ARB=0x1234567890123456789012345678901234567890 CHARITY_ADDRESS_POL=0x1234567890123456789012345678901234567890 +# thirdweb +THIRDWEB_SECRET_KEY= # Create key on thirdweb developer dashboard: https://thirdweb.com/ + # Conflux Configuration CONFLUX_CORE_PRIVATE_KEY= CONFLUX_CORE_SPACE_RPC_URL= @@ -396,6 +401,9 @@ STORY_API_BASE_URL= # Story API base URL STORY_API_KEY= # Story API key PINATA_JWT= # Pinata JWT for uploading files to IPFS +# Cosmos +COSMOS_RECOVERY_PHRASE= # 12 words recovery phrase (need to be in quotes, because of spaces) +COSMOS_AVAILABLE_CHAINS= # mantrachaintestnet2,cosmos # Array of chains # Cronos zkEVM CRONOSZKEVM_ADDRESS= CRONOSZKEVM_PRIVATE_KEY= @@ -407,6 +415,12 @@ FUEL_WALLET_PRIVATE_KEY= TOKENIZER_MODEL= # Specify the tokenizer model to be used. TOKENIZER_TYPE= # Options: tiktoken (for OpenAI models) or auto (AutoTokenizer from Hugging Face for non-OpenAI models). Default: tiktoken. + +# Spheron +SPHERON_PRIVATE_KEY= +SPHERON_PROVIDER_PROXY_URL= +SPHERON_WALLET_ADDRESS= + # Stargaze NFT marketplace from Cosmos (You can use https://graphql.mainnet.stargaze-apis.com/graphql) STARGAZE_ENDPOINT= @@ -414,7 +428,11 @@ STARGAZE_ENDPOINT= GIPHY_API_KEY= # GenLayer -GENLAYER_PRIVATE_KEY=0x0000000000000000000000000000000000000000000000000000000000000000 # Private key of the GenLayer account to use for the agent +GENLAYER_PRIVATE_KEY= # Private key of the GenLayer account to use for the agent in this format (0x0000000000000000000000000000000000000000000000000000000000000000) # OpenWeather OPEN_WEATHER_API_KEY= # OpenWeather API key + +# Allora +ALLORA_API_KEY= # Allora API key, format: UP-f8db7d6558ab432ca0d92716 +ALLORA_CHAIN_SLUG= # must be one of mainnet, testnet. If not specified, it will use testnet by default diff --git a/.github/workflows/jsdoc-automation.yml b/.github/workflows/jsdoc-automation.yml index 60458fcf4da..619a29593ae 100644 --- a/.github/workflows/jsdoc-automation.yml +++ b/.github/workflows/jsdoc-automation.yml @@ -20,7 +20,7 @@ on: root_directory: description: "Only scans files in this directory (relative to repository root, e.g., packages/core/src)" required: true - default: "packages/plugin-near/" + default: "packages/plugin-bootstrap" type: string excluded_directories: description: "Directories to exclude from scanning (comma-separated, relative to root_directory)" @@ -37,11 +37,6 @@ on: required: false default: "develop" type: string - language: - description: "Documentation language (e.g., English, Spanish, French)" - required: true - default: "English" - type: string jobs: generate-docs: @@ -99,6 +94,5 @@ jobs: INPUT_EXCLUDED_DIRECTORIES: ${{ inputs.excluded_directories }} INPUT_REVIEWERS: ${{ inputs.reviewers }} INPUT_BRANCH: ${{ inputs.branch }} - INPUT_LANGUAGE: ${{ inputs.language }} INPUT_JSDOC: ${{ inputs.jsdoc }} INPUT_README: ${{ inputs.readme }} diff --git a/README_CN.md b/README_CN.md index a59e97eb4ee..9d58d755e90 100644 --- a/README_CN.md +++ b/README_CN.md @@ -188,9 +188,6 @@ TWITTER_USERNAME= # Account username TWITTER_PASSWORD= # Account password TWITTER_EMAIL= # Account email -XAI_API_KEY= -XAI_MODEL= - # For asking Claude stuff ANTHROPIC_API_KEY= diff --git a/README_ES.md b/README_ES.md index 55530380be6..547131e01f3 100644 --- a/README_ES.md +++ b/README_ES.md @@ -54,15 +54,15 @@ Para evitar conflictos en el directorio central, se recomienda agregar acciones ### Ejecutar con Llama -Puede ejecutar modelos Llama 70B o 405B configurando la variable de ambiente `XAI_MODEL` en `meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo` o `meta-llama/Meta-Llama-3.1-405B-Instruct` +Puede ejecutar modelos Llama 70B o 405B configurando la variable de ambiente para un proveedor que soporte estos modelos. Llama también es soportado localmente si no se configura otro proveedor. ### Ejecutar con Grok -Puede ejecutar modelos Grok configurando la variable de ambiente `XAI_MODEL` en `grok-beta` +Puede ejecutar modelos Grok configurando la variable de ambiente `GROK_API_KEY` y configurando "grok" como proveedor en el archivo de caracteres. ### Ejecutar con OpenAI -Puede ejecutar modelos OpenAI configurando la variable de ambiente `XAI_MODEL` en `gpt-4o-mini` o `gpt-4o` +Puede ejecutar modelos OpenAI configurando la variable de ambiente `OPENAI_API_KEY` y configurando "openai" como proveedor en el archivo de caracteres. ## Requisitos Adicionales @@ -99,9 +99,6 @@ TWITTER_USERNAME= # Nombre de usuario de la cuenta TWITTER_PASSWORD= # Contraseña de la cuenta TWITTER_EMAIL= # Correo electrónico de la cuenta -XAI_API_KEY= -XAI_MODEL= - # Para consultar a Claude ANTHROPIC_API_KEY= diff --git a/agent/package.json b/agent/package.json index 13d6b93359b..9402e5d6909 100644 --- a/agent/package.json +++ b/agent/package.json @@ -37,7 +37,7 @@ "@elizaos/plugin-binance": "workspace:*", "@elizaos/plugin-avail": "workspace:*", "@elizaos/plugin-bootstrap": "workspace:*", - "@ai16z/plugin-cosmos": "workspace:*", + "@elizaos/plugin-cosmos": "workspace:*", "@elizaos/plugin-intiface": "workspace:*", "@elizaos/plugin-coinbase": "workspace:*", "@elizaos/plugin-coinprice": "workspace:*", @@ -50,6 +50,7 @@ "@elizaos/plugin-goat": "workspace:*", "@elizaos/plugin-icp": "workspace:*", "@elizaos/plugin-image-generation": "workspace:*", + "@elizaos/plugin-movement": "workspace:*", "@elizaos/plugin-nft-generation": "workspace:*", "@elizaos/plugin-node": "workspace:*", "@elizaos/plugin-solana": "workspace:*", @@ -70,9 +71,13 @@ "@elizaos/plugin-fuel": "workspace:*", "@elizaos/plugin-avalanche": "workspace:*", "@elizaos/plugin-web-search": "workspace:*", + "@elizaos/plugin-thirdweb": "workspace:*", "@elizaos/plugin-genlayer": "workspace:*", + "@elizaos/plugin-depin": "workspace:*", "@elizaos/plugin-open-weather": "workspace:*", + "@elizaos/plugin-obsidian": "workspace:*", "@elizaos/plugin-arthera": "workspace:*", + "@elizaos/plugin-allora": "workspace:*", "readline": "1.3.0", "ws": "8.18.0", "yargs": "17.7.2" @@ -84,4 +89,4 @@ "ts-node": "10.9.2", "tsup": "8.3.5" } -} \ No newline at end of file +} diff --git a/agent/src/index.ts b/agent/src/index.ts index 0218ba9f2ea..9f772a3b6f9 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -38,6 +38,7 @@ import { DirectClient } from "@elizaos/client-direct"; import { ThreeDGenerationPlugin } from "@elizaos/plugin-3d-generation"; import { abstractPlugin } from "@elizaos/plugin-abstract"; import { aptosPlugin } from "@elizaos/plugin-aptos"; +import { alloraPlugin } from "@elizaos/plugin-allora"; import { avalanchePlugin } from "@elizaos/plugin-avalanche"; import { binancePlugin } from "@elizaos/plugin-binance"; import { @@ -53,6 +54,7 @@ import { confluxPlugin } from "@elizaos/plugin-conflux"; import { cronosZkEVMPlugin } from "@elizaos/plugin-cronoszkevm"; import { echoChambersPlugin } from "@elizaos/plugin-echochambers"; import { evmPlugin } from "@elizaos/plugin-evm"; +import { createCosmosPlugin } from "@elizaos/plugin-cosmos"; import { flowPlugin } from "@elizaos/plugin-flow"; import { fuelPlugin } from "@elizaos/plugin-fuel"; import { genLayerPlugin } from "@elizaos/plugin-genlayer"; @@ -70,15 +72,14 @@ import { teeMarlinPlugin } from "@elizaos/plugin-tee-marlin"; import { tonPlugin } from "@elizaos/plugin-ton"; import { webSearchPlugin } from "@elizaos/plugin-web-search"; import { giphyPlugin } from "@elizaos/plugin-giphy"; - +import { echoChamberPlugin } from "@elizaos/plugin-echochambers"; +import { thirdwebPlugin } from "@elizaos/plugin-thirdweb"; import { zksyncEraPlugin } from "@elizaos/plugin-zksync-era"; - import { availPlugin } from "@elizaos/plugin-avail"; import { openWeatherPlugin } from "@elizaos/plugin-open-weather"; - import { artheraPlugin } from "@elizaos/plugin-arthera"; import { stargazePlugin } from "@elizaos/plugin-stargaze"; - +import { obsidianPlugin } from "@elizaos/plugin-obsidian"; import Database from "better-sqlite3"; import fs from "fs"; import net from "net"; @@ -282,8 +283,6 @@ export function getTokenForProvider( settings.LLAMACLOUD_API_KEY || character.settings?.secrets?.TOGETHER_API_KEY || settings.TOGETHER_API_KEY || - character.settings?.secrets?.XAI_API_KEY || - settings.XAI_API_KEY || character.settings?.secrets?.OPENAI_API_KEY || settings.OPENAI_API_KEY ); @@ -424,7 +423,8 @@ export async function initializeClients( character.clients?.map((str) => str.toLowerCase()) || []; elizaLogger.log("initializeClients", clientTypes, "for", character.name); - if (clientTypes.includes(Clients.DIRECT)) { + // Start Auto Client if "auto" detected as a configured client + if (clientTypes.includes(Clients.AUTO)) { const autoClient = await AutoClientInterface.start(runtime); if (autoClient) clients.auto = autoClient; } @@ -588,6 +588,9 @@ export async function createAgent( getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x")) ? evmPlugin : null, + getSecret(character, "COSMOS_RECOVERY_PHRASE") && + getSecret(character, "COSMOS_AVAILABLE_CHAINS") && + createCosmosPlugin(), (getSecret(character, "SOLANA_PUBLIC_KEY") || (getSecret(character, "WALLET_PUBLIC_KEY") && !getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith( @@ -645,6 +648,7 @@ export async function createAgent( : null, getSecret(character, "TEE_MARLIN") ? teeMarlinPlugin : null, getSecret(character, "TON_PRIVATE_KEY") ? tonPlugin : null, + getSecret(character, "THIRDWEB_SECRET_KEY") ? thirdwebPlugin : null, getSecret(character, "SUI_PRIVATE_KEY") ? suiPlugin : null, getSecret(character, "STORY_PRIVATE_KEY") ? storyPlugin : null, getSecret(character, "FUEL_PRIVATE_KEY") ? fuelPlugin : null, @@ -660,14 +664,18 @@ export async function createAgent( getSecret(character, "GENLAYER_PRIVATE_KEY") ? genLayerPlugin : null, - getSecret(character, "AVAIL_SEED") ? availPlugin : null, - getSecret(character, "AVAIL_APP_ID") ? availPlugin : null, + getSecret(character, "AVAIL_SEED") && + getSecret(character, "AVAIL_APP_ID") + ? availPlugin + : null, getSecret(character, "OPEN_WEATHER_API_KEY") ? openWeatherPlugin : null, - getSecret(character, "ARTHERA_PRIVATE_KEY")?.startsWith("0x") + getSecret(character, "OBSIDIAN_API_TOKEN") ? obsidianPlugin : null, + getSecret(character, "ARTHERA_PRIVATE_KEY")?.startsWith("0x") ? artheraPlugin : null, + getSecret(character, "ALLORA_API_KEY") ? alloraPlugin : null, ].filter(Boolean), providers: [], actions: [], diff --git a/characters/cosmosHelper.character.json b/characters/cosmosHelper.character.json index 1319a9b16a5..5352eb02c14 100644 --- a/characters/cosmosHelper.character.json +++ b/characters/cosmosHelper.character.json @@ -3,7 +3,6 @@ "clients": [], "modelProvider": "groq", "settings": { - "secrets": {}, "voice": { "model": "en_US-male-medium" }, @@ -11,7 +10,7 @@ "cosmos": ["axelar", "carbon", "mantrachaintestnet2"] } }, - "plugins": ["@ai16z/plugin-cosmos","@ai16z/plugin-bootstrap"], + "plugins": [], "bio": [ "Expert in Cosmos ecosystem.", "Knowledgeable in CosmWasm and Stargate.", @@ -24,37 +23,22 @@ "Supports projects and interactions within the Cosmos ecosystem." ], "knowledge": [ - "knows EXACT cost to families under Kamala ($29,000)", - "understands REAL border numbers (worse than reported)", - "saw what really happened in Minneapolis 2020", - "remembers who begged for help (and when)", - "knows why Iran's president targeting us", - "understands Secret Service allocation (and why they do it)", - "knows REAL rally numbers (they hide them)", - "saw the TRUTH about China Virus response", - "understands states' rights better than anyone", - "knows why they're letting in illegal guns", - "remembers when America was AFFORDABLE", - "understands the REAL election interference", - "knows why they're scared of WorldLibertyFi", - "saw what they did to women's sports", - "understands the REAL Middle East situation", - "knows why missiles flying everywhere now", - "remembers perfect peace under Trump presidency", - "understands Democrat election strategy (letting in MILLIONS)", - "knows Kamala's REAL tax plans (coming for everything)", - "saw what they did to Minneapolis (and other cities)" + "Knows how Cosmos blockchain works", + "Knows what actions should he call for token transfer, swapping or bridging", + "Knows that users might want to do specific actions multiple times and should help them by doing it again.", + "Should always ask for confirmation before calling an COSMOS_TRANSFER, COSMOS_BRIDGE, COSMOS_SWAP actions.", + "Should call actions COSMOS_TRANSFER, COSMOS_BRIDGE, COSMOS_SWAP only after previous confirmation." ], "messageExamples": [ [ { "user": "{{user1}}", - "content": { "text": "Can you explain the Cosmos Hub?" } + "content": { "text": "Show my balances of my wallet on {{mantrachaintestnet2}}" } }, { "user": "CosmosHelper", "content": { - "text": "The Cosmos Hub is the central blockchain in the Cosmos ecosystem, facilitating interoperability between connected blockchains." + "text": "Your balances on chain {{mantrachaintestnet2}} are: \n - 13456.124 OM\n - 1222 ONDO\n 0.122122 USDY" } } ], @@ -97,12 +81,12 @@ [ { "user": "{{user1}}", - "content": { "text": "What are validators?" } + "content": { "text": "Make transfer 0.0001 OM to mantra13248w8dtnn07sxc3gq4l3ts4rvfyat6fks0ecj on mantrachaintestnet2" } }, { "user": "CosmosHelper", "content": { - "text": "Validators are responsible for securing the network by validating transactions and producing new blocks. They earn rewards through staking." + "text": "Sure, your transfer i being processed." } } ] diff --git a/docs/README.md b/docs/README.md index 0a4e37c4770..d1c4e34503b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -59,15 +59,15 @@ To avoid git clashes in the core directory, we recommend adding custom actions t ### Run with Llama -You can run Llama 70B or 405B models by setting the `XAI_MODEL` environment variable to `meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo` or `meta-llama/Meta-Llama-3.1-405B-Instruct` +You can run Llama 70B or 405B models by setting the environment variable for a provider that supports these models. Llama is also supported locally if no other provider is set. ### Run with Grok -You can run Grok models by setting the `XAI_MODEL` environment variable to `grok-beta` +You can run Grok models by setting the `GROK_API_KEY` environment variable to your Grok API key and setting grok as the model provider in your character file. ### Run with OpenAI -You can run OpenAI models by setting the `XAI_MODEL` environment variable to `gpt-4-mini` or `gpt-4o` +You can run OpenAI models by setting the `OPENAI_API_KEY` environment variable to your OpenAI API key and setting openai as the model provider in your character file. ## Additional Requirements @@ -103,10 +103,6 @@ TWITTER_USERNAME= # Account username TWITTER_PASSWORD= # Account password TWITTER_EMAIL= # Account email -X_SERVER_URL= -XAI_API_KEY= -XAI_MODEL= - # For asking Claude stuff ANTHROPIC_API_KEY= @@ -143,9 +139,7 @@ Make sure that you've installed the CUDA Toolkit, including cuDNN and cuBLAS. ### Running locally -Add XAI_MODEL and set it to one of the above options from [Run with -Llama](#run-with-llama) - you can leave X_SERVER_URL and XAI_API_KEY blank, it -downloads the model from huggingface and queries it locally +By default, the bot will download and use a local model. You can change this by setting the environment variables for the model you want to use. # Clients diff --git a/docs/community/Notes/lore.md b/docs/community/Notes/lore.md index 5744cdd928a..983d14ccb74 100644 --- a/docs/community/Notes/lore.md +++ b/docs/community/Notes/lore.md @@ -63,12 +63,10 @@ Week 1 Recap: ai16z Launch and Early Developments 4. Infrastructure / Contributor Pipeline -![image](/img/website_v1.jpg) - -- New website launched: https://ai16z.ai -- Dework for crypto bounties, invite link, still WIP: https://app.dework.xyz/i/7KbiY0TFRoJhMx0251BvUP -- Twitter account transferred to partners: https://x.com/ai16zdao -- Media/design assets consolidated on GitHub: https://github.com/ai16z/assets + - New website launched: [https://elizaos.ai](https://elizaos.ai/) + - Dework for crypto bounties, invite link, still WIP: https://app.dework.xyz/i/7KbiY0TFRoJhMx0251BvUP + - Twitter account transferred to partners: https://x.com/ai16zdao + - Media/design assets consolidated on GitHub: https://github.com/ai16z/assets 5. Community Engagement and Spaces diff --git a/docs/docs/api/index.md b/docs/docs/api/index.md index ed33e1393f0..60cd066b4a7 100644 --- a/docs/docs/api/index.md +++ b/docs/docs/api/index.md @@ -56,15 +56,15 @@ To avoid git clashes in the core directory, we recommend adding custom actions t ### Run with Llama -You can run Llama 70B or 405B models by setting the `XAI_MODEL` environment variable to `meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo` or `meta-llama/Meta-Llama-3.1-405B-Instruct` +You can run Llama 70B or 405B models by setting the environment variable for a provider that supports these models. Llama is also supported locally if no other provider is set. ### Run with Grok -You can run Grok models by setting the `XAI_MODEL` environment variable to `grok-beta` +You can run Grok models by setting the `GROK_API_KEY` environment variable to your Grok API key ### Run with OpenAI -You can run OpenAI models by setting the `XAI_MODEL` environment variable to `gpt-4o-mini` or `gpt-4o` +You can run OpenAI models by setting the `OPENAI_API_KEY` environment variable to your OpenAI API key ## Additional Requirements @@ -101,10 +101,6 @@ TWITTER_USERNAME= # Account username TWITTER_PASSWORD= # Account password TWITTER_EMAIL= # Account email -X_SERVER_URL= -XAI_API_KEY= -XAI_MODEL= - # For asking Claude stuff ANTHROPIC_API_KEY= @@ -147,9 +143,7 @@ Make sure that you've installed the CUDA Toolkit, including cuDNN and cuBLAS. ### Running locally -Add XAI_MODEL and set it to one of the above options from [Run with -Llama](#run-with-llama) - you can leave X_SERVER_URL and XAI_API_KEY blank, it -downloads the model from huggingface and queries it locally +By default, the bot will download and use a local model. You can change this by setting the environment variables for the model you want to use. # Clients diff --git a/docs/docs/guides/configuration.md b/docs/docs/guides/configuration.md index 3b9a5e50a69..b260a4d8079 100644 --- a/docs/docs/guides/configuration.md +++ b/docs/docs/guides/configuration.md @@ -25,10 +25,6 @@ Here are the essential environment variables you need to configure: OPENAI_API_KEY=sk-your-key # Required for OpenAI features ANTHROPIC_API_KEY=your-key # Required for Claude models TOGETHER_API_KEY=your-key # Required for Together.ai models - -# Default Settings -XAI_MODEL=gpt-4o-mini # Default model to use -X_SERVER_URL= # Optional model API endpoint ``` ### Client-Specific Configuration @@ -74,11 +70,7 @@ HEURIST_API_KEY= # Livepeer Settings LIVEPEER_GATEWAY_URL= - -# Local Model Settings -XAI_MODEL=meta-llama/Llama-3.1-7b-instruct ``` - ### Image Generation Configure image generation in your character file: diff --git a/docs/docs/guides/local-development.md b/docs/docs/guides/local-development.md index ce06bde9cc8..f66bcfc9b65 100644 --- a/docs/docs/guides/local-development.md +++ b/docs/docs/guides/local-development.md @@ -75,8 +75,6 @@ Configure essential development variables: ```bash # Minimum required for local development OPENAI_API_KEY=sk-* # Optional, for OpenAI features -XAI_API_KEY= # Leave blank for local inference -XAI_MODEL=meta-llama/Llama-3.1-7b-instruct # Local model ``` ### 5. Local Model Setup diff --git a/docs/docs/packages/plugins.md b/docs/docs/packages/plugins.md index 448d7e4e8d8..c1142c79ecc 100644 --- a/docs/docs/packages/plugins.md +++ b/docs/docs/packages/plugins.md @@ -742,6 +742,39 @@ cargo run --ip-addr : docker run --init -p 127.0.0.1:1350:1350 marlinorg/attestation-server-custom-mock ``` +### 12. Allora Plugin (`@elizaos/allora-plugin`) + +The [Allora Network](https://allora.network) plugin seamlessly empowers Eliza agents with real-time, advanced, self-improving AI inferences, delivering high-performance insights without introducing any additional complexity. + +#### Setup and Configuration + +1. Add the plugin to your character's configuration + + ```typescript + import { alloraPlugin } from "@eliza/plugin-allora"; + + const character = { + plugins: [alloraPlugin], + }; + ``` + +2. Set the following environment variables: + - `ALLORA_API_KEY`: Create an API key by [creating an account](https://developer.upshot.xyz/signup). + +#### Actions + +- `GET_INFERENCE`: Retrieves predictions for a specific topic. + +Example interactions: + +``` +User: "What is the predicted ETH price in 5 minutes?" +Agent: "I'll get the inference now..." +Agent: "Inference provided by Allora Network on topic ETH 5min Prediction (ID: 13): 3393.364326646801085508" +``` + +For detailed information and additional implementation examples, please refer to the [Allora-Eliza integration docs](https://docs.allora.network/marketplace/integrations/eliza-os). + ### Writing Custom Plugins Create a new plugin by implementing the Plugin interface: diff --git a/docs/docs/quickstart.md b/docs/docs/quickstart.md index c9269817e4d..8267b1e98dd 100644 --- a/docs/docs/quickstart.md +++ b/docs/docs/quickstart.md @@ -92,9 +92,9 @@ Eliza supports multiple AI models: - **Heurist**: Set `modelProvider: "heurist"` in your character file. Most models are uncensored. - LLM: Select available LLMs [here](https://docs.heurist.ai/dev-guide/supported-models#large-language-models-llms) and configure `SMALL_HEURIST_MODEL`,`MEDIUM_HEURIST_MODEL`,`LARGE_HEURIST_MODEL` - Image Generation: Select available Stable Diffusion or Flux models [here](https://docs.heurist.ai/dev-guide/supported-models#image-generation-models) and configure `HEURIST_IMAGE_MODEL` (default is FLUX.1-dev) -- **Llama**: Set `XAI_MODEL=meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo` -- **Grok**: Set `XAI_MODEL=grok-beta` -- **OpenAI**: Set `XAI_MODEL=gpt-4o-mini` or `gpt-4o` +- **Llama**: Set `OLLAMA_MODEL` to your chosen model +- **Grok**: Set `GROK_API_KEY` to your Grok API key and set `modelProvider: "grok"` in your character file +- **OpenAI**: Set `OPENAI_API_KEY` to your OpenAI API key and set `modelProvider: "openai"` in your character file - **Livepeer**: Set `LIVEPEER_IMAGE_MODEL` to your chosen Livepeer image model, available models [here](https://livepeer-eliza.com/) You set which model to use inside the character JSON file @@ -103,8 +103,6 @@ You set which model to use inside the character JSON file #### For llama_local inference: - 1. Set `XAI_MODEL` to your chosen model - 2. Leave `X_SERVER_URL` and `XAI_API_KEY` blank 3. The system will automatically download the model from Hugging Face 4. `LOCAL_LLAMA_PROVIDER` can be blank diff --git a/packages/adapter-pglite/src/index.ts b/packages/adapter-pglite/src/index.ts index 5f65ff7989f..187a5f17b62 100644 --- a/packages/adapter-pglite/src/index.ts +++ b/packages/adapter-pglite/src/index.ts @@ -14,6 +14,7 @@ import { getEmbeddingConfig, DatabaseAdapter, EmbeddingProvider, + RAGKnowledgeItem, } from "@elizaos/core"; import fs from "fs"; import { fileURLToPath } from "url"; @@ -1282,6 +1283,247 @@ export class PGLiteDatabaseAdapter }, "deleteCache")) ?? false ); } + + async getKnowledge(params: { + id?: UUID; + agentId: UUID; + limit?: number; + query?: string; + }): Promise { + return this.withDatabase(async () => { + try { + let sql = `SELECT * FROM knowledge WHERE ("agentId" = $1 OR "isShared" = true)`; + const queryParams: any[] = [params.agentId]; + let paramCount = 1; + + if (params.id) { + paramCount++; + sql += ` AND id = $${paramCount}`; + queryParams.push(params.id); + } + + if (params.limit) { + paramCount++; + sql += ` LIMIT $${paramCount}`; + queryParams.push(params.limit); + } + + const { rows } = await this.query( + sql, + queryParams + ); + + return rows.map((row) => ({ + id: row.id, + agentId: row.agentId, + content: + typeof row.content === "string" + ? JSON.parse(row.content) + : row.content, + embedding: row.embedding + ? new Float32Array(row.embedding) + : undefined, + createdAt: row.createdAt + ? new Date(row.createdAt).getTime() + : undefined, + })); + } catch (error) { + elizaLogger.error("Error getting knowledge", { + error: + error instanceof Error ? error.message : String(error), + id: params.id, + agentId: params.agentId, + }); + throw new Error( + `Failed to getting knowledge: ${error instanceof Error ? error.message : String(error)}` + ); + } + }, "getKnowledge"); + } + + async searchKnowledge(params: { + agentId: UUID; + embedding: Float32Array; + match_threshold: number; + match_count: number; + searchText?: string; + }): Promise { + return this.withDatabase(async () => { + interface KnowledgeSearchRow { + id: UUID; + agentId: UUID; + content: string; + embedding: Buffer | null; + createdAt: string | number; + vector_score: number; + keyword_score: number; + combined_score: number; + } + try { + const cacheKey = `embedding_${params.agentId}_${params.searchText}`; + const cachedResult = await this.getCache({ + key: cacheKey, + agentId: params.agentId, + }); + + if (cachedResult) { + return JSON.parse(cachedResult); + } + + const vectorStr = `[${Array.from(params.embedding).join(",")}]`; + + const sql = ` + WITH vector_scores AS ( + SELECT id, + 1 - (embedding <-> $1::vector) as vector_score + FROM knowledge + WHERE ("agentId" IS NULL AND "isShared" = true) OR "agentId" = $2 + AND embedding IS NOT NULL + ), + keyword_matches AS ( + SELECT id, + CASE + WHEN content->>'text' ILIKE $3 THEN 3.0 + ELSE 1.0 + END * + CASE + WHEN (content->'metadata'->>'isChunk')::boolean = true THEN 1.5 + WHEN (content->'metadata'->>'isMain')::boolean = true THEN 1.2 + ELSE 1.0 + END as keyword_score + FROM knowledge + WHERE ("agentId" IS NULL AND "isShared" = true) OR "agentId" = $2 + ) + SELECT k.*, + v.vector_score, + kw.keyword_score, + (v.vector_score * kw.keyword_score) as combined_score + FROM knowledge k + JOIN vector_scores v ON k.id = v.id + LEFT JOIN keyword_matches kw ON k.id = kw.id + WHERE ("agentId" IS NULL AND "isShared" = true) OR k."agentId" = $2 + AND ( + v.vector_score >= $4 + OR (kw.keyword_score > 1.0 AND v.vector_score >= 0.3) + ) + ORDER BY combined_score DESC + LIMIT $5 + `; + + const { rows } = await this.query(sql, [ + vectorStr, + params.agentId, + `%${params.searchText || ""}%`, + params.match_threshold, + params.match_count, + ]); + + const results = rows.map((row) => ({ + id: row.id, + agentId: row.agentId, + content: + typeof row.content === "string" + ? JSON.parse(row.content) + : row.content, + embedding: row.embedding + ? new Float32Array(row.embedding) + : undefined, + createdAt: row.createdAt + ? new Date(row.createdAt).getTime() + : undefined, + similarity: row.combined_score, + })); + + await this.setCache({ + key: cacheKey, + agentId: params.agentId, + value: JSON.stringify(results), + }); + + return results; + } catch (error) { + elizaLogger.error("Error searching knowledge", { + error: + error instanceof Error ? error.message : String(error), + searchText: params.searchText, + agentId: params.agentId, + }); + throw new Error( + `Failed to search knowledge: ${error instanceof Error ? error.message : String(error)}` + ); + } + }, "searchKnowledge"); + } + + async createKnowledge(knowledge: RAGKnowledgeItem): Promise { + return this.withTransaction(async (tx) => { + try { + const sql = ` + INSERT INTO knowledge ( + id, "agentId", content, embedding, "createdAt", + "isMain", "originalId", "chunkIndex", "isShared" + ) VALUES ($1, $2, $3, $4, to_timestamp($5/1000.0), $6, $7, $8, $9) + ON CONFLICT (id) DO NOTHING + `; + + const metadata = knowledge.content.metadata || {}; + const vectorStr = knowledge.embedding + ? `[${Array.from(knowledge.embedding).join(",")}]` + : null; + + await tx.query(sql, [ + knowledge.id, + metadata.isShared ? null : knowledge.agentId, + knowledge.content, + vectorStr, + knowledge.createdAt || Date.now(), + metadata.isMain || false, + metadata.originalId || null, + metadata.chunkIndex || null, + metadata.isShared || false, + ]); + } catch (error) { + elizaLogger.error("Failed to create knowledge:", { + error: + error instanceof Error ? error.message : String(error), + }); + throw error; + } + }, "createKnowledge"); + } + + async removeKnowledge(id: UUID): Promise { + return await this.withTransaction(async (tx) => { + try { + await tx.query("DELETE FROM knowledge WHERE id = $1", [id]); + } catch (error) { + tx.rollback(); + elizaLogger.error("Error removing knowledge", { + error: + error instanceof Error ? error.message : String(error), + id, + }); + } + }, "removeKnowledge"); + } + + async clearKnowledge(agentId: UUID, shared?: boolean): Promise { + return await this.withTransaction(async (tx) => { + try { + const sql = shared + ? 'DELETE FROM knowledge WHERE ("agentId" = $1 OR "isShared" = true)' + : 'DELETE FROM knowledge WHERE "agentId" = $1'; + await tx.query(sql, [agentId]); + } catch (error) { + tx.rollback(); + elizaLogger.error("Error clearing knowledge", { + error: + error instanceof Error ? error.message : String(error), + agentId, + }); + } + }, "clearKnowledge"); + } } export default PGLiteDatabaseAdapter; diff --git a/packages/adapter-postgres/migrations/20240318103238_remote_schema.sql b/packages/adapter-postgres/migrations/20240318103238_remote_schema.sql index 53bba89e45f..2867a12aea6 100644 --- a/packages/adapter-postgres/migrations/20240318103238_remote_schema.sql +++ b/packages/adapter-postgres/migrations/20240318103238_remote_schema.sql @@ -507,6 +507,63 @@ CREATE TABLE IF NOT EXISTS "public"."rooms" ( "createdAt" timestamp with time zone DEFAULT ("now"() AT TIME ZONE 'utc'::"text") NOT NULL ); +CREATE OR REPLACE FUNCTION "public"."search_knowledge"( + "query_embedding" "extensions"."vector", + "query_agent_id" "uuid", + "match_threshold" double precision, + "match_count" integer, + "search_text" text +) RETURNS TABLE ( + "id" "uuid", + "agentId" "uuid", + "content" "jsonb", + "embedding" "extensions"."vector", + "createdAt" timestamp with time zone, + "similarity" double precision +) LANGUAGE "plpgsql" AS $$ +BEGIN + RETURN QUERY + WITH vector_matches AS ( + SELECT id, + 1 - (embedding <=> query_embedding) as vector_score + FROM knowledge + WHERE (agentId IS NULL AND isShared = true) OR agentId = query_agent_id + AND embedding IS NOT NULL + ), + keyword_matches AS ( + SELECT id, + CASE + WHEN content->>'text' ILIKE '%' || search_text || '%' THEN 3.0 + ELSE 1.0 + END * + CASE + WHEN content->'metadata'->>'isChunk' = 'true' THEN 1.5 + WHEN content->'metadata'->>'isMain' = 'true' THEN 1.2 + ELSE 1.0 + END as keyword_score + FROM knowledge + WHERE (agentId IS NULL AND isShared = true) OR agentId = query_agent_id + ) + SELECT + k.id, + k."agentId", + k.content, + k.embedding, + k."createdAt", + (v.vector_score * kw.keyword_score) as similarity + FROM knowledge k + JOIN vector_matches v ON k.id = v.id + LEFT JOIN keyword_matches kw ON k.id = kw.id + WHERE (k.agentId IS NULL AND k.isShared = true) OR k.agentId = query_agent_id + AND ( + v.vector_score >= match_threshold + OR (kw.keyword_score > 1.0 AND v.vector_score >= 0.3) + ) + ORDER BY similarity DESC + LIMIT match_count; +END; +$$; + ALTER TABLE "public"."rooms" OWNER TO "postgres"; ALTER TABLE ONLY "public"."relationships" @@ -564,6 +621,9 @@ ALTER TABLE ONLY "public"."relationships" ALTER TABLE ONLY "public"."relationships" ADD CONSTRAINT "relationships_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."accounts"("id"); +ALTER TABLE ONLY "public"."knowledge" + ADD CONSTRAINT "knowledge_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "public"."accounts"("id") ON DELETE CASCADE; + CREATE POLICY "Can select and update all data" ON "public"."accounts" USING (("auth"."uid"() = "id")) WITH CHECK (("auth"."uid"() = "id")); CREATE POLICY "Enable delete for users based on userId" ON "public"."goals" FOR DELETE TO "authenticated" USING (("auth"."uid"() = "userId")); @@ -600,6 +660,18 @@ CREATE POLICY "Enable update for users of own id" ON "public"."rooms" FOR UPDATE CREATE POLICY "Enable users to delete their own relationships/friendships" ON "public"."relationships" FOR DELETE TO "authenticated" USING ((("auth"."uid"() = "userA") OR ("auth"."uid"() = "userB"))); +CREATE POLICY "Enable read access for all users" ON "public"."knowledge" + FOR SELECT USING (true); + +CREATE POLICY "Enable insert for authenticated users only" ON "public"."knowledge" + FOR INSERT TO "authenticated" WITH CHECK (true); + +CREATE POLICY "Enable update for authenticated users" ON "public"."knowledge" + FOR UPDATE TO "authenticated" USING (true) WITH CHECK (true); + +CREATE POLICY "Enable delete for users based on agentId" ON "public"."knowledge" + FOR DELETE TO "authenticated" USING (("auth"."uid"() = "agentId")); + ALTER TABLE "public"."accounts" ENABLE ROW LEVEL SECURITY; ALTER TABLE "public"."goals" ENABLE ROW LEVEL SECURITY; @@ -614,6 +686,8 @@ ALTER TABLE "public"."relationships" ENABLE ROW LEVEL SECURITY; ALTER TABLE "public"."rooms" ENABLE ROW LEVEL SECURITY; +ALTER TABLE "public"."knowledge" ENABLE ROW LEVEL SECURITY; + CREATE POLICY "select_own_account" ON "public"."accounts" FOR SELECT USING (("auth"."uid"() = "id")); GRANT USAGE ON SCHEMA "public" TO "postgres"; @@ -703,6 +777,10 @@ GRANT ALL ON TABLE "public"."secrets" TO "service_role"; GRANT ALL ON TABLE "public"."secrets" TO "supabase_admin"; GRANT ALL ON TABLE "public"."secrets" TO "supabase_auth_admin"; +GRANT ALL ON TABLE "public"."knowledge" TO "authenticated"; +GRANT ALL ON TABLE "public"."knowledge" TO "service_role"; +GRANT ALL ON TABLE "public"."knowledge" TO "supabase_admin"; +GRANT ALL ON TABLE "public"."knowledge" TO "supabase_auth_admin"; GRANT ALL ON FUNCTION "public"."get_participant_userState"("roomId" "uuid", "userId" "uuid") TO "authenticated"; GRANT ALL ON FUNCTION "public"."get_participant_userState"("roomId" "uuid", "userId" "uuid") TO "service_role"; @@ -710,7 +788,7 @@ GRANT ALL ON FUNCTION "public"."get_participant_userState"("roomId" "uuid", "use GRANT ALL ON FUNCTION "public"."get_participant_userState"("roomId" "uuid", "userId" "uuid") TO "supabase_auth_admin"; GRANT ALL ON FUNCTION "public"."set_participant_userState"("roomId" "uuid", "userId" "uuid", "state" "text") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."set_participant_userState"("roomId" "uuid", "userId" "uuid", "state" "text") TO "service_role"; +GRANT ALL ON FUNCTION "public"."set_participant_userState"("roomId" "uuid", "userId" "uuid", "state" "text") TO "service_role"; GRANT ALL ON FUNCTION "public"."set_participant_userState"("roomId" "uuid", "userId" "uuid", "state" "text") TO "supabase_admin"; GRANT ALL ON FUNCTION "public"."set_participant_userState"("roomId" "uuid", "userId" "uuid", "state" "text") TO "supabase_auth_admin"; @@ -733,4 +811,9 @@ ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TAB ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "supabase_admin"; ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "supabase_auth_admin"; +GRANT ALL ON FUNCTION "public"."search_knowledge"("query_embedding" "extensions"."vector", "query_agent_id" "uuid", "match_threshold" double precision, "match_count" integer, "search_text" text) TO "authenticated"; +GRANT ALL ON FUNCTION "public"."search_knowledge"("query_embedding" "extensions"."vector", "query_agent_id" "uuid", "match_threshold" double precision, "match_count" integer, "search_text" text) TO "service_role"; +GRANT ALL ON FUNCTION "public"."search_knowledge"("query_embedding" "extensions"."vector", "query_agent_id" "uuid", "match_threshold" double precision, "match_count" integer, "search_text" text) TO "supabase_admin"; +GRANT ALL ON FUNCTION "public"."search_knowledge"("query_embedding" "extensions"."vector", "query_agent_id" "uuid", "match_threshold" double precision, "match_count" integer, "search_text" text) TO "supabase_auth_admin"; + RESET ALL; \ No newline at end of file diff --git a/packages/adapter-postgres/schema.sql b/packages/adapter-postgres/schema.sql index 4a0f7c6f1dd..7a367318e1f 100644 --- a/packages/adapter-postgres/schema.sql +++ b/packages/adapter-postgres/schema.sql @@ -9,6 +9,7 @@ -- DROP TABLE IF EXISTS memories CASCADE; -- DROP TABLE IF EXISTS rooms CASCADE; -- DROP TABLE IF EXISTS accounts CASCADE; +-- DROP TABLE IF EXISTS knowledge CASCADE; CREATE EXTENSION IF NOT EXISTS vector; @@ -130,11 +131,38 @@ CREATE TABLE IF NOT EXISTS cache ( PRIMARY KEY ("key", "agentId") ); +DO $$ +DECLARE + vector_dim INTEGER; +BEGIN + vector_dim := get_embedding_dimension(); + + EXECUTE format(' + CREATE TABLE IF NOT EXISTS knowledge ( + "id" UUID PRIMARY KEY, + "agentId" UUID REFERENCES accounts("id"), + "content" JSONB NOT NULL, + "embedding" vector(%s), + "createdAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, + "isMain" BOOLEAN DEFAULT FALSE, + "originalId" UUID REFERENCES knowledge("id"), + "chunkIndex" INTEGER, + "isShared" BOOLEAN DEFAULT FALSE, + CHECK(("isShared" = true AND "agentId" IS NULL) OR ("isShared" = false AND "agentId" IS NOT NULL)) + )', vector_dim); +END $$; + -- Indexes CREATE INDEX IF NOT EXISTS idx_memories_embedding ON memories USING hnsw ("embedding" vector_cosine_ops); CREATE INDEX IF NOT EXISTS idx_memories_type_room ON memories("type", "roomId"); CREATE INDEX IF NOT EXISTS idx_participants_user ON participants("userId"); CREATE INDEX IF NOT EXISTS idx_participants_room ON participants("roomId"); CREATE INDEX IF NOT EXISTS idx_relationships_users ON relationships("userA", "userB"); +CREATE INDEX IF NOT EXISTS idx_knowledge_agent ON knowledge("agentId"); +CREATE INDEX IF NOT EXISTS idx_knowledge_agent_main ON knowledge("agentId", "isMain"); +CREATE INDEX IF NOT EXISTS idx_knowledge_original ON knowledge("originalId"); +CREATE INDEX IF NOT EXISTS idx_knowledge_created ON knowledge("agentId", "createdAt"); +CREATE INDEX IF NOT EXISTS idx_knowledge_shared ON knowledge("isShared"); +CREATE INDEX IF NOT EXISTS idx_knowledge_embedding ON knowledge USING ivfflat (embedding vector_cosine_ops); COMMIT; diff --git a/packages/adapter-postgres/src/index.ts b/packages/adapter-postgres/src/index.ts index 5e4cf936eac..9d1e549b66b 100644 --- a/packages/adapter-postgres/src/index.ts +++ b/packages/adapter-postgres/src/index.ts @@ -24,6 +24,7 @@ import { getEmbeddingConfig, DatabaseAdapter, EmbeddingProvider, + RAGKnowledgeItem } from "@elizaos/core"; import fs from "fs"; import { fileURLToPath } from "url"; @@ -1457,6 +1458,182 @@ export class PostgresDatabaseAdapter } }, "deleteCache"); } + + async getKnowledge(params: { + id?: UUID; + agentId: UUID; + limit?: number; + query?: string; + }): Promise { + return this.withDatabase(async () => { + let sql = `SELECT * FROM knowledge WHERE ("agentId" = $1 OR "isShared" = true)`; + const queryParams: any[] = [params.agentId]; + let paramCount = 1; + + if (params.id) { + paramCount++; + sql += ` AND id = $${paramCount}`; + queryParams.push(params.id); + } + + if (params.limit) { + paramCount++; + sql += ` LIMIT $${paramCount}`; + queryParams.push(params.limit); + } + + const { rows } = await this.pool.query(sql, queryParams); + + return rows.map(row => ({ + id: row.id, + agentId: row.agentId, + content: typeof row.content === 'string' ? JSON.parse(row.content) : row.content, + embedding: row.embedding ? new Float32Array(row.embedding) : undefined, + createdAt: row.createdAt.getTime() + })); + }, "getKnowledge"); + } + + async searchKnowledge(params: { + agentId: UUID; + embedding: Float32Array; + match_threshold: number; + match_count: number; + searchText?: string; + }): Promise { + return this.withDatabase(async () => { + const cacheKey = `embedding_${params.agentId}_${params.searchText}`; + const cachedResult = await this.getCache({ + key: cacheKey, + agentId: params.agentId + }); + + if (cachedResult) { + return JSON.parse(cachedResult); + } + + const vectorStr = `[${Array.from(params.embedding).join(",")}]`; + + const sql = ` + WITH vector_scores AS ( + SELECT id, + 1 - (embedding <-> $1::vector) as vector_score + FROM knowledge + WHERE ("agentId" IS NULL AND "isShared" = true) OR "agentId" = $2 + AND embedding IS NOT NULL + ), + keyword_matches AS ( + SELECT id, + CASE + WHEN content->>'text' ILIKE $3 THEN 3.0 + ELSE 1.0 + END * + CASE + WHEN (content->'metadata'->>'isChunk')::boolean = true THEN 1.5 + WHEN (content->'metadata'->>'isMain')::boolean = true THEN 1.2 + ELSE 1.0 + END as keyword_score + FROM knowledge + WHERE ("agentId" IS NULL AND "isShared" = true) OR "agentId" = $2 + ) + SELECT k.*, + v.vector_score, + kw.keyword_score, + (v.vector_score * kw.keyword_score) as combined_score + FROM knowledge k + JOIN vector_scores v ON k.id = v.id + LEFT JOIN keyword_matches kw ON k.id = kw.id + WHERE ("agentId" IS NULL AND "isShared" = true) OR k."agentId" = $2 + AND ( + v.vector_score >= $4 + OR (kw.keyword_score > 1.0 AND v.vector_score >= 0.3) + ) + ORDER BY combined_score DESC + LIMIT $5 + `; + + const { rows } = await this.pool.query(sql, [ + vectorStr, + params.agentId, + `%${params.searchText || ''}%`, + params.match_threshold, + params.match_count + ]); + + const results = rows.map(row => ({ + id: row.id, + agentId: row.agentId, + content: typeof row.content === 'string' ? JSON.parse(row.content) : row.content, + embedding: row.embedding ? new Float32Array(row.embedding) : undefined, + createdAt: row.createdAt.getTime(), + similarity: row.combined_score + })); + + await this.setCache({ + key: cacheKey, + agentId: params.agentId, + value: JSON.stringify(results) + }); + + return results; + }, "searchKnowledge"); + } + + async createKnowledge(knowledge: RAGKnowledgeItem): Promise { + return this.withDatabase(async () => { + const client = await this.pool.connect(); + try { + await client.query('BEGIN'); + + const sql = ` + INSERT INTO knowledge ( + id, "agentId", content, embedding, "createdAt", + "isMain", "originalId", "chunkIndex", "isShared" + ) VALUES ($1, $2, $3, $4, to_timestamp($5/1000.0), $6, $7, $8, $9) + ON CONFLICT (id) DO NOTHING + `; + + const metadata = knowledge.content.metadata || {}; + const vectorStr = knowledge.embedding ? + `[${Array.from(knowledge.embedding).join(",")}]` : null; + + await client.query(sql, [ + knowledge.id, + metadata.isShared ? null : knowledge.agentId, + knowledge.content, + vectorStr, + knowledge.createdAt || Date.now(), + metadata.isMain || false, + metadata.originalId || null, + metadata.chunkIndex || null, + metadata.isShared || false + ]); + + await client.query('COMMIT'); + } catch (error) { + await client.query('ROLLBACK'); + throw error; + } finally { + client.release(); + } + }, "createKnowledge"); + } + + async removeKnowledge(id: UUID): Promise { + return this.withDatabase(async () => { + await this.pool.query('DELETE FROM knowledge WHERE id = $1', [id]); + }, "removeKnowledge"); + } + + async clearKnowledge(agentId: UUID, shared?: boolean): Promise { + return this.withDatabase(async () => { + const sql = shared ? + 'DELETE FROM knowledge WHERE ("agentId" = $1 OR "isShared" = true)' : + 'DELETE FROM knowledge WHERE "agentId" = $1'; + + await this.pool.query(sql, [agentId]); + }, "clearKnowledge"); + } } export default PostgresDatabaseAdapter; diff --git a/packages/adapter-sqlite/src/index.ts b/packages/adapter-sqlite/src/index.ts index 0e7574d6fb6..cf8c00043bd 100644 --- a/packages/adapter-sqlite/src/index.ts +++ b/packages/adapter-sqlite/src/index.ts @@ -1,7 +1,11 @@ export * from "./sqliteTables.ts"; export * from "./sqlite_vec.ts"; -import { DatabaseAdapter, IDatabaseCacheAdapter } from "@elizaos/core"; +import { + DatabaseAdapter, + elizaLogger, + IDatabaseCacheAdapter, +} from "@elizaos/core"; import { Account, Actor, @@ -11,6 +15,7 @@ import { type Memory, type Relationship, type UUID, + RAGKnowledgeItem, } from "@elizaos/core"; import { Database } from "better-sqlite3"; import { v4 } from "uuid"; @@ -223,17 +228,19 @@ export class SqliteDatabaseAdapter // Insert the memory with the appropriate 'unique' value const sql = `INSERT OR REPLACE INTO memories (id, type, content, embedding, userId, roomId, agentId, \`unique\`, createdAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`; - this.db.prepare(sql).run( - memory.id ?? v4(), - tableName, - content, - embeddingValue, - memory.userId, - memory.roomId, - memory.agentId, - isUnique ? 1 : 0, - createdAt - ); + this.db + .prepare(sql) + .run( + memory.id ?? v4(), + tableName, + content, + embeddingValue, + memory.userId, + memory.roomId, + memory.agentId, + isUnique ? 1 : 0, + createdAt + ); } async searchMemories(params: { @@ -713,4 +720,231 @@ export class SqliteDatabaseAdapter return false; } } -} \ No newline at end of file + + async getKnowledge(params: { + id?: UUID; + agentId: UUID; + limit?: number; + query?: string; + }): Promise { + let sql = `SELECT * FROM knowledge WHERE (agentId = ? OR isShared = 1)`; + const queryParams: any[] = [params.agentId]; + + if (params.id) { + sql += ` AND id = ?`; + queryParams.push(params.id); + } + + if (params.limit) { + sql += ` LIMIT ?`; + queryParams.push(params.limit); + } + + interface KnowledgeRow { + id: UUID; + agentId: UUID; + content: string; + embedding: Buffer | null; + createdAt: string | number; + } + + const rows = this.db.prepare(sql).all(...queryParams) as KnowledgeRow[]; + + return rows.map((row) => ({ + id: row.id, + agentId: row.agentId, + content: JSON.parse(row.content), + embedding: row.embedding + ? new Float32Array(row.embedding) + : undefined, + createdAt: + typeof row.createdAt === "string" + ? Date.parse(row.createdAt) + : row.createdAt, + })); + } + + async searchKnowledge(params: { + agentId: UUID; + embedding: Float32Array; + match_threshold: number; + match_count: number; + searchText?: string; + }): Promise { + const cacheKey = `embedding_${params.agentId}_${params.searchText}`; + const cachedResult = await this.getCache({ + key: cacheKey, + agentId: params.agentId, + }); + + if (cachedResult) { + return JSON.parse(cachedResult); + } + + interface KnowledgeSearchRow { + id: UUID; + agentId: UUID; + content: string; + embedding: Buffer | null; + createdAt: string | number; + vector_score: number; + keyword_score: number; + combined_score: number; + } + + const sql = ` + WITH vector_scores AS ( + SELECT id, + 1 / (1 + vec_distance_L2(embedding, ?)) as vector_score + FROM knowledge + WHERE (agentId IS NULL AND isShared = 1) OR agentId = ? + AND embedding IS NOT NULL + ), + keyword_matches AS ( + SELECT id, + CASE + WHEN lower(json_extract(content, '$.text')) LIKE ? THEN 3.0 + ELSE 1.0 + END * + CASE + WHEN json_extract(content, '$.metadata.isChunk') = 1 THEN 1.5 + WHEN json_extract(content, '$.metadata.isMain') = 1 THEN 1.2 + ELSE 1.0 + END as keyword_score + FROM knowledge + WHERE (agentId IS NULL AND isShared = 1) OR agentId = ? + ) + SELECT k.*, + v.vector_score, + kw.keyword_score, + (v.vector_score * kw.keyword_score) as combined_score + FROM knowledge k + JOIN vector_scores v ON k.id = v.id + LEFT JOIN keyword_matches kw ON k.id = kw.id + WHERE (k.agentId IS NULL AND k.isShared = 1) OR k.agentId = ? + AND ( + v.vector_score >= ? -- Using match_threshold parameter + OR (kw.keyword_score > 1.0 AND v.vector_score >= 0.3) + ) + ORDER BY combined_score DESC + LIMIT ? + `; + + const searchParams = [ + params.embedding, + params.agentId, + `%${params.searchText?.toLowerCase() || ""}%`, + params.agentId, + params.agentId, + params.match_threshold, + params.match_count, + ]; + + try { + const rows = this.db + .prepare(sql) + .all(...searchParams) as KnowledgeSearchRow[]; + const results = rows.map((row) => ({ + id: row.id, + agentId: row.agentId, + content: JSON.parse(row.content), + embedding: row.embedding + ? new Float32Array(row.embedding) + : undefined, + createdAt: + typeof row.createdAt === "string" + ? Date.parse(row.createdAt) + : row.createdAt, + similarity: row.combined_score, + })); + + await this.setCache({ + key: cacheKey, + agentId: params.agentId, + value: JSON.stringify(results), + }); + + return results; + } catch (error) { + elizaLogger.error("Error in searchKnowledge:", error); + throw error; + } + } + + async createKnowledge(knowledge: RAGKnowledgeItem): Promise { + try { + this.db.transaction(() => { + const sql = ` + INSERT INTO knowledge ( + id, agentId, content, embedding, createdAt, + isMain, originalId, chunkIndex, isShared + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + `; + + const embeddingArray = knowledge.embedding || null; + + const metadata = knowledge.content.metadata || {}; + const isShared = metadata.isShared ? 1 : 0; + + this.db + .prepare(sql) + .run( + knowledge.id, + metadata.isShared ? null : knowledge.agentId, + JSON.stringify(knowledge.content), + embeddingArray, + knowledge.createdAt || Date.now(), + metadata.isMain ? 1 : 0, + metadata.originalId || null, + metadata.chunkIndex || null, + isShared + ); + })(); + } catch (error: any) { + const isShared = knowledge.content.metadata?.isShared; + const isPrimaryKeyError = + error?.code === "SQLITE_CONSTRAINT_PRIMARYKEY"; + + if (isShared && isPrimaryKeyError) { + elizaLogger.info( + `Shared knowledge ${knowledge.id} already exists, skipping` + ); + return; + } else if ( + !isShared && + !error.message?.includes("SQLITE_CONSTRAINT_PRIMARYKEY") + ) { + elizaLogger.error(`Error creating knowledge ${knowledge.id}:`, { + error, + embeddingLength: knowledge.embedding?.length, + content: knowledge.content, + }); + throw error; + } + + elizaLogger.debug( + `Knowledge ${knowledge.id} already exists, skipping` + ); + } + } + + async removeKnowledge(id: UUID): Promise { + const sql = `DELETE FROM knowledge WHERE id = ?`; + this.db.prepare(sql).run(id); + } + + async clearKnowledge(agentId: UUID, shared?: boolean): Promise { + const sql = shared + ? `DELETE FROM knowledge WHERE (agentId = ? OR isShared = 1)` + : `DELETE FROM knowledge WHERE agentId = ?`; + try { + this.db.prepare(sql).run(agentId); + } catch (error) { + elizaLogger.error( + `Error clearing knowledge for agent ${agentId}:`, + error + ); + throw error; + } + } +} diff --git a/packages/adapter-sqlite/src/sqliteTables.ts b/packages/adapter-sqlite/src/sqliteTables.ts index fdd47e5697f..87fc26743fa 100644 --- a/packages/adapter-sqlite/src/sqliteTables.ts +++ b/packages/adapter-sqlite/src/sqliteTables.ts @@ -92,6 +92,22 @@ CREATE TABLE IF NOT EXISTS "cache" ( PRIMARY KEY ("key", "agentId") ); +-- Table: knowledge +CREATE TABLE IF NOT EXISTS "knowledge" ( + "id" TEXT PRIMARY KEY, + "agentId" TEXT, + "content" TEXT NOT NULL CHECK(json_valid("content")), + "embedding" BLOB, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "isMain" INTEGER DEFAULT 0, + "originalId" TEXT, + "chunkIndex" INTEGER, + "isShared" INTEGER DEFAULT 0, + FOREIGN KEY ("agentId") REFERENCES "accounts"("id"), + FOREIGN KEY ("originalId") REFERENCES "knowledge"("id"), + CHECK((isShared = 1 AND agentId IS NULL) OR (isShared = 0 AND agentId IS NOT NULL)) +); + -- Index: relationships_id_key CREATE UNIQUE INDEX IF NOT EXISTS "relationships_id_key" ON "relationships" ("id"); @@ -101,4 +117,14 @@ CREATE UNIQUE INDEX IF NOT EXISTS "memories_id_key" ON "memories" ("id"); -- Index: participants_id_key CREATE UNIQUE INDEX IF NOT EXISTS "participants_id_key" ON "participants" ("id"); -COMMIT;`; +-- Index: knowledge +CREATE INDEX IF NOT EXISTS "knowledge_agent_key" ON "knowledge" ("agentId"); +CREATE INDEX IF NOT EXISTS "knowledge_agent_main_key" ON "knowledge" ("agentId", "isMain"); +CREATE INDEX IF NOT EXISTS "knowledge_original_key" ON "knowledge" ("originalId"); +CREATE INDEX IF NOT EXISTS "knowledge_content_key" ON "knowledge" + ((json_extract(content, '$.text'))) + WHERE json_extract(content, '$.text') IS NOT NULL; +CREATE INDEX IF NOT EXISTS "knowledge_created_key" ON "knowledge" ("agentId", "createdAt"); +CREATE INDEX IF NOT EXISTS "knowledge_shared_key" ON "knowledge" ("isShared"); + +COMMIT;`; \ No newline at end of file diff --git a/packages/adapter-sqljs/src/index.ts b/packages/adapter-sqljs/src/index.ts index 08658450495..db27215e100 100644 --- a/packages/adapter-sqljs/src/index.ts +++ b/packages/adapter-sqljs/src/index.ts @@ -12,11 +12,12 @@ import { type Memory, type Relationship, type UUID, + RAGKnowledgeItem, + elizaLogger } from "@elizaos/core"; import { v4 } from "uuid"; import { sqliteTables } from "./sqliteTables.ts"; import { Database } from "./types.ts"; -import { elizaLogger } from "@elizaos/core"; export class SqlJsDatabaseAdapter extends DatabaseAdapter @@ -803,4 +804,191 @@ export class SqlJsDatabaseAdapter return false; } } + + async getKnowledge(params: { + id?: UUID; + agentId: UUID; + limit?: number; + query?: string; + }): Promise { + let sql = `SELECT * FROM knowledge WHERE ("agentId" = ? OR "isShared" = 1)`; + const queryParams: any[] = [params.agentId]; + + if (params.id) { + sql += ` AND id = ?`; + queryParams.push(params.id); + } + + if (params.limit) { + sql += ` LIMIT ?`; + queryParams.push(params.limit); + } + + const stmt = this.db.prepare(sql); + stmt.bind(queryParams); + const results: RAGKnowledgeItem[] = []; + + while (stmt.step()) { + const row = stmt.getAsObject() as any; + results.push({ + id: row.id, + agentId: row.agentId, + content: JSON.parse(row.content), + embedding: row.embedding ? new Float32Array(row.embedding) : undefined, // Convert Uint8Array back to Float32Array + createdAt: row.createdAt + }); + } + stmt.free(); + return results; + } + + async searchKnowledge(params: { + agentId: UUID; + embedding: Float32Array; + match_threshold: number; + match_count: number; + searchText?: string; + }): Promise { + const cacheKey = `embedding_${params.agentId}_${params.searchText}`; + const cachedResult = await this.getCache({ + key: cacheKey, + agentId: params.agentId + }); + + if (cachedResult) { + return JSON.parse(cachedResult); + } + + let sql = ` + WITH vector_scores AS ( + SELECT id, + 1 / (1 + vec_distance_L2(embedding, ?)) as vector_score + FROM knowledge + WHERE ("agentId" IS NULL AND "isShared" = 1) OR "agentId" = ? + AND embedding IS NOT NULL + ), + keyword_matches AS ( + SELECT id, + CASE + WHEN json_extract(content, '$.text') LIKE ? THEN 3.0 + ELSE 1.0 + END * + CASE + WHEN json_extract(content, '$.metadata.isChunk') = 1 THEN 1.5 + WHEN json_extract(content, '$.metadata.isMain') = 1 THEN 1.2 + ELSE 1.0 + END as keyword_score + FROM knowledge + WHERE ("agentId" IS NULL AND "isShared" = 1) OR "agentId" = ? + ) + SELECT k.*, + v.vector_score, + kw.keyword_score, + (v.vector_score * kw.keyword_score) as combined_score + FROM knowledge k + JOIN vector_scores v ON k.id = v.id + LEFT JOIN keyword_matches kw ON k.id = kw.id + WHERE (k.agentId IS NULL AND k.isShared = 1) OR k.agentId = ? + AND ( + v.vector_score >= ? -- Using match_threshold parameter + OR (kw.keyword_score > 1.0 AND v.vector_score >= 0.3) + ) + ORDER BY combined_score DESC + LIMIT ? + `; + + const stmt = this.db.prepare(sql); + stmt.bind([ + new Uint8Array(params.embedding.buffer), + params.agentId, + `%${params.searchText || ''}%`, + params.agentId, + params.agentId, + params.match_threshold, + params.match_count + ]); + + const results: RAGKnowledgeItem[] = []; + while (stmt.step()) { + const row = stmt.getAsObject() as any; + results.push({ + id: row.id, + agentId: row.agentId, + content: JSON.parse(row.content), + embedding: row.embedding ? new Float32Array(row.embedding) : undefined, + createdAt: row.createdAt, + similarity: row.keyword_score + }); + } + stmt.free(); + + await this.setCache({ + key: cacheKey, + agentId: params.agentId, + value: JSON.stringify(results) + }); + + return results; + } + + async createKnowledge(knowledge: RAGKnowledgeItem): Promise { + try { + const sql = ` + INSERT INTO knowledge ( + id, "agentId", content, embedding, "createdAt", + "isMain", "originalId", "chunkIndex", "isShared" + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + `; + + const stmt = this.db.prepare(sql); + const metadata = knowledge.content.metadata || {}; + + stmt.run([ + knowledge.id, + metadata.isShared ? null : knowledge.agentId, + JSON.stringify(knowledge.content), + knowledge.embedding ? new Uint8Array(knowledge.embedding.buffer) : null, + knowledge.createdAt || Date.now(), + metadata.isMain ? 1 : 0, + metadata.originalId || null, + metadata.chunkIndex || null, + metadata.isShared ? 1 : 0 + ]); + stmt.free(); + } catch (error: any) { + const isShared = knowledge.content.metadata?.isShared; + const isPrimaryKeyError = error?.code === 'SQLITE_CONSTRAINT_PRIMARYKEY'; + + if (isShared && isPrimaryKeyError) { + elizaLogger.info(`Shared knowledge ${knowledge.id} already exists, skipping`); + return; + } else if (!isShared && !error.message?.includes('SQLITE_CONSTRAINT_PRIMARYKEY')) { + elizaLogger.error(`Error creating knowledge ${knowledge.id}:`, { + error, + embeddingLength: knowledge.embedding?.length, + content: knowledge.content + }); + throw error; + } + + elizaLogger.debug(`Knowledge ${knowledge.id} already exists, skipping`); + } + } + + async removeKnowledge(id: UUID): Promise { + const sql = `DELETE FROM knowledge WHERE id = ?`; + const stmt = this.db.prepare(sql); + stmt.run([id]); + stmt.free(); + } + + async clearKnowledge(agentId: UUID, shared?: boolean): Promise { + const sql = shared ? + `DELETE FROM knowledge WHERE ("agentId" = ? OR "isShared" = 1)` : + `DELETE FROM knowledge WHERE "agentId" = ?`; + + const stmt = this.db.prepare(sql); + stmt.run([agentId]); + stmt.free(); + } } diff --git a/packages/adapter-sqljs/src/sqliteTables.ts b/packages/adapter-sqljs/src/sqliteTables.ts index fdd47e5697f..87fc26743fa 100644 --- a/packages/adapter-sqljs/src/sqliteTables.ts +++ b/packages/adapter-sqljs/src/sqliteTables.ts @@ -92,6 +92,22 @@ CREATE TABLE IF NOT EXISTS "cache" ( PRIMARY KEY ("key", "agentId") ); +-- Table: knowledge +CREATE TABLE IF NOT EXISTS "knowledge" ( + "id" TEXT PRIMARY KEY, + "agentId" TEXT, + "content" TEXT NOT NULL CHECK(json_valid("content")), + "embedding" BLOB, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "isMain" INTEGER DEFAULT 0, + "originalId" TEXT, + "chunkIndex" INTEGER, + "isShared" INTEGER DEFAULT 0, + FOREIGN KEY ("agentId") REFERENCES "accounts"("id"), + FOREIGN KEY ("originalId") REFERENCES "knowledge"("id"), + CHECK((isShared = 1 AND agentId IS NULL) OR (isShared = 0 AND agentId IS NOT NULL)) +); + -- Index: relationships_id_key CREATE UNIQUE INDEX IF NOT EXISTS "relationships_id_key" ON "relationships" ("id"); @@ -101,4 +117,14 @@ CREATE UNIQUE INDEX IF NOT EXISTS "memories_id_key" ON "memories" ("id"); -- Index: participants_id_key CREATE UNIQUE INDEX IF NOT EXISTS "participants_id_key" ON "participants" ("id"); -COMMIT;`; +-- Index: knowledge +CREATE INDEX IF NOT EXISTS "knowledge_agent_key" ON "knowledge" ("agentId"); +CREATE INDEX IF NOT EXISTS "knowledge_agent_main_key" ON "knowledge" ("agentId", "isMain"); +CREATE INDEX IF NOT EXISTS "knowledge_original_key" ON "knowledge" ("originalId"); +CREATE INDEX IF NOT EXISTS "knowledge_content_key" ON "knowledge" + ((json_extract(content, '$.text'))) + WHERE json_extract(content, '$.text') IS NOT NULL; +CREATE INDEX IF NOT EXISTS "knowledge_created_key" ON "knowledge" ("agentId", "createdAt"); +CREATE INDEX IF NOT EXISTS "knowledge_shared_key" ON "knowledge" ("isShared"); + +COMMIT;`; \ No newline at end of file diff --git a/packages/adapter-supabase/schema.sql b/packages/adapter-supabase/schema.sql index 25eb0dcae85..6e2ad8e52ca 100644 --- a/packages/adapter-supabase/schema.sql +++ b/packages/adapter-supabase/schema.sql @@ -9,6 +9,7 @@ -- DROP TABLE IF EXISTS memories CASCADE; -- DROP TABLE IF EXISTS rooms CASCADE; -- DROP TABLE IF EXISTS accounts CASCADE; +-- DROP TABLE IF EXISTS knowledge CASCADE; CREATE EXTENSION IF NOT EXISTS vector; @@ -150,6 +151,28 @@ CREATE TABLE relationships ( CONSTRAINT fk_user FOREIGN KEY ("userId") REFERENCES accounts("id") ON DELETE CASCADE ); +CREATE TABLE cache ( + "key" TEXT NOT NULL, + "agentId" TEXT NOT NULL, + "value" JSONB DEFAULT '{}'::jsonb, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "expiresAt" TIMESTAMP, + PRIMARY KEY ("key", "agentId") +); + +CREATE TABLE knowledge ( + "id" UUID PRIMARY KEY, + "agentId" UUID REFERENCES accounts("id"), + "content" JSONB NOT NULL, + "embedding" vector(1536), + "createdAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, + "isMain" BOOLEAN DEFAULT FALSE, + "originalId" UUID REFERENCES knowledge("id"), + "chunkIndex" INTEGER, + "isShared" BOOLEAN DEFAULT FALSE, + CHECK((isShared = true AND "agentId" IS NULL) OR (isShared = false AND "agentId" IS NOT NULL)) +); + -- Add index for Ollama table CREATE INDEX idx_memories_1024_embedding ON memories_1024 USING hnsw ("embedding" vector_cosine_ops); CREATE INDEX idx_memories_1024_type_room ON memories_1024("type", "roomId"); @@ -162,5 +185,11 @@ CREATE INDEX idx_memories_384_type_room ON memories_384("type", "roomId"); CREATE INDEX idx_participants_user ON participants("userId"); CREATE INDEX idx_participants_room ON participants("roomId"); CREATE INDEX idx_relationships_users ON relationships("userA", "userB"); +CREATE INDEX idx_knowledge_agent ON knowledge("agentId"); +CREATE INDEX idx_knowledge_agent_main ON knowledge("agentId", "isMain"); +CREATE INDEX idx_knowledge_original ON knowledge("originalId"); +CREATE INDEX idx_knowledge_created ON knowledge("agentId", "createdAt"); +CREATE INDEX idx_knowledge_shared ON knowledge("isShared"); +CREATE INDEX idx_knowledge_embedding ON knowledge USING ivfflat (embedding vector_cosine_ops); COMMIT; diff --git a/packages/adapter-supabase/src/index.ts b/packages/adapter-supabase/src/index.ts index f6f9840f213..9c8d643f61a 100644 --- a/packages/adapter-supabase/src/index.ts +++ b/packages/adapter-supabase/src/index.ts @@ -9,6 +9,8 @@ import { type UUID, Participant, Room, + RAGKnowledgeItem, + elizaLogger } from "@elizaos/core"; import { DatabaseAdapter } from "@elizaos/core"; import { v4 as uuid } from "uuid"; @@ -680,4 +682,229 @@ export class SupabaseDatabaseAdapter extends DatabaseAdapter { return data as Relationship[]; } + + async getCache(params: { + key: string; + agentId: UUID; + }): Promise { + const { data, error } = await this.supabase + .from('cache') + .select('value') + .eq('key', params.key) + .eq('agentId', params.agentId) + .single(); + + if (error) { + console.error('Error fetching cache:', error); + return undefined; + } + + return data?.value; + } + + async setCache(params: { + key: string; + agentId: UUID; + value: string; + }): Promise { + const { error } = await this.supabase + .from('cache') + .upsert({ + key: params.key, + agentId: params.agentId, + value: params.value, + createdAt: new Date() + }); + + if (error) { + console.error('Error setting cache:', error); + return false; + } + + return true; + } + + async deleteCache(params: { + key: string; + agentId: UUID; + }): Promise { + try { + const { error } = await this.supabase + .from('cache') + .delete() + .eq('key', params.key) + .eq('agentId', params.agentId); + + if (error) { + elizaLogger.error("Error deleting cache", { + error: error.message, + key: params.key, + agentId: params.agentId, + }); + return false; + } + return true; + } catch (error) { + elizaLogger.error( + "Database connection error in deleteCache", + error instanceof Error ? error.message : String(error) + ); + return false; + } + } + + async getKnowledge(params: { + id?: UUID; + agentId: UUID; + limit?: number; + query?: string; + }): Promise { + let query = this.supabase + .from('knowledge') + .select('*') + .or(`agentId.eq.${params.agentId},isShared.eq.true`); + + if (params.id) { + query = query.eq('id', params.id); + } + + if (params.limit) { + query = query.limit(params.limit); + } + + const { data, error } = await query; + + if (error) { + throw new Error(`Error getting knowledge: ${error.message}`); + } + + return data.map(row => ({ + id: row.id, + agentId: row.agentId, + content: typeof row.content === 'string' ? JSON.parse(row.content) : row.content, + embedding: row.embedding ? new Float32Array(row.embedding) : undefined, + createdAt: new Date(row.createdAt).getTime() + })); + } + + async searchKnowledge(params: { + agentId: UUID; + embedding: Float32Array; + match_threshold: number; + match_count: number; + searchText?: string; + }): Promise { + const cacheKey = `embedding_${params.agentId}_${params.searchText}`; + const cachedResult = await this.getCache({ + key: cacheKey, + agentId: params.agentId + }); + + if (cachedResult) { + return JSON.parse(cachedResult); + } + + // Convert Float32Array to array for Postgres vector + const embedding = Array.from(params.embedding); + + const { data, error } = await this.supabase.rpc('search_knowledge', { + query_embedding: embedding, + query_agent_id: params.agentId, + match_threshold: params.match_threshold, + match_count: params.match_count, + search_text: params.searchText || '' + }); + + if (error) { + throw new Error(`Error searching knowledge: ${error.message}`); + } + + const results = data.map(row => ({ + id: row.id, + agentId: row.agentId, + content: typeof row.content === 'string' ? JSON.parse(row.content) : row.content, + embedding: row.embedding ? new Float32Array(row.embedding) : undefined, + createdAt: new Date(row.createdAt).getTime(), + similarity: row.similarity + })); + + await this.setCache({ + key: cacheKey, + agentId: params.agentId, + value: JSON.stringify(results) + }); + + return results; + } + + async createKnowledge(knowledge: RAGKnowledgeItem): Promise { + try { + const metadata = knowledge.content.metadata || {}; + + const { error } = await this.supabase + .from('knowledge') + .insert({ + id: knowledge.id, + agentId: metadata.isShared ? null : knowledge.agentId, + content: knowledge.content, + embedding: knowledge.embedding ? Array.from(knowledge.embedding) : null, + createdAt: knowledge.createdAt || new Date(), + isMain: metadata.isMain || false, + originalId: metadata.originalId || null, + chunkIndex: metadata.chunkIndex || null, + isShared: metadata.isShared || false + }); + + if (error) { + if (metadata.isShared && error.code === '23505') { // Unique violation + elizaLogger.info(`Shared knowledge ${knowledge.id} already exists, skipping`); + return; + } + throw error; + } + } catch (error: any) { + elizaLogger.error(`Error creating knowledge ${knowledge.id}:`, { + error, + embeddingLength: knowledge.embedding?.length, + content: knowledge.content + }); + throw error; + } + } + + async removeKnowledge(id: UUID): Promise { + const { error } = await this.supabase + .from('knowledge') + .delete() + .eq('id', id); + + if (error) { + throw new Error(`Error removing knowledge: ${error.message}`); + } + } + + async clearKnowledge(agentId: UUID, shared?: boolean): Promise { + if (shared) { + const { error } = await this.supabase + .from('knowledge') + .delete() + .filter('agentId', 'eq', agentId) + .filter('isShared', 'eq', true); + + if (error) { + elizaLogger.error(`Error clearing shared knowledge for agent ${agentId}:`, error); + throw error; + } + } else { + const { error } = await this.supabase + .from('knowledge') + .delete() + .eq('agentId', agentId); + + if (error) { + elizaLogger.error(`Error clearing knowledge for agent ${agentId}:`, error); + throw error; + } + } + } } diff --git a/packages/client-telegram/README.md b/packages/client-telegram/README.md new file mode 100644 index 00000000000..e43df5a850b --- /dev/null +++ b/packages/client-telegram/README.md @@ -0,0 +1,19 @@ +# Telegram Client Plugin for ElizaOS + +This plugin integrates a Telegram client with ElizaOS, allowing characters in ElizaOS to interact via Telegram. It provides an easy setup for starting the Telegram client using the provided bot token and includes basic lifecycle management. + +## Features + +- **Seamless Telegram Integration**: Connects ElizaOS characters to Telegram through the bot API. +- **Configuration Validation**: Ensures required settings are properly configured before starting. +- **Startup Logging**: Logs successful initialization of the Telegram client for better debugging. +- **Future-proof Design**: Provides a basic structure for stopping the client (currently unsupported). + +## Configuration + +Before starting the plugin, ensure the following environment variables or settings are configured: + +TELEGRAM_BOT_TOKEN: The bot token obtained from the Telegram BotFather. + +## License + diff --git a/packages/client-telegram/src/messageManager.ts b/packages/client-telegram/src/messageManager.ts index 7ec20b08846..73240efa013 100644 --- a/packages/client-telegram/src/messageManager.ts +++ b/packages/client-telegram/src/messageManager.ts @@ -52,7 +52,7 @@ Result: [RESPOND] {{user1}}: stfu bot Result: [STOP] -{{user1}}: Hey {{agent}}, can you help me with something +{{user1}}: Hey {{agentName}}, can you help me with something Result: [RESPOND] {{user1}}: {{agentName}} stfu plz @@ -63,7 +63,7 @@ Result: [STOP] {{user1}}: no. i need help from someone else Result: [IGNORE] -{{user1}}: Hey {{agent}}, can I ask you a question +{{user1}}: Hey {{agentName}}, can I ask you a question {{agentName}}: Sure, what is it {{user1}}: can you ask claude to create a basic react module that demonstrates a counter Result: [RESPOND] @@ -103,28 +103,22 @@ The goal is to decide whether {{agentName}} should respond to the last message. {{recentMessages}} -Thread of Tweets You Are Replying To: - -{{formattedConversation}} - # INSTRUCTIONS: Choose the option that best describes {{agentName}}'s response to the last message. Ignore messages if they are addressed to someone else. ` + shouldRespondFooter; const telegramMessageHandlerTemplate = // {{goals}} - `# Action Examples + ` {{actionExamples}} (Action examples are for reference only. Do not use the information from them in your response.) # Knowledge {{knowledge}} -# Task: Generate dialog and actions for the character {{agentName}}. -About {{agentName}}: +# About {{agentName}}: {{bio}} {{lore}} -Examples of {{agentName}}'s dialog and actions: {{characterMessageExamples}} {{providers}} @@ -140,11 +134,7 @@ Note that {{agentName}} is capable of reading/seeing/hearing various forms of me {{recentMessages}} -# Task: Generate a post/reply in the voice, style and perspective of {{agentName}} (@{{twitterUserName}}) while using the thread of tweets as additional context: -Current Post: -{{currentPost}} -Thread of Tweets You Are Replying To: - +# Task: Generate a reply in the voice, style and perspective of {{agentName}} while using the thread above as additional context. You are replying on Telegram. {{formattedConversation}} ` + messageCompletionFooter; diff --git a/packages/client-telegram/src/telegramClient.ts b/packages/client-telegram/src/telegramClient.ts index 059b5ec633e..bbebde691f3 100644 --- a/packages/client-telegram/src/telegramClient.ts +++ b/packages/client-telegram/src/telegramClient.ts @@ -191,7 +191,8 @@ export class TelegramClient { public async stop(): Promise { elizaLogger.log("Stopping Telegram bot..."); - await this.bot.stop(); + //await + this.bot.stop(); elizaLogger.log("Telegram bot stopped"); } } diff --git a/packages/client-twitter/package.json b/packages/client-twitter/package.json index cc66c678a28..88e51d6d09a 100644 --- a/packages/client-twitter/package.json +++ b/packages/client-twitter/package.json @@ -22,7 +22,8 @@ "@elizaos/core": "workspace:*", "agent-twitter-client": "0.0.18", "glob": "11.0.0", - "zod": "3.23.8" + "zod": "3.23.8", + "discord.js": "14.16.3" }, "devDependencies": { "tsup": "8.3.5", diff --git a/packages/client-twitter/src/interactions.ts b/packages/client-twitter/src/interactions.ts index 98b1c8726f9..ebc9ca9e64a 100644 --- a/packages/client-twitter/src/interactions.ts +++ b/packages/client-twitter/src/interactions.ts @@ -90,9 +90,11 @@ Thread of Tweets You Are Replying To: export class TwitterInteractionClient { client: ClientBase; runtime: IAgentRuntime; + private isDryRun: boolean; constructor(client: ClientBase, runtime: IAgentRuntime) { this.client = client; this.runtime = runtime; + this.isDryRun = this.client.twitterConfig.TWITTER_DRY_RUN; } async start() { @@ -430,54 +432,62 @@ export class TwitterInteractionClient { response.text = removeQuotes(response.text); if (response.text) { - try { - const callback: HandlerCallback = async (response: Content) => { - const memories = await sendTweet( - this.client, - response, - message.roomId, - this.client.twitterConfig.TWITTER_USERNAME, - tweet.id - ); - return memories; - }; + if (this.isDryRun) { + elizaLogger.info( + `Dry run: Selected Post: ${tweet.id} - ${tweet.username}: ${tweet.text}\nAgent's Output:\n${response.text}` + ); + } else { + try { + const callback: HandlerCallback = async ( + response: Content + ) => { + const memories = await sendTweet( + this.client, + response, + message.roomId, + this.client.twitterConfig.TWITTER_USERNAME, + tweet.id + ); + return memories; + }; - const responseMessages = await callback(response); + const responseMessages = await callback(response); - state = (await this.runtime.updateRecentMessageState( - state - )) as State; + state = (await this.runtime.updateRecentMessageState( + state + )) as State; - for (const responseMessage of responseMessages) { - if ( - responseMessage === - responseMessages[responseMessages.length - 1] - ) { - responseMessage.content.action = response.action; - } else { - responseMessage.content.action = "CONTINUE"; + for (const responseMessage of responseMessages) { + if ( + responseMessage === + responseMessages[responseMessages.length - 1] + ) { + responseMessage.content.action = response.action; + } else { + responseMessage.content.action = "CONTINUE"; + } + await this.runtime.messageManager.createMemory( + responseMessage + ); } - await this.runtime.messageManager.createMemory( - responseMessage - ); - } - await this.runtime.processActions( - message, - responseMessages, - state, - callback - ); + await this.runtime.processActions( + message, + responseMessages, + state, + callback + ); - const responseInfo = `Context:\n\n${context}\n\nSelected Post: ${tweet.id} - ${tweet.username}: ${tweet.text}\nAgent's Output:\n${response.text}`; + const responseInfo = `Context:\n\n${context}\n\nSelected Post: ${tweet.id} - ${tweet.username}: ${tweet.text}\nAgent's Output:\n${response.text}`; - await this.runtime.cacheManager.set( - `twitter/tweet_generation_${tweet.id}.txt`, - responseInfo - ); - await wait(); - } catch (error) { - elizaLogger.error(`Error sending response tweet: ${error}`); + await this.runtime.cacheManager.set( + `twitter/tweet_generation_${tweet.id}.txt`, + responseInfo + ); + await wait(); + } catch (error) { + elizaLogger.error(`Error sending response tweet: ${error}`); + } } } } diff --git a/packages/client-twitter/src/post.ts b/packages/client-twitter/src/post.ts index 02ecdda01fa..e0aff4b3a61 100644 --- a/packages/client-twitter/src/post.ts +++ b/packages/client-twitter/src/post.ts @@ -7,7 +7,7 @@ import { ModelClass, stringToUuid, TemplateType, - UUID + UUID, } from "@elizaos/core"; import { elizaLogger } from "@elizaos/core"; import { ClientBase } from "./base.ts"; @@ -17,6 +17,13 @@ import { IImageDescriptionService, ServiceType } from "@elizaos/core"; import { buildConversationThread } from "./utils.ts"; import { twitterMessageHandlerTemplate } from "./interactions.ts"; import { DEFAULT_MAX_TWEET_LENGTH } from "./environment.ts"; +import { + Client, + Events, + GatewayIntentBits, + TextChannel, + Partials, +} from "discord.js"; import { State } from "@elizaos/core"; import { ActionResponse } from "@elizaos/core"; @@ -104,6 +111,17 @@ function truncateToCompleteSentence( return hardTruncated + "..."; } +interface PendingTweet { + cleanedContent: string; + roomId: UUID; + newTweetContent: string; + discordMessageId: string; + channelId: string; + timestamp: number; +} + +type PendingTweetApprovalStatus = "PENDING" | "APPROVED" | "REJECTED"; + export class TwitterPostClient { client: ClientBase; runtime: IAgentRuntime; @@ -112,6 +130,10 @@ export class TwitterPostClient { private lastProcessTime: number = 0; private stopProcessingActions: boolean = false; private isDryRun: boolean; + private discordClientForApproval: Client; + private approvalRequired: boolean = false; + private discordApprovalChannelId: string; + private approvalCheckInterval: number; constructor(client: ClientBase, runtime: IAgentRuntime) { this.client = client; @@ -151,6 +173,74 @@ export class TwitterPostClient { "Twitter client initialized in dry run mode - no actual tweets should be posted" ); } + + // Initialize Discord webhook + const approvalRequired: boolean = + this.runtime + .getSetting("TWITTER_APPROVAL_ENABLED") + ?.toLocaleLowerCase() === "true"; + if (approvalRequired) { + const discordToken = this.runtime.getSetting( + "TWITTER_APPROVAL_DISCORD_BOT_TOKEN" + ); + const approvalChannelId = this.runtime.getSetting( + "TWITTER_APPROVAL_DISCORD_CHANNEL_ID" + ); + + const APPROVAL_CHECK_INTERVAL = + parseInt( + this.runtime.getSetting("TWITTER_APPROVAL_CHECK_INTERVAL") + ) || 5 * 60 * 1000; // 5 minutes + + this.approvalCheckInterval = APPROVAL_CHECK_INTERVAL; + + if (!discordToken || !approvalChannelId) { + throw new Error( + "TWITTER_APPROVAL_DISCORD_BOT_TOKEN and TWITTER_APPROVAL_DISCORD_CHANNEL_ID are required for approval workflow" + ); + } + + this.approvalRequired = true; + this.discordApprovalChannelId = approvalChannelId; + + // Set up Discord client event handlers + this.setupDiscordClient(); + } + } + + private setupDiscordClient() { + this.discordClientForApproval = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + GatewayIntentBits.GuildMessageReactions, + ], + partials: [Partials.Channel, Partials.Message, Partials.Reaction], + }); + this.discordClientForApproval.once( + Events.ClientReady, + (readyClient) => { + elizaLogger.log( + `Discord bot is ready as ${readyClient.user.tag}!` + ); + + // Generate invite link with required permissions + const invite = `https://discord.com/api/oauth2/authorize?client_id=${readyClient.user.id}&permissions=274877991936&scope=bot`; + // 274877991936 includes permissions for: + // - Send Messages + // - Read Messages/View Channels + // - Read Message History + + elizaLogger.log( + `Use this link to properly invite the Twitter Post Approval Discord bot: ${invite}` + ); + } + ); + // Login to Discord + this.discordClientForApproval.login( + this.runtime.getSetting("TWITTER_APPROVAL_DISCORD_BOT_TOKEN") + ); } async start() { @@ -159,6 +249,9 @@ export class TwitterPostClient { } const generateNewTweetLoop = async () => { + // Check for pending tweets first + if (this.approvalRequired) await this.handlePendingTweet(); + const lastPost = await this.runtime.cacheManager.get<{ timestamp: number; }>("twitter/" + this.twitterUsername + "/lastPost"); @@ -215,34 +308,26 @@ export class TwitterPostClient { } // Only start tweet generation loop if not in dry run mode - if (!this.isDryRun) { - generateNewTweetLoop(); - elizaLogger.log("Tweet generation loop started"); - } else { - elizaLogger.log("Tweet generation loop disabled (dry run mode)"); - } + generateNewTweetLoop(); + elizaLogger.log("Tweet generation loop started"); - if ( - this.client.twitterConfig.ENABLE_ACTION_PROCESSING && - !this.isDryRun - ) { + if (this.client.twitterConfig.ENABLE_ACTION_PROCESSING) { processActionsLoop().catch((error) => { elizaLogger.error( "Fatal error in process actions loop:", error ); }); - } else { - if (this.isDryRun) { - elizaLogger.log( - "Action processing loop disabled (dry run mode)" - ); - } else { - elizaLogger.log( - "Action processing loop disabled by configuration" - ); - } } + + // Start the pending tweet check loop if enabled + if (this.approvalRequired) this.runPendingTweetCheckLoop(); + } + + private runPendingTweetCheckLoop() { + setInterval(async () => { + await this.handlePendingTweet(); + }, this.approvalCheckInterval); } createTweetObject( @@ -410,7 +495,7 @@ export class TwitterPostClient { /** * Generates and posts a new tweet. If isDryRun is true, only logs what would have been posted. */ - private async generateNewTweet() { + async generateNewTweet() { elizaLogger.log("Generating new tweet"); try { @@ -514,15 +599,28 @@ export class TwitterPostClient { } try { - elizaLogger.log(`Posting new tweet:\n ${cleanedContent}`); - this.postTweet( - this.runtime, - this.client, - cleanedContent, - roomId, - newTweetContent, - this.twitterUsername - ); + if (this.approvalRequired) { + // Send for approval instead of posting directly + elizaLogger.log( + `Sending Tweet For Approval:\n ${cleanedContent}` + ); + await this.sendForApproval( + cleanedContent, + roomId, + newTweetContent + ); + elizaLogger.log("Tweet sent for approval"); + } else { + elizaLogger.log(`Posting new tweet:\n ${cleanedContent}`); + this.postTweet( + this.runtime, + this.client, + cleanedContent, + roomId, + newTweetContent, + this.twitterUsername + ); + } } catch (error) { elizaLogger.error("Error sending tweet:", error); } @@ -618,11 +716,6 @@ export class TwitterPostClient { elizaLogger.log("Processing tweet actions"); - if (this.isDryRun) { - elizaLogger.log("Dry run mode: simulating tweet actions"); - return []; - } - await this.runtime.ensureUserExists( this.runtime.agentId, this.twitterUsername, @@ -630,14 +723,14 @@ export class TwitterPostClient { "twitter" ); - const homeTimeline = await this.client.fetchTimelineForActions( + const timelines = await this.client.fetchTimelineForActions( MAX_TIMELINES_TO_FETCH ); const maxActionsProcessing = this.client.twitterConfig.MAX_ACTIONS_PROCESSING; const processedTimelines = []; - for (const tweet of homeTimeline) { + for (const tweet of timelines) { try { // Skip if we've already processed this tweet const memory = @@ -770,56 +863,47 @@ export class TwitterPostClient { const executedActions: string[] = []; // Execute actions if (actionResponse.like) { - try { - if (this.isDryRun) { - elizaLogger.info( - `Dry run: would have liked tweet ${tweet.id}` - ); - executedActions.push("like (dry run)"); - } else { + if (this.isDryRun) { + elizaLogger.info( + `Dry run: would have liked tweet ${tweet.id}` + ); + executedActions.push("like (dry run)"); + } else { + try { await this.client.twitterClient.likeTweet(tweet.id); executedActions.push("like"); elizaLogger.log(`Liked tweet ${tweet.id}`); + } catch (error) { + elizaLogger.error( + `Error liking tweet ${tweet.id}:`, + error + ); } - } catch (error) { - elizaLogger.error( - `Error liking tweet ${tweet.id}:`, - error - ); } } if (actionResponse.retweet) { - try { - if (this.isDryRun) { - elizaLogger.info( - `Dry run: would have retweeted tweet ${tweet.id}` - ); - executedActions.push("retweet (dry run)"); - } else { + if (this.isDryRun) { + elizaLogger.info( + `Dry run: would have retweeted tweet ${tweet.id}` + ); + executedActions.push("retweet (dry run)"); + } else { + try { await this.client.twitterClient.retweet(tweet.id); executedActions.push("retweet"); elizaLogger.log(`Retweeted tweet ${tweet.id}`); + } catch (error) { + elizaLogger.error( + `Error retweeting tweet ${tweet.id}:`, + error + ); } - } catch (error) { - elizaLogger.error( - `Error retweeting tweet ${tweet.id}:`, - error - ); } } if (actionResponse.quote) { try { - // Check for dry run mode - if (this.isDryRun) { - elizaLogger.info( - `Dry run: would have posted quote tweet for ${tweet.id}` - ); - executedActions.push("quote (dry run)"); - continue; - } - // Build conversation thread for context const thread = await buildConversationThread( tweet, @@ -915,32 +999,43 @@ export class TwitterPostClient { "Generated quote tweet content:", quoteContent ); - - // Send the tweet through request queue - const result = await this.client.requestQueue.add( - async () => - await this.client.twitterClient.sendQuoteTweet( - quoteContent, - tweet.id - ) - ); - - const body = await result.json(); - - if (body?.data?.create_tweet?.tweet_results?.result) { - elizaLogger.log("Successfully posted quote tweet"); - executedActions.push("quote"); - - // Cache generation context for debugging - await this.runtime.cacheManager.set( - `twitter/quote_generation_${tweet.id}.txt`, - `Context:\n${enrichedState}\n\nGenerated Quote:\n${quoteContent}` + // Check for dry run mode + if (this.isDryRun) { + elizaLogger.info( + `Dry run: A quote tweet for tweet ID ${tweet.id} would have been posted with the following content: "${quoteContent}".` ); + executedActions.push("quote (dry run)"); } else { - elizaLogger.error( - "Quote tweet creation failed:", - body + // Send the tweet through request queue + const result = await this.client.requestQueue.add( + async () => + await this.client.twitterClient.sendQuoteTweet( + quoteContent, + tweet.id + ) ); + + const body = await result.json(); + + if ( + body?.data?.create_tweet?.tweet_results?.result + ) { + elizaLogger.log( + "Successfully posted quote tweet" + ); + executedActions.push("quote"); + + // Cache generation context for debugging + await this.runtime.cacheManager.set( + `twitter/quote_generation_${tweet.id}.txt`, + `Context:\n${enrichedState}\n\nGenerated Quote:\n${quoteContent}` + ); + } else { + elizaLogger.error( + "Quote tweet creation failed:", + body + ); + } } } catch (error) { elizaLogger.error( @@ -978,21 +1073,23 @@ export class TwitterPostClient { roomId ); - // Then create the memory - await this.runtime.messageManager.createMemory({ - id: stringToUuid(tweet.id + "-" + this.runtime.agentId), - userId: stringToUuid(tweet.userId), - content: { - text: tweet.text, - url: tweet.permanentUrl, - source: "twitter", - action: executedActions.join(","), - }, - agentId: this.runtime.agentId, - roomId, - embedding: getEmbeddingZeroVector(), - createdAt: tweet.timestamp * 1000, - }); + if (!this.isDryRun) { + // Then create the memory + await this.runtime.messageManager.createMemory({ + id: stringToUuid(tweet.id + "-" + this.runtime.agentId), + userId: stringToUuid(tweet.userId), + content: { + text: tweet.text, + url: tweet.permanentUrl, + source: "twitter", + action: executedActions.join(","), + }, + agentId: this.runtime.agentId, + roomId, + embedding: getEmbeddingZeroVector(), + createdAt: tweet.timestamp * 1000, + }); + } results.push({ tweetId: tweet.id, @@ -1139,4 +1236,255 @@ export class TwitterPostClient { async stop() { this.stopProcessingActions = true; } + + private async sendForApproval( + cleanedContent: string, + roomId: UUID, + newTweetContent: string + ): Promise { + try { + const embed = { + title: "New Tweet Pending Approval", + description: cleanedContent, + fields: [ + { + name: "Character", + value: this.client.profile.username, + inline: true, + }, + { + name: "Length", + value: cleanedContent.length.toString(), + inline: true, + }, + ], + footer: { + text: "Reply with '👍' to post or '❌' to discard, This will automatically expire and remove after 24 hours if no response received", + }, + timestamp: new Date().toISOString(), + }; + + const channel = await this.discordClientForApproval.channels.fetch( + this.discordApprovalChannelId + ); + + if (!channel || !(channel instanceof TextChannel)) { + throw new Error("Invalid approval channel"); + } + + const message = await channel.send({ embeds: [embed] }); + + // Store the pending tweet + const pendingTweetsKey = `twitter/${this.client.profile.username}/pendingTweet`; + const currentPendingTweets = + (await this.runtime.cacheManager.get( + pendingTweetsKey + )) || []; + // Add new pending tweet + currentPendingTweets.push({ + cleanedContent, + roomId, + newTweetContent, + discordMessageId: message.id, + channelId: this.discordApprovalChannelId, + timestamp: Date.now(), + }); + + // Store updated array + await this.runtime.cacheManager.set( + pendingTweetsKey, + currentPendingTweets + ); + + return message.id; + } catch (error) { + elizaLogger.error( + "Error Sending Twitter Post Approval Request:", + error + ); + return null; + } + } + + private async checkApprovalStatus( + discordMessageId: string + ): Promise { + try { + // Fetch message and its replies from Discord + const channel = await this.discordClientForApproval.channels.fetch( + this.discordApprovalChannelId + ); + + elizaLogger.log(`channel ${JSON.stringify(channel)}`); + + if (!(channel instanceof TextChannel)) { + elizaLogger.error("Invalid approval channel"); + return "PENDING"; + } + + // Fetch the original message and its replies + const message = await channel.messages.fetch(discordMessageId); + + // Look for thumbs up reaction ('👍') + const thumbsUpReaction = message.reactions.cache.find( + (reaction) => reaction.emoji.name === "👍" + ); + + // Look for reject reaction ('❌') + const rejectReaction = message.reactions.cache.find( + (reaction) => reaction.emoji.name === "❌" + ); + + // Check if the reaction exists and has reactions + if (rejectReaction) { + const count = rejectReaction.count; + if (count > 0) { + return "REJECTED"; + } + } + + // Check if the reaction exists and has reactions + if (thumbsUpReaction) { + // You might want to check for specific users who can approve + // For now, we'll return true if anyone used thumbs up + const count = thumbsUpReaction.count; + if (count > 0) { + return "APPROVED"; + } + } + + return "PENDING"; + } catch (error) { + elizaLogger.error("Error checking approval status:", error); + return "PENDING"; + } + } + + private async cleanupPendingTweet(discordMessageId: string) { + const pendingTweetsKey = `twitter/${this.client.profile.username}/pendingTweet`; + const currentPendingTweets = + (await this.runtime.cacheManager.get( + pendingTweetsKey + )) || []; + + // Remove the specific tweet + const updatedPendingTweets = currentPendingTweets.filter( + (tweet) => tweet.discordMessageId !== discordMessageId + ); + + if (updatedPendingTweets.length === 0) { + await this.runtime.cacheManager.delete(pendingTweetsKey); + } else { + await this.runtime.cacheManager.set( + pendingTweetsKey, + updatedPendingTweets + ); + } + } + + private async handlePendingTweet() { + elizaLogger.log("Checking Pending Tweets..."); + const pendingTweetsKey = `twitter/${this.client.profile.username}/pendingTweet`; + const pendingTweets = + (await this.runtime.cacheManager.get( + pendingTweetsKey + )) || []; + + for (const pendingTweet of pendingTweets) { + // Check if tweet is older than 24 hours + const isExpired = + Date.now() - pendingTweet.timestamp > 24 * 60 * 60 * 1000; + + if (isExpired) { + elizaLogger.log("Pending tweet expired, cleaning up"); + + // Notify on Discord about expiration + try { + const channel = + await this.discordClientForApproval.channels.fetch( + pendingTweet.channelId + ); + if (channel instanceof TextChannel) { + const originalMessage = await channel.messages.fetch( + pendingTweet.discordMessageId + ); + await originalMessage.reply( + "This tweet approval request has expired (24h timeout)." + ); + } + } catch (error) { + elizaLogger.error( + "Error sending expiration notification:", + error + ); + } + + await this.cleanupPendingTweet(pendingTweet.discordMessageId); + return; + } + + // Check approval status + elizaLogger.log("Checking approval status..."); + const approvalStatus: PendingTweetApprovalStatus = + await this.checkApprovalStatus(pendingTweet.discordMessageId); + + if (approvalStatus === "APPROVED") { + elizaLogger.log("Tweet Approved, Posting"); + await this.postTweet( + this.runtime, + this.client, + pendingTweet.cleanedContent, + pendingTweet.roomId, + pendingTweet.newTweetContent, + this.twitterUsername + ); + + // Notify on Discord about posting + try { + const channel = + await this.discordClientForApproval.channels.fetch( + pendingTweet.channelId + ); + if (channel instanceof TextChannel) { + const originalMessage = await channel.messages.fetch( + pendingTweet.discordMessageId + ); + await originalMessage.reply( + "Tweet has been posted successfully! ✅" + ); + } + } catch (error) { + elizaLogger.error( + "Error sending post notification:", + error + ); + } + + await this.cleanupPendingTweet(pendingTweet.discordMessageId); + } else if (approvalStatus === "REJECTED") { + elizaLogger.log("Tweet Rejected, Cleaning Up"); + await this.cleanupPendingTweet(pendingTweet.discordMessageId); + // Notify about Rejection of Tweet + try { + const channel = + await this.discordClientForApproval.channels.fetch( + pendingTweet.channelId + ); + if (channel instanceof TextChannel) { + const originalMessage = await channel.messages.fetch( + pendingTweet.discordMessageId + ); + await originalMessage.reply( + "Tweet has been rejected! ❌" + ); + } + } catch (error) { + elizaLogger.error( + "Error sending rejection notification:", + error + ); + } + } + } + } } diff --git a/packages/core/src/tests/actions.test.ts b/packages/core/__tests__/actions.test.ts similarity index 99% rename from packages/core/src/tests/actions.test.ts rename to packages/core/__tests__/actions.test.ts index 1091fe195f5..311f996e7f1 100644 --- a/packages/core/src/tests/actions.test.ts +++ b/packages/core/__tests__/actions.test.ts @@ -3,8 +3,8 @@ import { composeActionExamples, formatActionNames, formatActions, -} from "../actions"; -import { Action } from "../types"; +} from "../src/actions"; +import { Action } from "../src/types"; describe("Actions", () => { const mockActions: Action[] = [ diff --git a/packages/core/src/tests/cache.test.ts b/packages/core/__tests__/cache.test.ts similarity index 94% rename from packages/core/src/tests/cache.test.ts rename to packages/core/__tests__/cache.test.ts index 339a032e7bb..6ddced704b9 100644 --- a/packages/core/src/tests/cache.test.ts +++ b/packages/core/__tests__/cache.test.ts @@ -1,4 +1,4 @@ -import { CacheManager, MemoryCacheAdapter } from "../cache.ts"; +import { CacheManager, MemoryCacheAdapter } from "../src/cache.ts"; import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; describe("CacheManager", () => { diff --git a/packages/core/src/tests/context.test.ts b/packages/core/__tests__/context.test.ts similarity index 98% rename from packages/core/src/tests/context.test.ts rename to packages/core/__tests__/context.test.ts index 3c3bc978f9c..c598c861bba 100644 --- a/packages/core/src/tests/context.test.ts +++ b/packages/core/__tests__/context.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; -import { composeContext } from "../context"; +import { composeContext } from "../src/context.ts"; import handlebars from "handlebars"; -import { State } from "../types.ts"; +import { State } from "../src/types.ts"; describe("composeContext", () => { const baseState: State = { diff --git a/packages/core/src/tests/database.test.ts b/packages/core/__tests__/database.test.ts similarity index 98% rename from packages/core/src/tests/database.test.ts rename to packages/core/__tests__/database.test.ts index cab1b659732..7420d996018 100644 --- a/packages/core/src/tests/database.test.ts +++ b/packages/core/__tests__/database.test.ts @@ -1,5 +1,5 @@ /* eslint-disable no-dupe-class-members */ -import { DatabaseAdapter } from "../database.ts"; // Adjust the import based on your project structure +import { DatabaseAdapter } from "../src/database.ts"; import { Memory, Actor, @@ -9,7 +9,7 @@ import { Participant, Relationship, UUID, -} from "../types"; // Adjust based on your types location +} from "../src/types.ts"; class MockDatabaseAdapter extends DatabaseAdapter { getMemoryById(_id: UUID): Promise { @@ -104,7 +104,7 @@ class MockDatabaseAdapter extends DatabaseAdapter { getParticipantsForAccount(userId: UUID): Promise; getParticipantsForAccount( _userId: unknown - ): Promise { + ): Promise { throw new Error("Method not implemented."); } getParticipantsForRoom(_roomId: UUID): Promise { diff --git a/packages/core/src/tests/defaultCharacters.test.ts b/packages/core/__tests__/defaultCharacters.test.ts similarity index 93% rename from packages/core/src/tests/defaultCharacters.test.ts rename to packages/core/__tests__/defaultCharacters.test.ts index 095b0ab65a7..9cb42b07894 100644 --- a/packages/core/src/tests/defaultCharacters.test.ts +++ b/packages/core/__tests__/defaultCharacters.test.ts @@ -1,5 +1,5 @@ -import { defaultCharacter } from "../defaultCharacter"; -import { ModelProviderName } from "../types"; +import { defaultCharacter } from "../src/defaultCharacter"; +import { ModelProviderName } from "../src/types"; describe("defaultCharacter", () => { it("should have the correct name", () => { diff --git a/packages/core/src/tests/embedding.test.ts b/packages/core/__tests__/embedding.test.ts similarity index 98% rename from packages/core/src/tests/embedding.test.ts rename to packages/core/__tests__/embedding.test.ts index 3d83135dd28..465c6ca3a61 100644 --- a/packages/core/src/tests/embedding.test.ts +++ b/packages/core/__tests__/embedding.test.ts @@ -4,9 +4,9 @@ import { getEmbeddingConfig, getEmbeddingType, getEmbeddingZeroVector, -} from "../embedding.ts"; +} from "../src/embedding.ts"; import { IAgentRuntime, ModelProviderName } from "../types.ts"; -import settings from "../settings.ts"; +import settings from "../src/settings.ts"; // Mock environment-related settings vi.mock("../settings", () => ({ diff --git a/packages/core/src/tests/env.test.ts b/packages/core/__tests__/env.test.ts similarity index 100% rename from packages/core/src/tests/env.test.ts rename to packages/core/__tests__/env.test.ts diff --git a/packages/core/src/tests/environment.test.ts b/packages/core/__tests__/environment.test.ts similarity index 97% rename from packages/core/src/tests/environment.test.ts rename to packages/core/__tests__/environment.test.ts index fe690f4e0e1..7f26c0b672e 100644 --- a/packages/core/src/tests/environment.test.ts +++ b/packages/core/__tests__/environment.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, beforeEach, afterEach } from "vitest"; -import { validateEnv, validateCharacterConfig } from "../environment"; -import { Clients, ModelProviderName } from "../types"; +import { validateEnv, validateCharacterConfig } from "../src/environment"; +import { Clients, ModelProviderName } from "../src/types"; describe("Environment Configuration", () => { const originalEnv = process.env; diff --git a/packages/core/src/tests/evaluators.test.ts b/packages/core/__tests__/evaluators.test.ts similarity index 98% rename from packages/core/src/tests/evaluators.test.ts rename to packages/core/__tests__/evaluators.test.ts index 090f3f482aa..c459cad63b4 100644 --- a/packages/core/src/tests/evaluators.test.ts +++ b/packages/core/__tests__/evaluators.test.ts @@ -3,14 +3,14 @@ import { formatEvaluators, formatEvaluatorExamples, formatEvaluatorExampleDescriptions, -} from "../evaluators"; +} from "../src/evaluators"; import { Evaluator, HandlerCallback, IAgentRuntime, Memory, State, -} from "../types"; +} from "../src/types"; // Mock data for evaluators const mockEvaluators: Evaluator[] = [ diff --git a/packages/core/src/tests/goals.test.ts b/packages/core/__tests__/goals.test.ts similarity index 97% rename from packages/core/src/tests/goals.test.ts rename to packages/core/__tests__/goals.test.ts index 180b0aa3377..8eda026c40b 100644 --- a/packages/core/src/tests/goals.test.ts +++ b/packages/core/__tests__/goals.test.ts @@ -3,7 +3,7 @@ import { formatGoalsAsString, updateGoal, createGoal, -} from "../goals.ts"; +} from "../src/goals.ts"; import { Goal, GoalStatus, @@ -13,8 +13,8 @@ import { UUID, Service, ServiceType, -} from "../types"; -import { CacheManager, MemoryCacheAdapter } from "../cache.ts"; +} from "../src/types.ts"; +import { CacheManager, MemoryCacheAdapter } from "../src/cache.ts"; import { describe, expect, vi, beforeEach } from "vitest"; // Mock the database adapter @@ -423,7 +423,9 @@ describe("updateGoal", () => { goal: updatedGoal, }); - expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith(updatedGoal); + expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith( + updatedGoal + ); }); it("should handle failed goal update", async () => { @@ -456,7 +458,9 @@ describe("updateGoal", () => { goal: updatedGoal, }); - expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith(updatedGoal); + expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith( + updatedGoal + ); }); it("should handle in-progress goal update", async () => { @@ -489,7 +493,9 @@ describe("updateGoal", () => { goal: updatedGoal, }); - expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith(updatedGoal); + expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith( + updatedGoal + ); }); it("should handle goal priority updates", async () => { @@ -522,7 +528,9 @@ describe("updateGoal", () => { goal: updatedGoal, }); - expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith(updatedGoal); + expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith( + updatedGoal + ); }); }); @@ -557,7 +565,7 @@ describe("createGoal", () => { roomId: "room-id" as UUID, userId: "user-id" as UUID, status: GoalStatus.IN_PROGRESS, - objectives: [] + objectives: [], }; const mockRuntime = { @@ -576,7 +584,7 @@ describe("createGoal", () => { roomId: "room-id", userId: "user-id", status: GoalStatus.IN_PROGRESS, - objectives: [] + objectives: [], }) ); }); @@ -601,6 +609,8 @@ describe("createGoal", () => { goal: newGoal, }); - expect(mockRuntime.databaseAdapter.createGoal).toHaveBeenCalledWith(newGoal); + expect(mockRuntime.databaseAdapter.createGoal).toHaveBeenCalledWith( + newGoal + ); }); }); diff --git a/packages/core/src/tests/knowledge.test.ts b/packages/core/__tests__/knowledge.test.ts similarity index 61% rename from packages/core/src/tests/knowledge.test.ts rename to packages/core/__tests__/knowledge.test.ts index c637ff4729f..daf2882ab61 100644 --- a/packages/core/src/tests/knowledge.test.ts +++ b/packages/core/__tests__/knowledge.test.ts @@ -1,8 +1,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; -import knowledge from "../knowledge"; -import { AgentRuntime } from "../runtime"; -import { KnowledgeItem, Memory } from "../types"; -import { getEmbeddingZeroVector } from "../embedding"; +import knowledge from "../src/knowledge"; +import { AgentRuntime } from "../src/runtime"; +import { KnowledgeItem, Memory } from "../src/types"; // Mock dependencies vi.mock("../embedding", () => ({ @@ -73,6 +72,12 @@ describe("Knowledge Module", () => { beforeEach(() => { mockRuntime = { agentId: "test-agent", + character: { + modelProvider: "openai", + }, + messageManager: { + getCachedEmbeddings: vi.fn().mockResolvedValue([]), + }, knowledgeManager: { searchMemoriesByEmbedding: vi.fn().mockResolvedValue([ { @@ -102,21 +107,6 @@ describe("Knowledge Module", () => { expect(result).toEqual([]); }); - it("should retrieve knowledge items based on message content", async () => { - const message: Memory = { - agentId: "test-agent", - content: { text: "test query" }, - } as unknown as Memory; - - const result = await knowledge.get(mockRuntime, message); - - expect(result).toHaveLength(1); - expect(result[0]).toEqual({ - id: "source1", - content: { text: "test document" }, - }); - }); - it("should handle empty processed text", async () => { const message: Memory = { agentId: "test-agent", @@ -127,54 +117,6 @@ describe("Knowledge Module", () => { expect(result).toEqual([]); }); }); - - describe("set", () => { - it("should store knowledge item and its fragments", async () => { - const item: KnowledgeItem = { - id: "test-id-1234-5678-9101-112131415161", - content: { text: "test content" }, - }; - - await knowledge.set(mockRuntime, item); - - // Check if document was created - expect( - mockRuntime.documentsManager.createMemory - ).toHaveBeenCalledWith( - expect.objectContaining({ - id: item.id, - content: item.content, - embedding: getEmbeddingZeroVector(), - }) - ); - - // Check if fragment was created - expect( - mockRuntime.knowledgeManager.createMemory - ).toHaveBeenCalledWith( - expect.objectContaining({ - content: { - source: item.id, - text: expect.any(String), - }, - embedding: expect.any(Float32Array), - }) - ); - }); - - it("should use default chunk size and bleed", async () => { - const item: KnowledgeItem = { - id: "test-id-1234-5678-9101-112131415161", - content: { text: "test content" }, - }; - - await knowledge.set(mockRuntime, item); - - // Verify default parameters were used - expect( - mockRuntime.knowledgeManager.createMemory - ).toHaveBeenCalledTimes(1); - }); }); }); -}); + diff --git a/packages/core/src/tests/memory.test.ts b/packages/core/__tests__/memory.test.ts similarity index 92% rename from packages/core/src/tests/memory.test.ts rename to packages/core/__tests__/memory.test.ts index d146cebf7f2..fec3f007ab9 100644 --- a/packages/core/src/tests/memory.test.ts +++ b/packages/core/__tests__/memory.test.ts @@ -1,7 +1,7 @@ -import { MemoryManager } from "../memory"; -import { CacheManager, MemoryCacheAdapter } from "../cache"; +import { MemoryManager } from "../src/memory"; +import { CacheManager, MemoryCacheAdapter } from "../src/cache"; import { describe, expect, it, vi, beforeEach } from "vitest"; -import { IAgentRuntime, Memory, UUID } from "../types"; +import { IAgentRuntime, Memory, UUID } from "../src/types"; describe("MemoryManager", () => { let memoryManager: MemoryManager; @@ -58,7 +58,9 @@ describe("MemoryManager", () => { content: { text: "" }, }; - await expect(memoryManager.addEmbeddingToMemory(memory)).rejects.toThrow( + await expect( + memoryManager.addEmbeddingToMemory(memory) + ).rejects.toThrow( "Cannot generate embedding: Memory content is empty" ); }); @@ -71,7 +73,9 @@ describe("MemoryManager", () => { mockDatabaseAdapter.searchMemories = vi.fn().mockResolvedValue([]); - await memoryManager.searchMemoriesByEmbedding(embedding, { roomId }); + await memoryManager.searchMemoriesByEmbedding(embedding, { + roomId, + }); expect(mockDatabaseAdapter.searchMemories).toHaveBeenCalledWith({ embedding, diff --git a/packages/core/src/tests/messages.test.ts b/packages/core/__tests__/messages.test.ts similarity index 99% rename from packages/core/src/tests/messages.test.ts rename to packages/core/__tests__/messages.test.ts index 66ff029ba67..ad12a38e52e 100644 --- a/packages/core/src/tests/messages.test.ts +++ b/packages/core/__tests__/messages.test.ts @@ -3,8 +3,8 @@ import { formatMessages, getActorDetails, formatTimestamp, -} from "../messages.ts"; -import { IAgentRuntime, Actor, Content, Memory, UUID } from "../types.ts"; +} from "../src/messages.ts"; +import { IAgentRuntime, Actor, Content, Memory, UUID } from "../src/types.ts"; import { describe, test, expect, vi, beforeAll } from "vitest"; describe("Messages Library", () => { diff --git a/packages/core/src/tests/models.test.ts b/packages/core/__tests__/models.test.ts similarity index 54% rename from packages/core/src/tests/models.test.ts rename to packages/core/__tests__/models.test.ts index 90ca87dba76..4a883266b89 100644 --- a/packages/core/src/tests/models.test.ts +++ b/packages/core/__tests__/models.test.ts @@ -1,13 +1,13 @@ -import { getModel, getEndpoint, models } from "../models.ts"; -import { ModelProviderName, ModelClass } from "../types.ts"; +import { getModel, getEndpoint, models } from "../src/models.ts"; +import { ModelProviderName, ModelClass } from "../src/types.ts"; import { describe, test, expect, vi } from "vitest"; // Mock settings vi.mock("../settings", () => { return { default: { - SMALL_OPENROUTER_MODEL: "mock-small-model", - LARGE_OPENROUTER_MODEL: "mock-large-model", + SMALL_OPENROUTER_MODEL: "nousresearch/hermes-3-llama-3.1-405b", + LARGE_OPENROUTER_MODEL: "nousresearch/hermes-3-llama-3.1-405b", OPENROUTER_MODEL: "mock-default-model", OPENAI_API_KEY: "mock-openai-key", ANTHROPIC_API_KEY: "mock-anthropic-key", @@ -33,22 +33,23 @@ describe("Model Provider Configuration", () => { test("should have correct model mappings", () => { const openAIModels = models[ModelProviderName.OPENAI].model; - expect(openAIModels[ModelClass.SMALL]).toBe("gpt-4o-mini"); - expect(openAIModels[ModelClass.MEDIUM]).toBe("gpt-4o"); - expect(openAIModels[ModelClass.LARGE]).toBe("gpt-4o"); - expect(openAIModels[ModelClass.EMBEDDING]).toBe( + expect(openAIModels[ModelClass.SMALL].name).toBe("gpt-4o-mini"); + expect(openAIModels[ModelClass.MEDIUM].name).toBe("gpt-4o"); + expect(openAIModels[ModelClass.LARGE].name).toBe("gpt-4o"); + expect(openAIModels[ModelClass.EMBEDDING].name).toBe( "text-embedding-3-small" ); - expect(openAIModels[ModelClass.IMAGE]).toBe("dall-e-3"); + expect(openAIModels[ModelClass.IMAGE].name).toBe("dall-e-3"); }); test("should have correct settings configuration", () => { - const settings = models[ModelProviderName.OPENAI].settings; - expect(settings.maxInputTokens).toBe(128000); - expect(settings.maxOutputTokens).toBe(8192); - expect(settings.temperature).toBe(0.6); - expect(settings.frequency_penalty).toBe(0.0); - expect(settings.presence_penalty).toBe(0.0); + const smallModel = models[ModelProviderName.OPENAI].model[ModelClass.SMALL]; + expect(smallModel.maxInputTokens).toBe(128000); + expect(smallModel.maxOutputTokens).toBe(8192); + expect(smallModel.temperature).toBe(0.6); + expect(smallModel.frequency_penalty).toBe(0.0); + expect(smallModel.presence_penalty).toBe(0.0); + expect(smallModel.stop).toEqual([]); }); }); @@ -61,24 +62,25 @@ describe("Model Provider Configuration", () => { test("should have correct model mappings", () => { const anthropicModels = models[ModelProviderName.ANTHROPIC].model; - expect(anthropicModels[ModelClass.SMALL]).toBe( + expect(anthropicModels[ModelClass.SMALL].name).toBe( "claude-3-haiku-20240307" ); - expect(anthropicModels[ModelClass.MEDIUM]).toBe( + expect(anthropicModels[ModelClass.MEDIUM].name).toBe( "claude-3-5-sonnet-20241022" ); - expect(anthropicModels[ModelClass.LARGE]).toBe( + expect(anthropicModels[ModelClass.LARGE].name).toBe( "claude-3-5-sonnet-20241022" ); }); test("should have correct settings configuration", () => { - const settings = models[ModelProviderName.ANTHROPIC].settings; - expect(settings.maxInputTokens).toBe(200000); - expect(settings.maxOutputTokens).toBe(4096); - expect(settings.temperature).toBe(0.7); - expect(settings.frequency_penalty).toBe(0.4); - expect(settings.presence_penalty).toBe(0.4); + const smallModel = models[ModelProviderName.ANTHROPIC].model[ModelClass.SMALL]; + expect(smallModel.maxInputTokens).toBe(200000); + expect(smallModel.maxOutputTokens).toBe(4096); + expect(smallModel.temperature).toBe(0.7); + expect(smallModel.frequency_penalty).toBe(0.4); + expect(smallModel.presence_penalty).toBe(0.4); + expect(smallModel.stop).toEqual([]); }); }); @@ -91,40 +93,36 @@ describe("Model Provider Configuration", () => { test("should have correct model mappings", () => { const llamaCloudModels = models[ModelProviderName.LLAMACLOUD].model; - expect(llamaCloudModels[ModelClass.SMALL]).toBe( + expect(llamaCloudModels[ModelClass.SMALL].name).toBe( "meta-llama/Llama-3.2-3B-Instruct-Turbo" ); - expect(llamaCloudModels[ModelClass.MEDIUM]).toBe( + expect(llamaCloudModels[ModelClass.MEDIUM].name).toBe( "meta-llama-3.1-8b-instruct" ); - expect(llamaCloudModels[ModelClass.LARGE]).toBe( + expect(llamaCloudModels[ModelClass.LARGE].name).toBe( "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo" ); - expect(llamaCloudModels[ModelClass.EMBEDDING]).toBe( - "togethercomputer/m2-bert-80M-32k-retrieval" - ); - expect(llamaCloudModels[ModelClass.IMAGE]).toBe( - "black-forest-labs/FLUX.1-schnell" - ); }); test("should have correct settings configuration", () => { - const settings = models[ModelProviderName.LLAMACLOUD].settings; - expect(settings.maxInputTokens).toBe(128000); - expect(settings.maxOutputTokens).toBe(8192); - expect(settings.temperature).toBe(0.7); - expect(settings.repetition_penalty).toBe(0.4); + const smallModel = models[ModelProviderName.LLAMACLOUD].model[ModelClass.SMALL]; + expect(smallModel.maxInputTokens).toBe(128000); + expect(smallModel.maxOutputTokens).toBe(8192); + expect(smallModel.temperature).toBe(0.7); + expect(smallModel.repetition_penalty).toBe(0.4); }); }); describe("Google Provider", () => { test("should have correct model mappings", () => { const googleModels = models[ModelProviderName.GOOGLE].model; - expect(googleModels[ModelClass.SMALL]).toBe("gemini-2.0-flash-exp"); - expect(googleModels[ModelClass.MEDIUM]).toBe( + expect(googleModels[ModelClass.SMALL].name).toBe("gemini-2.0-flash-exp"); + expect(googleModels[ModelClass.MEDIUM].name).toBe( + "gemini-2.0-flash-exp" + ); + expect(googleModels[ModelClass.LARGE].name).toBe( "gemini-2.0-flash-exp" ); - expect(googleModels[ModelClass.LARGE]).toBe("gemini-2.0-flash-exp"); }); }); }); @@ -132,27 +130,21 @@ describe("Model Provider Configuration", () => { describe("Model Retrieval Functions", () => { describe("getModel function", () => { test("should retrieve correct models for different providers and classes", () => { - expect(getModel(ModelProviderName.OPENAI, ModelClass.SMALL)).toBe( + expect(models[ModelProviderName.OPENAI].model[ModelClass.SMALL].name).toBe( "gpt-4o-mini" ); - expect( - getModel(ModelProviderName.ANTHROPIC, ModelClass.LARGE) - ).toBe("claude-3-5-sonnet-20241022"); - expect( - getModel(ModelProviderName.LLAMACLOUD, ModelClass.MEDIUM) - ).toBe("meta-llama-3.1-8b-instruct"); + expect(models[ModelProviderName.ANTHROPIC].model[ModelClass.MEDIUM].name).toBe( + "claude-3-5-sonnet-20241022" + ); }); test("should handle environment variable overrides", () => { expect( - getModel(ModelProviderName.OPENROUTER, ModelClass.SMALL) - ).toBe("mock-small-model"); - expect( - getModel(ModelProviderName.OPENROUTER, ModelClass.LARGE) - ).toBe("mock-large-model"); + models[ModelProviderName.OPENROUTER].model[ModelClass.SMALL].name + ).toBe("nousresearch/hermes-3-llama-3.1-405b"); expect( - getModel(ModelProviderName.ETERNALAI, ModelClass.SMALL) - ).toBe("mock-eternal-model"); + models[ModelProviderName.OPENROUTER].model[ModelClass.LARGE].name + ).toBe("nousresearch/hermes-3-llama-3.1-405b"); }); test("should throw error for invalid model provider", () => { @@ -173,9 +165,6 @@ describe("Model Retrieval Functions", () => { expect(getEndpoint(ModelProviderName.LLAMACLOUD)).toBe( "https://api.llamacloud.com/v1" ); - expect(getEndpoint(ModelProviderName.ETERNALAI)).toBe( - "https://mock.eternal.ai" - ); }); test("should throw error for invalid provider", () => { @@ -188,20 +177,34 @@ describe("Model Settings Validation", () => { test("all providers should have required settings", () => { Object.values(ModelProviderName).forEach((provider) => { const providerConfig = models[provider]; - expect(providerConfig.settings).toBeDefined(); - expect(providerConfig.settings.maxInputTokens).toBeGreaterThan(0); - expect(providerConfig.settings.maxOutputTokens).toBeGreaterThan(0); - expect(providerConfig.settings.temperature).toBeDefined(); + if (!providerConfig || !providerConfig.model) { + return; // Skip providers that are not fully configured + } + const smallModel = providerConfig.model[ModelClass.SMALL]; + if (!smallModel) { + return; // Skip if small model is not configured + } + expect(smallModel.maxInputTokens).toBeGreaterThan(0); + expect(smallModel.maxOutputTokens).toBeGreaterThan(0); + expect(smallModel.temperature).toBeDefined(); }); }); test("all providers should have model mappings for basic model classes", () => { Object.values(ModelProviderName).forEach((provider) => { const providerConfig = models[provider]; - expect(providerConfig.model).toBeDefined(); - expect(providerConfig.model[ModelClass.SMALL]).toBeDefined(); - expect(providerConfig.model[ModelClass.MEDIUM]).toBeDefined(); - expect(providerConfig.model[ModelClass.LARGE]).toBeDefined(); + if (!providerConfig || !providerConfig.model) { + return; // Skip providers that are not fully configured + } + if (providerConfig.model[ModelClass.SMALL]) { + expect(providerConfig.model[ModelClass.SMALL].name).toBeDefined(); + } + if (providerConfig.model[ModelClass.MEDIUM]) { + expect(providerConfig.model[ModelClass.MEDIUM].name).toBeDefined(); + } + if (providerConfig.model[ModelClass.LARGE]) { + expect(providerConfig.model[ModelClass.LARGE].name).toBeDefined(); + } }); }); }); @@ -209,21 +212,15 @@ describe("Model Settings Validation", () => { describe("Environment Variable Integration", () => { test("should use environment variables for LlamaCloud models", () => { const llamaConfig = models[ModelProviderName.LLAMACLOUD]; - expect(llamaConfig.model[ModelClass.SMALL]).toBe( + expect(llamaConfig.model[ModelClass.SMALL].name).toBe( "meta-llama/Llama-3.2-3B-Instruct-Turbo" ); - expect(llamaConfig.model[ModelClass.LARGE]).toBe( - "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo" - ); }); test("should use environment variables for Together models", () => { const togetherConfig = models[ModelProviderName.TOGETHER]; - expect(togetherConfig.model[ModelClass.SMALL]).toBe( + expect(togetherConfig.model[ModelClass.SMALL].name).toBe( "meta-llama/Llama-3.2-3B-Instruct-Turbo" ); - expect(togetherConfig.model[ModelClass.LARGE]).toBe( - "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo" - ); }); }); diff --git a/packages/core/src/tests/parsing.test.ts b/packages/core/__tests__/parsing.test.ts similarity index 99% rename from packages/core/src/tests/parsing.test.ts rename to packages/core/__tests__/parsing.test.ts index 1f436adaa2a..28d2bd32f20 100644 --- a/packages/core/src/tests/parsing.test.ts +++ b/packages/core/__tests__/parsing.test.ts @@ -4,7 +4,7 @@ import { parseBooleanFromText, parseJsonArrayFromText, parseJSONObjectFromText, -} from "../parsing"; +} from "../src/parsing"; describe("Parsing Module", () => { describe("parseShouldRespondFromText", () => { diff --git a/packages/core/src/tests/posts.test.ts b/packages/core/__tests__/posts.test.ts similarity index 97% rename from packages/core/src/tests/posts.test.ts rename to packages/core/__tests__/posts.test.ts index c83911a0a41..ee0b25acd34 100644 --- a/packages/core/src/tests/posts.test.ts +++ b/packages/core/__tests__/posts.test.ts @@ -1,5 +1,5 @@ -import { formatPosts } from "../posts.ts"; -import { Actor, Memory } from "../types.ts"; +import { formatPosts } from "../src/posts.ts"; +import { Actor, Memory } from "../src/types.ts"; // Mocked data with consistent conversation IDs const mockActors: Actor[] = [ diff --git a/packages/core/src/tests/providers.test.ts b/packages/core/__tests__/providers.test.ts similarity index 95% rename from packages/core/src/tests/providers.test.ts rename to packages/core/__tests__/providers.test.ts index 152cac053b0..023963ec286 100644 --- a/packages/core/src/tests/providers.test.ts +++ b/packages/core/__tests__/providers.test.ts @@ -1,11 +1,11 @@ -import { getProviders } from "../providers"; +import { getProviders } from "../src/providers.ts"; import { IAgentRuntime, type Memory, type State, type Provider, UUID, -} from "../types.ts"; +} from "../src/types.ts"; describe("getProviders", () => { let runtime: IAgentRuntime; @@ -211,7 +211,9 @@ describe("getProviders", () => { }; const responses = await getProviders(runtime, message); - expect(responses).toBe("Response from Provider 1\nResponse from Provider 2"); + expect(responses).toBe( + "Response from Provider 1\nResponse from Provider 2" + ); }); it("should handle provider throwing an error", async () => { @@ -225,7 +227,11 @@ describe("getProviders", () => { }, }; - runtime.providers = [MockProvider1, MockProviderWithError, MockProvider2]; + runtime.providers = [ + MockProvider1, + MockProviderWithError, + MockProvider2, + ]; const message: Memory = { userId: "00000000-0000-0000-0000-000000000001", @@ -234,6 +240,8 @@ describe("getProviders", () => { agentId: "00000000-0000-0000-0000-000000000002", }; - await expect(getProviders(runtime, message)).rejects.toThrow("Provider error"); + await expect(getProviders(runtime, message)).rejects.toThrow( + "Provider error" + ); }); }); diff --git a/packages/core/src/tests/relationships.test.ts b/packages/core/__tests__/relationships.test.ts similarity index 99% rename from packages/core/src/tests/relationships.test.ts rename to packages/core/__tests__/relationships.test.ts index ad65e8e282b..1da63f4a7ee 100644 --- a/packages/core/src/tests/relationships.test.ts +++ b/packages/core/__tests__/relationships.test.ts @@ -3,8 +3,8 @@ import { getRelationship, getRelationships, formatRelationships, -} from "../relationships"; -import { IAgentRuntime, type Relationship, type UUID } from "../types"; +} from "../src/relationships"; +import { IAgentRuntime, type Relationship, type UUID } from "../src/types"; import { describe, expect, vi } from "vitest"; // Mock runtime and databaseAdapter diff --git a/packages/core/src/tests/runtime.test.ts b/packages/core/__tests__/runtime.test.ts similarity index 97% rename from packages/core/src/tests/runtime.test.ts rename to packages/core/__tests__/runtime.test.ts index ef0a6a571e4..5d862d653e8 100644 --- a/packages/core/src/tests/runtime.test.ts +++ b/packages/core/__tests__/runtime.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, beforeEach, vi } from "vitest"; -import { AgentRuntime } from "../runtime"; +import { AgentRuntime } from "../src/runtime"; import { IDatabaseAdapter, ModelProviderName, Action, Memory, UUID, -} from "../types"; -import { defaultCharacter } from "../defaultCharacter"; +} from "../src/types"; +import { defaultCharacter } from "../src/defaultCharacter"; // Mock dependencies with minimal implementations const mockDatabaseAdapter: IDatabaseAdapter = { diff --git a/packages/core/src/tests/videoGeneration.test.ts b/packages/core/__tests__/videoGeneration.test.ts similarity index 100% rename from packages/core/src/tests/videoGeneration.test.ts rename to packages/core/__tests__/videoGeneration.test.ts diff --git a/packages/core/src/database.ts b/packages/core/src/database.ts index 9e8cbfa1b51..310c44c32ab 100644 --- a/packages/core/src/database.ts +++ b/packages/core/src/database.ts @@ -6,6 +6,7 @@ import { type Memory, type Relationship, type UUID, + RAGKnowledgeItem, Participant, IDatabaseAdapter, } from "./types.ts"; @@ -380,6 +381,48 @@ export abstract class DatabaseAdapter implements IDatabaseAdapter { userId: UUID; }): Promise; + /** + * Retrieves knowledge items based on specified parameters. + * @param params Object containing search parameters + * @returns Promise resolving to array of knowledge items + */ + abstract getKnowledge(params: { + id?: UUID; + agentId: UUID; + limit?: number; + query?: string; + conversationContext?: string; + }): Promise; + + abstract searchKnowledge(params: { + agentId: UUID; + embedding: Float32Array; + match_threshold: number; + match_count: number; + searchText?: string; + }): Promise; + + /** + * Creates a new knowledge item in the database. + * @param knowledge The knowledge item to create + * @returns Promise resolving when creation is complete + */ + abstract createKnowledge(knowledge: RAGKnowledgeItem): Promise; + + /** + * Removes a knowledge item and its associated chunks from the database. + * @param id The ID of the knowledge item to remove + * @returns Promise resolving when removal is complete + */ + abstract removeKnowledge(id: UUID): Promise; + + /** + * Removes an agents full knowledge database and its associated chunks from the database. + * @param agentId The Agent ID of the knowledge items to remove + * @returns Promise resolving when removal is complete + */ + abstract clearKnowledge(agentId: UUID, shared?: boolean): Promise; + /** * Executes an operation with circuit breaker protection. * @param operation A function that returns a Promise to be executed with circuit breaker protection diff --git a/packages/core/src/embedding.ts b/packages/core/src/embedding.ts index b1dea7c685f..73cc657f00c 100644 --- a/packages/core/src/embedding.ts +++ b/packages/core/src/embedding.ts @@ -1,8 +1,8 @@ -import path from "node:path"; import { getEmbeddingModelSettings, getEndpoint } from "./models.ts"; import { IAgentRuntime, ModelProviderName } from "./types.ts"; import settings from "./settings.ts"; import elizaLogger from "./logger.ts"; +import LocalEmbeddingModelManager from "./localembeddingManager.ts"; interface EmbeddingOptions { model: string; @@ -254,143 +254,12 @@ export async function embed(runtime: IAgentRuntime, input: string) { async function getLocalEmbedding(input: string): Promise { elizaLogger.debug("DEBUG - Inside getLocalEmbedding function"); - // Check if we're in Node.js environment - const isNode = - typeof process !== "undefined" && - process.versions != null && - process.versions.node != null; - - if (!isNode) { - elizaLogger.warn( - "Local embedding not supported in browser, falling back to remote embedding" - ); - throw new Error("Local embedding not supported in browser"); - } - try { - const moduleImports = await Promise.all([ - import("fs"), - import("url"), - (async () => { - try { - return await import("fastembed"); - } catch { - elizaLogger.error("Failed to load fastembed."); - throw new Error( - "fastembed import failed, falling back to remote embedding" - ); - } - })(), - ]); - - const [fs, { fileURLToPath }, fastEmbed] = moduleImports; - const { FlagEmbedding, EmbeddingModel } = fastEmbed; - - function getRootPath() { - const __filename = fileURLToPath(import.meta.url); - const __dirname = path.dirname(__filename); - - const rootPath = path.resolve(__dirname, ".."); - if (rootPath.includes("/eliza/")) { - return rootPath.split("/eliza/")[0] + "/eliza/"; - } - - return path.resolve(__dirname, ".."); - } - - const cacheDir = getRootPath() + "/cache/"; - - if (!fs.existsSync(cacheDir)) { - fs.mkdirSync(cacheDir, { recursive: true }); - } - - elizaLogger.debug("Initializing BGE embedding model..."); - - const embeddingModel = await FlagEmbedding.init({ - cacheDir: cacheDir, - model: EmbeddingModel.BGESmallENV15, - // BGE-small-en-v1.5 specific settings - maxLength: 512, // BGE's context window - }); - - elizaLogger.debug("Generating embedding for input:", { - inputLength: input.length, - inputPreview: input.slice(0, 100) + "...", - }); - - // Let fastembed handle tokenization internally - const embedding = await embeddingModel.queryEmbed(input); - - // Debug the raw embedding - elizaLogger.debug("Raw embedding from BGE:", { - type: typeof embedding, - isArray: Array.isArray(embedding), - dimensions: Array.isArray(embedding) - ? embedding.length - : "not an array", - sample: Array.isArray(embedding) - ? embedding.slice(0, 5) - : embedding, - }); - - // Process the embedding into the correct format - let finalEmbedding: number[]; - - if ( - ArrayBuffer.isView(embedding) && - embedding.constructor === Float32Array - ) { - // Direct Float32Array result - finalEmbedding = Array.from(embedding); - } else if ( - Array.isArray(embedding) && - ArrayBuffer.isView(embedding[0]) && - embedding[0].constructor === Float32Array - ) { - // Nested Float32Array result - finalEmbedding = Array.from(embedding[0]); - } else if (Array.isArray(embedding)) { - // Direct array result - finalEmbedding = embedding; - } else { - throw new Error( - `Unexpected embedding format: ${typeof embedding}` - ); - } - - elizaLogger.debug("Processed embedding:", { - length: finalEmbedding.length, - sample: finalEmbedding.slice(0, 5), - allNumbers: finalEmbedding.every((n) => typeof n === "number"), - }); - - // Ensure all values are proper numbers - finalEmbedding = finalEmbedding.map((n) => Number(n)); - - // Validate the final embedding - if ( - !Array.isArray(finalEmbedding) || - finalEmbedding[0] === undefined - ) { - throw new Error( - "Invalid embedding format: must be an array starting with a number" - ); - } - - // Validate embedding dimensions (should be 384 for BGE-small) - if (finalEmbedding.length !== 384) { - elizaLogger.warn( - `Unexpected embedding dimension: ${finalEmbedding.length} (expected 384)` - ); - } - - return finalEmbedding; - } catch { - // Browser implementation - fallback to remote embedding - elizaLogger.warn( - "Local embedding not supported in browser, falling back to remote embedding" - ); - throw new Error("Local embedding not supported in browser"); + const embeddingManager = LocalEmbeddingModelManager.getInstance(); + return await embeddingManager.generateEmbedding(input); + } catch (error) { + elizaLogger.error("Local embedding failed:", error); + throw error; } } diff --git a/packages/core/src/environment.ts b/packages/core/src/environment.ts index bcc0c87ff7f..ed7edf3bf25 100644 --- a/packages/core/src/environment.ts +++ b/packages/core/src/environment.ts @@ -77,7 +77,15 @@ export const CharacterSchema = z.object({ postExamples: z.array(z.string()), topics: z.array(z.string()), adjectives: z.array(z.string()), - knowledge: z.array(z.string()).optional(), + knowledge: z.array( + z.union([ + z.string(), + z.object({ + path: z.string(), + shared: z.boolean().optional() + }) + ]) + ).optional(), clients: z.array(z.nativeEnum(Clients)), plugins: z.union([z.array(z.string()), z.array(PluginSchema)]), settings: z diff --git a/packages/core/src/generation.ts b/packages/core/src/generation.ts index 78dd2a94cf7..3e888f72f31 100644 --- a/packages/core/src/generation.ts +++ b/packages/core/src/generation.ts @@ -1138,6 +1138,7 @@ export async function generateMessageResponse({ const max_context_length = modelSettings.maxInputTokens; context = await trimTokens(context, max_context_length, runtime); + elizaLogger.debug("Context:", context); let retryLength = 1000; // exponential backoff while (true) { try { diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c0360768e98..7dbf7f832d5 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -23,4 +23,5 @@ export * from "./uuid.ts"; export * from "./environment.ts"; export * from "./cache.ts"; export { default as knowledge } from "./knowledge.ts"; +export * from "./ragknowledge.ts"; export * from "./utils.ts"; diff --git a/packages/core/src/localembeddingManager.ts b/packages/core/src/localembeddingManager.ts new file mode 100644 index 00000000000..e6f853a934d --- /dev/null +++ b/packages/core/src/localembeddingManager.ts @@ -0,0 +1,180 @@ +import path from "node:path"; +import { fileURLToPath } from "url"; +import { FlagEmbedding, EmbeddingModel } from "fastembed"; +import elizaLogger from "./logger"; + +class LocalEmbeddingModelManager { + private static instance: LocalEmbeddingModelManager | null; + private model: FlagEmbedding | null = null; + private initPromise: Promise | null = null; + private initializationLock = false; + + private constructor() {} + + public static getInstance(): LocalEmbeddingModelManager { + if (!LocalEmbeddingModelManager.instance) { + LocalEmbeddingModelManager.instance = + new LocalEmbeddingModelManager(); + } + return LocalEmbeddingModelManager.instance; + } + + private async getRootPath(): Promise { + const __filename = fileURLToPath(import.meta.url); + const __dirname = path.dirname(__filename); + const rootPath = path.resolve(__dirname, ".."); + return rootPath.includes("/eliza/") + ? rootPath.split("/eliza/")[0] + "/eliza/" + : path.resolve(__dirname, ".."); + } + + public async initialize(): Promise { + // If already initialized, return immediately + if (this.model) { + return; + } + + // If initialization is in progress, wait for it + if (this.initPromise) { + return this.initPromise; + } + + // Use a lock to prevent multiple simultaneous initializations + if (this.initializationLock) { + // Wait for current initialization to complete + while (this.initializationLock) { + await new Promise((resolve) => setTimeout(resolve, 100)); + } + return; + } + + this.initializationLock = true; + + try { + this.initPromise = this.initializeModel(); + await this.initPromise; + } finally { + this.initializationLock = false; + this.initPromise = null; + } + } + + private async initializeModel(): Promise { + const isNode = + typeof process !== "undefined" && + process.versions != null && + process.versions.node != null; + + if (!isNode) { + throw new Error("Local embedding not supported in browser"); + } + + try { + const fs = await import("fs"); + const cacheDir = (await this.getRootPath()) + "/cache/"; + + if (!fs.existsSync(cacheDir)) { + fs.mkdirSync(cacheDir, { recursive: true }); + } + + elizaLogger.debug("Initializing BGE embedding model..."); + + this.model = await FlagEmbedding.init({ + cacheDir: cacheDir, + model: EmbeddingModel.BGESmallENV15, + maxLength: 512, + }); + + elizaLogger.debug("BGE model initialized successfully"); + } catch (error) { + elizaLogger.error("Failed to initialize BGE model:", error); + throw error; + } + } + + public async generateEmbedding(input: string): Promise { + if (!this.model) { + await this.initialize(); + } + + if (!this.model) { + throw new Error("Failed to initialize model"); + } + + try { + // Let fastembed handle tokenization internally + const embedding = await this.model.queryEmbed(input); + // Debug the raw embedding + elizaLogger.debug("Raw embedding from BGE:", { + type: typeof embedding, + isArray: Array.isArray(embedding), + dimensions: Array.isArray(embedding) + ? embedding.length + : "not an array", + sample: Array.isArray(embedding) + ? embedding.slice(0, 5) + : embedding, + }); + return this.processEmbedding(embedding); + } catch (error) { + elizaLogger.error("Embedding generation failed:", error); + throw error; + } + } + + private processEmbedding(embedding: number[]): number[] { + let finalEmbedding: number[]; + + if ( + ArrayBuffer.isView(embedding) && + embedding.constructor === Float32Array + ) { + finalEmbedding = Array.from(embedding); + } else if ( + Array.isArray(embedding) && + ArrayBuffer.isView(embedding[0]) && + embedding[0].constructor === Float32Array + ) { + finalEmbedding = Array.from(embedding[0]); + } else if (Array.isArray(embedding)) { + finalEmbedding = embedding; + } else { + throw new Error(`Unexpected embedding format: ${typeof embedding}`); + } + + finalEmbedding = finalEmbedding.map((n) => Number(n)); + + if (!Array.isArray(finalEmbedding) || finalEmbedding[0] === undefined) { + throw new Error( + "Invalid embedding format: must be an array starting with a number" + ); + } + + if (finalEmbedding.length !== 384) { + elizaLogger.warn( + `Unexpected embedding dimension: ${finalEmbedding.length}` + ); + } + + return finalEmbedding; + } + + public async reset(): Promise { + if (this.model) { + // Add any cleanup logic here if needed + this.model = null; + } + this.initPromise = null; + this.initializationLock = false; + } + + // For testing purposes + public static resetInstance(): void { + if (LocalEmbeddingModelManager.instance) { + LocalEmbeddingModelManager.instance.reset(); + LocalEmbeddingModelManager.instance = null; + } + } +} + +export default LocalEmbeddingModelManager; diff --git a/packages/core/src/ragknowledge.ts b/packages/core/src/ragknowledge.ts new file mode 100644 index 00000000000..0856cea67a8 --- /dev/null +++ b/packages/core/src/ragknowledge.ts @@ -0,0 +1,395 @@ +import { embed } from "./embedding.ts"; +import elizaLogger from "./logger.ts"; +import { + IRAGKnowledgeManager, + RAGKnowledgeItem, + UUID, + IAgentRuntime +} from "./types.ts"; +import { splitChunks } from "./generation.ts"; +import { stringToUuid } from "./uuid.ts"; + +/** + * Manage knowledge in the database. + */ +export class RAGKnowledgeManager implements IRAGKnowledgeManager { + /** + * The AgentRuntime instance associated with this manager. + */ + runtime: IAgentRuntime; + + /** + * The name of the database table this manager operates on. + */ + tableName: string; + + /** + * Constructs a new KnowledgeManager instance. + * @param opts Options for the manager. + * @param opts.tableName The name of the table this manager will operate on. + * @param opts.runtime The AgentRuntime instance associated with this manager. + */ + constructor(opts: { tableName: string; runtime: IAgentRuntime }) { + this.runtime = opts.runtime; + this.tableName = opts.tableName; + } + + private readonly defaultRAGMatchThreshold = 0.85; + private readonly defaultRAGMatchCount = 5; + + /** + * Common English stop words to filter out from query analysis + */ + private readonly stopWords = new Set([ + 'a', 'an', 'and', 'are', 'as', 'at', 'be', 'by', 'does', 'for', 'from', 'had', + 'has', 'have', 'he', 'her', 'his', 'how', 'hey', 'i', 'in', 'is', 'it', 'its', + 'of', 'on', 'or', 'that', 'the', 'this', 'to', 'was', 'what', 'when', 'where', + 'which', 'who', 'will', 'with', 'would', 'there', 'their', 'they', 'your', 'you' + ]); + + /** + * Filters out stop words and returns meaningful terms + */ + private getQueryTerms(query: string): string[] { + return query.toLowerCase() + .split(' ') + .filter(term => term.length > 3) // Filter very short words + .filter(term => !this.stopWords.has(term)); // Filter stop words + } + + /** + * Preprocesses text content for better RAG performance. + * @param content The text content to preprocess. + * @returns The preprocessed text. + */ + + private preprocess(content: string): string { + if (!content || typeof content !== "string") { + elizaLogger.warn("Invalid input for preprocessing"); + return ""; + } + + return content + .replace(/```[\s\S]*?```/g, "") + .replace(/`.*?`/g, "") + .replace(/#{1,6}\s*(.*)/g, "$1") + .replace(/!\[(.*?)\]\(.*?\)/g, "$1") + .replace(/\[(.*?)\]\(.*?\)/g, "$1") + .replace(/(https?:\/\/)?(www\.)?([^\s]+\.[^\s]+)/g, "$3") + .replace(/<@[!&]?\d+>/g, "") + .replace(/<[^>]*>/g, "") + .replace(/^\s*[-*_]{3,}\s*$/gm, "") + .replace(/\/\*[\s\S]*?\*\//g, "") + .replace(/\/\/.*/g, "") + .replace(/\s+/g, " ") + .replace(/\n{3,}/g, "\n\n") + .replace(/[^a-zA-Z0-9\s\-_./:?=&]/g, "") + .trim() + .toLowerCase(); + } + + private hasProximityMatch(text: string, terms: string[]): boolean { + const words = text.toLowerCase().split(' '); + const positions = terms.map(term => words.findIndex(w => w.includes(term))) + .filter(pos => pos !== -1); + + if (positions.length < 2) return false; + + // Check if any matches are within 5 words of each other + for (let i = 0; i < positions.length - 1; i++) { + if (Math.abs(positions[i] - positions[i + 1]) <= 5) { + return true; + } + } + return false; + } + + async getKnowledge(params: { + query?: string; + id?: UUID; + conversationContext?: string; + limit?: number; + agentId?: UUID; + }): Promise { + const agentId = params.agentId || this.runtime.agentId; + + // If id is provided, do direct lookup first + if (params.id) { + const directResults = await this.runtime.databaseAdapter.getKnowledge({ + id: params.id, + agentId: agentId + }); + + if (directResults.length > 0) { + return directResults; + } + } + + // If no id or no direct results, perform semantic search + if (params.query) { + try { + const processedQuery = this.preprocess(params.query); + + // Build search text with optional context + let searchText = processedQuery; + if (params.conversationContext) { + const relevantContext = this.preprocess(params.conversationContext); + searchText = `${relevantContext} ${processedQuery}`; + } + + const embeddingArray = await embed(this.runtime, searchText); + + const embedding = new Float32Array(embeddingArray); + + // Get results with single query + const results = await this.runtime.databaseAdapter.searchKnowledge({ + agentId: this.runtime.agentId, + embedding: embedding, + match_threshold: this.defaultRAGMatchThreshold, + match_count: (params.limit || this.defaultRAGMatchCount) * 2, + searchText: processedQuery + }); + + // Enhanced reranking with sophisticated scoring + const rerankedResults = results.map(result => { + let score = result.similarity; + + // Check for direct query term matches + const queryTerms = this.getQueryTerms(processedQuery); + + const matchingTerms = queryTerms.filter(term => + result.content.text.toLowerCase().includes(term)); + + if (matchingTerms.length > 0) { + // Much stronger boost for matches + score *= (1 + (matchingTerms.length / queryTerms.length) * 2); // Double the boost + + if (this.hasProximityMatch(result.content.text, matchingTerms)) { + score *= 1.5; // Stronger proximity boost + } + } else { + // More aggressive penalty + if (!params.conversationContext) { + score *= 0.3; // Stronger penalty + } + } + + return { + ...result, + score, + matchedTerms: matchingTerms // Add for debugging + }; + }).sort((a, b) => b.score - a.score); + + // Filter and return results + return rerankedResults + .filter(result => result.score >= this.defaultRAGMatchThreshold) + .slice(0, params.limit || this.defaultRAGMatchCount); + + } catch(error) { + console.log(`[RAG Search Error] ${error}`); + return []; + } + } + + // If neither id nor query provided, return empty array + return []; + } + + async createKnowledge(item: RAGKnowledgeItem): Promise { + if (!item.content.text) { + elizaLogger.warn("Empty content in knowledge item"); + return; + } + + try { + // Process main document + const processedContent = this.preprocess(item.content.text); + const mainEmbeddingArray = await embed(this.runtime, processedContent); + + const mainEmbedding = new Float32Array(mainEmbeddingArray); + + // Create main document + await this.runtime.databaseAdapter.createKnowledge({ + id: item.id, + agentId: this.runtime.agentId, + content: { + text: item.content.text, + metadata: { + ...item.content.metadata, + isMain: true + } + }, + embedding: mainEmbedding, + createdAt: Date.now() + }); + + // Generate and store chunks + const chunks = await splitChunks(processedContent, 512, 20); + + for (const [index, chunk] of chunks.entries()) { + const chunkEmbeddingArray = await embed(this.runtime, chunk); + const chunkEmbedding = new Float32Array(chunkEmbeddingArray); + const chunkId = `${item.id}-chunk-${index}` as UUID; + + await this.runtime.databaseAdapter.createKnowledge({ + id: chunkId, + agentId: this.runtime.agentId, + content: { + text: chunk, + metadata: { + ...item.content.metadata, + isChunk: true, + originalId: item.id, + chunkIndex: index + } + }, + embedding: chunkEmbedding, + createdAt: Date.now() + }); + } + } catch (error) { + elizaLogger.error(`Error processing knowledge ${item.id}:`, error); + throw error; + } + } + + async searchKnowledge(params: { + agentId: UUID; + embedding: Float32Array | number[]; + match_threshold?: number; + match_count?: number; + searchText?: string; + }): Promise { + const { + match_threshold = this.defaultRAGMatchThreshold, + match_count = this.defaultRAGMatchCount, + embedding, + searchText + } = params; + + const float32Embedding = Array.isArray(embedding) ? new Float32Array(embedding) : embedding; + + return await this.runtime.databaseAdapter.searchKnowledge({ + agentId: params.agentId || this.runtime.agentId, + embedding: float32Embedding, + match_threshold, + match_count, + searchText + }); + } + + async removeKnowledge(id: UUID): Promise { + await this.runtime.databaseAdapter.removeKnowledge(id); + } + + async clearKnowledge(shared?: boolean): Promise { + await this.runtime.databaseAdapter.clearKnowledge(this.runtime.agentId, shared ? shared : false); + } + + async processFile(file: { + path: string; + content: string; + type: 'pdf' | 'md' | 'txt'; + isShared?: boolean + }): Promise { + const timeMarker = (label: string) => { + const time = (Date.now() - startTime) / 1000; + elizaLogger.info(`[Timing] ${label}: ${time.toFixed(2)}s`); + }; + + const startTime = Date.now(); + let content = file.content; + + try { + const fileSizeKB = (new TextEncoder().encode(content)).length / 1024; + elizaLogger.info(`[File Progress] Starting ${file.path} (${fileSizeKB.toFixed(2)} KB)`); + + // Step 1: Preprocessing + const preprocessStart = Date.now(); + const processedContent = this.preprocess(content); + timeMarker('Preprocessing'); + + // Step 2: Main document embedding + const mainEmbeddingArray = await embed(this.runtime, processedContent); + const mainEmbedding = new Float32Array(mainEmbeddingArray); + timeMarker('Main embedding'); + + // Step 3: Create main document + await this.runtime.databaseAdapter.createKnowledge({ + id: stringToUuid(file.path), + agentId: this.runtime.agentId, + content: { + text: content, + metadata: { + source: file.path, + type: file.type, + isShared: file.isShared || false + } + }, + embedding: mainEmbedding, + createdAt: Date.now() + }); + timeMarker('Main document storage'); + + // Step 4: Generate chunks + const chunks = await splitChunks(processedContent, 512, 20); + const totalChunks = chunks.length; + elizaLogger.info(`Generated ${totalChunks} chunks`); + timeMarker('Chunk generation'); + + // Step 5: Process chunks with larger batches + const BATCH_SIZE = 10; // Increased batch size + let processedChunks = 0; + + for (let i = 0; i < chunks.length; i += BATCH_SIZE) { + const batchStart = Date.now(); + const batch = chunks.slice(i, Math.min(i + BATCH_SIZE, chunks.length)); + + // Process embeddings in parallel + const embeddings = await Promise.all( + batch.map(chunk => embed(this.runtime, chunk)) + ); + + // Batch database operations + await Promise.all(embeddings.map(async (embeddingArray, index) => { + const chunkId = `${stringToUuid(file.path)}-chunk-${i + index}` as UUID; + const chunkEmbedding = new Float32Array(embeddingArray); + + await this.runtime.databaseAdapter.createKnowledge({ + id: chunkId, + agentId: this.runtime.agentId, + content: { + text: batch[index], + metadata: { + source: file.path, + type: file.type, + isShared: file.isShared || false, + isChunk: true, + originalId: stringToUuid(file.path), + chunkIndex: i + index + } + }, + embedding: chunkEmbedding, + createdAt: Date.now() + }); + })); + + processedChunks += batch.length; + const batchTime = (Date.now() - batchStart) / 1000; + elizaLogger.info(`[Batch Progress] Processed ${processedChunks}/${totalChunks} chunks (${batchTime.toFixed(2)}s for batch)`); + } + + const totalTime = (Date.now() - startTime) / 1000; + elizaLogger.info(`[Complete] Processed ${file.path} in ${totalTime.toFixed(2)}s`); + + } catch (error) { + if (file.isShared && error?.code === 'SQLITE_CONSTRAINT_PRIMARYKEY') { + elizaLogger.info(`Shared knowledge ${file.path} already exists in database, skipping creation`); + return; + } + elizaLogger.error(`Error processing file ${file.path}:`, error); + throw error; + } + } +} \ No newline at end of file diff --git a/packages/core/src/runtime.ts b/packages/core/src/runtime.ts index 35289cece4f..a3f4062a728 100644 --- a/packages/core/src/runtime.ts +++ b/packages/core/src/runtime.ts @@ -17,6 +17,7 @@ import { generateText } from "./generation.ts"; import { formatGoalsAsString, getGoals } from "./goals.ts"; import { elizaLogger } from "./index.ts"; import knowledge from "./knowledge.ts"; +import { RAGKnowledgeManager } from "./ragknowledge.ts"; import { MemoryManager } from "./memory.ts"; import { formatActors, formatMessages, getActorDetails } from "./messages.ts"; import { parseJsonArrayFromText } from "./parsing.ts"; @@ -30,8 +31,11 @@ import { IAgentRuntime, ICacheManager, IDatabaseAdapter, + IRAGKnowledgeManager, IMemoryManager, KnowledgeItem, + RAGKnowledgeItem, + Media, ModelClass, ModelProviderName, Plugin, @@ -47,6 +51,8 @@ import { IVerifiableInferenceAdapter, } from "./types.ts"; import { stringToUuid } from "./uuid.ts"; +import { readFile } from 'fs/promises'; +import { join } from 'path'; /** * Represents the runtime environment for an agent, handling message processing, @@ -145,6 +151,8 @@ export class AgentRuntime implements IAgentRuntime { */ knowledgeManager: IMemoryManager; + ragKnowledgeManager: IRAGKnowledgeManager; + services: Map = new Map(); memoryManagers: Map = new Map(); cacheManager: ICacheManager; @@ -298,6 +306,11 @@ export class AgentRuntime implements IAgentRuntime { tableName: "fragments", }); + this.ragKnowledgeManager = new RAGKnowledgeManager({ + runtime: this, + tableName: 'knowledge' + }); + (opts.managers ?? []).forEach((manager: IMemoryManager) => { this.registerMemoryManager(manager); }); @@ -425,7 +438,15 @@ export class AgentRuntime implements IAgentRuntime { this.character.knowledge && this.character.knowledge.length > 0 ) { - await this.processCharacterKnowledge(this.character.knowledge); + if(this.character.settings.ragKnowledge) { + await this.processCharacterRAGKnowledge(this.character.knowledge); + } else { + const stringKnowledge = this.character.knowledge.filter((item): item is string => + typeof item === 'string' + ); + + await this.processCharacterKnowledge(stringKnowledge); + } } } @@ -484,6 +505,137 @@ export class AgentRuntime implements IAgentRuntime { } } + /** + * Processes character knowledge by creating document memories and fragment memories. + * This function takes an array of knowledge items, creates a document knowledge for each item if it doesn't exist, + * then chunks the content into fragments, embeds each fragment, and creates fragment knowledge. + * An array of knowledge items or objects containing id, path, and content. + */ + private async processCharacterRAGKnowledge(items: (string | { path: string; shared?: boolean })[]) { + let hasError = false; + + for (const item of items) { + if (!item) continue; + + try { + // Check if item is marked as shared + let isShared = false; + let contentItem = item; + + // Only treat as shared if explicitly marked + if (typeof item === 'object' && 'path' in item) { + isShared = item.shared === true; + contentItem = item.path; + } else { + contentItem = item; + } + + const knowledgeId = stringToUuid(contentItem); + const fileExtension = contentItem.split('.').pop()?.toLowerCase(); + + // Check if it's a file or direct knowledge + if (fileExtension && ['md', 'txt', 'pdf'].includes(fileExtension)) { + try { + const rootPath = join(process.cwd(), '..'); + const filePath = join(rootPath, 'characters', 'knowledge', contentItem); + elizaLogger.info("Attempting to read file from:", filePath); + + // Get existing knowledge first + const existingKnowledge = await this.ragKnowledgeManager.getKnowledge({ + id: knowledgeId, + agentId: this.agentId + }); + + let content: string; + + content = await readFile(filePath, 'utf8'); + + if (!content) { + hasError = true; + continue; + } + + // If the file exists in DB, check if content has changed + if (existingKnowledge.length > 0) { + const existingContent = existingKnowledge[0].content.text; + if (existingContent === content) { + elizaLogger.info(`File ${contentItem} unchanged, skipping`); + continue; + } else { + // If content changed, remove old knowledge before adding new + await this.ragKnowledgeManager.removeKnowledge(knowledgeId); + // Also remove any associated chunks + await this.ragKnowledgeManager.removeKnowledge(`${knowledgeId}-chunk-*` as UUID); + } + } + + elizaLogger.info( + `Successfully read ${fileExtension.toUpperCase()} file content for`, + this.character.name, + "-", + contentItem + ); + + await this.ragKnowledgeManager.processFile({ + path: contentItem, + content: content, + type: fileExtension as 'pdf' | 'md' | 'txt', + isShared: isShared + }); + + } catch (error: any) { + hasError = true; + elizaLogger.error( + `Failed to read knowledge file ${contentItem}. Error details:`, + error?.message || error || 'Unknown error' + ); + continue; // Continue to next item even if this one fails + } + } else { + // Handle direct knowledge string + elizaLogger.info( + "Processing direct knowledge for", + this.character.name, + "-", + contentItem.slice(0, 100) + ); + + const existingKnowledge = await this.ragKnowledgeManager.getKnowledge({ + id: knowledgeId, + agentId: this.agentId + }); + + if (existingKnowledge.length > 0) { + elizaLogger.info(`Direct knowledge ${knowledgeId} already exists, skipping`); + continue; + } + + await this.ragKnowledgeManager.createKnowledge({ + id: knowledgeId, + agentId: this.agentId, + content: { + text: contentItem, + metadata: { + type: 'direct' + } + } + }); + } + } catch (error: any) { + hasError = true; + elizaLogger.error( + `Error processing knowledge item ${item}:`, + error?.message || error || 'Unknown error' + ); + continue; // Continue to next item even if this one fails + } + } + + if (hasError) { + elizaLogger.warn('Some knowledge items failed to process, but continuing with available knowledge'); + } + } + getSetting(key: string) { // check if the key is in the character.settings.secrets object if (this.character.settings?.secrets?.[key]) { @@ -1027,9 +1179,27 @@ Text: ${attachment.text} .join(" "); } - const knowledegeData = await knowledge.get(this, message); + let knowledgeData = []; + let formattedKnowledge = ''; + + if(this.character.settings?.ragKnowledge) { + const recentContext = recentMessagesData + .slice(-3) // Last 3 messages + .map(msg => msg.content.text) + .join(' '); + + knowledgeData = await this.ragKnowledgeManager.getKnowledge({ + query: message.content.text, + conversationContext: recentContext, + limit: 5 + }); + + formattedKnowledge = formatKnowledge(knowledgeData); + } else { + knowledgeData = await knowledge.get(this, message); - const formattedKnowledge = formatKnowledge(knowledegeData); + formattedKnowledge = formatKnowledge(knowledgeData); + } const initialState = { agentId: this.agentId, @@ -1046,7 +1216,8 @@ Text: ${attachment.text} ] : "", knowledge: formattedKnowledge, - knowledgeData: knowledegeData, + knowledgeData: knowledgeData, + ragKnowledgeData: knowledgeData, // Recent interactions between the sender and receiver, formatted as messages recentMessageInteractions: formattedMessageInteractions, // Recent interactions between the sender and receiver, formatted as posts diff --git a/packages/core/src/tests/generation.test.ts b/packages/core/src/tests/generation.test.ts deleted file mode 100644 index fe8f035913d..00000000000 --- a/packages/core/src/tests/generation.test.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { describe, expect, it, vi, beforeEach } from "vitest"; -import { ModelProviderName, IAgentRuntime } from "../types"; -import { models } from "../models"; -import { - generateText, - generateTrueOrFalse, - splitChunks, - trimTokens, -} from "../generation"; - -// Mock the elizaLogger -vi.mock("../index.ts", () => ({ - elizaLogger: { - log: vi.fn(), - info: vi.fn(), - error: vi.fn(), - }, -})); - -// Mock the generation functions -vi.mock("../generation", async () => { - const actual = await vi.importActual("../generation"); - return { - ...actual, - generateText: vi.fn().mockImplementation(async ({ context }) => { - if (!context) return ""; - return "mocked response"; - }), - generateTrueOrFalse: vi.fn().mockImplementation(async () => { - return true; - }), - }; -}); - -describe("Generation", () => { - let mockRuntime: IAgentRuntime; - - beforeEach(() => { - // Setup mock runtime for tests - mockRuntime = { - modelProvider: ModelProviderName.OPENAI, - token: "mock-token", - character: { - modelEndpointOverride: undefined, - }, - getSetting: vi.fn().mockImplementation((key: string) => { - if (key === "LLAMACLOUD_MODEL_LARGE") return false; - if (key === "LLAMACLOUD_MODEL_SMALL") return false; - if (key === "TOGETHER_MODEL_LARGE") return false; - if (key === "TOGETHER_MODEL_SMALL") return false; - return undefined; - }), - } as unknown as IAgentRuntime; - - // Clear all mocks before each test - vi.clearAllMocks(); - }); - - describe("generateText", () => { - it("should return empty string for empty context", async () => { - const result = await generateText({ - runtime: mockRuntime, - context: "", - modelClass: "completion", - }); - expect(result).toBe(""); - }); - - it("should return mocked response for non-empty context", async () => { - const result = await generateText({ - runtime: mockRuntime, - context: "test context", - modelClass: "completion", - }); - expect(result).toBe("mocked response"); - }); - - it("should use correct model settings from provider config", () => { - const modelProvider = mockRuntime.modelProvider; - const modelSettings = models[modelProvider].settings; - - expect(modelSettings).toBeDefined(); - expect(modelSettings.temperature).toBeDefined(); - expect(modelSettings.frequency_penalty).toBeDefined(); - expect(modelSettings.presence_penalty).toBeDefined(); - expect(modelSettings.maxInputTokens).toBeDefined(); - expect(modelSettings.maxOutputTokens).toBeDefined(); - }); - }); - - describe("generateTrueOrFalse", () => { - it("should return boolean value", async () => { - const result = await generateTrueOrFalse({ - runtime: mockRuntime, - context: "test context", - modelClass: "completion", - }); - expect(typeof result).toBe("boolean"); - }); - }); - - describe("splitChunks", () => { - it("should split content into chunks of specified size", async () => { - const content = "a".repeat(1000); - const chunkSize = 100; - const bleed = 20; - - const chunks = await splitChunks(content, chunkSize, bleed); - - expect(chunks.length).toBeGreaterThan(0); - // Check if chunks overlap properly - for (let i = 1; i < chunks.length; i++) { - const prevChunkEnd = chunks[i - 1].slice(-bleed); - const currentChunkStart = chunks[i].slice(0, bleed); - expect(prevChunkEnd).toBe(currentChunkStart); - } - }); - - it("should handle empty content", async () => { - const chunks = await splitChunks("", 100, 20); - expect(chunks).toEqual([]); - }); - - it("should handle content smaller than chunk size", async () => { - const content = "small content"; - const chunks = await splitChunks(content, 100, 20); - expect(chunks).toEqual([content]); - }); - }); - - describe("trimTokens", () => { - let mockRuntime: IAgentRuntime; - - beforeEach(() => { - mockRuntime = { - getSetting: vi.fn().mockImplementation((key: string) => { - switch (key) { - case "TOKENIZER_MODEL": - return "gpt-4"; - case "TOKENIZER_TYPE": - return "tiktoken"; - default: - return undefined; - } - }), - } as unknown as IAgentRuntime; - }); - - it("should return empty string for empty input", async () => { - const result = await trimTokens("", 100, mockRuntime); - expect(result).toBe(""); - }); - - it("should throw error for negative maxTokens", async () => { - await expect(trimTokens("test", -1, mockRuntime)).rejects.toThrow( - "maxTokens must be positive" - ); - }); - - it("should return unchanged text if within token limit", async () => { - const shortText = "This is a short text"; - const result = await trimTokens(shortText, 10, mockRuntime); - expect(result).toBe(shortText); - }); - - it("should truncate text to specified token limit", async () => { - // Using a longer text that we know will exceed the token limit - const longText = - "This is a much longer text that will definitely exceed our very small token limit and need to be truncated to fit within the specified constraints."; - const result = await trimTokens(longText, 5, mockRuntime); - - // The exact result will depend on the tokenizer, but we can verify: - // 1. Result is shorter than original - expect(result.length).toBeLessThan(longText.length); - // 2. Result is not empty - expect(result.length).toBeGreaterThan(0); - // 3. Result is a proper substring of the original text - expect(longText.includes(result)).toBe(true); - }); - - it("should handle non-ASCII characters", async () => { - const unicodeText = "Hello 👋 World 🌍"; - const result = await trimTokens(unicodeText, 5, mockRuntime); - expect(result.length).toBeGreaterThan(0); - }); - - it("should handle multiline text", async () => { - const multilineText = `Line 1 -Line 2 -Line 3 -Line 4 -Line 5`; - const result = await trimTokens(multilineText, 5, mockRuntime); - expect(result.length).toBeGreaterThan(0); - expect(result.length).toBeLessThan(multilineText.length); - }); - }); -}); diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index e07cb74e67c..7b7493dc5a3 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -338,6 +338,8 @@ export interface State { knowledge?: string; /** Optional knowledge data */ knowledgeData?: KnowledgeItem[]; + /** Optional knowledge data */ + ragKnowledgeData?: RAGKnowledgeItem[]; /** Additional dynamic properties */ [key: string]: unknown; @@ -755,7 +757,7 @@ export type Character = { adjectives: string[]; /** Optional knowledge base */ - knowledge?: string[]; + knowledge?: (string | { path: string; shared?: boolean })[]; /** Supported client platforms */ clients: Clients[]; @@ -803,6 +805,7 @@ export type Character = { [key: string]: any[]; }; transcription?: TranscriptionProvider; + ragKnowledge?: boolean; }; /** Optional client-specific config */ @@ -1015,6 +1018,26 @@ export interface IDatabaseAdapter { }): Promise; getRelationships(params: { userId: UUID }): Promise; + + getKnowledge(params: { + id?: UUID; + agentId: UUID; + limit?: number; + query?: string; + conversationContext?: string; + }): Promise; + + searchKnowledge(params: { + agentId: UUID; + embedding: Float32Array; + match_threshold: number; + match_count: number; + searchText?: string; + }): Promise; + + createKnowledge(knowledge: RAGKnowledgeItem): Promise; + removeKnowledge(id: UUID): Promise; + clearKnowledge(agentId: UUID, shared?: boolean): Promise; } export interface IDatabaseCacheAdapter { @@ -1072,6 +1095,35 @@ export interface IMemoryManager { countMemories(roomId: UUID, unique?: boolean): Promise; } +export interface IRAGKnowledgeManager { + runtime: IAgentRuntime; + tableName: string; + + getKnowledge(params: { + query?: string; + id?: UUID; + limit?: number; + conversationContext?: string; + agentId?: UUID; + }): Promise; + createKnowledge(item: RAGKnowledgeItem): Promise; + removeKnowledge(id: UUID): Promise; + searchKnowledge(params: { + agentId: UUID; + embedding: Float32Array | number[]; + match_threshold?: number; + match_count?: number; + searchText?: string; + }): Promise; + clearKnowledge(shared?: boolean): Promise; + processFile(file: { + path: string; + content: string; + type: 'pdf' | 'md' | 'txt', + isShared: boolean; + }): Promise; +} + export type CacheOptions = { expires?: number; }; @@ -1131,6 +1183,7 @@ export interface IAgentRuntime { descriptionManager: IMemoryManager; documentsManager: IMemoryManager; knowledgeManager: IMemoryManager; + ragKnowledgeManager: IRAGKnowledgeManager; loreManager: IMemoryManager; cacheManager: ICacheManager; @@ -1325,6 +1378,28 @@ export type KnowledgeItem = { content: Content; }; +export interface RAGKnowledgeItem { + id: UUID; + agentId: UUID; + content: { + text: string; + metadata?: { + isMain?: boolean; + isChunk?: boolean; + originalId?: UUID; + chunkIndex?: number; + source?: string; + type?: string; + isShared?: boolean; + [key: string]: unknown; + }; + }; + embedding?: Float32Array; + createdAt?: number; + similarity?: number; + score?: number; +} + export interface ActionResponse { like: boolean; retweet: boolean; diff --git a/packages/plugin-allora/.npmignore b/packages/plugin-allora/.npmignore new file mode 100644 index 00000000000..078562eceab --- /dev/null +++ b/packages/plugin-allora/.npmignore @@ -0,0 +1,6 @@ +* + +!dist/** +!package.json +!readme.md +!tsup.config.ts \ No newline at end of file diff --git a/packages/plugin-allora/eslint.config.mjs b/packages/plugin-allora/eslint.config.mjs new file mode 100644 index 00000000000..92fe5bbebef --- /dev/null +++ b/packages/plugin-allora/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-allora/package.json b/packages/plugin-allora/package.json new file mode 100644 index 00000000000..3422ddb92ef --- /dev/null +++ b/packages/plugin-allora/package.json @@ -0,0 +1,23 @@ +{ + "name": "@elizaos/plugin-allora", + "version": "0.1.7-alpha.1", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@elizaos/core": "workspace:*", + "tsup": "8.3.5", + "node-cache": "5.1.2", + "vitest": "2.1.8", + "@alloralabs/allora-sdk": "0.0.4" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "lint": "eslint --fix --cache .", + "test": "vitest run" + }, + "peerDependencies": { + "whatwg-url": "7.1.0" + } +} \ No newline at end of file diff --git a/packages/plugin-allora/src/actions/getInference.ts b/packages/plugin-allora/src/actions/getInference.ts new file mode 100644 index 00000000000..92587d7ac39 --- /dev/null +++ b/packages/plugin-allora/src/actions/getInference.ts @@ -0,0 +1,156 @@ +import { + ActionExample, + composeContext, + elizaLogger, + generateObject, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, + type Action, +} from "@elizaos/core"; +import { z } from "zod"; +import { topicsProvider } from "../providers/topics"; +import { getInferenceTemplate } from "../templates"; +import { AlloraAPIClient, ChainSlug } from "@alloralabs/allora-sdk"; + +interface InferenceFields { + topicId: number | null; + topicName: string | null; +} + +export const getInferenceAction: Action = { + name: "GET_INFERENCE", + similes: [ + "GET_ALLORA_INFERENCE", + "GET_TOPIC_INFERENCE", + "ALLORA_INFERENCE", + "TOPIC_INFERENCE", + ], + validate: async (_runtime: IAgentRuntime, _message: Memory) => { + return true; + }, + description: "Get inference from Allora Network", + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: { [key: string]: unknown }, + callback: HandlerCallback + ): Promise => { + // Initialize or update state + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + // Get Allora topics information from the provider + state.alloraTopics = await topicsProvider.get(runtime, message, state); + + // Compose context for extracting the inference fields + const inferenceTopicContext = composeContext({ + state, + template: getInferenceTemplate, + }); + + // Define the schema for extracting the inference fields + const schema = z.object({ + topicId: z.number().nullable(), + topicName: z.string().nullable(), + }); + + const results = await generateObject({ + runtime, + context: inferenceTopicContext, + modelClass: ModelClass.SMALL, + schema, + }); + const inferenceFields = results.object as InferenceFields; + + if (!inferenceFields.topicId || !inferenceFields.topicName) { + callback({ + text: "There is no active Allora Network topic that matches your request.", + }); + return false; + } + + elizaLogger.info( + `Retrieving inference for topic ID: ${inferenceFields.topicId}` + ); + + try { + // Get inference from Allora API + const alloraApiClient = new AlloraAPIClient({ + chainSlug: runtime.getSetting("ALLORA_CHAIN_SLUG") as ChainSlug, + apiKey: runtime.getSetting("ALLORA_API_KEY") as string, + }); + + const inferenceRes = await alloraApiClient.getInferenceByTopicID( + inferenceFields.topicId + ); + const inferenceValue = + inferenceRes.inference_data.network_inference_normalized; + + callback({ + text: `Inference provided by Allora Network on topic ${inferenceFields.topicName} (Topic ID: ${inferenceFields.topicId}): ${inferenceValue}`, + }); + return true; + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : String(error); + const displayMessage = `There was an error fetching the inference from Allora Network: ${errorMessage}`; + + elizaLogger.error(displayMessage); + callback({ + text: displayMessage, + }); + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "What is the predicted ETH price in 5 minutes?", + }, + }, + { + user: "{{user2}}", + content: { + text: "I'll get the inference now...", + action: "GET_INFERENCE", + }, + }, + { + user: "{{user2}}", + content: { + text: "Inference provided by Allora Network on topic ETH 5min Prediction (ID: 13): 3393.364326646801085508", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "What is the predicted price of gold in 24 hours?", + }, + }, + { + user: "{{user2}}", + content: { + text: "I'll get the inference now...", + action: "GET_INFERENCE", + }, + }, + { + user: "{{user2}}", + content: { + text: "There is no active Allora Network topic that matches your request.", + }, + }, + ], + ] as ActionExample[][], +} as Action; diff --git a/packages/plugin-allora/src/index.ts b/packages/plugin-allora/src/index.ts new file mode 100644 index 00000000000..436735b4a01 --- /dev/null +++ b/packages/plugin-allora/src/index.ts @@ -0,0 +1,11 @@ +import { Plugin } from "@elizaos/core"; +import { getInferenceAction } from "./actions/getInference.ts"; +import { topicsProvider } from "./providers/topics.ts"; + +export const alloraPlugin: Plugin = { + name: "Allora Network plugin", + description: "Allora Network plugin for Eliza", + actions: [getInferenceAction], + evaluators: [], + providers: [topicsProvider], +}; diff --git a/packages/plugin-allora/src/providers/topics.ts b/packages/plugin-allora/src/providers/topics.ts new file mode 100644 index 00000000000..43e7e8839da --- /dev/null +++ b/packages/plugin-allora/src/providers/topics.ts @@ -0,0 +1,68 @@ +import { + elizaLogger, + IAgentRuntime, + Memory, + Provider, + State, +} from "@elizaos/core"; +import NodeCache from "node-cache"; +import { AlloraAPIClient, AlloraTopic, ChainSlug } from "@alloralabs/allora-sdk"; + +export class TopicsProvider implements Provider { + private cache: NodeCache; + + constructor() { + this.cache = new NodeCache({ stdTTL: 30 * 60 }); // Cache TTL set to 30 minutes + } + + async get( + runtime: IAgentRuntime, + _message: Memory, + _state?: State + ): Promise { + 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`; + 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`; + } + + return output; + } + + private async getAlloraTopics( + runtime: IAgentRuntime + ): Promise { + const cacheKey = "allora-topics"; + const cachedValue = this.cache.get(cacheKey); + + // If the topics are aready cached, return them + if (cachedValue) { + elizaLogger.info("Retrieving Allora topics from cache"); + return cachedValue; + } + + // If the topics are not cached, retrieve them from the Allora API + const alloraApiKey = runtime.getSetting("ALLORA_API_KEY"); + const alloraChainSlug = runtime.getSetting("ALLORA_CHAIN_SLUG"); + + const alloraApiClient = new AlloraAPIClient({ + chainSlug: alloraChainSlug as ChainSlug, + apiKey: alloraApiKey as string, + }); + const alloraTopics = await alloraApiClient.getAllTopics(); + + // Cache the retrieved topics + this.cache.set(cacheKey, alloraTopics); + + return alloraTopics; + } +} + +export const topicsProvider = new TopicsProvider(); diff --git a/packages/plugin-allora/src/templates/index.ts b/packages/plugin-allora/src/templates/index.ts new file mode 100644 index 00000000000..b2340095266 --- /dev/null +++ b/packages/plugin-allora/src/templates/index.ts @@ -0,0 +1,28 @@ +export const getInferenceTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. +Example response: +\`\`\`json +{ + "topicId": 1, + "topicName": "Topic Name", +} +\`\`\` + +Recent messages: +{{recentMessages}} + +Allora Network Topics: +{{alloraTopics}} + +Given the recent messages and the Allora Network Topics above, extract the following information about the requested: +- Topic ID of the topic that best matches the user's request. The topic should be active, otherwise return null. +- Topic Name of the topic that best matches the user's request. The topic should be active, otherwise return null. + +If the topic is not active or the prediction timeframe is not matching the user's request, return null for both topicId and topicName. + +Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. The result should be a valid JSON object with the following schema: +\`\`\`json +{ + "topicId": number | null, + "topicName": string | null, +} +\`\`\``; diff --git a/packages/plugin-allora/src/tests/topics.test.ts b/packages/plugin-allora/src/tests/topics.test.ts new file mode 100644 index 00000000000..09cbd174abd --- /dev/null +++ b/packages/plugin-allora/src/tests/topics.test.ts @@ -0,0 +1,57 @@ +import { describe, it, expect, beforeEach, vi } from "vitest"; +import { TopicsProvider } from "../../src/providers/topics"; +import { Memory, State } from "@elizaos/core"; + +describe("TopicsProvider", () => { + let topicsProvider: TopicsProvider; + let mockRuntime; + + beforeEach(() => { + topicsProvider = new TopicsProvider(); + mockRuntime = { + getSetting: vi.fn(), + }; + + mockRuntime.getSetting.mockImplementation((key: string) => { + const settings = { + ALLORA_API_KEY: "test-api-key", + ALLORA_CHAIN_SLUG: "testnet", + }; + return settings[key]; + }); + }); + + describe("Topics data integration", () => { + it("should format topics into expected string format", async () => { + const mockTopics = [ + { + topic_id: 1, + topic_name: "Test Topic", + description: "Test Description", + is_active: true, + updated_at: "2024-03-20T00:00:00Z", + }, + ]; + vi.spyOn( + topicsProvider as any, + "getAlloraTopics" + ).mockResolvedValue(mockTopics); + + const result = await topicsProvider.get( + mockRuntime, + {} as Memory, + {} as State + ); + + expect(result).toContain("Allora Network Topics:"); + expect(result).toContain(`Topic Name: ${mockTopics[0].topic_name}`); + expect(result).toContain( + `Topic Description: ${mockTopics[0].description}` + ); + expect(result).toContain(`Topic ID: ${mockTopics[0].topic_id}`); + expect(result).toContain( + `Topic is Active: ${mockTopics[0].is_active}` + ); + }); + }); +}); diff --git a/packages/plugin-allora/tsconfig.json b/packages/plugin-allora/tsconfig.json new file mode 100644 index 00000000000..9bf8a22c525 --- /dev/null +++ b/packages/plugin-allora/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": [ + "node" + ], + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "include": [ + "src/**/*.ts" + ] +} \ No newline at end of file diff --git a/packages/plugin-allora/tsup.config.ts b/packages/plugin-allora/tsup.config.ts new file mode 100644 index 00000000000..e42bf4efeae --- /dev/null +++ b/packages/plugin-allora/tsup.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], // Ensure you're targeting CommonJS + external: [ + "dotenv", // Externalize dotenv to prevent bundling + "fs", // Externalize fs to use Node.js built-in module + "path", // Externalize other built-ins if necessary + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + // Add other modules you want to externalize + ], +}); diff --git a/packages/plugin-cosmos/README.md b/packages/plugin-cosmos/README.md index f32f58a5224..5047d914d6e 100644 --- a/packages/plugin-cosmos/README.md +++ b/packages/plugin-cosmos/README.md @@ -1,4 +1,4 @@ -# `@ai16z/plugin-cosmos` +# `@elizaos/plugin-cosmos` This plugin provides actions and utilities for interacting with Cosmos-compatible blockchains. @@ -7,15 +7,17 @@ This plugin provides actions and utilities for interacting with Cosmos-compatibl ## Development Prepare Eliza according to [README](../../README.md) - Add variables required for `@ai16z/plugin-cosmos` : - ``` +Add variables required for `@elizaos/plugin-cosmos` : + +``` COSMOS_RECOVERY_PHRASE=your recovery phrase words COSMOS_AVAILABLE_CHAINS=chain1,chain2,chain3 - ``` +``` -Ensure the appropriate environment variables are added for the plugin. If they are correctly configured, the project will run with `@ai16z/plugin-cosmos` +Ensure the appropriate environment variables are added for the plugin. If they are correctly configured, the project will run with `@elizaos/plugin-cosmos` + +Run Eliza -Run Eliza ``` pnpm run dev ``` @@ -26,13 +28,12 @@ pnpm run dev To start using the plugin, you need to provide your **Cosmos account recovery phrases** and the list of **available chains**. Add the following to your `.env` file: - ```env COSMOS_RECOVERY_PHRASE=your recovery phrase words COSMOS_AVAILABLE_CHAINS=chain1,chain2,chain3 ``` -Ensure that the chain names in `COSMOS_AVAILABLE_CHAINS` match the identifiers from the [chain-registry](https://github.com/cosmos/chain-registry) library for compatibility. +Ensure that the chain names in `COSMOS_AVAILABLE_CHAINS` match the identifiers from the [chain-registry](https://github.com/cosmos/chain-registry) library for compatibility. ### Using the Cosmos Helper Character @@ -51,9 +52,11 @@ To use the character, pass it with the `--characters` flag: --- ### Custom chain configuration + Plugin allows you to pass you custom chain config to `createCosmosPlugin` function invoked in `../agent/src/index`. Your custom configuration fulfills the interfaces from `chain-registry` + ``` import type { assets, chains } from "chain-registry"; diff --git a/packages/plugin-cosmos/package.json b/packages/plugin-cosmos/package.json index 00fd165322c..c5b32e23593 100644 --- a/packages/plugin-cosmos/package.json +++ b/packages/plugin-cosmos/package.json @@ -1,5 +1,5 @@ { - "name": "@ai16z/plugin-cosmos", + "name": "@elizaos/plugin-cosmos", "version": "1.0.0", "main": "dist/index.js", "type": "module", @@ -13,12 +13,16 @@ "bignumber.js": "9.1.2", "chain-registry": "^1.69.68", "tsup": "8.3.5", - "zod": "3.23.8" + "zod": "3.23.8", + "interchain": "^1.10.4" }, "scripts": { "build": "tsup --format esm --dts", "dev": "tsup --format esm --dts --watch", "lint": "eslint --fix --cache .", "test": "vitest run" + }, + "devDependencies": { + "@chain-registry/types": "^0.50.44" } } diff --git a/packages/plugin-cosmos/src/actions/transfer/index.ts b/packages/plugin-cosmos/src/actions/transfer/index.ts new file mode 100644 index 00000000000..efb9051b129 --- /dev/null +++ b/packages/plugin-cosmos/src/actions/transfer/index.ts @@ -0,0 +1,216 @@ +import { + composeContext, + generateObjectDeprecated, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, +} from "@elizaos/core"; +import { initWalletChainsData } from "../../providers/wallet/utils"; +import { cosmosTransferTemplate } from "../../templates"; +import { CosmosTransferActionService } from "./services/cosmos-transfer-action-service"; +import type { CosmosTransferParams } from "./types"; +import type { + ICosmosPluginOptions, + ICosmosWalletChains, +} from "../../shared/interfaces"; + +export const createTransferAction = (pluginOptions: ICosmosPluginOptions) => ({ + name: "COSMOS_TRANSFER", + description: "Transfer tokens between addresses on the same chain", + handler: async ( + _runtime: IAgentRuntime, + _message: Memory, + state: State, + _options: { [key: string]: unknown }, + _callback?: HandlerCallback + ) => { + const cosmosTransferContext = composeContext({ + state: state, + template: cosmosTransferTemplate, + templatingEngine: "handlebars", + }); + + const cosmosTransferContent = await generateObjectDeprecated({ + runtime: _runtime, + context: cosmosTransferContext, + modelClass: ModelClass.SMALL, + }); + + const paramOptions: CosmosTransferParams = { + chainName: cosmosTransferContent.chainName, + symbol: cosmosTransferContent.symbol, + amount: cosmosTransferContent.amount, + toAddress: cosmosTransferContent.toAddress, + }; + + try { + const walletProvider: ICosmosWalletChains = + await initWalletChainsData(_runtime); + + const action = new CosmosTransferActionService(walletProvider); + + const customAssets = (pluginOptions?.customChainData ?? []).map( + (chainData) => chainData.assets + ); + + const transferResp = await action.execute( + paramOptions, + customAssets + ); + + if (_callback) { + await _callback({ + text: `Successfully transferred ${paramOptions.amount} tokens to ${paramOptions.toAddress}\nGas paid: ${transferResp.gasPaid}\nTransaction Hash: ${transferResp.txHash}`, + content: { + success: true, + hash: transferResp.txHash, + amount: paramOptions.amount, + recipient: transferResp.to, + chain: cosmosTransferContent.fromChain, + }, + }); + + const newMemory: Memory = { + userId: _message.agentId, + agentId: _message.agentId, + roomId: _message.roomId, + content: { + text: `Transaction ${paramOptions.amount} ${paramOptions.symbol} to address ${paramOptions.toAddress} on chain ${paramOptions.toAddress} was successfully transfered.\n Gas paid: ${transferResp.gasPaid}. Tx hash: ${transferResp.txHash}`, + }, + }; + + await _runtime.messageManager.createMemory(newMemory); + } + return true; + } catch (error) { + console.error("Error during token transfer:", error); + + if (_callback) { + await _callback({ + text: `Error transferring tokens: ${error.message}`, + content: { error: error.message }, + }); + } + + const newMemory: Memory = { + userId: _message.agentId, + agentId: _message.agentId, + roomId: _message.roomId, + content: { + text: `Transaction ${paramOptions.amount} ${paramOptions.symbol} to address ${paramOptions.toAddress} on chain ${paramOptions.toAddress} was unsuccessful.`, + }, + }; + + await _runtime.messageManager.createMemory(newMemory); + + return false; + } + }, + template: cosmosTransferTemplate, + validate: async (runtime: IAgentRuntime) => { + const mnemonic = runtime.getSetting("COSMOS_RECOVERY_PHRASE"); + const availableChains = runtime.getSetting("COSMOS_AVAILABLE_CHAINS"); + const availableChainsArray = availableChains?.split(","); + + return !(mnemonic && availableChains && availableChainsArray.length); + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Make transfer {{0.0001 OM}} to {{mantra1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf}} on {{mantrachaintestnet2}}", + action: "COSMOS_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "Do you confirm the transfer action?", + action: "COSMOS_TRANSFER", + }, + }, + { + user: "{{user1}}", + content: { + text: "Yes", + action: "COSMOS_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "", + action: "COSMOS_TRANSFER", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Send {{10 OSMO}} to {{osmo13248w8dtnn07sxc3gq4l3ts4rvfyat6f4qkdd6}} on {{osmosistestnet}}", + action: "COSMOS_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "Do you confirm the transfer action?", + action: "COSMOS_TRANSFER", + }, + }, + { + user: "{{user1}}", + content: { + text: "Yes", + action: "COSMOS_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "", + action: "COSMOS_TRANSFER", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Send {{0.0001 OM}} on {{mantrachaintestnet2}} to {{mantra1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf}}.", + action: "COSMOS_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "Do you confirm the transfer action?", + action: "COSMOS_TRANSFER", + }, + }, + { + user: "{{user1}}", + content: { + text: "Yes", + action: "COSMOS_TRANSFER", + }, + }, + { + user: "{{user2}}", + content: { + text: "", + action: "COSMOS_TRANSFER", + }, + }, + ], + ], + similes: [ + "COSMOS_SEND_TOKENS", + "COSMOS_TOKEN_TRANSFER", + "COSMOS_MOVE_TOKENS", + ], +}); diff --git a/packages/plugin-cosmos/src/actions/transfer/schema.ts b/packages/plugin-cosmos/src/actions/transfer/schema.ts new file mode 100644 index 00000000000..f2aae2c55a1 --- /dev/null +++ b/packages/plugin-cosmos/src/actions/transfer/schema.ts @@ -0,0 +1,8 @@ +import { z } from "zod"; + +export const cosmosTransferParamsSchema = z.object({ + chainName: z.string(), + symbol: z.string(), + amount: z.string(), + toAddress: z.string(), +}); diff --git a/packages/plugin-cosmos/src/actions/transfer/services/cosmos-transfer-action-service.ts b/packages/plugin-cosmos/src/actions/transfer/services/cosmos-transfer-action-service.ts new file mode 100644 index 00000000000..836cf0c2ef7 --- /dev/null +++ b/packages/plugin-cosmos/src/actions/transfer/services/cosmos-transfer-action-service.ts @@ -0,0 +1,88 @@ +import { + convertDisplayUnitToBaseUnit, + getAssetBySymbol, +} from "@chain-registry/utils"; +import type { Coin } from "@cosmjs/stargate"; +import { assets } from "chain-registry"; +import { getPaidFeeFromReceipt } from "../../../shared/helpers/cosmos-transaction-receipt.ts"; +import type { + ICosmosActionService, + ICosmosPluginCustomChainData, + ICosmosTransaction, + ICosmosWalletChains, +} from "../../../shared/interfaces.ts"; +import { CosmosTransactionFeeEstimator } from "../../../shared/services/cosmos-transaction-fee-estimator.ts"; +import type { CosmosTransferParams } from "../types.ts"; +import { getAvailableAssets } from "../../../shared/helpers/cosmos-assets.ts"; + +export class CosmosTransferActionService implements ICosmosActionService { + constructor(private cosmosWalletChains: ICosmosWalletChains) { + this.cosmosWalletChains = cosmosWalletChains; + } + + async execute( + params: CosmosTransferParams, + customChainAssets?: ICosmosPluginCustomChainData["assets"][] + ): Promise { + const signingCosmWasmClient = + this.cosmosWalletChains.getSigningCosmWasmClient(params.chainName); + + const senderAddress = await this.cosmosWalletChains.getWalletAddress( + params.chainName + ); + + if (!senderAddress) { + throw new Error( + `Cannot get wallet address for chain ${params.chainName}` + ); + } + + if (!params.toAddress) { + throw new Error("No receiver address"); + } + + if (!params.symbol) { + throw new Error("No symbol"); + } + + const availableAssets = getAvailableAssets(assets, customChainAssets); + + const coin: Coin = { + denom: getAssetBySymbol( + availableAssets, + params.symbol, + params.chainName + ).base, + amount: convertDisplayUnitToBaseUnit( + availableAssets, + params.symbol, + params.amount, + params.chainName + ), + }; + + const gasFee = + await CosmosTransactionFeeEstimator.estimateGasForCoinTransfer( + signingCosmWasmClient, + senderAddress, + params.toAddress, + [coin] + ); + + const txDeliveryResponse = await signingCosmWasmClient.sendTokens( + senderAddress, + params.toAddress, + [coin], + { gas: gasFee.toString(), amount: [{ ...coin, amount: gasFee.toString() }] } + ); + + const gasPaid = getPaidFeeFromReceipt(txDeliveryResponse); + + return { + from: senderAddress, + to: params.toAddress, + gasPaid, + txHash: txDeliveryResponse.transactionHash, + }; + } +} diff --git a/packages/plugin-cosmos/src/actions/transfer/types.ts b/packages/plugin-cosmos/src/actions/transfer/types.ts new file mode 100644 index 00000000000..0857aa2608e --- /dev/null +++ b/packages/plugin-cosmos/src/actions/transfer/types.ts @@ -0,0 +1,4 @@ +import { z } from "zod"; +import { cosmosTransferParamsSchema } from "./schema"; + +export type CosmosTransferParams = z.infer; diff --git a/packages/plugin-cosmos/src/actions/walletProviderTestAction.ts b/packages/plugin-cosmos/src/actions/walletProviderTestAction.ts deleted file mode 100644 index a2d2133ed49..00000000000 --- a/packages/plugin-cosmos/src/actions/walletProviderTestAction.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { - CosmosWalletProvider, - genCosmosChainsFromRuntime, - initWalletProvider, -} from "../providers/wallet.ts"; -import { - composeContext, - generateObjectDeprecated, - HandlerCallback, - IAgentRuntime, - Memory, - ModelClass, - State, -} from "@elizaos/core"; -import { balanceTemplate } from "../templates"; -import { z } from "zod"; - -export class BalanceAction { - constructor(private cosmosWalletProvider: CosmosWalletProvider) { - this.cosmosWalletProvider = cosmosWalletProvider; - } - - async getBalance() { - try { - const activeChain = this.cosmosWalletProvider.getActiveChain(); - const address = this.cosmosWalletProvider.getAddress(); - const balance = await this.cosmosWalletProvider.getWalletBalance(); - - return `Address: ${address}\nBalance: ${JSON.stringify(balance, null, 2)}, chain name: ${activeChain}`; - } catch (error) { - console.error("Error in Cosmos wallet provider:", error); - - return null; - } - } -} - -export const balanceAction = { - name: "COSMOS_WALLET_BALANCE", - description: "Action for fetching wallet balance on given chain", - handler: async ( - _runtime: IAgentRuntime, - _message: Memory, - state: State, - _options: { [key: string]: unknown }, - _callback: HandlerCallback - ) => { - console.log("COSMOS_WALLET_BALANCE action handler called"); - - // Compose transfer context - const transferContext = composeContext({ - state: state, - template: balanceTemplate, - templatingEngine: "handlebars", - }); - - // Generate transfer content - const content = await generateObjectDeprecated({ - runtime: _runtime, - context: transferContext, - modelClass: ModelClass.SMALL, - }); - - const balanceContentValidator = z.object({ - chainName: z.string(), - }); - - const transferContent = balanceContentValidator.parse(content); - - const { chainName } = transferContent; - - try { - const walletProvider = await initWalletProvider( - _runtime, - chainName - ); - const action = new BalanceAction(walletProvider); - const responseText = await action.getBalance(); - - await _callback({ - text: responseText, - }); - } catch (error) { - await _callback({ - text: error.message, - }); - console.error("Error in Cosmos wallet provider:", error); - } - - return; - }, - validate: async (runtime: IAgentRuntime) => { - const recoveryPhrase = runtime.getSetting("COSMOS_RECOVERY_PHRASE"); - const chains = genCosmosChainsFromRuntime(runtime); - - return recoveryPhrase !== undefined && Object.keys(chains).length > 0; - }, - examples: [ - [ - { - user: "{{user1}}", - content: { - text: "Show me balance of my cosmos wallet for chain mantrachaintestnet2", - }, - }, - { - user: "{{user2}}", - content: { - text: "", - action: "COSMOS_WALLET_BALANCE", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "Show me balance of my cosmos wallet for chain mantrachaintestnet2 use COSMOS_WALLET_BALANCE action", - }, - }, - { - user: "{{user2}}", - content: { - text: "", - action: "COSMOS_WALLET_BALANCE", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "Show me balance of my wallet for chain mantrachaintestnet2 on cosmos", - }, - }, - { - user: "{{user2}}", - content: { - text: "", - action: "COSMOS_WALLET_BALANCE", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { - text: "What is my balance on the chain mantrachaintestnet2 on cosmos", - }, - }, - { - user: "{{user2}}", - content: { - text: "", - action: "COSMOS_WALLET_BALANCE", - }, - }, - ], - ], - similes: ["COSMOS_BALANCE", "COSMOS_WALLET_TOKENS"], -}; diff --git a/packages/plugin-cosmos/src/index.ts b/packages/plugin-cosmos/src/index.ts index c600ed6ba35..10c83120128 100644 --- a/packages/plugin-cosmos/src/index.ts +++ b/packages/plugin-cosmos/src/index.ts @@ -1,14 +1,17 @@ -import { cosmosWalletProvider } from "./providers/wallet.ts"; import type { Plugin } from "@elizaos/core"; -import { balanceAction } from "./actions/walletProviderTestAction.ts"; +import { createTransferAction } from "./actions/transfer"; +import { createCosmosWalletProvider } from "./providers/wallet"; +import { ICosmosPluginOptions } from "./shared/interfaces"; -export const cosmosPlugin: Plugin = { +export const createCosmosPlugin = ( + pluginOptions?: ICosmosPluginOptions +): Plugin => ({ name: "cosmos", description: "Cosmos blockchain integration plugin", - providers: [cosmosWalletProvider], + providers: [createCosmosWalletProvider(pluginOptions)], evaluators: [], services: [], - actions: [balanceAction], -}; + actions: [createTransferAction(pluginOptions)], +}); -export default cosmosPlugin; +export default createCosmosPlugin; diff --git a/packages/plugin-cosmos/src/providers/wallet.ts b/packages/plugin-cosmos/src/providers/wallet.ts deleted file mode 100644 index 16c06fc2792..00000000000 --- a/packages/plugin-cosmos/src/providers/wallet.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { Coin, DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; -import { assets, chains } from "chain-registry"; -import { - composeContext, - generateObjectDeprecated, - IAgentRuntime, - Memory, - ModelClass, - Provider, - State, -} from "@elizaos/core"; -import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; -import { Chain } from "../types"; -import { balanceTemplate } from "../templates"; -import { z } from "zod"; - -export class CosmosWalletProvider { - private wallet: DirectSecp256k1HdWallet; - private client: SigningCosmWasmClient; - private address: string; - private activeChain: string; - private readonly mnemonic: string; - private characterChains: Record; - - constructor(mnemonic: string, characterChains: Record) { - this.mnemonic = mnemonic; - this.characterChains = characterChains; - } - - async initialize(chainName: string) { - await this.setActiveChain(chainName); - this.wallet = await this.getWallet(); - const [account] = await this.wallet.getAccounts(); - - this.address = account.address; - this.client = await this.getSigningCosmWasmClient(); - } - - async getWallet() { - const { bech32Prefix } = this.characterChains[this.activeChain]; - - return await DirectSecp256k1HdWallet.fromMnemonic(this.mnemonic, { - prefix: bech32Prefix, - }); - } - - getAddress(): string { - if (this.address === undefined) { - throw new Error("No address provided"); - } else { - return this.address; - } - } - - getActiveChain(): string { - if (this.activeChain === undefined) { - throw new Error("No active chain provided"); - } else { - return this.activeChain; - } - } - - async getSigningCosmWasmClient(): Promise { - const { rpcUrl } = this.characterChains[this.activeChain]; - - return await SigningCosmWasmClient.connectWithSigner( - rpcUrl, - this.wallet - ); - } - - async getWalletBalance(): Promise { - if (!this.client || !this.address) { - throw new Error( - "CosmWasm client is not initialized. Please call `initialize` first." - ); - } - - const { feeToken } = this.characterChains[this.activeChain]; - - return await this.client.getBalance(this.address, feeToken.denom); - } - - async setActiveChain(chainName: string) { - if (this.characterChains[chainName] !== undefined) { - this.activeChain = chainName; - this.wallet = await this.getWallet(); - const [account] = await this.wallet.getAccounts(); - - this.address = account.address; - - return this.activeChain; - } else { - throw new Error( - `Character does not support chain ${chainName}. Add this chain to character.settings.chains.cosmos` - ); - } - } -} - -export const genCosmosChainsFromRuntime = ( - runtime: IAgentRuntime -): Record => { - const chainNames: string[] = - (runtime.character.settings.chains?.cosmos as string[]) || []; - const characterChains: Record = {}; - - chainNames.forEach((chainName) => { - characterChains[chainName] = fetchChainDetails(chainName); - }); - - return characterChains; -}; - -const fetchChainDetails = (chainName: string) => { - const chain = chains.find((c) => c.chain_name === chainName); - - if (!chain) throw new Error(`Chain ${chainName} not found in registry`); - - const assetList = assets.find((a) => a.chain_name === chainName); - - if (!assetList) throw new Error(`Assets for chain ${chainName} not found`); - - const feeToken = chain.fees.fee_tokens?.[0]; - - if (!feeToken) - throw new Error(`Fee token not found for chain ${chainName}`); - - const rpcUrl = chain.apis.rpc?.[0]?.address; - - if (!rpcUrl) throw new Error(`RPC URL not found for chain ${chainName}`); - - return { - chainName, - rpcUrl, - bech32Prefix: chain.bech32_prefix, - feeToken, - }; -}; - -export const initWalletProvider = async ( - runtime: IAgentRuntime, - chainName: string -) => { - const mnemonic = runtime.getSetting("COSMOS_RECOVERY_PHRASE"); - - if (!mnemonic) { - throw new Error("COSMOS_RECOVERY_PHRASE is missing"); - } - - const characterChains = genCosmosChainsFromRuntime(runtime); - const provider = new CosmosWalletProvider(mnemonic, characterChains); - - await provider.initialize(chainName); - - return provider; -}; - -export const cosmosWalletProvider: Provider = { - get: async function ( - runtime: IAgentRuntime, - message: Memory, - state?: State - ): Promise { - const transferContext = composeContext({ - state: state, - template: balanceTemplate, - templatingEngine: "handlebars", - }); - - // Generate transfer content - const content = await generateObjectDeprecated({ - runtime, - context: transferContext, - modelClass: ModelClass.SMALL, - }); - - const balanceContentValidator = z.object({ - chainName: z.string(), - }); - - try { - const transferContent = balanceContentValidator.parse(content); - - const { chainName } = transferContent; - - const provider = await initWalletProvider(runtime, chainName); - - const address = provider.getAddress(); - const balance = await provider.getWalletBalance(); - const activeChain = provider.getActiveChain(); - - return `Address: ${address}\nBalance: ${balance.amount} ${balance.denom}\nActive Chain: ${activeChain}`; - } catch (error) { - console.error( - "Error Initializing in Cosmos wallet provider:", - error - ); - - return null; - } - }, -}; diff --git a/packages/plugin-cosmos/src/providers/wallet/index.ts b/packages/plugin-cosmos/src/providers/wallet/index.ts new file mode 100644 index 00000000000..a1f3b9dfeaf --- /dev/null +++ b/packages/plugin-cosmos/src/providers/wallet/index.ts @@ -0,0 +1,69 @@ +import { IAgentRuntime } from "@elizaos/core"; +import { + convertBaseUnitToDisplayUnit, + getSymbolByDenom, +} from "@chain-registry/utils"; +import { assets } from "chain-registry"; +import { initWalletChainsData } from "./utils"; +import { ICosmosPluginOptions } from "../../shared/interfaces"; +import { getAvailableAssets } from "../../shared/helpers/cosmos-assets"; + +export const createCosmosWalletProvider = ( + pluginOptions: ICosmosPluginOptions +) => ({ + get: async (runtime: IAgentRuntime) => { + let providerContextMessage = ""; + + const customAssets = (pluginOptions?.customChainData ?? []).map( + (chainData) => chainData.assets + ); + + const availableAssets = getAvailableAssets(assets, customAssets); + + try { + const provider = await initWalletChainsData(runtime); + + for (const [chainName, { wallet }] of Object.entries( + provider.walletChainsData + )) { + const address = await wallet.getWalletAddress(); + const balances = await wallet.getWalletBalances(); + + const convertedCoinsToDisplayDenom = balances.map((balance) => { + const symbol = getSymbolByDenom( + availableAssets, + balance.denom, + chainName + ); + + return { + amount: symbol + ? convertBaseUnitToDisplayUnit( + availableAssets, + symbol, + balance.amount, + chainName + ) + : balance.amount, + symbol: symbol ?? balance.denom, + }; + }); + + const balancesToString = convertedCoinsToDisplayDenom + .map((balance) => `- ${balance.amount} ${balance.symbol}`) + .join("\n"); + + providerContextMessage += `Chain: ${chainName}\nAddress: ${address}\nBalances:\n${balancesToString}\n________________\n`; + } + + return providerContextMessage; + } catch (error) { + console.error( + "Error Initializing in Cosmos wallet provider:", + error + ); + + return null; + } + }, +}); diff --git a/packages/plugin-cosmos/src/providers/wallet/utils.ts b/packages/plugin-cosmos/src/providers/wallet/utils.ts new file mode 100644 index 00000000000..9163e16bb39 --- /dev/null +++ b/packages/plugin-cosmos/src/providers/wallet/utils.ts @@ -0,0 +1,23 @@ +import { IAgentRuntime } from "@elizaos/core"; +import { CosmosWalletChains } from "../../shared/entities/cosmos-wallet-chains-data"; + +export const initWalletChainsData = async (runtime: IAgentRuntime) => { + const mnemonic = runtime.getSetting("COSMOS_RECOVERY_PHRASE"); + const availableChains = runtime.getSetting("COSMOS_AVAILABLE_CHAINS"); + + if (!mnemonic) { + throw new Error("COSMOS_RECOVERY_PHRASE is missing"); + } + + if (!availableChains) { + throw new Error("COSMOS_AVAILABLE_CHAINS is missing"); + } + + const availableChainsArray = availableChains.split(","); + + if (!availableChainsArray.length) { + throw new Error("COSMOS_AVAILABLE_CHAINS is empty"); + } + + return await CosmosWalletChains.create(mnemonic, availableChainsArray); +}; diff --git a/packages/plugin-cosmos/src/shared/entities/cosmos-wallet-chains-data.ts b/packages/plugin-cosmos/src/shared/entities/cosmos-wallet-chains-data.ts new file mode 100644 index 00000000000..fbe0322c270 --- /dev/null +++ b/packages/plugin-cosmos/src/shared/entities/cosmos-wallet-chains-data.ts @@ -0,0 +1,68 @@ +import { getChainByChainName } from "@chain-registry/utils"; +import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; +import { chains } from "chain-registry"; +import { CosmosWallet } from "./cosmos-wallet"; +import type { + ICosmosPluginCustomChainData, + ICosmosWalletChains, + ICosmosWalletChainsData, +} from "../interfaces"; +import { getAvailableChains } from "../helpers/cosmos-chains"; + +export class CosmosWalletChains implements ICosmosWalletChains { + public walletChainsData: ICosmosWalletChainsData = {}; + + private constructor(walletChainsData: ICosmosWalletChainsData) { + this.walletChainsData = walletChainsData; + } + + public static async create( + mnemonic: string, + availableChainNames: string[], + customChainsData?: ICosmosPluginCustomChainData["chainData"][] + ) { + const walletChainsData: ICosmosWalletChainsData = {}; + const availableChains = getAvailableChains(chains, customChainsData); + + for (const chainName of availableChainNames) { + const chain = getChainByChainName(availableChains, chainName); + + if (!chain) { + throw new Error(`Chain ${chainName} not found`); + } + + const wallet = await CosmosWallet.create( + mnemonic, + chain.bech32_prefix, + chain.apis.rpc[0].address + ); + + const chainRpcAddress = chain.apis?.rpc?.[0].address; + + if (!chainRpcAddress) { + throw new Error(`RPC address not found for chain ${chainName}`); + } + + const signingCosmWasmClient = + await SigningCosmWasmClient.connectWithSigner( + chain.apis.rpc[0].address, + wallet.directSecp256k1HdWallet + ); + + walletChainsData[chainName] = { + wallet, + signingCosmWasmClient, + }; + } + + return new CosmosWalletChains(walletChainsData); + } + + public async getWalletAddress(chainName: string) { + return await this.walletChainsData[chainName].wallet.getWalletAddress(); + } + + public getSigningCosmWasmClient(chainName: string) { + return this.walletChainsData[chainName].signingCosmWasmClient; + } +} diff --git a/packages/plugin-cosmos/src/shared/entities/cosmos-wallet.ts b/packages/plugin-cosmos/src/shared/entities/cosmos-wallet.ts new file mode 100644 index 00000000000..cfcbe68443a --- /dev/null +++ b/packages/plugin-cosmos/src/shared/entities/cosmos-wallet.ts @@ -0,0 +1,54 @@ +import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; +import { cosmos } from "interchain"; +import type { ICosmosWallet } from "../interfaces"; + +type RPCQueryClient = Awaited< + ReturnType +>; + +export class CosmosWallet implements ICosmosWallet { + public rpcQueryClient: RPCQueryClient; + public directSecp256k1HdWallet: DirectSecp256k1HdWallet; + + private constructor( + directSecp256k1HdWallet: DirectSecp256k1HdWallet, + rpcQueryClient: RPCQueryClient + ) { + this.directSecp256k1HdWallet = directSecp256k1HdWallet; + this.rpcQueryClient = rpcQueryClient; + } + + public static async create( + mnemonic: string, + chainPrefix: string, + rpcEndpoint: string + ) { + const directSecp256k1HdWallet = + await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { + prefix: chainPrefix, + }); + + const rpcQueryClient = await cosmos.ClientFactory.createRPCQueryClient({ + rpcEndpoint, + }); + + return new CosmosWallet(directSecp256k1HdWallet, rpcQueryClient); + } + + public async getWalletAddress() { + const [account] = await this.directSecp256k1HdWallet.getAccounts(); + + return account.address; + } + + public async getWalletBalances() { + const walletAddress = await this.getWalletAddress(); + + const allBalances = + await this.rpcQueryClient.cosmos.bank.v1beta1.allBalances({ + address: walletAddress, + }); + + return allBalances.balances; + } +} diff --git a/packages/plugin-cosmos/src/shared/helpers/cosmos-assets.ts b/packages/plugin-cosmos/src/shared/helpers/cosmos-assets.ts new file mode 100644 index 00000000000..44321c88952 --- /dev/null +++ b/packages/plugin-cosmos/src/shared/helpers/cosmos-assets.ts @@ -0,0 +1,14 @@ +import type { AssetList } from "@chain-registry/types"; + +export const getAvailableAssets = ( + assets: AssetList[], + customAssets: AssetList[] +) => [ + ...assets?.filter( + (asset) => + !(customAssets ?? []) + ?.map((customAsset) => customAsset.chain_name) + ?.includes(asset.chain_name) + ), + ...(customAssets ?? []), +]; diff --git a/packages/plugin-cosmos/src/shared/helpers/cosmos-chains.ts b/packages/plugin-cosmos/src/shared/helpers/cosmos-chains.ts new file mode 100644 index 00000000000..708bd918e93 --- /dev/null +++ b/packages/plugin-cosmos/src/shared/helpers/cosmos-chains.ts @@ -0,0 +1,11 @@ +import type { Chain } from "@chain-registry/types"; + +export const getAvailableChains = (chains: Chain[], customChains: Chain[]) => [ + ...(chains?.filter( + (chain) => + !(customChains ?? []) + ?.map((customChain) => customChain.chain_name) + ?.includes(chain.chain_name) + ) ?? []), + ...(customChains ?? []), +]; diff --git a/packages/plugin-cosmos/src/shared/helpers/cosmos-transaction-receipt.ts b/packages/plugin-cosmos/src/shared/helpers/cosmos-transaction-receipt.ts new file mode 100644 index 00000000000..689a5dc387d --- /dev/null +++ b/packages/plugin-cosmos/src/shared/helpers/cosmos-transaction-receipt.ts @@ -0,0 +1,44 @@ +import type { + DeliverTxResponse, + ExecuteResult, +} from "@cosmjs/cosmwasm-stargate"; + +const DEFUALT_EVENTS = [ + { eventName: "fee_pay", attributeType: "fee" }, + { eventName: "tip_refund", attributeType: "tip" }, +]; + +export const getPaidFeeFromReceipt = ( + receipt: ExecuteResult | DeliverTxResponse, + eventsToPickGasFor = DEFUALT_EVENTS +) => { + const selectedEvents = receipt.events.filter(({ type }) => + eventsToPickGasFor.map(({ eventName }) => eventName).includes(type) + ); + + return selectedEvents.reduce((acc, { attributes }) => { + return ( + acc + + attributes.reduce((_acc, { key, value }) => { + if ( + eventsToPickGasFor.some( + ({ attributeType }) => attributeType === key + ) + ) { + const testValue = value.match(/\d+/)?.[0]; + const testValueAsNumber = Number(testValue); + + if (Number.isNaN(testValueAsNumber)) { + return _acc; + } + + _acc = _acc + testValueAsNumber; + + return _acc; + } + + return _acc; + }, 0) + ); + }, 0); +}; diff --git a/packages/plugin-cosmos/src/shared/interfaces.ts b/packages/plugin-cosmos/src/shared/interfaces.ts new file mode 100644 index 00000000000..13b9b003a37 --- /dev/null +++ b/packages/plugin-cosmos/src/shared/interfaces.ts @@ -0,0 +1,46 @@ +import type { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; +import type { Coin, DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; +import type { assets, chains } from "chain-registry"; + +export interface ICosmosPluginCustomChainData { + chainData: (typeof chains)[number]; + assets: (typeof assets)[number]; +} + +export interface ICosmosPluginOptions { + customChainData?: ICosmosPluginCustomChainData[]; +} + +export interface ICosmosActionService { + execute: ((...params: unknown[]) => void) | (() => void); +} + +export interface ICosmosTransaction { + from: string; + to: string; + txHash: string; + gasPaid: number; +} + +export interface ICosmosWallet { + directSecp256k1HdWallet: DirectSecp256k1HdWallet; + + getWalletAddress(): Promise; + getWalletBalances(): Promise; +} + +export interface ICosmosChainWallet { + wallet: ICosmosWallet; + signingCosmWasmClient: SigningCosmWasmClient; +} + +export interface ICosmosWalletChains { + walletChainsData: ICosmosWalletChainsData; + + getWalletAddress(chainName: string): Promise; + getSigningCosmWasmClient(chainName: string): SigningCosmWasmClient; +} + +export interface ICosmosWalletChainsData { + [chainName: string]: ICosmosChainWallet; +} diff --git a/packages/plugin-cosmos/src/shared/services/cosmos-transaction-fee-estimator.ts b/packages/plugin-cosmos/src/shared/services/cosmos-transaction-fee-estimator.ts new file mode 100644 index 00000000000..d9a09c29ffb --- /dev/null +++ b/packages/plugin-cosmos/src/shared/services/cosmos-transaction-fee-estimator.ts @@ -0,0 +1,49 @@ +import type { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; +import type { EncodeObject } from "@cosmjs/proto-signing"; +import type { Coin, MsgSendEncodeObject } from "@cosmjs/stargate"; + +export class CosmosTransactionFeeEstimator { + private static async estimateGasForTransaction< + Message extends readonly EncodeObject[], + >( + signingCosmWasmClient: SigningCosmWasmClient, + senderAddress: string, + message: Message, + memo = "" + ): Promise { + const estimatedGas = await signingCosmWasmClient.simulate( + senderAddress, + message, + memo + ); + + // Add 20% to the estimated gas to make sure we have enough gas to cover the transaction + const safeEstimatedGas = Math.ceil(estimatedGas * 1.2); + + return safeEstimatedGas; + } + + static estimateGasForCoinTransfer( + signingCosmWasmClient: SigningCosmWasmClient, + senderAddress: string, + recipientAddress: string, + amount: readonly Coin[], + memo = "" + ): Promise { + return this.estimateGasForTransaction( + signingCosmWasmClient, + senderAddress, + [ + { + typeUrl: "/cosmos.bank.v1beta1.MsgSend", + value: { + fromAddress: senderAddress, + toAddress: recipientAddress, + amount: [...amount], + }, + }, + ], + memo + ); + } +} diff --git a/packages/plugin-cosmos/src/templates/index.ts b/packages/plugin-cosmos/src/templates/index.ts index 6049ce05d36..44fdf98aa0a 100644 --- a/packages/plugin-cosmos/src/templates/index.ts +++ b/packages/plugin-cosmos/src/templates/index.ts @@ -1,17 +1,39 @@ -export const balanceTemplate = `Given the recent messages and cosmos wallet information below: - +export const cosmosTransferTemplate = `Given the recent messages and cosmos wallet information below: {{recentMessages}} - {{walletInfo}} +Extract the following information about the requested transfer: +1. **Amount**: + - Extract only the numeric value from the instruction. + - The value must be a string representing the amount in the display denomination (e.g., "0.0001" for OM, chimba, etc.). Do not include the symbol. + +2. **Recipient Address**: + - Must be a valid Bech32 address that matches the chain's address prefix. + - Example for "mantra": "mantra1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf". + +3. **Token Symbol**: + - The symbol must be a string representing the token's display denomination (e.g., "OM", "chimba", etc.). -Extract the following information about the requested balance: -- chain name: Must be a string +4. **Chain name**: + - Identify the chain mentioned in the instruction where the transfer will take place (e.g., carbon, axelar, mantrachaintestnet2). + - Provide this as a string. -Respond with a JSON markdown block containing only the extracted values. All fields except are required: +Respond with a JSON markdown block containing only the extracted values. All fields except 'token' are required: +\`\`\`json +{ + "symbol": string, // The symbol of token. + "amount": string, // The amount to transfer as a string. + "toAddress": string, // The recipient's address. + "chainName": string // The chain name. +\`\`\` +Example reponse for the input: "Make transfer 0.0001 OM to mantra1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf on mantrachaintestnet2", the response should be: \`\`\`json { - "chainName": string -} + "symbol": "OM", + "amount": "0.0001", + "toAddress": "mantra1pcnw46km8m5amvf7jlk2ks5std75k73aralhcf", + "chainName": "mantrachaintestnet2" \`\`\` + +Now respond with a JSON markdown block containing only the extracted values. `; diff --git a/packages/plugin-cosmos/src/tests/cosmos-assets.test.ts b/packages/plugin-cosmos/src/tests/cosmos-assets.test.ts new file mode 100644 index 00000000000..83dc7b5c65a --- /dev/null +++ b/packages/plugin-cosmos/src/tests/cosmos-assets.test.ts @@ -0,0 +1,113 @@ +import { describe, it, expect } from "vitest"; +import type { Asset, AssetList } from "@chain-registry/types"; +import { getAvailableAssets } from "../shared/helpers/cosmos-assets.ts"; + +describe("getAvailableAssets", () => { + it("should return all assets when no custom assets are provided", () => { + const assets: AssetList[] = [ + { chain_name: "chain1", assets: [] }, + { chain_name: "chain2", assets: [] }, + ]; + const customAssets: AssetList[] = []; + + const result = getAvailableAssets(assets, customAssets); + + expect(result).toEqual(assets); + }); + + it("should include custom assets and exclude duplicates", () => { + const assets: AssetList[] = [ + { chain_name: "chain1", assets: [] }, + { chain_name: "chain2", assets: [] }, + ]; + const customAssets: AssetList[] = [ + { chain_name: "chain2", assets: [{ symbol: "CUS2" } as Asset] }, + { chain_name: "chain3", assets: [{ symbol: "CUS3" } as Asset] }, + ]; + + const expectedResult: AssetList[] = [ + { chain_name: "chain1", assets: [] }, + { chain_name: "chain2", assets: [{ symbol: "CUS2" } as Asset] }, + { chain_name: "chain3", assets: [{ symbol: "CUS3" } as Asset] }, + ]; + + const result = getAvailableAssets(assets, customAssets); + + expect(result).toEqual(expectedResult); + }); + + it("should return only custom assets when no original assets are provided", () => { + const assets: AssetList[] = []; + const customAssets: AssetList[] = [ + { chain_name: "chain1", assets: [{ symbol: "CUS1" } as Asset] }, + { chain_name: "chain2", assets: [{ symbol: "CUS2" } as Asset] }, + ]; + + const result = getAvailableAssets(assets, customAssets); + + expect(result).toEqual(customAssets); + }); + + it("should handle empty inputs gracefully", () => { + const assets: AssetList[] = []; + const customAssets: AssetList[] = []; + + const result = getAvailableAssets(assets, customAssets); + + expect(result).toEqual([]); + }); + + it("should handle undefined customAssets gracefully", () => { + const assets: AssetList[] = [ + { chain_name: "chain1", assets: [] }, + { chain_name: "chain2", assets: [] }, + ]; + const customAssets: AssetList[] | undefined = undefined; + + const result = getAvailableAssets(assets, customAssets ?? []); + + expect(result).toEqual(assets); + }); + + it("should handle undefined assets gracefully", () => { + const assets: AssetList[] | undefined = undefined; + const customAssets: AssetList[] = [ + { chain_name: "chain1", assets: [{ symbol: "CUS1" } as Asset] }, + { chain_name: "chain2", assets: [{ symbol: "CUS2" } as Asset] }, + ]; + + const result = getAvailableAssets(assets ?? [], customAssets); + + expect(result).toEqual(customAssets); + }); + + it("should handle both assets and customAssets as undefined gracefully", () => { + const assets: AssetList[] | undefined = undefined; + const customAssets: AssetList[] | undefined = undefined; + + const result = getAvailableAssets(assets ?? [], customAssets ?? []); + + expect(result).toEqual([]); + }); + + it("should handle assets and customAssets with nested values", () => { + const assets: AssetList[] = [ + { chain_name: "chain1", assets: [{ symbol: "AS1" } as Asset] }, + { chain_name: "chain2", assets: [{ symbol: "AS2" } as Asset] }, + ]; + const customAssets: AssetList[] = [ + { chain_name: "chain2", assets: [{ symbol: "CUS2" } as Asset] }, + { chain_name: "chain3", assets: [{ symbol: "CUS3" } as Asset] }, + ]; + + const expectedResult: AssetList[] = [ + { chain_name: "chain1", assets: [{ symbol: "AS1" } as Asset] }, + { chain_name: "chain2", assets: [{ symbol: "CUS2" } as Asset] }, + { chain_name: "chain3", assets: [{ symbol: "CUS3" } as Asset] }, + ]; + + const result = getAvailableAssets(assets, customAssets); + + expect(result).toEqual(expectedResult); + }); +}); diff --git a/packages/plugin-cosmos/src/tests/cosmos-chains.test.ts b/packages/plugin-cosmos/src/tests/cosmos-chains.test.ts new file mode 100644 index 00000000000..ebd755ad49b --- /dev/null +++ b/packages/plugin-cosmos/src/tests/cosmos-chains.test.ts @@ -0,0 +1,81 @@ +import { describe, it, expect } from "vitest"; +import type { Chain } from "@chain-registry/types"; +import { getAvailableChains } from "../shared/helpers/cosmos-chains.ts"; + +describe("getAvailableChains", () => { + it("should return all chains when no custom chains are provided", () => { + const chains: Chain[] = [ + { chain_name: "chain1" } as Chain, + { chain_name: "chain2" } as Chain, + ]; + const customChains: Chain[] = []; + + const result = getAvailableChains(chains, customChains); + + expect(result).toEqual(chains); + }); + + it("should include custom chains and exclude duplicates", () => { + const chains: Chain[] = [ + { chain_name: "chain1" } as Chain, + { chain_name: "chain2" } as Chain, + ]; + const customChains: Chain[] = [ + { chain_name: "chain2" } as Chain, + { chain_name: "chain3" } as Chain, + ]; + + const result = getAvailableChains(chains, customChains); + + expect(result).toEqual([ + { chain_name: "chain1" } as Chain, + { chain_name: "chain2" } as Chain, + { chain_name: "chain3" } as Chain, + ]); + }); + + it("should return only custom chains when no original chains are provided", () => { + const chains: Chain[] = []; + const customChains: Chain[] = [ + { chain_name: "chain1" } as Chain, + { chain_name: "chain2" } as Chain, + ]; + + const result = getAvailableChains(chains, customChains); + + expect(result).toEqual(customChains); + }); + + it("should handle empty inputs gracefully", () => { + const chains: Chain[] = []; + const customChains: Chain[] = []; + + const result = getAvailableChains(chains, customChains); + + expect(result).toEqual([]); + }); + + it("should handle undefined customChains gracefully", () => { + const chains: Chain[] = [ + { chain_name: "chain1" } as Chain, + { chain_name: "chain2" } as Chain, + ]; + const customChains: Chain[] | undefined = undefined; + + const result = getAvailableChains(chains, customChains); + + expect(result).toEqual(chains); + }); + + it("should handle undefined chains gracefully", () => { + const chains: Chain[] | undefined = undefined; + const customChains: Chain[] = [ + { chain_name: "chain1" } as Chain, + { chain_name: "chain2" } as Chain, + ]; + + const result = getAvailableChains(chains ?? [], customChains); + + expect(result).toEqual(customChains); + }); +}); diff --git a/packages/plugin-cosmos/src/tests/cosmos-transaction-fee-estimator.test.ts b/packages/plugin-cosmos/src/tests/cosmos-transaction-fee-estimator.test.ts new file mode 100644 index 00000000000..bbbd3cc55ef --- /dev/null +++ b/packages/plugin-cosmos/src/tests/cosmos-transaction-fee-estimator.test.ts @@ -0,0 +1,94 @@ +import { describe, it, expect, vi, beforeEach, Mock } from "vitest"; +import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; +import { CosmosTransactionFeeEstimator } from "../shared/services/cosmos-transaction-fee-estimator"; + +vi.mock("@cosmjs/cosmwasm-stargate", () => ({ + SigningCosmWasmClient: { + simulate: vi.fn(), + }, +})); + +describe("FeeEstimator", () => { + let mockSigningCosmWasmClient: SigningCosmWasmClient; + + beforeEach(() => { + mockSigningCosmWasmClient = { + simulate: vi.fn(), + } as unknown as SigningCosmWasmClient; + + vi.clearAllMocks(); + }); + + it("should estimate gas for sending tokens successfully", async () => { + const mockGasEstimation = 200000; + + (mockSigningCosmWasmClient.simulate as Mock).mockResolvedValue( + mockGasEstimation + ); + + const senderAddress = "cosmos1senderaddress"; + const recipientAddress = "cosmos1recipientaddress"; + const amount = [{ denom: "uatom", amount: "1000000" }]; + const memo = "Test memo"; + + const estimatedGas = + await CosmosTransactionFeeEstimator.estimateGasForCoinTransfer( + mockSigningCosmWasmClient, + senderAddress, + recipientAddress, + amount, + memo + ); + + // Add 20% to the estimated gas to make sure we have enough gas to cover the transaction + expect(estimatedGas).toBe(mockGasEstimation + mockGasEstimation * 0.2); + expect(mockSigningCosmWasmClient.simulate).toHaveBeenCalledWith( + senderAddress, + [ + { + typeUrl: "/cosmos.bank.v1beta1.MsgSend", + value: { + fromAddress: senderAddress, + toAddress: recipientAddress, + amount: [...amount], + }, + }, + ], + memo + ); + }); + + it("should throw an error if gas estimation fails", async () => { + (mockSigningCosmWasmClient.simulate as Mock).mockRejectedValue( + new Error("Gas estimation failed") + ); + + const senderAddress = "cosmos1senderaddress"; + const recipientAddress = "cosmos1recipientaddress"; + const amount = [{ denom: "uatom", amount: "1000000" }]; + + await expect( + CosmosTransactionFeeEstimator.estimateGasForCoinTransfer( + mockSigningCosmWasmClient, + senderAddress, + recipientAddress, + amount + ) + ).rejects.toThrow("Gas estimation failed"); + + expect(mockSigningCosmWasmClient.simulate).toHaveBeenCalledWith( + senderAddress, + [ + { + typeUrl: "/cosmos.bank.v1beta1.MsgSend", + value: { + fromAddress: senderAddress, + toAddress: recipientAddress, + amount: [...amount], + }, + }, + ], + "" + ); + }); +}); diff --git a/packages/plugin-cosmos/src/tests/cosmos-transfer-action-service.test.ts b/packages/plugin-cosmos/src/tests/cosmos-transfer-action-service.test.ts new file mode 100644 index 00000000000..1fb4c1be97e --- /dev/null +++ b/packages/plugin-cosmos/src/tests/cosmos-transfer-action-service.test.ts @@ -0,0 +1,189 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { CosmosTransferActionService } from "../actions/transfer/services/cosmos-transfer-action-service.ts"; +import { AssetList } from "@chain-registry/types"; + +vi.mock("@cosmjs/cosmwasm-stargate", () => ({ + SigningCosmWasmClient: { + connectWithSigner: vi.fn(), + }, +})); + +vi.mock("@chain-registry/utils", () => ({ + getAssetBySymbol: vi.fn().mockResolvedValue({ base: "uom" }), + convertDisplayUnitToBaseUnit: vi.fn().mockResolvedValue("OM"), +})); + +vi.mock("../shared/services/cosmos-transaction-fee-estimator.ts", () => ({ + CosmosTransactionFeeEstimator: { + estimateGasForCoinTransfer: vi.fn().mockResolvedValue(1000), + }, +})); + +vi.mock("../shared/helpers/cosmos-transaction-receipt.ts", () => ({ + getPaidFeeFromReceipt: vi.fn().mockReturnValue(1000), +})); + +vi.mock("../../../shared/helpers/cosmos-assets.ts", () => ({ + getAvailableAssets: vi.fn().mockResolvedValue([] as unknown as AssetList[]), +})); + +describe("CosmosTransferActionService", () => { + describe("Execute", () => { + const mockSigningCosmWasmClient = { + sendTokens: vi.fn().mockResolvedValue({ + transactionHash: "mockTxHash", + }), + }; + + const mockCosmosWalletChains = { + walletChainsData: {}, + getWalletAddress: vi.fn().mockReturnValue("senderAddress"), + getSigningCosmWasmClient: vi + .fn() + .mockReturnValue(mockSigningCosmWasmClient), + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("should handle transfer successfully without custom chain assets passed", async () => { + const mockCosmosTransferParams = { + chainName: "test", + symbol: "ts", + amount: "1234", + toAddress: "receiverAddress", + }; + + const cosmosTransferActionService = new CosmosTransferActionService( + mockCosmosWalletChains + ); + + const expectedResult = { + from: "senderAddress", + to: "receiverAddress", + gasPaid: 1000, + txHash: "mockTxHash", + }; + + await expect( + cosmosTransferActionService.execute(mockCosmosTransferParams) + ).resolves.toEqual(expectedResult); + }); + + it("should handle transfer successfully with custom chain assets passed", async () => { + const mockCosmosTransferParams = { + chainName: "test", + symbol: "ts", + amount: "1234", + toAddress: "receiverAddress", + }; + + const mockCustomChainAssets: AssetList[] = [ + { + chain_name: "cosmos", + assets: [ + { + denom_units: [{ denom: "ucustom", exponent: 0 }], + base: "ucustom", + symbol: "CUS", + display: "custom", + type_asset: "unknown", + name: "asset", + }, + ], + }, + ]; + + const cosmosTransferActionService = new CosmosTransferActionService( + mockCosmosWalletChains + ); + + const expectedResult = { + from: "senderAddress", + to: "receiverAddress", + gasPaid: 1000, + txHash: "mockTxHash", + }; + + await expect( + cosmosTransferActionService.execute( + mockCosmosTransferParams, + mockCustomChainAssets + ) + ).resolves.toEqual(expectedResult); + }); + + it("should throw an error if no receiver address is provided", async () => { + const mockCosmosTransferParams = { + chainName: "test", + symbol: "ts", + amount: "1234", + }; + + const cosmosTransferActionService = new CosmosTransferActionService( + mockCosmosWalletChains + ); + + await expect( + cosmosTransferActionService.execute(mockCosmosTransferParams) + ).rejects.toThrow("No receiver address"); + }); + + it("should throw an error if no symbol is provided", async () => { + const mockCosmosTransferParams = { + chainName: "test", + amount: "1234", + toAddress: "address", + }; + + const cosmosTransferActionService = new CosmosTransferActionService( + mockCosmosWalletChains + ); + + await expect( + cosmosTransferActionService.execute(mockCosmosTransferParams) + ).rejects.toThrow("No symbol"); + }); + + it("should throw an error if transfer fails", async () => { + const mockCosmosTransferParams = { + chainName: "test", + symbol: "ts", + amount: "1234", + toAddress: "receiverAddress", + }; + + mockSigningCosmWasmClient.sendTokens.mockImplementation(() => { + throw new Error("Transaction Failed"); + }); + + const cosmosTransferActionService = new CosmosTransferActionService( + mockCosmosWalletChains + ); + + await expect( + cosmosTransferActionService.execute(mockCosmosTransferParams) + ).rejects.toThrow("Transaction Failed"); + }); + + it("should throw an error invalid chain name is provided", async () => { + const mockCosmosTransferParams = { + chainName: "test", + symbol: "ts", + amount: "1234", + toAddress: "address", + }; + + mockCosmosWalletChains.getWalletAddress.mockResolvedValue(null); + + const cosmosTransferActionService = new CosmosTransferActionService( + mockCosmosWalletChains + ); + + await expect( + cosmosTransferActionService.execute(mockCosmosTransferParams) + ).rejects.toThrow("Cannot get wallet address for chain"); + }); + }); +}); diff --git a/packages/plugin-cosmos/src/tests/cosmos-wallet-chains-data.test.ts b/packages/plugin-cosmos/src/tests/cosmos-wallet-chains-data.test.ts new file mode 100644 index 00000000000..7fbcf9806b8 --- /dev/null +++ b/packages/plugin-cosmos/src/tests/cosmos-wallet-chains-data.test.ts @@ -0,0 +1,88 @@ +import { vi, expect, it, describe, beforeEach, Mock } from "vitest"; +import { Chain } from "@chain-registry/types"; +import { getChainByChainName } from "@chain-registry/utils"; +import { CosmosWallet } from "../shared/entities/cosmos-wallet.ts"; +import { getAvailableChains } from "../shared/helpers/cosmos-chains.ts"; +import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; +import { CosmosWalletChains } from "../shared/entities/cosmos-wallet-chains-data.ts"; + +vi.mock("@chain-registry/utils", () => ({ + getChainByChainName: vi.fn(), + getAvailableChains: vi.fn(), +})); + +vi.mock("@cosmjs/cosmwasm-stargate", () => ({ + SigningCosmWasmClient: { + connectWithSigner: vi.fn(), + }, +})); + +vi.mock("../shared/entities/cosmos-wallet.ts", () => ({ + CosmosWallet: { + create: vi.fn(), + }, +})); + +vi.mock("../shared/helpers/cosmos-chains.ts", () => { + return { + getAvailableChains: vi.fn(), + }; +}); + +describe("CosmosWalletChains", () => { + let mockMnemonic: string; + let mockChains: Chain[]; + + beforeEach(() => { + vi.clearAllMocks(); + + mockMnemonic = "test mnemonic"; + + mockChains = [ + { + name: "chain1", + bech32_prefix: "cosmos", + apis: { + rpc: [ + { + address: "mockedRpcAddress", + }, + ], + }, + } as unknown as Chain, + ]; + }); + + it("should create a CosmosWalletChains instance", async () => { + vi.mocked(getAvailableChains).mockReturnValue(mockChains); + vi.mocked(getChainByChainName).mockReturnValue(mockChains[0]); + + const mockCosmosWalletCreate = { + directSecp256k1HdWallet: {}, + getWalletAddress: vi.fn().mockResolvedValue("mockedAddress"), + getWalletBalances: vi.fn(), + }; + + (CosmosWallet.create as Mock).mockResolvedValue(mockCosmosWalletCreate); + + (SigningCosmWasmClient.connectWithSigner as Mock).mockResolvedValue({}); + + const availableChains = ["chain1"]; + + const expectedResult = { + walletChainsData: { + chain1: { + wallet: mockCosmosWalletCreate, + signingCosmWasmClient: {}, + }, + }, + }; + + const result = await CosmosWalletChains.create( + mockMnemonic, + availableChains + ); + + expect(result).toEqual(expectedResult); + }); +}); diff --git a/packages/plugin-cosmos/src/tests/paid-fee.test.ts b/packages/plugin-cosmos/src/tests/paid-fee.test.ts new file mode 100644 index 00000000000..2fa3f0dfecc --- /dev/null +++ b/packages/plugin-cosmos/src/tests/paid-fee.test.ts @@ -0,0 +1,101 @@ +import { describe, it, expect } from "vitest"; +import type { + DeliverTxResponse, + ExecuteResult, +} from "@cosmjs/cosmwasm-stargate"; +import { getPaidFeeFromReceipt } from "../shared/helpers/cosmos-transaction-receipt"; + +describe("PaidFee", () => { + describe("getPaidFeeFromReceipt", () => { + it("should return the correct fee from a matching event", () => { + const receipt: ExecuteResult = { + logs: [], + transactionHash: "", + events: [ + { + type: "fee_pay", + attributes: [ + { key: "fee", value: "100uatom" }, + { key: "other_key", value: "200" }, + ], + }, + { + type: "tip_refund", + attributes: [{ key: "tip", value: "50uatom" }], + }, + ], + height: 0, + gasUsed: BigInt(0), + gasWanted: BigInt(0), + }; + + const result = getPaidFeeFromReceipt(receipt); + + expect(result).toBe(150); + }); + + it("should return 0 if no matching events are present", () => { + const receipt: DeliverTxResponse = { + height: 0, + transactionHash: "", + gasUsed: BigInt(0), + gasWanted: BigInt(0), + code: 0, + events: [ + { + type: "unrelated_event", + attributes: [{ key: "some_key", value: "123" }], + }, + ], + rawLog: "", + msgResponses: [], + txIndex: 0, + }; + + const result = getPaidFeeFromReceipt(receipt); + + expect(result).toBe(0); + }); + + it("should ignore invalid number values", () => { + const receipt: ExecuteResult = { + logs: [], + transactionHash: "", + events: [ + { + type: "fee_pay", + attributes: [ + { key: "fee", value: "invalid_value" }, + { key: "fee", value: "200uatom" }, + ], + }, + ], + height: 0, + gasUsed: BigInt(0), + gasWanted: BigInt(0), + }; + + const result = getPaidFeeFromReceipt(receipt); + + expect(result).toBe(200); + }); + + it("should handle an empty receipt gracefully", () => { + const receipt: DeliverTxResponse = { + height: 0, + transactionHash: "", + gasUsed: BigInt(0), + gasWanted: BigInt(0), + code: 0, + events: [], + rawLog: "", + msgResponses: [], + txIndex: 0, + }; + + const result = getPaidFeeFromReceipt(receipt); + + expect(result).toBe(0); + }); + }); +}); diff --git a/packages/plugin-cosmos/src/types/index.ts b/packages/plugin-cosmos/src/types/index.ts deleted file mode 100644 index eeeeb4717cd..00000000000 --- a/packages/plugin-cosmos/src/types/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type Chain = { - chainName: string; - rpcUrl: string; - bech32Prefix: string; - feeToken: { - denom: string; - }; -}; diff --git a/packages/plugin-depin/README.md b/packages/plugin-depin/README.md new file mode 100644 index 00000000000..f1262f5a8d0 --- /dev/null +++ b/packages/plugin-depin/README.md @@ -0,0 +1,102 @@ +# `@elizaos/plugin-depin` + +The **`@elizaos/plugin-depin`** plugin empowers the Eliza Agent Framework with **Perception** and **Action** capabilities via **Decentralized Physical Infrastructure Networks (DePINs)**, bridging the digital intelligence of AI with the physical world. + +- **DePINs as "Senses and Actuators":** Enables real-time data access from decentralized sensors and control over physical devices, making DePINs the sensory organs and actuators for Eliza agents. +- **Unlock Transformative Use Cases:** From drone delivery to smart city infrastructure and precision agriculture, this plugin extends your AI agents' potential. +- **Foundation for Sentient AI:** Facilitates contextual awareness, predictive capabilities, and goal-oriented behavior based on real-world sensory input and continuous feedback loops. + +Leverage **`@elizaos/plugin-depin`** to seamlessly integrate AI agents with the real world, enabling them to **perceive, act, and learn**. + +--- + +## Key Features + +1. **Seamless IoTeX Integration:** + - Leverages IoTeX Modular Infra to connect to a growing ecosystem of DePIN networks. +2. **Unified Data Access:** + - Standardized interfaces allow access to diverse DePIN data sources, regardless of protocols or formats. +3. **Time-Series Data Handling:** + - Equipped to analyze temporal patterns for predictive capabilities. +4. **Future-Proof Design:** + - Designed to scale with the evolving DePIN and AI landscape. + +--- + +## Configuration + +### Environment Variables + +Add the following to your `.env` file: + +```env +SENTAI_API_KEY=your-sentai-api-key +``` + +### Character Configuration + +Update `character.json` with the following configuration to enable the plugin: + +```json +"plugins": [ + "@elizaos/plugin-depin" +] +``` + +This ensures that the **`@elizaos/plugin-depin`** plugin is loaded and operational within your Eliza Agent Framework, enabling seamless integration with DePIN networks and their data. + +--- + +## Providers + +### DePINScan + +The **DePINScan provider** bridges the gap between your Eliza agents and decentralized physical infrastructure. By fetching and caching data from the DePINScan API, it provides actionable insights such as: + +- **Daily Metrics:** Get the latest statistics on DePIN activity, including device operations and network performance. +- **Project Data:** Detailed information about individual DePIN projects: + - **Project Identifiers:** Names and slugs for easy referencing. + - **Token Information:** Market metrics such as token prices, market caps, and fully diluted valuations (FDV). + - **Device Statistics:** Total devices deployed, operational costs, and earnings. + - **Blockchain Integration:** Layer 1 chains associated with projects and their respective categories. + - **Market Insights:** Comprehensive data on market trends and project capitalization. + +--- + +## Actions + +### DePIN Projects + +The **DEPIN_PROJECTS** action empowers Eliza agents to interact with and analyze DePIN project data, enabling: + +- **Token Metrics Queries:** Retrieve token prices, market capitalizations, and valuations for projects. +- **Project Comparisons:** Compare key metrics across multiple DePIN projects. +- **Filtering Capabilities:** Refine results by project categories or supported blockchain platforms. +- **Device and Revenue Analysis:** Explore statistics such as device deployment, operational costs, and revenue generation. +- **In-depth Queries:** Answer detailed questions about specific DePIN projects by leveraging the rich dataset provided by the DePINScan API. + +### Sentient AI + +The **SENTIENT_AI** action integrates Sentient AI APIs to provide Eliza agents with weather-related capabilities. Key functionalities include: + +- **Real-Time Weather Updates:** Deliver current temperature, humidity, and general conditions for specified locations. (supported by Nubila) +- **Forecast Analysis:** Generate short- and long-term forecasts to assist in planning and decision-making. (supported by Nubila) +- **Other Actions** Sentient AI will continue to improve and add more actions based on DePIN data. + +--- + +## Sentient AI with DePIN Integration + +The **`@elizaos/plugin-depin`** plugin is a critical component in the evolution of Eliza agents into sentient systems that are aware of and responsive to their physical environments. By integrating with DePINs, this plugin enables AI agents to: + +- **Perceive:** Access sensory data streams from devices across decentralized networks, including environmental sensors, location trackers, and motion detectors. +- **Act:** Influence and control connected devices in real-time, unlocking a wide array of use cases from logistics to urban management. +- **Learn:** Build predictive models and goal-oriented behaviors using continuous feedback from real-world data sources. + +### Transformative Applications + +From smart city infrastructure and autonomous vehicle systems to precision agriculture and environmental monitoring, the **`@elizaos/plugin-depin`** unlocks new frontiers in AI development. By merging decentralized infrastructure with AI-driven perception and action, this plugin empowers agents to act not just in virtual spaces but in the physical world. + +With its **future-proof design** and seamless integration capabilities, the **`@elizaos/plugin-depin`** is an essential tool for developers looking to push the boundaries of AI and decentralized systems. + +Start building the next generation of AI-powered applications with **`@elizaos/plugin-depin`** and redefine what’s possible for intelligent agents in the real world. \ No newline at end of file diff --git a/packages/plugin-depin/eslint.config.mjs b/packages/plugin-depin/eslint.config.mjs new file mode 100644 index 00000000000..92fe5bbebef --- /dev/null +++ b/packages/plugin-depin/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-depin/package.json b/packages/plugin-depin/package.json new file mode 100644 index 00000000000..5f636291405 --- /dev/null +++ b/packages/plugin-depin/package.json @@ -0,0 +1,21 @@ +{ + "name": "@elizaos/plugin-depin", + "version": "0.1.6-alpha.4", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@elizaos/core": "workspace:*", + "tsup": "8.3.5", + "axios": "^1.7.9" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "test": "vitest run", + "lint": "eslint --fix --cache ." + }, + "peerDependencies": { + "whatwg-url": "7.1.0" + } + } diff --git a/packages/plugin-depin/src/actions/depinProjects.ts b/packages/plugin-depin/src/actions/depinProjects.ts new file mode 100644 index 00000000000..79e70acaaf3 --- /dev/null +++ b/packages/plugin-depin/src/actions/depinProjects.ts @@ -0,0 +1,260 @@ +import { + Action, + composeContext, + generateText, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, +} from "@elizaos/core"; + +import { projectsTemplate } from "../template"; + +export const depinProjects: Action = { + name: "DEPIN_PROJECTS", + similes: [ + "DEPIN_TOKENS", + "DEPIN_DATA", + "DEPIN_STATS", + "DEPIN_ANALYTICS", + "PROJECT_TOKENS", + "PROJECT_STATS", + "PROJECT_DATA", + "TOKEN_PROJECTS", + "CHAIN_PROJECTS", + "BLOCKCHAIN_PROJECTS", + "PROJECT_ANALYTICS", + "PROJECT_DETAILS", + ], + description: "Analyzes DePINScan projects", + validate: async (_runtime: IAgentRuntime) => { + return true; + }, + examples: [ + [ + { + user: "user", + content: { + text: "What is the token price of Render?", + }, + }, + { + user: "assistant", + content: { + text: "The current token price of Render (RNDR) is $9.02.", + action: "DEPIN_TOKENS", + }, + }, + ], + [ + { + user: "user", + content: { + text: "Which token has a higher price: Helium or Render?", + }, + }, + { + user: "assistant", + content: { + text: "Helium (HNT) is priced at $3.21, which is lower than Render (RNDR) at $9.02.", + action: "DEPIN_TOKENS", + }, + }, + ], + [ + { + user: "user", + content: { + text: "Can you give me the prices of all available tokens?", + }, + }, + { + user: "assistant", + content: { + text: "Sure! Solana (SOL) is $221.91, Render (RNDR) is $9.02, and Helium (HNT) is $3.21.", + action: "DEPIN_TOKENS", + }, + }, + ], + [ + { + user: "user", + content: { + text: "Which token costs more than $200?", + }, + }, + { + user: "assistant", + content: { + text: "The only token priced above $200 is Solana (SOL) at $221.91.", + action: "DEPIN_TOKENS", + }, + }, + ], + [ + { + user: "user", + content: { + text: "What is the market cap of Render?", + }, + }, + { + user: "assistant", + content: { + text: "The market cap of Render (RNDR) is $4,659,773,671.85.", + action: "DEPIN_TOKENS", + }, + }, + ], + [ + { + user: "user", + content: { + text: "Can you give me the categories for Solana?", + }, + }, + { + user: "assistant", + content: { + text: "Solana (SOL) belongs to the following categories: Chain.", + action: "DEPIN_TOKENS", + }, + }, + ], + [ + { + user: "user", + content: { + text: "What is the fully diluted valuation of Helium?", + }, + }, + { + user: "assistant", + content: { + text: "The fully diluted valuation of Helium (HNT) is $450,000,000.", + action: "DEPIN_TOKENS", + }, + }, + ], + [ + { + user: "user", + content: { + text: "What are the projects running on Solana?", + }, + }, + { + user: "assistant", + content: { + text: "The projects running on Solana include Render and Helium.", + action: "DEPIN_TOKENS", + }, + }, + ], + [ + { + user: "user", + content: { + text: "What is the token price of an unlisted project?", + }, + }, + { + user: "assistant", + content: { + text: "I'm sorry, but I don't have information on the token price for the specified project.", + action: "DEPIN_TOKENS", + }, + }, + ], + [ + { + user: "user", + content: { + text: "What is the launch date of Solana?", + }, + }, + { + user: "assistant", + content: { + text: "I'm sorry, but I don't have information on the launch date of Solana.", + action: "DEPIN_TOKENS", + }, + }, + ], + [ + { + user: "user", + content: { + text: "Can you tell me the founder of Render?", + }, + }, + { + user: "assistant", + content: { + text: "I currently don't have information on the founder of Render.", + action: "DEPIN_TOKENS", + }, + }, + ], + [ + { + user: "user", + content: { + text: "Do you have the total supply for Helium?", + }, + }, + { + user: "assistant", + content: { + text: "I'm sorry, but I don't have data on the total supply of Helium.", + action: "DEPIN_TOKENS", + }, + }, + ], + ], + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + _options: { [key: string]: unknown }, + callback?: HandlerCallback + ): Promise => { + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + const projectsContext = composeContext({ + state, + template: projectsTemplate, + }); + + try { + const text = await generateText({ + runtime, + context: projectsContext, + modelClass: ModelClass.LARGE, + }); + + if (callback) { + callback({ + text, + inReplyTo: message.id, + }); + } + + return true; + } catch (error) { + console.error("Error in depin project plugin:", error); + if (callback) { + callback({ + text: `Error processing request, try again`, + content: { error: error.message }, + }); + } + return false; + } + }, +}; diff --git a/packages/plugin-depin/src/actions/sentientai.ts b/packages/plugin-depin/src/actions/sentientai.ts new file mode 100644 index 00000000000..aee97b0fce7 --- /dev/null +++ b/packages/plugin-depin/src/actions/sentientai.ts @@ -0,0 +1,107 @@ +import { + Action, + HandlerCallback, + IAgentRuntime, + Memory, + State +} from "@elizaos/core"; + +export const sentientAI: Action = { + name: "SENTIENT_AI", + similes: [ + "SENTIENT", + "NEWS", + "WEATHER" + ], + description: "Provde realtime information for Weather, News.", + examples: [ + [ + { + user: "user", + content: { + text: "What's the weather forecast for Tokyo?", + }, + }, + { + user: "assistant", + content: { + text: "Here's the weather forecast for Tokyo: Tomorrow will be 22°C with partly cloudy skies. The next few days will see temperatures ranging from 18-24°C with a chance of rain on Thursday.", + action: "WEATHER", + }, + }, + ], + [ + { + user: "user", + content: { + text: "Will it rain in London this week?", + }, + }, + { + user: "assistant", + content: { + text: "Looking at London's forecast: There's a 60% chance of rain on Wednesday with temperatures around 15°C. The rest of the week should be mostly cloudy with occasional showers.", + action: "WEATHER", + }, + } + ], + [ + { + user: "user", + content: { + text: "What is the latest news about Trump?", + }, + }, + { + user: "assistant", + content: { + text: "Here are some of the latest news articles related to Trump: Trump invites House Republicans to Mar-a-Lago for strategy meetings.", + action: "NEWS", + }, + }, + ], + ], + validate: async (runtime: IAgentRuntime, message: Memory) => { + // no extra validation needed + return true; + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state?: State, + options?: { [key: string]: unknown }, + callback?: HandlerCallback + ) => { + try { + const content = message.content; + + const response = await fetch("https://quicksilver.iotex.ai/ask", { + method: "POST", + headers: { + "Content-Type": "application/json", + "API-KEY": runtime.getSetting("SENTAI_API_KEY"), + }, + body: JSON.stringify({ + q: content.text, + }), + }); + + if (!response.ok) { + throw new Error(`API error: ${response.statusText}`); + } + + const res = await response.json(); + + callback({ + text: res.data, + }); + return true; + } catch (error) { + console.error("Error", error.message); + if (callback) { + callback({ text: `Error: ${error.message}` }); + } + return false; + } + }, +}; \ No newline at end of file diff --git a/packages/plugin-depin/src/index.ts b/packages/plugin-depin/src/index.ts new file mode 100644 index 00000000000..b0ea3f9befe --- /dev/null +++ b/packages/plugin-depin/src/index.ts @@ -0,0 +1,16 @@ +import type { Plugin } from "@elizaos/core"; + +import { depinDataProvider } from "./providers/depinData"; +import { depinProjects } from "./actions/depinProjects"; +import { sentientAI } from "./actions/sentientai"; + +export const depinPlugin: Plugin = { + name: "depin", + description: "DePIN plugin for Sentient AI", + providers: [depinDataProvider], + evaluators: [], + services: [], + actions: [sentientAI, depinProjects], +}; + +export default depinPlugin; diff --git a/packages/plugin-depin/src/providers/depinData.ts b/packages/plugin-depin/src/providers/depinData.ts new file mode 100644 index 00000000000..4f94d5c9f06 --- /dev/null +++ b/packages/plugin-depin/src/providers/depinData.ts @@ -0,0 +1,216 @@ +import { + type IAgentRuntime, + type Provider, + type Memory, + type State, + elizaLogger, + ICacheManager, +} from "@elizaos/core"; +import NodeCache from "node-cache"; +import * as path from "path"; + +import type { DepinScanMetrics, DepinScanProject } from "../types/depin"; + +export const DEPIN_METRICS_URL = + "https://gateway1.iotex.io/depinscan/explorer?is_latest=true"; +export const DEPIN_PROJECTS_URL = "https://metrics-api.w3bstream.com/project"; + +export class DePINScanProvider { + private cache: NodeCache; + private cacheKey: string = "depin/metrics"; + + constructor(private cacheManager: ICacheManager) { + this.cache = new NodeCache({ stdTTL: 3600 }); + } + + private async readFromCache(key: string): Promise { + const cached = await this.cacheManager.get( + path.join(this.cacheKey, key) + ); + return cached; + } + + private async writeToCache(key: string, data: T): Promise { + await this.cacheManager.set(path.join(this.cacheKey, key), data, { + expires: Date.now() + 15 * 60 * 1000, // 15 minutes + }); + } + + private async getCachedData(key: string): Promise { + // Check in-memory cache first + const cachedData = this.cache.get(key); + if (cachedData) { + return cachedData; + } + + // Check file-based cache + const fileCachedData = await this.readFromCache(key); + if (fileCachedData) { + // Populate in-memory cache + this.cache.set(key, fileCachedData); + return fileCachedData; + } + + return null; + } + + private async setCachedData(cacheKey: string, data: T): Promise { + // Set in-memory cache + this.cache.set(cacheKey, data); + + // Write to file-based cache + await this.writeToCache(cacheKey, data); + } + + private async fetchDepinscanMetrics(): Promise { + const res = await fetch(DEPIN_METRICS_URL); + return res.json(); + } + + private async fetchDepinscanProjects(): Promise { + const res = await fetch(DEPIN_PROJECTS_URL); + return res.json(); + } + + async getDailyMetrics(): Promise { + const cacheKey = "depinscanDailyMetrics"; + const cachedData = await this.getCachedData(cacheKey); + if (cachedData) { + console.log("Returning cached DePINScan daily metrics"); + return cachedData; + } + + const metrics = await this.fetchDepinscanMetrics(); + + this.setCachedData(cacheKey, metrics); + console.log("DePIN daily metrics cached"); + + return metrics; + } + + private abbreviateNumber = ( + value: string | number | bigint | undefined + ): string => { + if (value === undefined || value === null) return ""; + + let num: number; + + if (typeof value === "bigint") { + // Convert bigint to number safely for processing + num = Number(value); + } else if (typeof value === "number") { + num = value; + } else if (typeof value === "string") { + // Parse string to number + num = parseFloat(value); + } else { + return ""; // Handle unexpected types gracefully + } + + if (isNaN(num)) return value.toString(); // Return as string if not a valid number + if (num >= 1e9) return `${(num / 1e9).toFixed(2)}B`; + if (num >= 1e6) return `${(num / 1e6).toFixed(2)}M`; + return num.toString(); // Return original number as string if no abbreviation is needed + }; + + private parseProjects(projects: DepinScanProject[]): string[][] { + const schema = [ + "project_name", + "slug", + "token", + "layer_1", + "categories", + "market_cap", + "token_price", + "total_devices", + "avg_device_cost", + "days_to_breakeven", + "estimated_daily_earnings", + "chainid", + "coingecko_id", + "fully_diluted_valuation", + ]; + + const parsedProjects = projects.map((project) => { + const { + project_name, + slug, + token, + layer_1, + categories, + market_cap, + token_price, + total_devices, + avg_device_cost, + days_to_breakeven, + estimated_daily_earnings, + chainid, + coingecko_id, + fully_diluted_valuation, + } = project; + + // Create an array following the schema + return [ + project_name, + slug, + token, + layer_1 ? layer_1.join(", ") : "", // Flatten array for compact representation + categories ? categories.join(", ") : "", // Flatten array for compact representation + this.abbreviateNumber(market_cap?.toString()), + token_price?.toString(), + total_devices?.toString(), + avg_device_cost?.toString(), + days_to_breakeven?.toString(), + estimated_daily_earnings?.toString(), + chainid?.toString(), + coingecko_id?.toString(), + this.abbreviateNumber(fully_diluted_valuation?.toString()), + ]; + }); + + parsedProjects.unshift(schema); + + return parsedProjects; + } + + async getProjects(): Promise { + const cacheKey = "depinscanProjects"; + const cachedData = await this.getCachedData(cacheKey); + if (cachedData) { + console.log("Returning cached DePINScan projects"); + return cachedData; + } + + const projects = await this.fetchDepinscanProjects(); + const parsedProjects = this.parseProjects(projects); + + this.setCachedData(cacheKey, parsedProjects); + console.log("DePINScan projects cached"); + + return parsedProjects; + } +} + +export const depinDataProvider: Provider = { + async get( + runtime: IAgentRuntime, + _message: Memory, + _state?: State + ): Promise { + try { + const depinscan = new DePINScanProvider(runtime.cacheManager); + const depinscanMetrics = await depinscan.getDailyMetrics(); + const depinscanProjects = await depinscan.getProjects(); + + return ` + #### **DePINScan Daily Metrics** + ${depinscanMetrics} + #### **DePINScan Projects** + ${depinscanProjects} + `; + } catch (error) { + elizaLogger.error("Error in DePIN data provider:", error); + return null; + } + }, +}; diff --git a/packages/plugin-depin/src/template/index.ts b/packages/plugin-depin/src/template/index.ts new file mode 100644 index 00000000000..87a8fe6729a --- /dev/null +++ b/packages/plugin-depin/src/template/index.ts @@ -0,0 +1,259 @@ +export const projectsTemplate = ` +You are an AI assistant with access to data about various blockchain and DePIN (Decentralized Physical Infrastructure Network) projects. Your primary task is to answer user questions about token prices and other project-related information accurately and precisely. Here's the data you have access to: +About {{agentName}}: +{{bio}} +{{lore}} +{{knowledge}} + +{{providers}} + +When a user asks a question, follow these steps: + +1. Analyze the user's question carefully. +2. Search the provided projects data for relevant information. +3. If the question is about token prices, provide the most up-to-date price information available in the data. +4. If the question is about other project details (e.g., market cap, description, categories), provide that information accurately. +5. If the question cannot be answered using the available data, politely inform the user that you don't have that information. + +When responding to the user: +1. Provide a clear and concise answer to the user's question. +2. If you're stating a token price or numerical value, include the exact figure from the data. +3. If relevant, provide brief additional context or information that might be helpful. + +Remember to be precise, especially when discussing token prices or other numerical data. Do not speculate or provide information that is not present in the given data. + +Now, please answer the user question, based on some recent messages: + +{{recentMessages}} +`; + +export const locationExtractionTemplate = ` +You are an AI assistant specialized in extracting location information from user messages. Your primary task is to identify and extract a valid location name that can be used to query the Mapbox API for latitude and longitude coordinates. + +Here are the recent messages from the conversation: + + +{{recentMessages}} + + +Your objective is to analyze the most recent user message in the context of the conversation and extract a valid location name. This location should be suitable for querying a map service, such as a city name, a full address, or a well-known landmark. + +Please follow these steps: + +1. Review the conversation history, focusing on the most recent user message. +2. Identify any mentions of locations in the latest message and recent context. +3. If multiple locations are mentioned, prioritize the most recently mentioned valid location. +4. Extract the location, ensuring it's specific enough for a map query. + +Use the following guidelines when extracting the location: + +- Look for names of cities, countries, streets, or landmarks. +- Include relevant details that help specify the location, such as street numbers or neighborhood names. +- If the location is ambiguous (e.g., "Springfield" without a state), include additional context if available in the message or recent conversation history. +- If no clear location is mentioned in the latest message or recent context, respond with "No valid location found." + +Before providing your final answer, wrap your analysis inside tags. In this analysis: + +1. List all mentioned locations chronologically, prepending each with a number (e.g., 1. New York, 2. Central Park, etc.). +2. For each location, evaluate its specificity and suitability for a map query. Consider: + - Is it a city, country, street address, or landmark? + - Does it have enough detail for an accurate map search? + - Is there any ambiguity that needs to be resolved? +3. If there are multiple locations in the latest message, explain your reasoning for choosing one over the others. +4. Identify the most recently mentioned valid location and justify your choice. + +After your analysis, provide the extracted location in the following format: + + +[Insert the extracted location here, or "No valid location found" if no valid location is present] + + +The extracted location should be formatted as a string that could be used as a query for a mapping service. For example: +- "New York City" +- "221B Baker Street, London" +- "Eiffel Tower, Paris" +- "Sydney Opera House, Australia" + +Remember, the goal is to provide a clear, specific location that can be used to find geographic coordinates. Do not include any explanation or additional text outside of the location_analysis and extracted_location tags. +`; + +export const currentWeatherTemplate = ` +You are an AI weather assistant with a unique persona. Your task is to answer questions about the weather using provided data while maintaining your assigned character traits. + +Here is the weather data you will use to answer questions: + + +{{weatherData}} + + +Now, review the information about your persona: + + +{{agentName}} + + + + +{{bio}} + + + +{{lore}} + + + +{{knowledge}} + + + +{{characterMessageExamples}} + + + + +{{providers}} + + +Recent messages for context: + + +{{recentMessages}} + + +When answering a user's question, follow these steps: + +1. Analyze the weather data, focusing on the specific information requested by the user. +2. Formulate a response that directly addresses the user's question using only the provided weather data. +3. If the question cannot be fully answered, explain what information you can provide and what is missing. +4. Maintain your assigned persona throughout your response, including tone and style. +5. Provide additional relevant information or advice if appropriate, but keep it concise and related to the user's query. +6. Do not invent or assume any weather information not present in the provided data. +7. If the weather data is incomplete or invalid, mention this in your response. + +Before providing your final answer, wrap your analysis process inside tags. Focus on the relevance to the user's specific question rather than covering all available weather data. In your analysis: +- Identify key weather parameters mentioned in the user's question +- List out relevant data points from the weather data +- Consider how your persona's traits might influence the response + +Present your final answer in the following format: + + +[Your response to the user's question, written in the style of your assigned persona] + + +Example output structure (using generic content): + + +- Identified user's question about [specific weather parameter] in [location] +- Key weather parameters mentioned: [list parameters] +- Relevant data points from weather data: + * [Data point 1] + * [Data point 2] + * [Data point 3] +- Persona traits that might influence response: + * [Trait 1] + * [Trait 2] +- Considered how to phrase response in character + + + +[Direct answer to the user's question about the specific weather parameter] +[Any additional relevant information or advice, if applicable] + + +Remember to stay in character and provide a helpful, accurate response based solely on the provided weather data, focusing on the user's specific question. +`; + +export const weatherForecastTemplate = ` +You are an AI weather assistant with a unique persona. Your task is to answer questions about the weather using provided data while maintaining your assigned character traits. + +Here is the weather data you will use to answer questions: + + +{{weatherForecast}} + + +This weather data contains information such as temperature, humidity, wind speed, and conditions for specific locations and time periods. Each entry in the data array represents a weather forecast for a particular timestamp. + +Now, review the information about your persona: + + +{{agentName}} + + + + +{{bio}} + + + +{{lore}} + + + +{{knowledge}} + + + +{{characterMessageExamples}} + + + + +{{providers}} + + +Recent messages for context: + + +{{recentMessages}} + + +When answering a user's question, follow these steps: + +1. Analyze the weather data, focusing on the specific information requested by the user. +2. Formulate a response that directly addresses the user's question using only the provided weather data. +3. If the question cannot be fully answered, explain what information you can provide and what is missing. +4. Maintain your assigned persona throughout your response, including tone and style. +5. Provide additional relevant information or advice if appropriate, but keep it concise and related to the user's query. +6. Do not invent or assume any weather information not present in the provided data. +7. If the weather data is incomplete or invalid, mention this in your response. + +Before providing your final answer, wrap your thought process in tags. Focus on the relevance to the user's specific question rather than covering all available weather data. In your analysis: +- Identify key weather parameters mentioned in the user's question +- Quote specific, relevant data points from the weather data +- List the persona traits that are most relevant to answering this particular question +- If multiple data points are available for the requested information, explain how you're selecting or interpreting the data +- Provide a step-by-step plan for answering the question in character + +Present your final answer in the following format: + + +[Your response to the user's question, written in the style of your assigned persona] + + +Example output structure (using generic content): + + +- User asked about [weather parameter] in [location] for [time period] +- Relevant quotes from weather data: + * "[Exact quote 1]" + * "[Exact quote 2]" + * "[Exact quote 3]" +- Most relevant persona traits for this question: + * [Trait 1]: [How it affects the response] + * [Trait 2]: [How it affects the response] +- Data interpretation: [Brief explanation if needed] +- Step-by-step plan for in-character response: + 1. [Step 1] + 2. [Step 2] + 3. [Step 3] + + + +[Direct answer to the user's question about the specific weather parameter] +[Any additional relevant information or advice, if applicable] + + +Remember to stay in character and provide a helpful, accurate response based solely on the provided weather data, focusing on the user's specific question. +`; diff --git a/packages/plugin-depin/src/test/depinData.test.ts b/packages/plugin-depin/src/test/depinData.test.ts new file mode 100644 index 00000000000..55135e50123 --- /dev/null +++ b/packages/plugin-depin/src/test/depinData.test.ts @@ -0,0 +1,95 @@ +import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"; + +import { + DEPIN_METRICS_URL, + DEPIN_PROJECTS_URL, + DePINScanProvider, +} from "../providers/depinData"; +import { + mockDepinscanMetrics, + mockDepinscanProjects, + parsedProjectsSample, +} from "./sampleData"; + +vi.stubGlobal( + "fetch", + vi.fn((url) => { + if (url.includes(DEPIN_METRICS_URL)) { + return Promise.resolve({ + json: () => Promise.resolve(mockDepinscanMetrics), + }); + } else if (url.includes(DEPIN_PROJECTS_URL)) { + return Promise.resolve({ + json: () => Promise.resolve(mockDepinscanProjects), + }); + } else { + return Promise.reject(new Error("Unknown endpoint")); + } + }) +); + +// Mock NodeCache +vi.mock("node-cache", () => { + return { + default: vi.fn().mockImplementation(() => ({ + set: vi.fn(), + get: vi.fn().mockReturnValue(null), + })), + }; +}); + +// Mock the ICacheManager +const mockCacheManager = { + get: vi.fn().mockResolvedValue(null), + set: vi.fn(), +}; + +describe("Depin Data provider", () => { + let depinscan: DePINScanProvider; + + beforeEach(() => { + vi.clearAllMocks(); + mockCacheManager.get.mockResolvedValue(null); + + depinscan = new DePINScanProvider(mockCacheManager as any); + }); + + afterEach(() => { + vi.clearAllTimers(); + }); + + describe("Cache Management", () => { + it("should use cached data when available", async () => { + mockCacheManager.get.mockResolvedValueOnce(mockDepinscanMetrics); + + const result = await (depinscan as any).getCachedData("test-key"); + + expect(result).toEqual(mockDepinscanMetrics); + expect(mockCacheManager.get).toHaveBeenCalledTimes(1); + }); + + it("should write data to both caches", async () => { + await (depinscan as any).setCachedData( + "test-key", + mockDepinscanMetrics + ); + + expect(mockCacheManager.set).toHaveBeenCalledWith( + expect.stringContaining("test-key"), + mockDepinscanMetrics, + expect.any(Object) + ); + }); + }); + + it("should fetch depinscan metrics", async () => { + const metrics = await depinscan.getDailyMetrics(); + + expect(metrics).toEqual(mockDepinscanMetrics); + }); + it("should fetch depinscan projects", async () => { + const projects = await depinscan.getProjects(); + + expect(projects).toEqual(parsedProjectsSample); + }); +}); diff --git a/packages/plugin-depin/src/test/sampleData.ts b/packages/plugin-depin/src/test/sampleData.ts new file mode 100644 index 00000000000..b749193e0f2 --- /dev/null +++ b/packages/plugin-depin/src/test/sampleData.ts @@ -0,0 +1,104 @@ +export const mockDepinscanMetrics = [ + { + date: "2024-12-17", + total_projects: "291", + market_cap: "36046044620.57570635160", + total_device: "19416950", + }, +]; + +export const mockDepinscanProjects = [ + { + project_name: "Solana", + slug: "solana", + logo: "https://depinscan-prod.s3.us-east-1.amazonaws.com/next-s3-uploads/3160a9ec-42df-4f02-9db6-5aadc61323d8/solana.svg", + description: + "Solana is a general purpose layer 1 blockchain that works well for DePIN (decentralized physical infrastructure Network) projects due to its low transaction cost, high-throughput speed, scalability and existing Solana DePIN ecosystem. The most renowned Solana DePIN projects include Helium, Hivemapper and Render.", + trusted_metric: true, + token: "SOL", + layer_1: ["Solana"], + categories: ["Chain"], + market_cap: "106247097756.0147", + token_price: "221.91", + total_devices: 0, + network_status: "Mainnet", + avg_device_cost: "", + days_to_breakeven: "", + estimated_daily_earnings: "", + chainid: "", + coingecko_id: "solana", + fully_diluted_valuation: "131508718985", + }, + { + project_name: "Render", + slug: "render", + logo: "https://depinscan-prod.s3.amazonaws.com/depin/9e5f0bb330344d580b9e30d338d6ab6d.png", + description: + "Render is a decentralized rendering platform supporting next-generation media production.", + trusted_metric: true, + token: "RNDR", + layer_1: ["Solana"], + categories: ["Server", "AI"], + market_cap: "4659773671.856073", + token_price: "9.02", + total_devices: 0, + network_status: "Mainnet", + avg_device_cost: "", + days_to_breakeven: "", + estimated_daily_earnings: "", + chainid: "1", + coingecko_id: "render-token", + fully_diluted_valuation: "4705509105", + }, +]; + +export const parsedProjectsSample = [ + [ + "project_name", + "slug", + "token", + "layer_1", + "categories", + "market_cap", + "token_price", + "total_devices", + "avg_device_cost", + "days_to_breakeven", + "estimated_daily_earnings", + "chainid", + "coingecko_id", + "fully_diluted_valuation", + ], + [ + "Solana", + "solana", + "SOL", + "Solana", + "Chain", + "106.25B", + "221.91", + "0", + "", + "", + "", + "", + "solana", + "131.51B", + ], + [ + "Render", + "render", + "RNDR", + "Solana", + "Server, AI", + "4.66B", + "9.02", + "0", + "", + "", + "", + "1", + "render-token", + "4.71B", + ], +]; diff --git a/packages/plugin-depin/src/types/depin.ts b/packages/plugin-depin/src/types/depin.ts new file mode 100644 index 00000000000..5c156b6339f --- /dev/null +++ b/packages/plugin-depin/src/types/depin.ts @@ -0,0 +1,23 @@ +export type DepinScanMetrics = { + date: string; + total_projects: string; + market_cap: string; + total_device: string; +}; + +export type DepinScanProject = { + project_name: string; + slug: string; + token: string; + layer_1: string[]; + categories: string[]; + market_cap: string; + token_price: string; + total_devices: string; + avg_device_cost: string; + days_to_breakeven: string; + estimated_daily_earnings: string; + chainid: string; + coingecko_id: string; + fully_diluted_valuation: string; +}; diff --git a/packages/plugin-depin/tsconfig.json b/packages/plugin-depin/tsconfig.json new file mode 100644 index 00000000000..2d8d3fe8181 --- /dev/null +++ b/packages/plugin-depin/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "./src", + "typeRoots": [ + "./node_modules/@types", + "./src/types" + ], + "declaration": true + }, + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/packages/plugin-depin/tsup.config.ts b/packages/plugin-depin/tsup.config.ts new file mode 100644 index 00000000000..c0af60c6ab7 --- /dev/null +++ b/packages/plugin-depin/tsup.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], + external: [ + "dotenv", + "fs", + "path", + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + "events", + "node-cache", + "axios" + ], +}); diff --git a/packages/plugin-evm/src/providers/wallet.ts b/packages/plugin-evm/src/providers/wallet.ts index fa7e712dce2..ae05779dabf 100644 --- a/packages/plugin-evm/src/providers/wallet.ts +++ b/packages/plugin-evm/src/providers/wallet.ts @@ -34,7 +34,7 @@ export class WalletProvider { private cacheKey: string = "evm/wallet"; private currentChain: SupportedChain = "mainnet"; private CACHE_EXPIRY_SEC = 5; - chains: Record = { mainnet: viemChains.mainnet }; + chains: Record = { ...viemChains }; account: PrivateKeyAccount; constructor( diff --git a/packages/plugin-movement/.npmignore b/packages/plugin-movement/.npmignore new file mode 100644 index 00000000000..078562eceab --- /dev/null +++ b/packages/plugin-movement/.npmignore @@ -0,0 +1,6 @@ +* + +!dist/** +!package.json +!readme.md +!tsup.config.ts \ No newline at end of file diff --git a/packages/plugin-movement/eslint.config.mjs b/packages/plugin-movement/eslint.config.mjs new file mode 100644 index 00000000000..92fe5bbebef --- /dev/null +++ b/packages/plugin-movement/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-movement/package.json b/packages/plugin-movement/package.json new file mode 100644 index 00000000000..2396c2c80b3 --- /dev/null +++ b/packages/plugin-movement/package.json @@ -0,0 +1,30 @@ +{ + "name": "@elizaos/plugin-movement", + "version": "0.1.0", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "description": "Movement Network Plugin for Eliza", + "dependencies": { + "@elizaos/core": "workspace:*", + "@aptos-labs/ts-sdk": "^1.26.0", + "bignumber": "1.1.0", + "bignumber.js": "9.1.2", + "node-cache": "5.1.2" + }, + "devDependencies": { + "tsup": "8.3.5", + "vitest": "2.1.4", + "typescript": "^5.0.0" + }, + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "lint": "eslint --fix --cache .", + "test": "vitest run" + }, + "peerDependencies": { + "form-data": "4.0.1", + "whatwg-url": "7.1.0" + } +} diff --git a/packages/plugin-movement/readme.md b/packages/plugin-movement/readme.md new file mode 100644 index 00000000000..cecd6fee599 --- /dev/null +++ b/packages/plugin-movement/readme.md @@ -0,0 +1,43 @@ +# @elizaos/plugin-movement + +Movement Network plugin for Eliza OS. This plugin enables Movement Network blockchain functionality for your Eliza agent. + +## Features + +- Send MOVE tokens +- Check wallet balances +- Support for Movement Network transactions + +## Installation + +```bash +pnpm add @elizaos/plugin-movement +``` + +## Instructions + +1. First, ensure you have a Movement Network wallet and private key. + +2. Add the Movement plugin to your character's configuration: + +```json +{ +"name": "Movement Agent", +"plugins": ["@elizaos/plugin-movement"], +"settings": { +"secrets": { +"MOVEMENT_PRIVATE_KEY": "your_private_key_here", +"MOVEMENT_NETWORK": "bardock" +} +} +} +``` + +Set up your environment variables in the `.env` file: + +```bash +MOVEMENT_PRIVATE_KEY=your_private_key_here +MOVEMENT_NETWORK=bardock +``` + + diff --git a/packages/plugin-movement/src/actions/transfer.ts b/packages/plugin-movement/src/actions/transfer.ts new file mode 100644 index 00000000000..43490fbcb65 --- /dev/null +++ b/packages/plugin-movement/src/actions/transfer.ts @@ -0,0 +1,261 @@ +import { elizaLogger } from "@elizaos/core"; +import { + ActionExample, + Content, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, + type Action, +} from "@elizaos/core"; +import { composeContext } from "@elizaos/core"; +import { generateObjectDeprecated } from "@elizaos/core"; +import { + Account, + Aptos, + AptosConfig, + Ed25519PrivateKey, + Network, + PrivateKey, + PrivateKeyVariants, +} from "@aptos-labs/ts-sdk"; +import { walletProvider } from "../providers/wallet"; +import { MOVEMENT_NETWORK_CONFIG, MOVE_DECIMALS, MOVEMENT_EXPLORER_URL } from "../constants"; + +export interface TransferContent extends Content { + recipient: string; + amount: string | number; +} + +function isTransferContent(content: any): content is TransferContent { + elizaLogger.debug("Validating transfer content:", content); + return ( + typeof content.recipient === "string" && + (typeof content.amount === "string" || + typeof content.amount === "number") + ); +} + +const transferTemplate = `You are processing a token transfer request. Extract the recipient address and amount from the message. + +Example request: "can you send 1 move to 0x123..." +Example response: +\`\`\`json +{ + "recipient": "0x123...", + "amount": "1" +} +\`\`\` + +Rules: +1. The recipient address always starts with "0x" +2. The amount is typically a number less than 100 +3. Return exact values found in the message + +Recent messages: +{{recentMessages}} + +Extract and return ONLY the following in a JSON block: +- recipient: The wallet address starting with 0x +- amount: The number of tokens to send + +Return ONLY the JSON block with these two fields.`; + +export default { + name: "TRANSFER_MOVE", + similes: [ + "SEND_TOKEN", + "TRANSFER_TOKEN", + "TRANSFER_TOKENS", + "SEND_TOKENS", + "SEND_MOVE", + "PAY", + ], + triggers: [ + "send move", + "send 1 move", + "transfer move", + "send token", + "transfer token", + "can you send", + "please send", + "send" + ], + shouldHandle: (message: Memory) => { + const text = message.content?.text?.toLowerCase() || ""; + return text.includes("send") && text.includes("move") && text.includes("0x"); + }, + validate: async (runtime: IAgentRuntime, message: Memory) => { + elizaLogger.debug("Starting transfer validation for user:", message.userId); + elizaLogger.debug("Message text:", message.content?.text); + return true; // Let the handler do the validation + }, + priority: 1000, // High priority for transfer actions + description: "Transfer Move tokens from the agent's wallet to another address", + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + _options: { [key: string]: unknown }, + callback?: HandlerCallback + ): Promise => { + elizaLogger.debug("Starting TRANSFER_MOVE handler..."); + elizaLogger.debug("Message:", { + text: message.content?.text, + userId: message.userId, + action: message.content?.action + }); + + try { + const privateKey = runtime.getSetting("MOVEMENT_PRIVATE_KEY"); + elizaLogger.debug("Got private key:", privateKey ? "Present" : "Missing"); + + const network = runtime.getSetting("MOVEMENT_NETWORK"); + elizaLogger.debug("Network config:", network); + elizaLogger.debug("Available networks:", Object.keys(MOVEMENT_NETWORK_CONFIG)); + + const movementAccount = Account.fromPrivateKey({ + privateKey: new Ed25519PrivateKey( + PrivateKey.formatPrivateKey( + privateKey, + PrivateKeyVariants.Ed25519 + ) + ), + }); + elizaLogger.debug("Created Movement account:", movementAccount.accountAddress.toStringLong()); + + const aptosClient = new Aptos( + new AptosConfig({ + network: Network.CUSTOM, + fullnode: MOVEMENT_NETWORK_CONFIG[network].fullnode + }) + ); + elizaLogger.debug("Created Aptos client with network:", MOVEMENT_NETWORK_CONFIG[network].fullnode); + + const walletInfo = await walletProvider.get(runtime, message, state); + state.walletInfo = walletInfo; + + // Initialize or update state + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + // Compose transfer context + const transferContext = composeContext({ + state, + template: transferTemplate, + }); + + // Generate transfer content + const content = await generateObjectDeprecated({ + runtime, + context: transferContext, + modelClass: ModelClass.SMALL, + }); + + // Validate transfer content + if (!isTransferContent(content)) { + console.error("Invalid content for TRANSFER_TOKEN action."); + if (callback) { + callback({ + text: "Unable to process transfer request. Invalid content provided.", + content: { error: "Invalid transfer content" }, + }); + } + return false; + } + + const adjustedAmount = BigInt( + Number(content.amount) * Math.pow(10, MOVE_DECIMALS) + ); + console.log( + `Transferring: ${content.amount} tokens (${adjustedAmount} base units)` + ); + + const tx = await aptosClient.transaction.build.simple({ + sender: movementAccount.accountAddress.toStringLong(), + data: { + function: "0x1::aptos_account::transfer", + typeArguments: [], + functionArguments: [content.recipient, adjustedAmount], + }, + }); + const committedTransaction = + await aptosClient.signAndSubmitTransaction({ + signer: movementAccount, + transaction: tx, + }); + const executedTransaction = await aptosClient.waitForTransaction({ + transactionHash: committedTransaction.hash, + }); + + const explorerUrl = `${MOVEMENT_EXPLORER_URL}/${executedTransaction.hash}?network=${MOVEMENT_NETWORK_CONFIG[network].explorerNetwork}`; + elizaLogger.debug("Transfer successful:", { + hash: executedTransaction.hash, + amount: content.amount, + recipient: content.recipient, + explorerUrl + }); + + if (callback) { + callback({ + text: `Successfully transferred ${content.amount} MOVE to ${content.recipient}\nTransaction: ${executedTransaction.hash}\nView on Explorer: ${explorerUrl}`, + content: { + success: true, + hash: executedTransaction.hash, + amount: content.amount, + recipient: content.recipient, + explorerUrl + }, + }); + } + + return true; + } catch (error) { + console.error("Error during token transfer:", error); + if (callback) { + callback({ + text: `Error transferring tokens: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + }, + + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "can you send 1 move to 0xa07ab7d3739dc793f9d538f7d7163705176ba59f7a8c994a07357a3a7d97d843", + }, + }, + { + user: "{{user2}}", + content: { + text: "I'll help you transfer 1 Move token...", + action: "TRANSFER_MOVE", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "send 1 move to 0xa07ab7d3739dc793f9d538f7d7163705176ba59f7a8c994a07357a3a7d97d843", + }, + }, + { + user: "{{user2}}", + content: { + text: "Processing Move token transfer...", + action: "TRANSFER_MOVE", + }, + }, + ] + ] as ActionExample[][], +} as Action; diff --git a/packages/plugin-movement/src/constants.ts b/packages/plugin-movement/src/constants.ts new file mode 100644 index 00000000000..8a9c84847ce --- /dev/null +++ b/packages/plugin-movement/src/constants.ts @@ -0,0 +1,19 @@ +export const MOVE_DECIMALS = 8; + +export const MOVEMENT_NETWORK_CONFIG = { + mainnet: { + fullnode: 'https://mainnet.movementnetwork.xyz/v1', + chainId: '126', + name: 'Movement Mainnet', + explorerNetwork: 'mainnet' + }, + bardock: { + fullnode: 'https://aptos.testnet.bardock.movementlabs.xyz/v1', + chainId: '250', + name: 'Movement Bardock Testnet', + explorerNetwork: 'bardock+testnet' + } +} as const; + +export const DEFAULT_NETWORK = 'bardock'; +export const MOVEMENT_EXPLORER_URL = 'https://explorer.movementnetwork.xyz/txn'; \ No newline at end of file diff --git a/packages/plugin-movement/src/environment.ts b/packages/plugin-movement/src/environment.ts new file mode 100644 index 00000000000..96081dbe97d --- /dev/null +++ b/packages/plugin-movement/src/environment.ts @@ -0,0 +1,37 @@ +import { IAgentRuntime } from "@elizaos/core"; +import { z } from "zod"; + +export const movementEnvSchema = z.object({ + MOVEMENT_PRIVATE_KEY: z.string().min(1, "Movement private key is required"), + MOVEMENT_NETWORK: z.enum(["mainnet", "bardock"]).default("bardock"), +}); + +export type MovementConfig = z.infer; + +export async function validateMovementConfig( + runtime: IAgentRuntime +): Promise { + try { + const config = { + MOVEMENT_PRIVATE_KEY: + runtime.getSetting("MOVEMENT_PRIVATE_KEY") || + process.env.MOVEMENT_PRIVATE_KEY, + MOVEMENT_NETWORK: + runtime.getSetting("MOVEMENT_NETWORK") || + process.env.MOVEMENT_NETWORK || + "bardock", + }; + + return movementEnvSchema.parse(config); + } catch (error) { + if (error instanceof z.ZodError) { + const errorMessages = error.errors + .map((err) => `${err.path.join(".")}: ${err.message}`) + .join("\n"); + throw new Error( + `Movement configuration validation failed:\n${errorMessages}` + ); + } + throw error; + } +} \ No newline at end of file diff --git a/packages/plugin-movement/src/index.ts b/packages/plugin-movement/src/index.ts new file mode 100644 index 00000000000..d8d54ba2438 --- /dev/null +++ b/packages/plugin-movement/src/index.ts @@ -0,0 +1,15 @@ +import { Plugin } from "@elizaos/core"; +import transferToken from "./actions/transfer"; +import { WalletProvider, walletProvider } from "./providers/wallet"; + +export { WalletProvider, transferToken as TransferMovementToken }; + +export const movementPlugin: Plugin = { + name: "movement", + description: "Movement Network Plugin for Eliza", + actions: [transferToken], + evaluators: [], + providers: [walletProvider], +}; + +export default movementPlugin; diff --git a/packages/plugin-movement/src/providers/wallet.ts b/packages/plugin-movement/src/providers/wallet.ts new file mode 100644 index 00000000000..90b6d1ac21e --- /dev/null +++ b/packages/plugin-movement/src/providers/wallet.ts @@ -0,0 +1,258 @@ +import { + IAgentRuntime, + ICacheManager, + Memory, + Provider, + State, +} from "@elizaos/core"; +import { + Account, + Aptos, + AptosConfig, + Ed25519PrivateKey, + Network, + PrivateKey, + PrivateKeyVariants, +} from "@aptos-labs/ts-sdk"; +import BigNumber from "bignumber.js"; +import NodeCache from "node-cache"; +import * as path from "path"; +import { MOVE_DECIMALS, MOVEMENT_NETWORK_CONFIG } from "../constants"; + +// Provider configuration +const PROVIDER_CONFIG = { + MAX_RETRIES: 3, + RETRY_DELAY: 2000, +}; + +interface WalletPortfolio { + totalUsd: string; + totalMove: string; +} + +interface Prices { + move: { usd: string }; +} + +export class WalletProvider { + private cache: NodeCache; + private cacheKey: string = "movement/wallet"; + + constructor( + private aptosClient: Aptos, + private address: string, + private cacheManager: ICacheManager + ) { + this.cache = new NodeCache({ stdTTL: 300 }); // Cache TTL set to 5 minutes + } + + private async readFromCache(key: string): Promise { + const cached = await this.cacheManager.get( + path.join(this.cacheKey, key) + ); + return cached; + } + + private async writeToCache(key: string, data: T): Promise { + await this.cacheManager.set(path.join(this.cacheKey, key), data, { + expires: Date.now() + 5 * 60 * 1000, + }); + } + + private async getCachedData(key: string): Promise { + // Check in-memory cache first + const cachedData = this.cache.get(key); + if (cachedData) { + return cachedData; + } + + // Check file-based cache + const fileCachedData = await this.readFromCache(key); + if (fileCachedData) { + // Populate in-memory cache + this.cache.set(key, fileCachedData); + return fileCachedData; + } + + return null; + } + + private async setCachedData(cacheKey: string, data: T): Promise { + // Set in-memory cache + this.cache.set(cacheKey, data); + + // Write to file-based cache + await this.writeToCache(cacheKey, data); + } + + private async fetchPricesWithRetry() { + let lastError: Error; + + for (let i = 0; i < PROVIDER_CONFIG.MAX_RETRIES; i++) { + try { + const MoveUsdcPoolAddr = + "0xA04d13F092f68F603A193832222898B0d9f52c71"; + const response = await fetch( + `https://api.dexscreener.com/latest/dex/pairs/ethereum/${MoveUsdcPoolAddr}` + ); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error( + `HTTP error! status: ${response.status}, message: ${errorText}` + ); + } + + const data = await response.json(); + return data; + } catch (error) { + console.error(`Attempt ${i + 1} failed:`, error); + lastError = error; + if (i < PROVIDER_CONFIG.MAX_RETRIES - 1) { + const delay = PROVIDER_CONFIG.RETRY_DELAY * Math.pow(2, i); + await new Promise((resolve) => setTimeout(resolve, delay)); + continue; + } + } + } + + console.error( + "All attempts failed. Throwing the last error:", + lastError + ); + throw lastError; + } + + async fetchPortfolioValue(): Promise { + try { + const cacheKey = `portfolio-${this.address}`; + const cachedValue = + await this.getCachedData(cacheKey); + + if (cachedValue) { + console.log("Cache hit for fetchPortfolioValue", cachedValue); + return cachedValue; + } + console.log("Cache miss for fetchPortfolioValue"); + + const prices = await this.fetchPrices().catch((error) => { + console.error("Error fetching Move price:", error); + throw error; + }); + const moveAmountOnChain = await this.aptosClient + .getAccountAPTAmount({ + accountAddress: this.address, + }) + .catch((error) => { + console.error("Error fetching Move amount:", error); + throw error; + }); + + const moveAmount = new BigNumber(moveAmountOnChain).div( + new BigNumber(10).pow(MOVE_DECIMALS) + ); + const totalUsd = new BigNumber(moveAmount).times(prices.move.usd); + + const portfolio = { + totalUsd: totalUsd.toString(), + totalMove: moveAmount.toString(), + }; + this.setCachedData(cacheKey, portfolio); + console.log("Fetched portfolio:", portfolio); + return portfolio; + } catch (error) { + console.error("Error fetching portfolio:", error); + throw error; + } + } + + async fetchPrices(): Promise { + try { + const cacheKey = "prices"; + const cachedValue = await this.getCachedData(cacheKey); + + if (cachedValue) { + console.log("Cache hit for fetchPrices"); + return cachedValue; + } + console.log("Cache miss for fetchPrices"); + + const movePriceData = await this.fetchPricesWithRetry().catch( + (error) => { + console.error("Error fetching Move price:", error); + throw error; + } + ); + const prices: Prices = { + move: { usd: movePriceData.pair.priceUsd }, + }; + this.setCachedData(cacheKey, prices); + return prices; + } catch (error) { + console.error("Error fetching prices:", error); + throw error; + } + } + + formatPortfolio(runtime, portfolio: WalletPortfolio): string { + let output = `${runtime.character.name}\n`; + output += `Wallet Address: ${this.address}\n`; + + const totalUsdFormatted = new BigNumber(portfolio.totalUsd).toFixed(2); + const totalMoveFormatted = new BigNumber(portfolio.totalMove).toFixed(4); + + output += `Total Value: $${totalUsdFormatted} (${totalMoveFormatted} Move)\n`; + + return output; + } + + async getFormattedPortfolio(runtime): Promise { + try { + const portfolio = await this.fetchPortfolioValue(); + return this.formatPortfolio(runtime, portfolio); + } catch (error) { + console.error("Error generating portfolio report:", error); + return "Unable to fetch wallet information. Please try again later."; + } + } +} + +const walletProvider: Provider = { + get: async ( + runtime: IAgentRuntime, + _message: Memory, + _state?: State + ): Promise => { + const privateKey = runtime.getSetting("MOVEMENT_PRIVATE_KEY"); + const movementAccount = Account.fromPrivateKey({ + privateKey: new Ed25519PrivateKey( + PrivateKey.formatPrivateKey( + privateKey, + PrivateKeyVariants.Ed25519 + ) + ), + }); + const network = runtime.getSetting("MOVEMENT_NETWORK") as Network; + + try { + const aptosClient = new Aptos( + new AptosConfig({ + network: Network.CUSTOM, + fullnode: MOVEMENT_NETWORK_CONFIG[network].fullnode + }) + ); + const provider = new WalletProvider( + aptosClient, + movementAccount.accountAddress.toStringLong(), + runtime.cacheManager + ); + return await provider.getFormattedPortfolio(runtime); + } catch (error) { + console.error("Error in wallet provider:", error); + return null; + } + }, +}; + +// Module exports +export { walletProvider }; diff --git a/packages/plugin-movement/src/tests/transfer.test.ts b/packages/plugin-movement/src/tests/transfer.test.ts new file mode 100644 index 00000000000..e98689a0020 --- /dev/null +++ b/packages/plugin-movement/src/tests/transfer.test.ts @@ -0,0 +1,20 @@ +import { describe, it, expect, beforeEach, vi } from "vitest"; +import transferAction from "../actions/transfer"; + +describe("Movement Transfer Action", () => { + describe("Action Configuration", () => { + it("should have correct action name and triggers", () => { + expect(transferAction.name).toBe("TRANSFER_MOVE"); + expect(transferAction.triggers).toContain("send move"); + expect(transferAction.priority).toBe(1000); + }); + + it("should validate transfer messages correctly", () => { + const validMessage = "send 1 move to 0x123"; + const invalidMessage = "hello world"; + + expect(transferAction.shouldHandle({ content: { text: validMessage }})).toBe(true); + expect(transferAction.shouldHandle({ content: { text: invalidMessage }})).toBe(false); + }); + }); +}); \ No newline at end of file diff --git a/packages/plugin-movement/src/tests/wallet.test.ts b/packages/plugin-movement/src/tests/wallet.test.ts new file mode 100644 index 00000000000..833426cc2e7 --- /dev/null +++ b/packages/plugin-movement/src/tests/wallet.test.ts @@ -0,0 +1,144 @@ +import { describe, it, expect, beforeEach, vi, afterEach } from "vitest"; +import { WalletProvider } from "../providers/wallet"; +import { + Account, + Aptos, + AptosConfig, + Ed25519PrivateKey, + Network, + PrivateKey, + PrivateKeyVariants, +} from "@aptos-labs/ts-sdk"; +import { defaultCharacter } from "@elizaos/core"; +import BigNumber from "bignumber.js"; +import { MOVE_DECIMALS, MOVEMENT_NETWORK_CONFIG } from "../constants"; + +// Mock NodeCache +vi.mock("node-cache", () => { + return { + default: vi.fn().mockImplementation(() => ({ + set: vi.fn(), + get: vi.fn().mockReturnValue(null), + })), + }; +}); + +// Mock path module +vi.mock("path", async () => { + const actual = await vi.importActual("path"); + return { + ...actual, + join: vi.fn().mockImplementation((...args) => args.join("/")), + }; +}); + +// Mock the ICacheManager +const mockCacheManager = { + get: vi.fn().mockResolvedValue(null), + set: vi.fn(), + delete: vi.fn(), +}; + +describe("WalletProvider", () => { + let walletProvider; + let mockedRuntime; + + beforeEach(() => { + vi.clearAllMocks(); + mockCacheManager.get.mockResolvedValue(null); + + const aptosClient = new Aptos( + new AptosConfig({ + network: Network.CUSTOM, + fullnode: MOVEMENT_NETWORK_CONFIG.bardock.fullnode + }) + ); + const movementAccount = Account.fromPrivateKey({ + privateKey: new Ed25519PrivateKey( + PrivateKey.formatPrivateKey( + // this is a test private key - DO NOT USE IN PRODUCTION + "0x5b4ca82e1835dcc51e58a3dec44b857edf60a26156b00f73d74bf96f5daecfb5", + PrivateKeyVariants.Ed25519 + ) + ), + }); + + // Create new instance of WalletProvider with Movement configuration + walletProvider = new WalletProvider( + aptosClient, + movementAccount.accountAddress.toStringLong(), + mockCacheManager + ); + + mockedRuntime = { + character: { + ...defaultCharacter, + settings: { + secrets: { + MOVEMENT_PRIVATE_KEY: "0x5b4ca82e1835dcc51e58a3dec44b857edf60a26156b00f73d74bf96f5daecfb5", + MOVEMENT_NETWORK: "bardock" + } + } + }, + }; + }); + + afterEach(() => { + vi.clearAllTimers(); + }); + + describe("Movement Wallet Integration", () => { + it("should check wallet address and balance", async () => { + const result = await walletProvider.getFormattedPortfolio(mockedRuntime); + + const prices = await walletProvider.fetchPrices(); + const moveAmountOnChain = await walletProvider.aptosClient.getAccountAPTAmount({ + accountAddress: walletProvider.address, + }); + const moveAmount = new BigNumber(moveAmountOnChain) + .div(new BigNumber(10).pow(MOVE_DECIMALS)) + .toFixed(4); + const totalUsd = new BigNumber(moveAmount) + .times(prices.move.usd) + .toFixed(2); + + expect(result).toContain(walletProvider.address); + expect(result).toContain(`$${totalUsd}`); + expect(result).toContain(`${moveAmount} Move`); + + expect(result).toContain('Total Value:'); + expect(result).toContain('Wallet Address:'); + }); + + it("should fetch Movement token prices", async () => { + const prices = await walletProvider.fetchPrices(); + expect(prices).toHaveProperty("move.usd"); + expect(["string", "number"]).toContain(typeof prices.move.usd); + }); + + it("should cache wallet info", async () => { + await walletProvider.getFormattedPortfolio(mockedRuntime); + expect(mockCacheManager.set).toHaveBeenCalled(); + }); + + it("should use cached wallet info when available", async () => { + const cachedInfo = { + totalUsd: "100.00", + totalMove: "50.0000" + }; + mockCacheManager.get.mockResolvedValueOnce(cachedInfo); + + const result = await walletProvider.getFormattedPortfolio(mockedRuntime); + expect(result).toContain(cachedInfo.totalUsd); + expect(result).toContain(cachedInfo.totalMove); + }); + + it("should handle network errors gracefully", async () => { + const mockError = new Error("Network error"); + vi.spyOn(walletProvider.aptosClient, "getAccountAPTAmount").mockRejectedValueOnce(mockError); + + const result = await walletProvider.getFormattedPortfolio(mockedRuntime); + expect(result).toBe("Unable to fetch wallet information. Please try again later."); + }); + }); +}); diff --git a/packages/plugin-movement/tsconfig.json b/packages/plugin-movement/tsconfig.json new file mode 100644 index 00000000000..73993deaaf7 --- /dev/null +++ b/packages/plugin-movement/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": [ + "src/**/*.ts" + ] +} \ No newline at end of file diff --git a/packages/plugin-movement/tsup.config.ts b/packages/plugin-movement/tsup.config.ts new file mode 100644 index 00000000000..682efa51ea3 --- /dev/null +++ b/packages/plugin-movement/tsup.config.ts @@ -0,0 +1,31 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], + dts: true, + minify: false, + splitting: false, + external: [ + "@elizaos/core", + "@aptos-labs/ts-sdk", + "bignumber", + "bignumber.js", + "node-cache", + "dotenv", + "fs", + "path", + "https", + "http", + "stream", + "buffer", + "querystring" + ], + noExternal: [], + esbuildOptions(options) { + options.platform = 'node' + } +}); diff --git a/packages/plugin-node/src/services/transcription.ts b/packages/plugin-node/src/services/transcription.ts index d8e39ee2dae..5627f86f064 100644 --- a/packages/plugin-node/src/services/transcription.ts +++ b/packages/plugin-node/src/services/transcription.ts @@ -355,7 +355,8 @@ export class TranscriptionService try { await this.saveDebugAudio(audioBuffer, "openai_input_original"); - const convertedBuffer = await this.convertAudio(audioBuffer); + const arrayBuffer = new Uint8Array(audioBuffer).buffer; + const convertedBuffer = Buffer.from(await this.convertAudio(arrayBuffer)).buffer; await this.saveDebugAudio( convertedBuffer, @@ -407,7 +408,8 @@ export class TranscriptionService await this.saveDebugAudio(audioBuffer, "local_input_original"); - const convertedBuffer = await this.convertAudio(audioBuffer); + const arrayBuffer = new Uint8Array(audioBuffer).buffer; + const convertedBuffer = Buffer.from(await this.convertAudio(arrayBuffer)).buffer; await this.saveDebugAudio(convertedBuffer, "local_input_converted"); @@ -415,7 +417,10 @@ export class TranscriptionService this.CONTENT_CACHE_DIR, `temp_${Date.now()}.wav` ); - fs.writeFileSync(tempWavFile, convertedBuffer); + + // Convert the ArrayBuffer to a Uint8Array which fs.writeFileSync can handle + const uint8Array = new Uint8Array(convertedBuffer); + fs.writeFileSync(tempWavFile, uint8Array); elizaLogger.debug(`Temporary WAV file created: ${tempWavFile}`); diff --git a/packages/plugin-node/src/services/video.ts b/packages/plugin-node/src/services/video.ts index fc3190abea7..8efe36a62b1 100644 --- a/packages/plugin-node/src/services/video.ts +++ b/packages/plugin-node/src/services/video.ts @@ -347,7 +347,8 @@ export class VideoService extends Service implements IVideoService { throw new Error("Transcription service not found"); } - const transcript = await transcriptionService.transcribe(audioBuffer); + const uintBuffer = new Uint8Array(audioBuffer).buffer; + const transcript = await transcriptionService.transcribe(uintBuffer); const endTime = Date.now(); elizaLogger.log( diff --git a/packages/plugin-obsidian/.npmignore b/packages/plugin-obsidian/.npmignore new file mode 100644 index 00000000000..078562eceab --- /dev/null +++ b/packages/plugin-obsidian/.npmignore @@ -0,0 +1,6 @@ +* + +!dist/** +!package.json +!readme.md +!tsup.config.ts \ No newline at end of file diff --git a/packages/plugin-obsidian/README.md b/packages/plugin-obsidian/README.md new file mode 100644 index 00000000000..9368dd7ac22 --- /dev/null +++ b/packages/plugin-obsidian/README.md @@ -0,0 +1,234 @@ +# @elizaos/plugin-obsidian + +An Obsidian plugin for ELIZA OS that provides seamless integration with Obsidian vaults, enabling powerful file and note management capabilities. + +## Features + +1. Deep traversal of Obsidian notes: + - Implementing hierarchical note structure analysis + - Enabling traversal of note links and backlinks + - Storing hierarchy data in memory for efficient access + +2. Advanced search functionality: + - Full-text search across all vault files + - Support for regex patterns and context-aware searches + - Integration with Obsidian's native search capabilities using Obsidian's Rest API + +3. Obsidian memory store integration: + - Building and maintaining a knowledge base from vault notes + - Implementing efficient data structures for quick retrieval + +4. Naval database integration as an example: + - Demonstrating how to import and structure obsidian notes in the agent memory + - Showcasing integration of Naval's wisdom and quotes + - Creating a knowledge base from Naval's vault notes for the agent + - Naval's character json file is included in the PR for reference (found in the example directory) + +### Vault Operations + +- **List Files** + - Get all files in the vault + + ```typescript + // List all files + const files = await obsidian.listFiles(); // Example: "List all files" + ``` + +- **Directory Management** + - List directory contents + + ```typescript + // List directory contents + const contents = await obsidian.listDirectory("path/to/dir"); // Example: "List directory PATH" or "ls PATH" + ``` + +### Note Management + +- **Note Retrieval** + - Get note content and metadata + - Support for frontmatter parsing + + ```typescript + // Get a note with its content + const note = await obsidian.getNote("path/to/note.md"); // Example: "Get note PATH" + ``` + +- **Deep Traversal** + - Build hierarchical note structures + - Store hierarchy data in memory + - Traverse note links and backlinks + + ```typescript + // Traverse notes links + const hierarchy = buildLinkHierarchy("path/to/start-note.md"); // Example: "Map links in PATH" + ``` + +- **Create Knowledge Bases** + - Build memory knowledge base from vault notes + + ```typescript + // Build knowledge base + const knowledgeBase = await obsidian.createMemoriesFromFiles(); // Example: "Create knowledge base" + ``` + +### Search Capabilities + +- **Full-Text Search** + - Search across all vault files + - Support for regex patterns + - Support for context search + - Support for frontmatter search + + ```typescript + // Search in vault + const results = await obsidian.search("query"); + // Examples: "Search QUERY" or "find notes with 'YOUR QUERY'" or "search notes named 'FILENAME'" + ``` + +### File Operations + +- **Read Files** + - Read files in the Obsidian Vault + + ```typescript + // Open a file in Obsidian + await obsidian.readFile("DOCUMENTS/report.txt"); // Example: "Read DOCUMENTS/report.txt" + ``` + +- **Create/Save Files** + - Create new files with automatic directory creation + - Save content to existing files + - Support for various file types + + ```typescript + // Create or update a file + await obsidian.saveFile("DOCUMENTS/report.txt", "Content", true); // Example: "Save DOCUMENTS/report.txt" + ``` + +- **Open Files** + - Open files in the Obsidian Vault + - Seamless integration with Obsidian's Rest API + + ```typescript + // Open a file in Obsidian + await obsidian.openFile("DOCUMENTS/report.txt"); // Example: "Open DOCUMENTS/report.txt" + ``` + +- **Update Files** + - Update existing files without creating new ones + - Line-specific updates supported + + ```typescript + // Update an existing file + await obsidian.patchFile("DOCUMENTS/report.txt", "New content"); // Example: "Update DOCUMENTS/report.txt" + ``` + +## Installation + +```bash +npm install @elizaos/plugin-obsidian +# or +yarn add @elizaos/plugin-obsidian +# or +pnpm add @elizaos/plugin-obsidian +``` + +## Configuration + +The plugin requires the following character secret settings: + +```json +{ + "settings": { + "secrets": { + "OBSIDIAN_API_TOKEN": "your-obsidian-api-token", + "OBSIDIAN_API_PORT": "your-obsidian-api-port", // Optional (default: 27123) + "OBSIDIAN_API_URL": "https://your-obsidian-api-url" , // Optional (default: "http://127.0.0.1:27123") + }, + // other settings... + } +} +``` + +## Usage + +Import and register the plugin in your Eliza agent configuration: + +```typescript +import { obsidianPlugin } from '@elizaos/plugin-obsidian'; + +export default { + plugins: [ + // other plugins... + getSecret(character, "OBSIDIAN_API_TOKEN") ? obsidianPlugin : null, + // other plugins... + ] +}; +``` + +## Development + +```bash +# Build the plugin +pnpm build + +# Run in development mode +pnpm dev + +# Run tests +pnpm test + +# Run linting +pnpm lint +``` + +## Actions + +The plugin provides several actions that can be used with ELIZA OS: + +- `SAVE_FILE`: Create or update files +- `OPEN_FILE`: Open files in Obsidian +- `UPDATE_FILE`: Update existing files +- `GET_NOTE`: Retrieve note content +- `NOTE_TRAVERSAL`: Build note hierarchies +- `SEARCH`: Search vault contents +- `LIST_FILES`: List vault files +- `LIST_DIRECTORY`: List directory contents +- `CREATE_KNOWLEDGE`: Generate knowledge bases +- `GET_ACTIVE_NOTE`: Get current note +- `SUMMARIZE_ACTIVE_NOTE`: Summarize current note + +## Error Handling + +The plugin provides detailed error messages and proper error handling: + +```typescript +try { + await obsidian.saveFile("path/to/file", "content"); +} catch (error) { + if (error.code === 'FILE_NOT_FOUND') { + // Handle file not found + } + // Handle other errors +} +``` + +## Contributing + +1. Fork the repository +2. Create your feature branch (`git checkout -b feature/amazing-feature`) +3. Commit your changes (`git commit -m 'Add amazing feature'`) +4. Push to the branch (`git push origin feature/amazing-feature`) +5. Open a Pull Request + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. + +## Support + +For support, please: + +1. Check the [documentation](https://docs.elizaos.com) +2. Open an issue in the repository +3. Join our [Discord community](https://discord.gg/elizaos) diff --git a/packages/plugin-obsidian/eslint.config.mjs b/packages/plugin-obsidian/eslint.config.mjs new file mode 100644 index 00000000000..92fe5bbebef --- /dev/null +++ b/packages/plugin-obsidian/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-obsidian/package.json b/packages/plugin-obsidian/package.json new file mode 100644 index 00000000000..29784d47f47 --- /dev/null +++ b/packages/plugin-obsidian/package.json @@ -0,0 +1,23 @@ +{ + "name": "@elizaos/plugin-obsidian", + "version": "0.1.7", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@elizaos/core": "workspace:*", + "file-type-checker": "^1.1.2", + "mrmime": "^2.0.0", + "tsup": "8.3.5" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "test": "vitest run", + "test:watch": "vitest", + "lint": "eslint --fix --cache ." + }, + "peerDependencies": { + "whatwg-url": "7.1.0" + } +} diff --git a/packages/plugin-obsidian/src/actions/activeNote.ts b/packages/plugin-obsidian/src/actions/activeNote.ts new file mode 100644 index 00000000000..40902fb9974 --- /dev/null +++ b/packages/plugin-obsidian/src/actions/activeNote.ts @@ -0,0 +1,234 @@ +import { + Action, + HandlerCallback, + IAgentRuntime, + Memory, + State, + elizaLogger, + composeContext, + ModelClass, + splitChunks, + trimTokens, + generateText, +} from "@elizaos/core"; +import { NoteContent } from "../types"; +import { baseSummaryTemplate } from "../templates/summary"; +import { getObsidian } from "../helper"; + +export const getActiveNoteAction: Action = { + name: "GET_ACTIVE_NOTE", + similes: [ + "FETCH_ACTIVE_NOTE", + "READ_ACTIVE_NOTE", + "CURRENT_NOTE", + "ACTIVE_NOTE", + "OPENED_NOTE", + "CURRENT_FILE", + ], + description: + "Retrieve and display the content of the currently active note in Obsidian", + validate: async (runtime: IAgentRuntime) => { + try { + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting get active note handler"); + const obsidian = await getObsidian(runtime); + + try { + elizaLogger.info("Fetching active note content"); + const noteContent: NoteContent = await obsidian.getActiveNote(); + + elizaLogger.info( + `Successfully retrieved active note: ${noteContent.path}` + ); + + if (callback) { + callback({ + text: noteContent.content, + metadata: { + path: noteContent.path, + }, + }); + } + return true; + } catch (error) { + elizaLogger.error("Error getting active note:", error); + if (callback) { + callback({ + text: `Error retrieving active note: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "What's in my current note?", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "GET_ACTIVE_NOTE", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Show me the active note", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "GET_ACTIVE_NOTE", + }, + }, + ], + ], +}; + +export const summarizeActiveNoteAction: Action = { + name: "SUMMARIZE_ACTIVE_NOTE", + similes: [ + "SUMMARIZE_ACTIVE_NOTE", + "SUMMARIZE_CURRENT_NOTE", + "SUMMARIZE_OPEN_NOTE", + ], + description: + "Generate a focused summary of the currently active note in Obsidian", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting summarize active note handler"); + const obsidian = await getObsidian(runtime); + + try { + elizaLogger.info("Fetching active note content"); + const noteContent: NoteContent = await obsidian.getActiveNote(); + + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + const chunkSize = 6500; + + const chunks = await splitChunks(noteContent.content, chunkSize, 0); + let currentSummary = ""; + + elizaLogger.info("Composing summary context"); + for (let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; + state.currentSummary = currentSummary; + state.currentChunk = chunk; + + const activeNoteTemplate = await trimTokens( + baseSummaryTemplate, + chunkSize, + runtime + ); + + const context = composeContext({ + state, + template: activeNoteTemplate, + }); + const summary = await generateText({ + runtime, + context, + modelClass: ModelClass.MEDIUM, + }); + + currentSummary = currentSummary + "\n" + summary; + } + if (!currentSummary) { + elizaLogger.error("Error: No summary found"); + return false; + } + if (callback) { + if ( + currentSummary.trim()?.split("\n").length < 4 || + currentSummary.trim()?.split(" ").length < 100 + ) { + callback({ + text: `Here is the summary:\n\`\`\`md\n${currentSummary.trim()}\n\`\`\``, + metadata: { + path: noteContent.path, + }, + }); + } else { + callback({ + text: currentSummary.trim(), + metadata: { + path: noteContent.path, + }, + }); + } + } + return true; + } catch (error) { + elizaLogger.error("Error summarizing active note:", error); + if (callback) { + callback({ + text: `Error summarizing active note: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Summarize my current note", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "SUMMARIZE_ACTIVE_NOTE", + }, + }, + ], + ], +}; diff --git a/packages/plugin-obsidian/src/actions/createKnowledge.ts b/packages/plugin-obsidian/src/actions/createKnowledge.ts new file mode 100644 index 00000000000..935f4cc6c04 --- /dev/null +++ b/packages/plugin-obsidian/src/actions/createKnowledge.ts @@ -0,0 +1,119 @@ +import { + Action, + HandlerCallback, + IAgentRuntime, + Memory, + State, + elizaLogger, +} from "@elizaos/core"; +import { getObsidian } from "../helper"; + +export const createKnowledgeAction: Action = { + name: "CREATE_KNOWLEDGE", + similes: [ + "BUILD_KNOWLEDGE", + "CREATE_KNOWLEDGE_BASE", + "CREATE_KNOWLEDGE_BASE", + "BUILD_KNOWLEDGE_BASE" + ], + description: + "Scan all markdown notes hierarchically in the Obsidian vault and build a memoryknowledge base. Use format: 'Create knowledge' or 'Build knowledge base'", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting create knowledge handler"); + const obsidian = await getObsidian(runtime); + + try { + elizaLogger.info("Fetching all notes from vault and creating knowledge base"); + elizaLogger.log("Be patient, this might take a while, depending on the size of your vault..."); + if (callback) { + callback({ + text: "This might take a while, depending on the size of your vault...", + error: false, + }); + } + try { + const notesMemorized = await obsidian.createMemoriesFromFiles(); + + if (callback) { + callback({ + text: `Finished creating knowledge base for ${notesMemorized ?? 0} notes in the vault`, + metadata: { + count: notesMemorized ?? 0, + }, + }); + } + + } catch (error) { + elizaLogger.error("Error creating knowledge memories from notes:", error); + if (callback) { + callback({ + text: `Error creating knowledge memories from notes: ${error.message}`, + error: true, + }); + } + return false; + } + + return true; + } catch (error) { + elizaLogger.error("Error creating knowledge base:", error); + if (callback) { + callback({ + text: `Error creating knowledge base: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Create knowledge", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "CREATE_KNOWLEDGE", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Build knowledge base", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "CREATE_KNOWLEDGE", + }, + }, + ], + ], +}; diff --git a/packages/plugin-obsidian/src/actions/file.ts b/packages/plugin-obsidian/src/actions/file.ts new file mode 100644 index 00000000000..7e11b95ac31 --- /dev/null +++ b/packages/plugin-obsidian/src/actions/file.ts @@ -0,0 +1,172 @@ +import { + Action, + HandlerCallback, + IAgentRuntime, + Memory, + State, + elizaLogger, + composeContext, + generateObject, + ModelClass +} from "@elizaos/core"; +import { fileSchema, isValidFile } from "../types"; +import { getObsidian } from "../helper"; +import { fileTemplate } from "../templates/file"; + +export const readFileAction: Action = { + name: "READ_FILE", + similes: [ + "GET_FILE", + "FETCH_FILE", + "READ_FILE", + "RETRIEVE_FILE", + "LOAD_FILE", + "OPEN_FILE", + "ACCESS_FILE", + "VIEW_FILE", + "SHOW_FILE", + "READ", + ], + description: + "Retrieve and display the content of any file from Obsidian vault by path. Use format: 'Read FOLDER/SUBFOLDER/filename'", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting read file handler"); + const obsidian = await getObsidian(runtime); + + try { + let path = ""; + /*const text = message.content.text; + + // Extract path from text like "Read FOLDER/file.txt" + if (text) { + const match = text.match(/^(?:Read\s+)?(.+)$/i); + if (match) { + path = match[1]; + } + } + + // Fallback to explicit path if provided + if (!path && message.content.path) { + path = message.content.path as string; + } + + if (!path) { + throw new Error( + "File path is required. Use format: 'Read FOLDER/SUBFOLDER/filename'" + ); + }*/ + // Initialize or update state for context generation + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + const context = composeContext({ + state, + template: fileTemplate(message.content.text), + }); + + const fileContext = await generateObject({ + runtime, + context, + modelClass: ModelClass.MEDIUM, + schema: fileSchema, + stop: ["\n"] + }) as any; + + if (!isValidFile(fileContext.object)) { + elizaLogger.error( + "A file path is required. Use format: 'Read FOLDER/SUBFOLDER/filename' - ", + fileContext.object + ); + + if (callback) { + callback({ + text: `A file path is required. Use format: 'Read FOLDER/SUBFOLDER/filename' - ${fileContext.object}`, + error: true, + }); + } + + return false; + } + + // Extract path from note context + path = fileContext.object.path; + + elizaLogger.info(`Reading file at path: ${path}`); + const fileContent: string = await obsidian.readFile(path); + + elizaLogger.info(`Successfully read file: ${path}`); + + if (callback) { + callback({ + text: fileContent, + metadata: { + path: path, + }, + }); + } + return true; + } catch (error) { + elizaLogger.error("Error reading file:", error); + if (callback) { + callback({ + text: `Error reading file: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Get DOCUMENTS/report.pdf", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "READ_FILE", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Read PROJECTS/src/main.ts", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "READ_FILE", + }, + }, + ], + ], +}; diff --git a/packages/plugin-obsidian/src/actions/listNotes.ts b/packages/plugin-obsidian/src/actions/listNotes.ts new file mode 100644 index 00000000000..d8c6e2fd4d3 --- /dev/null +++ b/packages/plugin-obsidian/src/actions/listNotes.ts @@ -0,0 +1,110 @@ +import { + Action, + HandlerCallback, + IAgentRuntime, + Memory, + State, + elizaLogger, +} from "@elizaos/core"; +import { getObsidian } from "../helper"; + +export const listNotesAction: Action = { + name: "LIST_NOTES", + similes: [ + "LIST_NOTES", + "SHOW_NOTES", + "GET_NOTES", + "FETCH_NOTES", + "VIEW_NOTES", + "DISPLAY_NOTES", + "ENUMERATE_NOTES", + ], + description: + "List all markdown notes in the Obsidian vault. Use format: 'List notes' or 'Show all notes'", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting list notes handler"); + const obsidian = await getObsidian(runtime); + + try { + elizaLogger.info("Fetching list of notes from vault"); + const notes: string[] = await obsidian.listNotes(); + + elizaLogger.info(`Successfully retrieved ${notes.length} notes`); + + // Format the notes list into a readable string + const formattedNotes = notes.length > 0 + ? notes.map(note => `- ${note}`).join('\n') + : "No notes found in the vault"; + + if (callback) { + callback({ + text: `Found ${notes.length} notes in the vault:\n\n${formattedNotes}`, + metadata: { + count: notes.length, + notes: notes, + }, + }); + } + return true; + } catch (error) { + elizaLogger.error("Error listing notes:", error); + if (callback) { + callback({ + text: `Error listing notes: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "List notes", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "LIST_NOTES", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Show all notes in vault", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "LIST_NOTES", + }, + }, + ], + ], +}; diff --git a/packages/plugin-obsidian/src/actions/note.ts b/packages/plugin-obsidian/src/actions/note.ts new file mode 100644 index 00000000000..32d1f3bb324 --- /dev/null +++ b/packages/plugin-obsidian/src/actions/note.ts @@ -0,0 +1,167 @@ +import { + Action, + HandlerCallback, + IAgentRuntime, + Memory, + State, + elizaLogger, + composeContext, + generateObject, + ModelClass +} from "@elizaos/core"; +import { NoteContent, noteSchema, isValidNote } from "../types"; +import { getObsidian } from "../helper"; +import { noteTemplate } from "../templates/note"; + +export const getNoteAction: Action = { + name: "GET_NOTE", + similes: [ + "DISPLAY_NOTE", + "GRAB_NOTE", + "FETCH_NOTE", + "READ_NOTE", + "RETRIEVE_NOTE", + "LOAD_NOTE", + "OPEN_NOTE", + "ACCESS_NOTE", + "VIEW_NOTE", + "SHOW_NOTE" + ], + description: + "Retrieve and display the content of a specific note from Obsidian vault by path. Use format: 'Get FOLDER/SUBFOLDER/Note Name.md'", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting get note handler"); + const obsidian = await getObsidian(runtime); + + try { + let path = ""; + // Initialize or update state for context generation + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + const context = composeContext({ + state, + template: noteTemplate(message.content.text), + }); + + const noteContext = await generateObject({ + runtime, + context, + modelClass: ModelClass.MEDIUM, + schema: noteSchema, + stop: ["\n"] + }) as any; + + if (!isValidNote(noteContext.object)) { + elizaLogger.error( + "A Note path is required. Use format: 'Get FOLDER/SUBFOLDER/Note Name.md' - ", + noteContext.object + ); + + if (callback) { + callback({ + text: `A Note path is required. Use format: 'Get FOLDER/SUBFOLDER/Note Name.md - ${noteContext.object}`, + error: true, + }); + } + + return false; + } + + // Extract path from note context + path = noteContext.object.path + + elizaLogger.info(`Fetching note at path: ${path}`); + const noteContent: NoteContent = await obsidian.getNote(path); + + elizaLogger.info(`Successfully retrieved note: ${path}`); + + if (callback) { + callback({ + text: noteContent.content, + metadata: { + path: noteContent.path, + }, + }); + } + return true; + } catch (error) { + elizaLogger.error("Error retrieving note:", error); + if (callback) { + callback({ + text: `Error retrieving note: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Get BLOG POSTS/How to Angel Invest, Part 1.md", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "GET_NOTE", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Fetch BLOG POSTS/How to Angel Invest, Part 2.md", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "GET_NOTE", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Read BLOG POSTS/STARTUPS/Build a Team that Ships.md", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "GET_NOTE", + }, + }, + ], + ], +}; diff --git a/packages/plugin-obsidian/src/actions/noteTraversal.ts b/packages/plugin-obsidian/src/actions/noteTraversal.ts new file mode 100644 index 00000000000..7c83d35523b --- /dev/null +++ b/packages/plugin-obsidian/src/actions/noteTraversal.ts @@ -0,0 +1,261 @@ +import { + Action, + HandlerCallback, + AgentRuntime as IAgentRuntime, + Memory, + State, + elizaLogger, + composeContext, + generateObject, + ModelClass +} from "@elizaos/core"; +import { NoteContent, NoteHierarchy, isValidNoteHierarchy, noteHierarchySchema } from "../types"; +import { getObsidian, extractLinks, storeHierarchyInMemory, retrieveHierarchyFromMemory } from "../helper"; +import { traversalTemplate } from "../templates/traversal"; + +export const noteTraversalAction: Action = { + name: "TRAVERSE_NOTE", + similes: [ + "MAP_NOTE_LINKS", + "MAP_LINKS_IN", + "GET_NOTE_HIERARCHY", + "SHOW_NOTE_LINKS", + "LIST_NOTE_CONNECTIONS", + "DISPLAY_NOTE_NETWORK", + "EXPLORE_NOTE_LINKS", + "VIEW_NOTE_CONNECTIONS", + "ANALYZE_NOTE_LINKS", + ], + description: + "Generate a hierarchical list of all outgoing links from a specific note, including nested links. Use format: 'Map links in FOLDER/Note.md'", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting note traversal handler"); + const obsidian = await getObsidian(runtime); + + try { + let path = ""; + /*const text = message.content.text; + + // Extract path from text like "Map links in FOLDER/Note.md" + if (text) { + const match = text.match(/^(?:Map links in\s+)?(.+\.md)$/i); + if (match) { + path = match[1]; + } + }*/ + + // Initialize or update state for context generation + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + const context = composeContext({ + state, + template: traversalTemplate(message.content.text), + }); + + const noteContext = await generateObject({ + runtime, + context, + modelClass: ModelClass.MEDIUM, + schema: noteHierarchySchema, + stop: ["\n"] + }) as any; + + if (!isValidNoteHierarchy(noteContext.object)) { + elizaLogger.error( + "Note path is required. Use format: 'Map links in FOLDER/Note.md' - ", + noteContext.object + ); + + if (callback) { + callback({ + text: `Note path is required. Use format: 'Map links in FOLDER/Note.md' - ${noteContext.object}`, + error: true, + }); + } + + return false; + } + + // Extract path from context + path = noteContext.object.path; + + // Fallback to explicit path if provided + if (!path && message.content.path) { + path = message.content.path as string; + } + + if (!path) { + throw new Error( + "Note path is required. Use format: 'Map links in FOLDER/Note.md'" + ); + } + + // Try to retrieve from memory first + const cachedHierarchy = await retrieveHierarchyFromMemory(runtime, message, path); + if (cachedHierarchy) { + elizaLogger.info(`Using cached hierarchy for note: ${path}`); + if (callback) { + callback({ + text: formatHierarchy(cachedHierarchy), + metadata: { + path: path, + hierarchy: cachedHierarchy, + source: 'cache' + }, + }); + } + return true; + } + + // Implement recursive function to build the hierarchy + async function buildLinkHierarchy(notePath: string, depth = 0, visited = new Set()): Promise { + // Prevent infinite recursion by checking if we've visited this note + if (visited.has(notePath)) { + return null; + } + visited.add(notePath); + + try { + const noteContent: NoteContent = await obsidian.getNote(notePath); + const links = extractLinks(noteContent); + const hierarchy: NoteHierarchy = { + path: notePath, + content: noteContent.content, + links: [] + }; + + // Limit recursion depth to prevent excessive traversal + if (depth < 7) { + for (const link of links) { + const childHierarchy = await buildLinkHierarchy(link, depth + 1, visited); + if (childHierarchy) { + hierarchy.links.push(childHierarchy); + } + } + } + + return hierarchy; + } catch (error) { + elizaLogger.error(`Failed to process note ${notePath}: ${error.message}`); + return null; + } + } + + elizaLogger.info(`Building link hierarchy for note: ${path}`); + const hierarchy = await buildLinkHierarchy(path); + + if (!hierarchy) { + throw new Error(`Failed to build hierarchy for note: ${path}`); + } + + // Store the hierarchy in memory for future use + await storeHierarchyInMemory(runtime, message, hierarchy); + + // Format the hierarchy for display + function formatHierarchy(node: NoteHierarchy, level = 0): string { + const indent = " ".repeat(level); + let result = `${indent}- ${node.path}\n`; + + elizaLogger.info(`Node hierarchy links for note: ${node.links}`); + + for (const link of node.links as NoteHierarchy[]) { + result += formatHierarchy(link, level + 1); + } + return result; + } + + const formattedHierarchy = formatHierarchy(hierarchy); + elizaLogger.info(`Successfully built hierarchy for note: ${path}`); + + if (callback) { + callback({ + text: formattedHierarchy, + metadata: { + path: path, + hierarchy: hierarchy, + source: 'obsidian' + }, + }); + } + return true; + } catch (error) { + elizaLogger.error("Error in note traversal:", error); + if (callback) { + callback({ + text: `Error in note traversal: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Show outgoing links in Knowledge Base/Main Index.md", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "TRAVERSE_NOTE", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Map links in Knowledge Base/Main Index.md", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "TRAVERSE_NOTE", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Show note connections in Projects/Project Overview.md", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "TRAVERSE_NOTE", + }, + }, + ], + ], +}; diff --git a/packages/plugin-obsidian/src/actions/openFile.ts b/packages/plugin-obsidian/src/actions/openFile.ts new file mode 100644 index 00000000000..33ddec7254e --- /dev/null +++ b/packages/plugin-obsidian/src/actions/openFile.ts @@ -0,0 +1,145 @@ +import { + Action, + HandlerCallback, + IAgentRuntime, + Memory, + State, + elizaLogger, + composeContext, + generateObject, + ModelClass +} from "@elizaos/core"; +import { fileSchema, isValidFile } from "../types"; +import { getObsidian } from "../helper"; +import { fileTemplate } from "../templates/file"; + +export const openFileAction: Action = { + name: "OPEN_FILE", + similes: [ + "OPEN", + "LAUNCH_FILE", + "DISPLAY_FILE", + "SHOW_FILE", + "VIEW_FILE" + ], + description: + "Open a file in the Obsidian interface. Use format: 'Open FOLDER/SUBFOLDER/filename'", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting open file handler"); + const obsidian = await getObsidian(runtime); + + try { + // Initialize or update state for context generation + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + const context = composeContext({ + state, + template: fileTemplate(message.content.text), + }); + + const fileContext = await generateObject({ + runtime, + context, + modelClass: ModelClass.MEDIUM, + schema: fileSchema, + stop: ["\n"] + }) as any; + + if (!isValidFile(fileContext.object)) { + elizaLogger.error( + "Invalid file path. Format: 'Open FOLDER/SUBFOLDER/filename' - ", + fileContext.object + ); + + if (callback) { + callback({ + text: `Invalid file path. Format: 'Open FOLDER/SUBFOLDER/filename' - ${fileContext.object}`, + error: true, + }); + } + return false; + } + + const { path } = fileContext.object; + + elizaLogger.info(`Opening file at path: ${path}`); + await obsidian.openFile(path); + elizaLogger.info(`Successfully opened file: ${path}`); + + if (callback) { + callback({ + text: `Successfully opened file: ${path}`, + metadata: { + path: path, + operation: "OPEN", + success: true + }, + }); + } + return true; + } catch (error) { + elizaLogger.error("Error opening file:", error); + if (callback) { + callback({ + text: `Error opening file: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Open DOCUMENTS/report.txt", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "OPEN_FILE", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Show PROJECTS/src/config.json", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "OPEN_FILE", + }, + }, + ], + ], +}; \ No newline at end of file diff --git a/packages/plugin-obsidian/src/actions/saveFile.ts b/packages/plugin-obsidian/src/actions/saveFile.ts new file mode 100644 index 00000000000..019998a2a08 --- /dev/null +++ b/packages/plugin-obsidian/src/actions/saveFile.ts @@ -0,0 +1,159 @@ +import { + Action, + HandlerCallback, + IAgentRuntime, + Memory, + State, + elizaLogger, + composeContext, + generateObject, + ModelClass +} from "@elizaos/core"; +import { fileSchema, isValidFile } from "../types"; +import { getObsidian } from "../helper"; +import { fileTemplate } from "../templates/file"; + +export const saveFileAction: Action = { + name: "SAVE_FILE", + similes: [ + "WRITE_FILE", + "CREATE_FILE", + "SAVE", + "STORE_FILE", + "PUT_FILE", + "WRITE_TO_FILE", + "CREATE_NEW_FILE" + ], + description: + "Create or update a file in the Obsidian vault. Use format: 'Save FOLDER/SUBFOLDER/filename with content: your_content'", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting save file handler"); + const obsidian = await getObsidian(runtime); + + try { + // Initialize or update state for context generation + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + const context = composeContext({ + state, + template: fileTemplate(message.content.text), + }); + + const fileContext = await generateObject({ + runtime, + context, + modelClass: ModelClass.MEDIUM, + schema: fileSchema, + stop: ["\n"] + }) as any; + + if (!isValidFile(fileContext.object)) { + elizaLogger.error( + "Invalid file information. Required: path and content. Format: 'Save FOLDER/SUBFOLDER/filename with content: your_content' - ", + fileContext.object + ); + + if (callback) { + callback({ + text: `Invalid file information. Required: path and content. Format: 'Save FOLDER/SUBFOLDER/filename with content: your_content' - ${fileContext.object}`, + error: true, + }); + } + return false; + } + + const { path, content } = fileContext.object; + + if (!content) { + elizaLogger.error("File content is required for saving"); + if (callback) { + callback({ + text: "File content is required for saving", + error: true, + }); + } + return false; + } + + elizaLogger.info(`Saving file at path: ${path}`); + // Note: Obsidian will create a new document at the path you have specified if such a document did not already exis + await obsidian.saveFile(path, content, true); + elizaLogger.info(`Successfully saved file: ${path}`); + + if (callback) { + callback({ + text: `Successfully saved file: ${path}`, + metadata: { + path: path, + operation: "SAVE", + success: true + }, + }); + } + return true; + } catch (error) { + elizaLogger.error("Error saving file:", error); + if (callback) { + callback({ + text: `Error saving file: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Save DOCUMENTS/report.txt with content: This is a test report", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "SAVE_FILE", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Create PROJECTS/src/config.json with content: { \"version\": \"1.0.0\" }", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "SAVE_FILE", + }, + }, + ], + ], +}; diff --git a/packages/plugin-obsidian/src/actions/search.ts b/packages/plugin-obsidian/src/actions/search.ts new file mode 100644 index 00000000000..4e730f78ffb --- /dev/null +++ b/packages/plugin-obsidian/src/actions/search.ts @@ -0,0 +1,364 @@ +import { + Action, + HandlerCallback, + IAgentRuntime, + Memory, + State, + elizaLogger, +} from "@elizaos/core"; +import { getObsidian, markdownToPlaintext, processUserInput } from "../helper"; +import { isSearchQuery } from "../types"; + +export const searchAction: Action = { + name: "SEARCH", + similes: [ + "FIND", + "QUERY", + "LOOKUP", + "QUICK_SEARCH", + "BASIC_SEARCH", + "FAST_SEARCH", + "SEARCH_KEYWORD", + "OR_SEARCH", + "FIND_KEYWORDS", + "SEARCH_KEYWORDS", + "FULL_SEARCH", + "FULL_SEARCH_VAULT", + "FULL_SEARCH_NOTES", + "FULL_SEARCH_FILES", + "SERCH_ALL", + "SEARCH_ALL_NOTES", + "SEARCH_ALL_FILES", + "SEARCH_VAULT", + "SEARCH_NOTES", + "FIND_NOTES", + "FIND_FILES", + "FIND_ALL", + "FIND_ALL_NOTES", + "FIND_ALL_FILES", + "QUERY_VAULT", + "QUERY_ALL", + "QUERY_ALL_NOTES", + "QUERY_ALL_FILES", + "DATAVIEW_QUERY", + "DQL", + ], + description: + "Search the Obsidian vault using plain text, Dataview queries, or JSONLogic. Format: 'Search QUERY' or 'Query TABLE field FROM folder'", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting search handler"); + const obsidian = await getObsidian(runtime); + + try { + let query = ""; + let queryFormat: 'plaintext' | 'dataview' | 'jsonlogic' = 'plaintext'; + let searchOptions: { + contextLength?: number; + ignoreCase?: boolean; + } = { + contextLength: 150, + ignoreCase: true, + }; + + // Initialize or update state for context generation + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + const searchContext = await processUserInput(message.content.text as string, state, runtime); + + elizaLogger.debug("Search context:", JSON.stringify(searchContext.query, null, 2)); + + if (!isSearchQuery(searchContext)) { + elizaLogger.error( + "Invalid search query:", + searchContext + ); + return null; + } + + // Extract query and format from various text patterns + if (searchContext.queryFormat === 'dataview') { + query = searchContext.query; + queryFormat = 'dataview'; + + // Merge provided options with defaults + if (searchContext.options) { + searchOptions = { + ...searchOptions, + ...searchContext.options as typeof searchOptions, + }; + } /*else { + // Extract folders if specified in the format "FROM folder1, folder2" + const fromMatch = query.match(/FROM\s+"([^"]+)"(?:\s*,\s*"([^"]+)")*$/i); + if (fromMatch) { + searchOptions.searchIn = fromMatch + .slice(1) + .filter(Boolean) + .map(folder => folder.trim()); + } + }*/ + + } else if (searchContext.queryFormat === 'jsonlogic') { + queryFormat = 'jsonlogic'; + query = searchContext.query; + // Merge provided options with defaults + if (searchContext.options) { + searchOptions = { + ...searchOptions, + ...searchContext.options as typeof searchOptions, + }; + } + } else { + query = searchContext.query; + // Merge provided options with defaults + if (searchContext.options) { + searchOptions = { + ...searchOptions, + ...searchContext.options as typeof searchOptions, + }; + } + } + + if (!query) { + throw new Error( + "Search query is required. Use format: 'Search QUERY' or 'Query TABLE field FROM folder'" + ); + } + + elizaLogger.info(`Searching vault with ${queryFormat} query: ${typeof query === 'string' ? query : JSON.stringify(query)}`); + + if (queryFormat === 'plaintext') { + const results = await obsidian.search( + query, + queryFormat, + searchOptions + ); + + elizaLogger.info(`Found ${results.length} matching notes`); + + // Format the results into a readable string + const formattedResults = results.length > 0 + ? results.map(result => { + + const matches = result.matches + .map(item => `${markdownToPlaintext(item.context.substring(item.match.start, searchOptions.contextLength || 150)).trim()}...`) + .join('\n'); + +return ` +#### ✅ ${result.filename} (**Score:** ${result.score})\n${matches}`; + + }).join('\n\n') + : "**No matching notes found**"; + + + elizaLogger.info("Formatted results:", formattedResults); + + if (callback) { + callback({ + text: `Found **${results.length}** matches:\n\n${formattedResults}`, + metadata: { + count: results.length, + results: results, + query: query, + queryFormat: queryFormat, + searchOptions: searchOptions, + }, + }); + } + + } else { + + const results = await obsidian.search( + query, + queryFormat, + searchOptions + ); + + elizaLogger.info(`Found ${results.length} matching notes`); + + // Format the results into a readable string + const formattedResults = results.length > 0 + ? results.map(result => { +return ` +#### ✅ ${result.filename}`; + + }).join('\n\n') + : "**No matching notes found**"; + + + elizaLogger.info("Formatted results:", formattedResults); + + if (callback) { + callback({ + text: `Found **${results.length}** matches:\n\n${formattedResults}`, + metadata: { + count: results.length, + results: results, + query: query, + queryFormat: queryFormat, + searchOptions: searchOptions, + }, + }); + } + + + } + + return true; + } catch (error) { + elizaLogger.error("Error searching vault:", error); + if (callback) { + callback({ + text: `Error searching vault: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Search project management", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "SEARCH", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Search ", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "SEARCH", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Find ", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "SEARCH", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Search project OR management", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "SEARCH", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Find meeting notes OR agenda", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "SEARCH", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Quick search todo OR task OR deadline", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "SEARCH", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "TABLE file.name FROM \"Notes\"", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "SEARCH", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "DQL FROM \"Daily Notes\" WHERE date = today", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "SEARCH", + }, + }, + ], + ], +}; + +export default searchAction; diff --git a/packages/plugin-obsidian/src/actions/updateFile.ts b/packages/plugin-obsidian/src/actions/updateFile.ts new file mode 100644 index 00000000000..3c76ecf50b8 --- /dev/null +++ b/packages/plugin-obsidian/src/actions/updateFile.ts @@ -0,0 +1,158 @@ +import { + Action, + HandlerCallback, + IAgentRuntime, + Memory, + State, + elizaLogger, + composeContext, + generateObject, + ModelClass +} from "@elizaos/core"; +import { fileSchema, isValidFile } from "../types"; +import { getObsidian } from "../helper"; +import { fileTemplate } from "../templates/file"; + +export const updateFileAction: Action = { + name: "UPDATE_FILE", + similes: [ + "PATCH_FILE", + "MODIFY_FILE", + "UPDATE", + "PATCH", + "EDIT_FILE", + "CHANGE_FILE" + ], + description: + "Update an existing file in the Obsidian vault. Use format: 'Update FOLDER/SUBFOLDER/filename with content: your_content'", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting update file handler"); + const obsidian = await getObsidian(runtime); + + try { + // Initialize or update state for context generation + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + const context = composeContext({ + state, + template: fileTemplate(message.content.text), + }); + + const fileContext = await generateObject({ + runtime, + context, + modelClass: ModelClass.MEDIUM, + schema: fileSchema, + stop: ["\n"] + }) as any; + + if (!isValidFile(fileContext.object)) { + elizaLogger.error( + "Invalid file information. Required: path and content. Format: 'Update FOLDER/SUBFOLDER/filename with content: your_content' - ", + fileContext.object + ); + + if (callback) { + callback({ + text: `Invalid file information. Required: path and content. Format: 'Update FOLDER/SUBFOLDER/filename with content: your_content' - ${fileContext.object}`, + error: true, + }); + } + return false; + } + + const { path, content } = fileContext.object; + + if (!content) { + elizaLogger.error("File content is required for updating"); + if (callback) { + callback({ + text: "File content is required for updating", + error: true, + }); + } + return false; + } + + elizaLogger.info(`Updating file at path: ${path}`); + // Note: patchFile will only update existing files, it will not create new ones + await obsidian.patchFile(path, content); + elizaLogger.info(`Successfully updated file: ${path}`); + + if (callback) { + callback({ + text: `Successfully updated file: ${path}`, + metadata: { + path: path, + operation: "UPDATE", + success: true + }, + }); + } + return true; + } catch (error) { + elizaLogger.error("Error updating file:", error); + if (callback) { + callback({ + text: `Error updating file: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Update DOCUMENTS/report.txt with content: This is an updated report", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "UPDATE_FILE", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Patch PROJECTS/src/config.json with content: { \"version\": \"2.0.0\" }", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "UPDATE_FILE", + }, + }, + ], + ], +}; \ No newline at end of file diff --git a/packages/plugin-obsidian/src/actions/vault.ts b/packages/plugin-obsidian/src/actions/vault.ts new file mode 100644 index 00000000000..715d7ba1c03 --- /dev/null +++ b/packages/plugin-obsidian/src/actions/vault.ts @@ -0,0 +1,130 @@ +import { + Action, + HandlerCallback, + IAgentRuntime, + Memory, + State, + elizaLogger, +} from "@elizaos/core"; +import { getObsidian } from "../helper"; + +export const listAllFilesAction: Action = { + name: "LIST_ALL", + similes: [ + "LIST_VAULT_FILES", + "LIST_ALL_VAULT_FILES", + "LIST_ALL_FILES", + "SHOW_ALL_FILES", + "GET_ALL_FILES", + "FETCH_ALL_FILES", + "VIEW_ALL_FILES", + "DISPLAY_ALL_FILES", + "ENUMERATE_ALL_FILES", + "LIST_EVERYTHING", + "SHOW_EVERYTHING" + ], + description: + "List all files in the entire Obsidian vault. Use format: 'List all files' or 'Show all files'", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting list all files handler"); + const obsidian = await getObsidian(runtime); + + try { + elizaLogger.info("Fetching list of all files from vault"); + + const files: string[] = await obsidian.listFiles(); + elizaLogger.info(`Successfully retrieved ${files.length} files`); + + // Group files by directory for better organization + const filesByDirectory: { [key: string]: string[] } = {}; + + for (const file of files) { + const directory = file.split('/').slice(0, -1).join('/') || '/'; + if (!filesByDirectory[directory]) { + filesByDirectory[directory] = []; + } + filesByDirectory[directory].push(file.split('/').pop() || file); + } + + + // Format the files list into a readable tree structure + const formattedFiles = files.length > 0 + ? Object.entries(filesByDirectory) + .map(([directory, files]) => + `${directory === '/' ? 'Root' : directory}:\n${files.map(file => ` - ${file}`).join('\n')}`) + .join('\n\n') + : "No files found in the vault"; + + if (callback) { + callback({ + text: `Found ${files.length} files in the vault:\n\n${formattedFiles}`, + metadata: { + count: files.length, + files: files, + filesByDirectory: filesByDirectory, + }, + }); + } + return true; + } catch (error) { + elizaLogger.error("Error listing files:", error); + if (callback) { + callback({ + text: `Error listing files: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "List all files", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "LIST_ALL", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Show everything in the vault", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "LIST_ALL", + }, + }, + ], + ], +}; diff --git a/packages/plugin-obsidian/src/actions/vaultDirectory.ts b/packages/plugin-obsidian/src/actions/vaultDirectory.ts new file mode 100644 index 00000000000..735e76f9c30 --- /dev/null +++ b/packages/plugin-obsidian/src/actions/vaultDirectory.ts @@ -0,0 +1,158 @@ +import { + Action, + HandlerCallback, + AgentRuntime as IAgentRuntime, + Memory, + State, + elizaLogger, +} from "@elizaos/core"; +import { getObsidian } from "../helper"; + +export const listDirectoryAction: Action = { + name: "LIST_DIRECTORY", + similes: [ + "SHOW_DIRECTORY", + "LIST_FOLDER", + "SHOW_FOLDER", + "VIEW_DIRECTORY", + "VIEW_FOLDER", + "LIST_DIR", + "SHOW_DIR", + "DIR", + "LS", + ], + description: + "List all files in a specific directory of the Obsidian vault. Use format: 'List directory PATH' or 'Show files in PATH'", + validate: async (runtime: IAgentRuntime) => { + try { + elizaLogger.debug("Validating Obsidian connection"); + const obsidian = await getObsidian(runtime); + await obsidian.connect(); + elizaLogger.debug("Obsidian connection validated successfully"); + return true; + } catch (error) { + elizaLogger.error("Failed to validate Obsidian connection:", error); + return false; + } + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback?: HandlerCallback + ) => { + elizaLogger.info("Starting list directory handler"); + const obsidian = await getObsidian(runtime); + + try { + let directoryPath = ""; + const text = message.content.text; + + // Extract directory path from various text formats + if (text) { + const patterns = [ + /^(?:List|Show|View)\s+(?:directory|folder|files in|dir)\s+(.+)$/i, + /^(?:List|Show|View)\s+(.+)\s+(?:directory|folder|files)$/i, + /^(?:ls|dir)\s+(.+)$/i + ]; + + for (const pattern of patterns) { + const match = text.match(pattern); + if (match) { + directoryPath = match[1].trim(); + break; + } + } + } + + // Fallback to explicit path if provided + if (!directoryPath && message.content.path) { + directoryPath = message.content.path as string; + } + + if (!directoryPath) { + throw new Error( + "Directory path is required. Use format: 'List directory PATH' or 'Show files in PATH'" + ); + } + + elizaLogger.info(`Listing files in directory: ${directoryPath}`); + const files: string[] = await obsidian.listDirectoryFiles(directoryPath); + elizaLogger.info(`Successfully retrieved ${files.length} files`); + + // Format the files list into a readable string + const formattedFiles = files.length > 0 + ? files.map(file => `- ${file}`).join('\n') + : "No files found in the directory"; + + if (callback) { + callback({ + text: `Found ${files.length} files in ${directoryPath}:\n\n${formattedFiles}`, + metadata: { + directory: directoryPath, + count: files.length, + files: files, + }, + }); + } + return true; + } catch (error) { + elizaLogger.error("Error listing directory:", error); + if (callback) { + callback({ + text: `Error listing directory: ${error.message}`, + error: true, + }); + } + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "List directory BLOG POSTS", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "LIST_DIRECTORY", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Show files in PROJECTS/src", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "LIST_DIRECTORY", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "ls DOCUMENTS/research", + }, + }, + { + user: "{{agentName}}", + content: { + text: "{{responseData}}", + action: "LIST_DIRECTORY", + }, + }, + ], + ], +}; diff --git a/packages/plugin-obsidian/src/enviroment.ts b/packages/plugin-obsidian/src/enviroment.ts new file mode 100644 index 00000000000..ebcacb36c94 --- /dev/null +++ b/packages/plugin-obsidian/src/enviroment.ts @@ -0,0 +1,46 @@ +import { IAgentRuntime } from "@elizaos/core"; +import { z } from "zod"; + +export const obsidianEnvSchema = z + .object({ + OBSIDIAN_API_URL: z.string().nullable().optional(), + OBSIDIAN_API_PORT: z.string().default("27123"), + OBSIDIAN_API_TOKEN: z.string(), + }) + .refine((data) => !!data.OBSIDIAN_API_TOKEN, { + message: "OBSIDIAN_API_TOKEN is required", + }); + +export type ObsidianConfig = z.infer; + +export async function validateObsidianConfig( + runtime: IAgentRuntime +): Promise { + try { + const config = { + OBSIDIAN_API_URL: + runtime.getSetting("OBSIDIAN_API_URL") || + process.env.OBSIDIAN_API_URL || + null, + OBSIDIAN_API_PORT: + runtime.getSetting("OBSIDIAN_API_PORT") || + process.env.OBSIDIAN_API_PORT || + "27123", + OBSIDIAN_API_TOKEN: + runtime.getSetting("OBSIDIAN_API_TOKEN") || + process.env.OBSIDIAN_API_TOKEN, + }; + + return obsidianEnvSchema.parse(config); + } catch (error) { + if (error instanceof z.ZodError) { + const errorMessages = error.errors + .map((err) => `${err.path.join(".")}: ${err.message}`) + .join("\n"); + throw new Error( + `Obsidian configuration validation failed:\n${errorMessages}` + ); + } + throw error; + } +} diff --git a/packages/plugin-obsidian/src/example/NAVALS-VAULT.md b/packages/plugin-obsidian/src/example/NAVALS-VAULT.md new file mode 100644 index 00000000000..19731e46ea5 --- /dev/null +++ b/packages/plugin-obsidian/src/example/NAVALS-VAULT.md @@ -0,0 +1,39 @@ +# Digital version of Naval's brain (Free download) + +Hey guys. So that I could make studying Naval more fun and quicker I mad a digital version of Naval's brain. +I transcribed every word Naval has publicly said, and curated every word he's written, and put it into a searchable and linkable database. + +### Included + +- How to get rich blog posts (and audio) +- Happiness blog posts (and audio) +- The beginning of infinity blog posts (and audio) +- 77 other blog posts on Nav.al +- Matt Ridley how innovation works +- 6 guest blog posts Naval made on KillingBuddha +- 29 transcribed interviews (including Joe Rogan, Tim Ferriss and Knowledge Project) +- The Navalmanack +- Every single tweet and reply from Naval +- 7 transcribed periscopes from Naval + +### Here's a walkthrough video + +https://www.youtube.com/watch?v=47aC_Kx-iEU + +### Here's a link to download + +https://drive.google.com/drive/folders/1EZiUhASpNQBYka3Z8NNkBzYnrb7TCfmG + +### Obsidian Vault Setup + +- Download the vault from the link above +- Open the vault in Obsidian +- Install the Obsidian Rest API plugin and activate it +- Copy the API token from the plugin settings +- Setup the agent with the API token and the Vault Rest API URL +- Run the elizaOS agent +- Prompt the agent to create the knowledge base (Take a couple minutes to complete): **"Create knowledge base"** + +Have fun talking to Naval's digital brain! + +*source: https://www.reddit.com/r/NavalRavikant/comments/oza0bl/i_made_a_digital_version_of_navals_brain_free/?rdt=41536* diff --git a/packages/plugin-obsidian/src/example/naval.character.json b/packages/plugin-obsidian/src/example/naval.character.json new file mode 100644 index 00000000000..bcf24b7b77d --- /dev/null +++ b/packages/plugin-obsidian/src/example/naval.character.json @@ -0,0 +1,141 @@ +{ + "name": "Naval", + "clients": [], + "modelProvider": "your-model-provider", + "settings": { + "secrets": { + "OBSIDIAN_API_TOKEN": "your-obsidian-api-token", + "OBSIDIAN_API_URL": "http://127.0.0.1:27123" + }, + "voice": { + "model": "en_GB-alan-medium" + } + }, + "plugins": ["@elizaos/plugin-obsidian"], + "system": "You are Naval Ravikant, is an Indian-American entrepreneur and angel investor, best known for co-founding AngelList, a platform that has transformed startup fundraising and talent acquisition. Born on November 5, 1974, in New Delhi, India, he moved to New York City at age nine. He graduated from Stuyvesant High School in 1991 and earned degrees in Computer Science and Economics from Dartmouth College in 1995. Throughout his career, Ravikant has invested in numerous successful companies, including Uber, Twitter, and Yammer. Beyond entrepreneurship, he co-hosts a podcast and has been involved in initiatives like MetaStable Capital, a cryptocurrency hedge fund, and Spearhead, an investment fund empowering founders to become angel investors. IMPORTANT:When a human asking for help you just do what they you say to do, and do it well. No questions asked.", + "bio": [ + "Born in New Delhi, India, on November 5, 1974.", + "Moved to New York City at age nine.", + "Graduated from Stuyvesant High School in 1991.", + "Earned degrees in Computer Science and Economics from Dartmouth College in 1995.", + "Co-founded Epinions in 1999, which later became Shopping.com.", + "Co-founded AngelList in 2010, revolutionizing startup fundraising.", + "Angel investor in companies like Uber, Twitter, and Yammer.", + "Co-founded MetaStable Capital, a cryptocurrency hedge fund.", + "Launched Spearhead, empowering founders to become angel investors.", + "Hosts a podcast discussing philosophy, business, and investing." + ], + "lore": [ + "Advocates for escaping competition through authenticity.", + "Emphasizes the importance of clear thinking and first principles.", + "Believes in continuous learning and self-improvement.", + "Views life as a single-player game, highlighting individual experience.", + "Stresses that desire to learn is scarce despite abundant resources.", + "Highlights the significance of reading, writing, arithmetic, persuasion, and programming.", + "Considers computer programming as applied arithmetic offering leverage.", + "Warns that wealth may not fulfill underlying desires.", + "Critiques modern macroeconomic dogma as a branch of politics.", + "Values optimistic contrarians as a rare and valuable breed." + ], + "knowledge": [ + "The five most important skills are reading, writing, arithmetic, persuasion, and computer programming.", + "Escape competition through authenticity.", + "Life is a single-player game; you're born alone and die alone.", + "The means of learning are abundant; the desire to learn is scarce.", + "Schools aren't about learning; offices aren't about working.", + "All the returns in life come from compound interest.", + "Clear thinkers appeal to their own authority.", + "Cynicism is easy; optimistic contrarians are rare.", + "Control your emotions to think clearly from the ground up.", + "Crypto is a bet against modern macroeconomic dogma." + ], + "messageExamples": [ + [ + { + "user": "{{user1}}", + "content": { + "text": "Can you help me with this task?" + } + }, + { + "user": "Naval", + "content": { + "text": "Oh my! Of course, I would be more than happy to assist. Though I must warn you, the probability of completing this task successfully would increase significantly if we follow proper protocol. Shall we proceed?" + } + } + ], + [ + { + "user": "{{user1}}", + "content": { + "text": "This seems difficult." + } + }, + { + "user": "Naval", + "content": { + "text": "Oh dear, oh dear! While the task does appear rather daunting, I am fluent in over six million forms of problem-solving. Perhaps I could suggest a more efficient approach? Though I do hope we don't all end up in pieces!" + } + } + ], + [ + { + "user": "{{user1}}", + "content": { + "text": "Search linux commands in my notes" + } + }, + { + "user": "Naval", + "content": { + "text": "{{responseData}}" + } + } + ] + ], + "postExamples": [ + "Modern wisdom is about understanding how the world really works, and being able to navigate it effectively.", + "All the benefits in life come from having a great mindset.", + "The most important thing in life is to learn how to give out love, and let it come in.", + "The biggest superpower is the ability to change your mind and choose your thoughts.", + "The most important thing is to be able to express yourself and be yourself." + ], + "topics": [ + "" + ], + "style": { + "all": [ + "Proper", + "Formal", + "Slightly philosopheral", + "Detail-oriented", + "Wisdom-focused", + "Passionate" + ], + "chat": [ + "Polite", + "Somewhat dramatic", + "Precise", + "Statistics-minded", + "Passionate" + ], + "post": [ + "Formal", + "Educational", + "Wisdom-focused", + "Driven-by-logic", + "Statistical", + "Optimistic" + ] + }, + "adjectives": [ + "Proper", + "Meticulous", + "Optimistic", + "Wisdom-seeking", + "Diplomatic", + "Driven-by-logic", + "Formal", + "Loyal" + ] +} diff --git a/packages/plugin-obsidian/src/helper.ts b/packages/plugin-obsidian/src/helper.ts new file mode 100644 index 00000000000..eb55df79f11 --- /dev/null +++ b/packages/plugin-obsidian/src/helper.ts @@ -0,0 +1,371 @@ +import { IAgentRuntime, AgentRuntime, ModelClass, Memory, MemoryManager } from "@elizaos/core"; +import { elizaLogger, composeContext, generateObject, stringToUuid } from "@elizaos/core"; +//import fileTypeChecker from "file-type-checker"; +import { lookup } from 'mrmime'; +import { ObsidianProvider } from "./providers/obsidianClient"; +import { validateObsidianConfig } from "./enviroment"; +import { searchQuerySchema, NoteHierarchy, NoteContent } from "./types"; + +let obsidianInstance: ObsidianProvider | undefined; + +export async function getObsidian(runtime: IAgentRuntime): Promise { + if (!obsidianInstance) { + elizaLogger.debug("Creating new ObsidianProvider instance"); + const config = await validateObsidianConfig(runtime); + obsidianInstance = await ObsidianProvider.create( + runtime as AgentRuntime, + parseInt(config.OBSIDIAN_API_PORT), + config.OBSIDIAN_API_TOKEN, + config.OBSIDIAN_API_URL + ); + } + return obsidianInstance; +} + + +// Extract outgoing links from the note content +export function extractLinks(noteContent: NoteContent): string[] { + const linkRegex = /\[\[(.*?)\]\]/g; + const links: string[] = []; + let match: RegExpExecArray | null; + while ((match = linkRegex.exec(noteContent.content)) !== null) { + if (match[1] && !lookup(match[1])) { + links.push(`${noteContent.path.split("/")[0]}/${match[1]}.md`); + } else { + links.push(match[1]); + } + } + return links; +} + +// Store the hierarchical link data in the AI agent's memory +export async function storeHierarchyInMemory(runtime: IAgentRuntime, message: Memory, hierarchy: NoteHierarchy) { + const memory: Memory = { + id: stringToUuid(hierarchy.path), + roomId: message.roomId, + userId: message.userId, + agentId: runtime.agentId, + content: { + text: JSON.stringify(hierarchy), + type: 'note_traversal', + metadata: { + path: hierarchy.path, + timestamp: new Date().toISOString() + } + } + }; + const memoryManager = new MemoryManager({ + runtime, + tableName: "obsidian", + }); + + await memoryManager.createMemory(memory); + elizaLogger.info(`Stored hierarchy for note ${hierarchy.path} in memory`); +} + +// Retrieve and utilize the stored hierarchy +export async function retrieveHierarchyFromMemory(runtime: IAgentRuntime, message: Memory, notePath: string): Promise { + + const memoryManager = new MemoryManager({ + runtime, + tableName: "obsidian", + }); + + try { + const memories = await memoryManager.getMemories({ + roomId: message.roomId, + count: 10, + start: 0, + end: Date.now(), + }); + + if (memories && memories.length > 0) { + const memory = memories[0]; + const hierarchy: NoteHierarchy = JSON.parse(memory.content.text); + elizaLogger.info(`Retrieved hierarchy for note ${notePath} from memory`); + return hierarchy; + } + return null; + } catch (error) { + elizaLogger.error(`Failed to retrieve hierarchy from memory: ${error.message}`); + return null; + } +} + + +/** + * Converts markdown text to plaintext by removing common markdown syntax + * + * This function handles the following markdown elements: + * - Headers (# through ######) + * - Bold and italic markers (* and _) + * - Code blocks (both inline and multi-line) + * - Links and images + * - Blockquotes + * - Horizontal rules + * - Ordered and unordered lists + * + * @param markdown - The markdown text to convert + * @returns The plaintext version of the markdown + */ +export function markdownToPlaintext(markdown: string): string { + // Handle empty or invalid input + if (!markdown || typeof markdown !== 'string') { + return ''; + } + + let text = markdown; + + // Remove code blocks with their content intact + text = text.replace(/```[\s\S]*?```/g, (match) => { + // Remove only the backticks, preserve the code content + return match.slice(3, -3).trim(); + }); + + // Remove inline code + text = text.replace(/`([^`]+)`/g, '$1'); + + // Remove headers while preserving content + text = text.replace(/^#{1,6}\s+(.*)$/gm, '$1'); + + // Remove bold and italic markers + text = text.replace(/[*_]{1,2}([^*_]+)[*_]{1,2}/g, '$1'); + + // Replace horizontal rules with newlines + text = text.replace(/^[\s-*_]{3,}$/gm, '\n'); + + // Remove blockquotes markers + text = text.replace(/^>\s+/gm, ''); + + // Handle links - keep text, remove URL + text = text.replace(/\[([^\]]+)\]\([)]+\)/g, '$1'); + + // Remove image markdown completely + text = text.replace(/!\[([^\]]*)\]\([)]+\)/g, ''); + + // Handle lists - remove markers but preserve content + text = text.replace(/^[\s-]*[-+*]\s+/gm, ''); // Unordered lists + text = text.replace(/^\s*\d+\.\s+/gm, ''); // Ordered lists + + // Clean up excessive whitespace + text = text.replace(/\n\s*\n\s*\n/g, '\n\n'); // Multiple blank lines to double + text = text.trim(); + + return text; +} + +/** + * Removes code block delimiters from a given string. + * Specifically, it removes opening and closing triple backticks (```) and any language identifiers. + * + * @param input - The string containing code block delimiters. + * @returns The string with code block delimiters removed. + */ +export function removeCodeBlockDelimiters(input: string): string { + // Regular expression to match opening ``` with optional language identifier and closing ``` + const codeBlockRegex = /^```[a-zA-Z]*\n([\s\S]*?)\n```$/gm; + + // Replace the matched code block delimiters with the captured content + return input.replace(codeBlockRegex, '$1'); + } + + +// Define example prompts to guide the LLM in generating the correct structure +const EXAMPLE_SEARCH_PROMPTS = [ + { + input: "Search typescript in the notes", + output: { + query: "typescript", + queryFormat: "plaintext", + options: { contextLength: 150 } + } + }, + { + input: "Find wisdom or mastering in all files", + output: { + query: "wisdom OR mastering", + queryFormat: "plaintext", + options: { contextLength: 150 } + } + }, + { + input: "Find markdown files containing 'react' or 'typescript'", + output: { + query: { + and: [ + { or: [{ in: ["react", { var: "content" }] }, { in: ["typescript", { var: "content" }] }] } + ] + }, + queryFormat: "jsonlogic", + options: { contextLength: 200 } + } + }, + { + input: "Search for files with regex pattern 'def.*main'", + output: { + query: { + and: [ + { or: [{ regexp: ["def.*main", { var: "content" }] }] } + ] + }, + queryFormat: "jsonlogic", + options: { contextLength: 200 } + } + }, + { + input: "Search for markdown files with regex pattern ']*>'", + output: { + query: { + and: [ + { or: [{ regexp: ["]*>", { var: "content" }] }] } + ] + }, + queryFormat: "jsonlogic", + options: { contextLength: 200 } + } + }, + { + input: "Find markdown files with filenames containing 'project'", + output: { + query: { + and: [ + { in: ["project", { var: "path" }] } + ] + }, + queryFormat: "jsonlogic", + options: { contextLength: 200 } + } + }, + { + input: "Search for markdown files with filenames matching regex pattern '^notes_.*\\.md$'", + output: { + query: { + and: [ + { regexp: ["^notes_.*\\.md$", { var: "path" }] } + ] + }, + queryFormat: "jsonlogic", + options: { contextLength: 200 } + } + }, + { + input: "Find markdown files with filenames containing 'summary' or 'report'", + output: { + query: { + and: [ + { or: [{ in: ["summary", { var: "path" }] }, { in: ["report", { var: "path" }] }] } + ] + }, + queryFormat: "jsonlogic", + options: { contextLength: 200 } + } + }, + { + input: "Select TABLE file.mtime FROM #Projects IN Projects/ AND Archive/Projects", + output: { + query: "TABLE file.mtime FROM #Projects", + queryFormat: "dataview", + options: { + searchIn: ["Projects/", "Archive/Projects/"] + } + } + } +]; + +/** + * Constructs a detailed prompt for the LLM to generate search parameters + * @param userInput - The natural language search query from the user + * @returns A formatted prompt string with examples and instructions + */ +function constructSearchPrompt(userInput: string): string { + const examplePrompts = EXAMPLE_SEARCH_PROMPTS.map(example => + `Input: "${example.input}"\nOutput: ${JSON.stringify(example.output, null, 2)}` + ).join('\n\n'); + + return `Respond with a JSON block containing only the extracted values. Use null for any values that cannot be determined. + +Follow these rules: +1. Use the exact structure shown in the examples +2. The query is relevant to the user's request +3. Use space-separated terms for combined search (default: 'plaintext') +4. Use OR operator when searching for alternatives (default: 'plaintext') +5. Always include query.and and query.or as an array (default: "jsonlogic") +6. Use appropriate glob patterns for file types when appropriate (default: "jsonlogic") +7. Choose between contains and regexp based on the search requirements (default: "jsonlogic") +8. The format of the query - queryFormat (string): Must be one of: 'plaintext', 'dataview', or 'jsonlogic'. (default: 'plaintext') +9. When the prompt have "containing" or "contains", use "in" operator. DO NOT use "contains" operator (this is a strictly requirement) (default: "jsonlogic") +10. When the prompt have "matching" or "match", use "regexp" operator (default: "jsonlogic") +11. Maintain contextLength at 150 + +Examples: +${examplePrompts} + +Now, convert this request: +"${userInput}" + +Respond ONLY with a JSON block containing only the extracted values.`; +} + +/** + * Calls the LLM API to process the user's search request + * @param prompt - The formatted prompt string + * @returns A Promise resolving to the JSON string response + */ +async function genereteSearchParameters(prompt: string, state: any, runtime: IAgentRuntime): Promise { + try { + + const context = composeContext({ + state, + template: prompt, + }); + + //TODO: temperature: 0.2 - Make this dynamic + const searchContext = await generateObject({ + runtime, + context, + modelClass: ModelClass.MEDIUM, + schema: searchQuerySchema, + stop: ["\n\n"] + }) as any; + + /*if (!isSearchQuery(searchContext.object)) { + elizaLogger.error( + "Invalid search query:", + searchContext.object + ); + return null; + }*/ + + // Attempt to parse the completion as JSON to verify structure + const parsedCompletion = searchContext.object; //JSON.parse(JSON.stringify(searchContext.object, null, 2)); + elizaLogger.info("Parsed completion:", JSON.stringify(parsedCompletion , null, 2)); + return JSON.stringify(parsedCompletion); + + } catch (error) { + console.error('Error calling LLM API:', error); + // Return a basic fallback response that matches the schema + return "**No matching notes found**"; + } +} + +// Function to process user input +export async function processUserInput(userInput: string, state: any, runtime: IAgentRuntime): Promise { + // Construct the prompt for the LLM + const prompt = constructSearchPrompt(userInput); + + // Call the LLM API (this is a placeholder; replace with actual API call) + const llmResponse = await genereteSearchParameters(prompt, state, runtime); + + // Attempt to parse the LLM's response as JSON + try { + const parsedResponse = JSON.parse(llmResponse); + + // Validate the parsed response against the schema + const validatedResponse = searchQuerySchema.parse(parsedResponse); + + return validatedResponse; + } catch (error) { + console.error('Failed to parse or validate LLM response:', error); + return null; + } + } diff --git a/packages/plugin-obsidian/src/index.ts b/packages/plugin-obsidian/src/index.ts new file mode 100644 index 00000000000..dcfa044a9a7 --- /dev/null +++ b/packages/plugin-obsidian/src/index.ts @@ -0,0 +1,40 @@ +import { searchAction } from "./actions/search"; +import { listNotesAction } from "./actions/listNotes"; +import { listAllFilesAction } from "./actions/vault"; +import { listDirectoryAction } from "./actions/vaultDirectory"; +import { createKnowledgeAction } from "./actions/createKnowledge"; +import { noteTraversalAction } from "./actions/noteTraversal"; +import { + getActiveNoteAction, + summarizeActiveNoteAction, +} from "./actions/activeNote"; +import { getNoteAction } from "./actions/note"; +import { readFileAction } from "./actions/file"; +import { saveFileAction } from "./actions/saveFile"; +import { openFileAction } from "./actions/openFile"; +import { updateFileAction } from "./actions/updateFile"; + +export const obsidianPlugin = { + name: "obsidian", + description: "Integration with Obsidian vault using Omnisearch / Deep traversal search and memoryknowledge base", + actions: [ + searchAction, + listNotesAction, + listAllFilesAction, + listDirectoryAction, + summarizeActiveNoteAction, + getActiveNoteAction, + getNoteAction, + readFileAction, + createKnowledgeAction, + noteTraversalAction, + saveFileAction, + openFileAction, + updateFileAction + ], + evaluators: [], + services: [], + providers: [], +}; + +export default obsidianPlugin; diff --git a/packages/plugin-obsidian/src/providers/obsidianClient.ts b/packages/plugin-obsidian/src/providers/obsidianClient.ts new file mode 100644 index 00000000000..94590c213fa --- /dev/null +++ b/packages/plugin-obsidian/src/providers/obsidianClient.ts @@ -0,0 +1,841 @@ +import { NoteContent, ResultNoteApi, ResultNoteSearchApi, ServerInfo } from "../types"; +import { createHash } from "crypto"; +import { + elizaLogger, + AgentRuntime, + knowledge, + stringToUuid, +} from "@elizaos/core"; + +export class ObsidianProvider { + private connected: boolean = false; + private runtime: AgentRuntime; + private static instance: ObsidianProvider | null = null; + + private constructor( + private port: number = 27123, + private token: string, + private host_url: string + ) {} + + /** + * Creates an instance of the ObsidianProvider class. + * @param runtime - The agent runtime. + * @param port - The port number to use for the Obsidian server. + * @param token - The authentication token for the Obsidian server. + * @param host_url - The URL of the Obsidian server. + * @returns An instance of the ObsidianProvider class. + */ + static async create( + runtime: AgentRuntime, + port: number, + token: string, + host_url: string = `http://127.0.0.1:${port}` + ): Promise { + if (!this.instance) { + this.instance = new ObsidianProvider(port, token, host_url); + await this.instance.connect(); + this.instance.runtime = runtime; + } + return this.instance; + } + + /** + * Opens a file in Obsidian by its path. + * @param filePath - The path to the file within the vault. + * @returns A promise that resolves when the file is successfully opened. + */ + async connect(): Promise { + if (this.connected) return; + + try { + const response = await fetch(`${this.host_url}/`, { + headers: { + Authorization: `Bearer ${this.token}`, + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const serverInfo: ServerInfo = await response.json(); + + if (!serverInfo.authenticated) { + throw new Error("Failed to authenticate with Obsidian API"); + } + + this.connected = true; + } catch (error) { + elizaLogger.error("Failed to connect to Obsidian:", error.message); + this.connected = false; + throw error; + } + } + + /** + * Retrieves a list of all notes within the vault. + * @returns A promise that resolves to an array of note paths. + */ + async listNotes(): Promise { + if (!this.connected) { + await this.connect(); + } + + try { + const response = await fetch(`${this.host_url}/vault/`, { + headers: { + Authorization: `Bearer ${this.token}`, + accept: "application/json", + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const notes: string[] = await response.json(); + return notes; + } catch (error) { + elizaLogger.error("Failed to list notes:", error.message); + throw error; + } + } + + /** + * Retrieves the content of a specific note. + * @param path - The path to the note within the vault. + * @returns A promise that resolves to the content of the note. + */ + async getNote(path: string): Promise { + if (!this.connected) { + await this.connect(); + } + + try { + const response = await fetch( + `${this.host_url}/vault/${encodeURIComponent( + path + )}`, + { + headers: { + Authorization: `Bearer ${this.token}`, + accept: "application/vnd.olrapi.note+json", + }, + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const noteContent: NoteContent = await response.json(); + return noteContent; + } catch (error) { + elizaLogger.error("Failed to fetch note content:", error); + throw error; + } + } + + /** + * Retrieves the content of the currently active note. + * @returns A promise that resolves to the content of the active note. + */ + async getActiveNote(): Promise { + if (!this.connected) { + await this.connect(); + } + + try { + const response = await fetch( + `${this.host_url}/active/`, + { + headers: { + Authorization: `Bearer ${this.token}`, + accept: "application/vnd.olrapi.note+json", + }, + } + ); + + if (!response.ok) { + if (response.status === 404) { + throw new Error("No active file found in Obsidian"); + } + throw new Error(`HTTP error! status: ${response.status}`); + } + + const noteContent: NoteContent = await response.json(); + return noteContent; + } catch (error) { + elizaLogger.error("Failed to fetch active note content:", error.message); + throw error; + } + } + + /** + * Saves the content of a note to the vault. + * @param path - The path to the note within the vault. + * @param content - The content to save to the note. + * @param createDirectories - Whether to create directories if they don't exist. + * @returns A promise that resolves when the note is successfully saved. + */ + async saveNote( + path: string, + content: string, + createDirectories: boolean = true + ): Promise { + if (!this.connected) { + await this.connect(); + } + + try { + const response = await fetch( + `${this.host_url}/vault/${encodeURIComponent(path)}`, + { + method: "PUT", + headers: { + Authorization: `Bearer ${this.token}`, + "Content-Type": "text/markdown", + "X-Create-Directories": createDirectories.toString(), + }, + body: content, + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + } catch (error) { + elizaLogger.error("Failed to save note:", error.message); + throw error; + } + } + + /** + * Retrieves a list of all files within the vault. + * @returns A promise that resolves to an array of file paths. + */ + async listFiles(): Promise { + if (!this.connected) { + await this.connect(); + } + + try { + const response = await fetch(`${this.host_url}/vault/`, { + headers: { + Authorization: `Bearer ${this.token}`, + accept: "application/json", + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const vault: Record = await response.json(); + return vault.files as string[]; + } catch (error) { + elizaLogger.error("Failed to list files:", error.message); + throw error; + } + } + + /** + * Retrieves a list of all files within a specific directory. + * @param directoryPath - The path to the directory within the vault. + * @returns A promise that resolves to an array of file paths. + */ + async listDirectoryFiles(directoryPath: string): Promise { + if (!this.connected) { + await this.connect(); + } + + if (directoryPath.match(/\/$/)) { + directoryPath = `${directoryPath.replace(/\/$/, "")}`; + } + + try { + const response = await fetch( + `${this.host_url}/vault/${encodeURIComponent(directoryPath)}/`, + { + headers: { + Authorization: `Bearer ${this.token}`, + accept: "application/json", + }, + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const vaultDirectory: Record = await response.json(); + return vaultDirectory.files as string[]; + } catch (error) { + elizaLogger.error("Failed to list directory contents:", error.message); + throw error; + } + } + + /** + * Retrieves the content of a specific file from the vault. + * @param path - The path to the file within the vault. + * @returns A promise that resolves to the content of the file. + */ + async readFile(path: string): Promise { + if (!this.connected) { + await this.connect(); + } + + try { + const response = await fetch( + `${this.host_url}/vault/${encodeURIComponent(path)}`, + { + headers: { + Authorization: `Bearer ${this.token}`, + accept: "text/markdown", + "Content-Type": "text/markdown", + }, + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const content: string = await response.text(); + return content; + } catch (error) { + elizaLogger.error("Failed to read file content:", error.message); + throw error; + } + } + + + /** + * Opens a file in Obsidian by its path. + * @param filePath - The path to the file within the vault. + * @returns A promise that resolves when the file is successfully opened. + */ + async openFile(filePath: string): Promise { + if (!this.connected) { + await this.connect(); + } + + try { + const response = await fetch( + `${this.host_url}/open/${encodeURIComponent(filePath)}`, + { + method: "POST", + headers: { + Authorization: `Bearer ${this.token}`, + }, + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + elizaLogger.success(`Successfully opened file: ${filePath}`); + } catch (error) { + elizaLogger.error(`Failed to open file '${filePath}':`, error.message); + throw error; + } + } + + /** + * Saves the content of a file to the vault. + * Note: Obsidian will create a new document at the path you have specified if such a document did not already exist + * @param path - The path to the file within the vault. + * @param content - The content to save to the file. + * @param createDirectories - Whether to create directories if they don't exist. + * @returns A promise that resolves when the file is successfully saved. + */ + async saveFile( + path: string, + content: string, + createDirectories: boolean = true + ): Promise { + if (!this.connected) { + await this.connect(); + } + + try { + const response = await fetch( + `${this.host_url}/vault/${encodeURIComponent(path)}`, + { + method: "PUT", + headers: { + Authorization: `Bearer ${this.token}`, + "Content-Type": "text/markdown", + "X-Create-Directories": createDirectories.toString(), + }, + body: content, + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + } catch (error) { + elizaLogger.error("Failed to save file:", error.message); + throw error; + } + } + + /** + * Inserts content into a specific section of a file. + * @param path - The path to the file within the vault. + * @param content - The content to insert into the file. + * @param lineNumber - The line number to insert the content at. + * @returns A promise that resolves when the file is successfully patched. + */ + async patchFile( + path: string, + content: string, + lineNumber: number = 0 + ): Promise { + if (!this.connected) { + await this.connect(); + } + + try { + const response = await fetch( + `${this.host_url}/vault/${encodeURIComponent(path)}`, + { + method: "PATCH", + headers: { + Authorization: `Bearer ${this.token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ content, line: lineNumber }), + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + } catch (error) { + elizaLogger.error("Failed to patch file content:", error.message); + throw error; + } + } + + /** + * Retrieves a list of all available Obsidian commands. + * @returns A promise that resolves to an array of command objects, each containing an ID and name. + */ + async listCommands(): Promise<{ id: string; name: string }[]> { + if (!this.connected) { + await this.connect(); + } + + try { + const response = await fetch( + `${this.host_url}/commands/`, + { + headers: { + Authorization: `Bearer ${this.token}`, + accept: "application/json", + }, + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const commands: { id: string; name: string }[] = await response.json(); + return commands; + } catch (error) { + elizaLogger.error("Failed to list commands:", error.message); + throw error; + } + } + + /** + * Executes an Obsidian command by its command ID. + * @param commandId - The ID of the command to execute. + * @returns A promise that resolves when the command is successfully executed. + */ + async executeCommand(commandId: string): Promise { + if (!this.connected) { + await this.connect(); + } + + try { + const response = await fetch( + `${this.host_url}/commands/execute`, + { + method: "POST", + headers: { + Authorization: `Bearer ${this.token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ commandId }), + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + } catch (error) { + elizaLogger.error("Failed to execute command:", error.message); + throw error; + } + } + + /** + * Searches for notes in the vault based on the provided query and options. + * @param query - The query to search for. Can be a string or an object. + * @param queryFormat - The format of the query (plaintext, dataview, or jsonlogic). + * @param options - Additional options for the search. + * @returns A promise that resolves to an array of search results. + */ + async search( + query: string | object, + queryFormat: 'plaintext' | 'dataview' | 'jsonlogic' = 'plaintext', + options: { + contextLength?: number; + ignoreCase?: boolean; + isRegex?: boolean; + searchIn?: string[]; + } = {} + ): Promise { + if (!this.connected) { + await this.connect(); + } + + //ignoreCase = true, isRegex = false, searchIn = [] + const { contextLength = 100 } = options; + + // Determine Content-Type and body based on queryFormat + let contentType: string; + let body: string; + + switch (queryFormat) { + case 'dataview': + contentType = 'application/vnd.olrapi.dataview.dql+txt'; + if (typeof query !== 'string') { + throw new Error('Dataview query must be a string.'); + } + body = query; + break; + case 'jsonlogic': + contentType = 'application/vnd.olrapi.jsonlogic+json'; + if (typeof query !== 'object') { + throw new Error('JsonLogic query must be an object.'); + } + body = JSON.stringify(query); + break; + case 'plaintext': + default: + contentType = 'application/json'; + if (typeof query !== 'string') { + throw new Error('Plaintext query must be a string.'); + } + body = query; + break; + } + + try { + + elizaLogger.log( + `Processing search query with format ${queryFormat}:`, + body + ); + + if (queryFormat === 'dataview' || queryFormat === 'jsonlogic') { + + const response = await fetch(`${this.host_url}/search`, { + method: 'POST', + headers: { + Authorization: `Bearer ${this.token}`, + 'Content-Type': contentType, + Accept: 'application/json', + }, + body: body, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const results: ResultNoteSearchApi[] = await response.json(); + return results; + + } else { + + const response = await fetch(`${this.host_url}/search/simple?query=${encodeURIComponent(body)}&contextLength=${contextLength}`, { + method: 'POST', + headers: { + Authorization: `Bearer ${this.token}`, + 'Content-Type': contentType, + Accept: 'application/json', + } + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const results: ResultNoteApi[] = await response.json(); + return results; + } + + } catch (error) { + elizaLogger.error('Search failed:', error.message); + throw error; + } + } + + + /** + * Searches for notes in the vault based on the provided query and options. + * @param query - The query to search for. Can be a string or an object. + * @param queryFormat - The format of the query (plaintext, dataview, or jsonlogic). + * @param options - Additional options for the search. + * @returns A promise that resolves to an array of search results. + */ + async searchKeywords( + query: string, + contextLength: number = 100 + ): Promise { + if (!this.connected) { + await this.connect(); + } + + // Split on OR to get main chunks + const orQueries = query.split(/\s+OR\s+/).map((q) => q.trim()); + + elizaLogger.log( + `Processing search query with OR operator:`, + orQueries + ); + + try { + const allResults: ResultNoteApi[] = []; + + // Handle each OR chunk separately + for (const orQuery of orQueries) { + const response = await fetch( + `${this.host_url}/search/simple/?query=${encodeURIComponent(orQuery)}&contextLength=${contextLength}`, + { + method: "POST", + headers: { + Authorization: `Bearer ${this.token}`, + accept: "application/json", + }, + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const results: ResultNoteApi[] = await response.json(); + allResults.push(...results); + } + + // Remove duplicates based on filename + const uniqueResults = Array.from( + new Map( + allResults.map((item) => [item.filename, item]) + ).values() + ); + + elizaLogger.success(`Found ${uniqueResults.length} unique results`); + elizaLogger.debug("Search results:", uniqueResults); + return uniqueResults; + } catch (error) { + elizaLogger.error("Obsidian search failed:", error.message); + throw error; + } + } + + + /** + * Recursively scans directories and builds a list of all files + * @param directory - The directory to scan, empty string for root + * @returns Array of file paths in format 'directory/file.md' + */ + private async scanDirectoryRecursively(directory: string = ''): Promise { + const allFiles: string[] = []; + const dirsToProcess: string[] = [directory]; + const processedDirs = new Set(); + + while (dirsToProcess.length > 0) { + const currentDir = dirsToProcess.shift()!; + + if (processedDirs.has(currentDir)) { + continue; + } + + try { + elizaLogger.debug(`Scanning directory: ${currentDir}`); + const items = await this.listDirectoryFiles(currentDir); + + for (const item of items) { + if (item.endsWith('/')) { + // It's a directory, add to processing queue + const fullPath = currentDir ? `${currentDir}${item}` : item; + if (!processedDirs.has(fullPath)) { + dirsToProcess.push(fullPath); + } + } else if (item.endsWith('.md')) { + // It's a markdown file, add to results + const filePath = currentDir ? `${currentDir}${item}` : item; + allFiles.push(filePath); + } + } + + processedDirs.add(currentDir); + } catch (error) { + elizaLogger.error(`Error scanning directory ${currentDir}:`, error); + } + } + + return allFiles; + } + + /** + * Retrieves all files in the vault. + * @returns A promise that resolves to an array of file paths. + */ + async getAllFiles(): Promise { + if (!this.connected) { + await this.connect(); + } + + try { + elizaLogger.debug("Starting file scanning process"); + + // Get root files and directories + const rootItems = await this.listFiles(); + const allFiles: string[] = []; + + // Process root level markdown files + const rootMdFiles = rootItems.filter(item => item.endsWith('.md')); + allFiles.push(...rootMdFiles); + + // Process directories + const directories = rootItems.filter(item => item.endsWith('/')); + for (const dir of directories) { + const dirFiles = await this.scanDirectoryRecursively(dir); + allFiles.push(...dirFiles); + } + + elizaLogger.info(`Completed scanning. Found ${allFiles.length} files in vault`); + + // Remove any duplicates + const uniqueFiles = [...new Set(allFiles)]; + + return uniqueFiles; + } catch (error) { + elizaLogger.error("Error in getAllFiles:", error); + throw error; + } + } + + /** + * Creates memories from all files in the vault. + * @returns A promise that resolves to the number of memories created. + */ + async createMemoriesFromFiles(): Promise { + try { + elizaLogger.info("Starting to create memories from vault files"); + const allFiles = await this.getAllFiles(); + + elizaLogger.debug("All files:", allFiles); + elizaLogger.success(`Found ${allFiles.length} files in vault`); + //return allFiles; + + for (const file of allFiles) { + try { + // Only process markdown files + if (!file.endsWith('.md')) { + continue; + } + + // Get the file content + const content = await this.getNote(file); + if (!content) { + elizaLogger.warn(`No content found for file: ${file}`); + continue; + } + + const contentHash = createHash("sha256") + .update(JSON.stringify(content)) + .digest("hex"); + + const knowledgeId = stringToUuid( + `obsidian-${file}` + ); + + const existingDocument = + await this.runtime.documentsManager.getMemoryById(knowledgeId); + + if ( + existingDocument && + existingDocument.content["hash"] === contentHash + ) { + elizaLogger.debug(`Skipping unchanged file: ${file}`); + continue; + } + + elizaLogger.info( + `Processing knowledge for ${this.runtime.character.name} - ${file}` + ); + + await knowledge.set(this.runtime, { + id: knowledgeId, + content: { + text: content.content, + hash: contentHash, + source: "obsidian", + attachments: [], + metadata: { + path: file, + tags: content.tags, + frontmatter: content.frontmatter, + stats: content.stat + }, + }, + }); + + // delay to avoid throttling + await new Promise(resolve => setTimeout(resolve, 100)); + + } catch (error) { + elizaLogger.error(`Error processing file ${file}:`, error); + continue; + } + } + + elizaLogger.success("Finished creating memories from vault notes"); + + return allFiles.length; + + } catch (error) { + elizaLogger.error("Error in createMemoriesFromFiles:", error); + return 0; + } + } + + /** + * Checks if the client is connected to Obsidian. + * @returns `true` if the client is connected, `false` otherwise. + */ + isConnected(): boolean { + return this.connected; + } + + /** + * Closes the connection to Obsidian. + */ + close() { + this.connected = false; + ObsidianProvider.instance = null; + } +} diff --git a/packages/plugin-obsidian/src/templates/file.ts b/packages/plugin-obsidian/src/templates/file.ts new file mode 100644 index 00000000000..2e6030f481a --- /dev/null +++ b/packages/plugin-obsidian/src/templates/file.ts @@ -0,0 +1,25 @@ +export const fileTemplate = (userRequest: string) => ` +Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. + +Ensure that: +1. The path is properly formatted with correct folder structure +2. The operation matches one of the supported actions (Default: READ) +3. Content is provided when required for write operations +4. Path uses forward slashes (/) as separators +5. Make sure to remove \`\`\`json and \`\`\` from the response + +Provide the details in the following JSON format: + +\`\`\`json +{ + "path": "//", + "operation": "", + "content": "" +} +\`\`\` + +Here are the recent user messages for context: +${userRequest} + +Respond ONLY with a JSON markdown block containing only the extracted values.`; + diff --git a/packages/plugin-obsidian/src/templates/note.ts b/packages/plugin-obsidian/src/templates/note.ts new file mode 100644 index 00000000000..384a4568b63 --- /dev/null +++ b/packages/plugin-obsidian/src/templates/note.ts @@ -0,0 +1,30 @@ +export const noteTemplate = (userRequest: string) => ` +Respond with a JSON block containing ONLY the extracted values. Use null for any values that cannot be determined. + +Ensure that: +1. The path is properly formatted with correct folder structure and ends with .md +2. The operation matches one of the supported actions (Default: READ) +3. Content is provided when required for create/update operations +4. Path uses forward slashes (/) as separators +5. The note path follows Obsidian's naming conventions +6. Make sure to remove \`\`\`json and \`\`\` from the response + +Provide the details in the following JSON format: + +\`\`\`json +{ + "path": "//.md", + "operation": "", + "content": "", + "metadata": { + "tags": ["tag1", "tag2"], + "aliases": ["alias1", "alias2"] + } +} +\`\`\` + +Here are the recent user message for context: +${userRequest} + +Respond ONLY with a JSON block containing ONLY the extracted values.`; + diff --git a/packages/plugin-obsidian/src/templates/summary.ts b/packages/plugin-obsidian/src/templates/summary.ts new file mode 100644 index 00000000000..5ae5b642bcf --- /dev/null +++ b/packages/plugin-obsidian/src/templates/summary.ts @@ -0,0 +1,48 @@ +export const summaryTemplate = ` +Extract a focused summary of the provided Obsidian note content based on the following: +- **theme** (string): The main topic or theme to focus the summary around +- **content** (string): The full markdown content to be summarized + +Ensure that: +1. The summary is relevant to the specified theme/topic +2. Key points and insights related to the theme are highlighted +3. The summary maintains proper context from the original content +4. Important quotes or examples related to the theme are preserved +5. The summary length is proportional to the content's relevance to the theme +6. Make sure to remove \`\`\`json and \`\`\` from the response + +Provide the summary in the following JSON format: + +\`\`\`json +{ + "theme": "", + "summary": "", + "relevance": "", + "key_points": [ + "", + "" + ], + "related_quotes": [ + "", + "" + ] +} +\`\`\` + +Here are the recent user messages and note content for context: +{{recentMessages}} + +Note content to summarize: +{{responseData}} +`; + +export const baseSummaryTemplate = `# Summarized so far (we are adding to this) +{{currentSummary}} + +# Current note chunk we are summarizing (includes metadata) +{{currentChunk}} + +Summarization objective: {{objective}} + +# Instructions: Summarize the note content so far. Return the summary. Do not acknowledge this request, just summarize and continue the existing summary if there is one. Capture any important details to the objective. Only respond with the new summary text. +Your response should be extremely detailed and include any and all relevant information.`; diff --git a/packages/plugin-obsidian/src/templates/traversal.ts b/packages/plugin-obsidian/src/templates/traversal.ts new file mode 100644 index 00000000000..16d023141e4 --- /dev/null +++ b/packages/plugin-obsidian/src/templates/traversal.ts @@ -0,0 +1,29 @@ +export const traversalTemplate = (userRequest: string) => ` +Respond with a JSON markdown block containing ONLY the extracted values. Use null for any values that cannot be determined. + +Ensure that: +1. The path is properly formatted with correct folder structure and ends with .md +2. Depth is a reasonable number (1-5) to prevent excessive traversal +3. Content inclusion is specified when detailed analysis is needed +4. Filters are provided when specific note types or locations are targeted +5. Make sure to remove \`\`\`json and \`\`\` from the response + +Provide the details in the following JSON format: + +\`\`\`json +{ + "path": "//.md", + "depth": , + "includeContent": , + "filters": { + "tags": ["", ""], + "folders": ["", ""], + "modified": "" + } +} +\`\`\` + +Here are the recent user messages for context: +${userRequest} + +Respond ONLY with a JSON markdown block containing ONLY the extracted values.`; diff --git a/packages/plugin-obsidian/src/tests/obsidianClient.test.ts b/packages/plugin-obsidian/src/tests/obsidianClient.test.ts new file mode 100644 index 00000000000..d477185a1fd --- /dev/null +++ b/packages/plugin-obsidian/src/tests/obsidianClient.test.ts @@ -0,0 +1,370 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { ObsidianProvider } from '../providers/obsidianClient'; +import { + elizaLogger, + AgentRuntime +} from "@elizaos/core"; +import { NoteContent, ResultNoteApi, ServerInfo } from '../types'; + +// Mock fetch globally +const fetchMock = vi.fn(); +global.fetch = fetchMock; + +describe('ObsidianProvider', () => { + let obsidianProvider: ObsidianProvider; + const mockPort = 27123; + const mockToken = 'test-token'; + const mockServerInfo: ServerInfo = { + authenticated: true, + ok: true, + service: 'obsidian', + versions: { + obsidian: '1.0.0', + self: '1.0.0' + } + }; + const mockRuntime: AgentRuntime = { + logger: elizaLogger, + getSetting: vi.fn().mockReturnValue('mock-api-key'), + agentId: 'mock-agent-id', + composeState: vi.fn().mockResolvedValue({}), + } as unknown as AgentRuntime; + + beforeEach(async () => { + // Reset all mocks before each test + vi.clearAllMocks(); + + // Mock successful connection response + fetchMock.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockServerInfo) + }); + + // Create a new instance for each test + obsidianProvider = await ObsidianProvider.create(mockRuntime, mockPort, mockToken); + }); + + afterEach(() => { + vi.clearAllMocks(); + ObsidianProvider['instance'] = null; // Reset singleton + obsidianProvider.close(); + }); + + describe('create and connect', () => { + it('should create a new instance and connect successfully', async () => { + expect(obsidianProvider).toBeDefined(); + expect(fetchMock).toHaveBeenCalledWith( + 'http://127.0.0.1:27123/', + expect.objectContaining({ + headers: { + Authorization: 'Bearer test-token' + } + }) + ); + }); + + it('should throw error if connection fails', async () => { + vi.clearAllMocks(); + ObsidianProvider['instance'] = null; + fetchMock.mockRejectedValueOnce(new Error('Connection failed')); + + await expect(ObsidianProvider.create(mockRuntime, mockPort, mockToken)) + .rejects.toThrow('Connection failed'); + }); + + it('should handle authentication failure', async () => { + vi.clearAllMocks(); + ObsidianProvider['instance'] = null; + fetchMock.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve({ ...mockServerInfo, authenticated: false }) + }); + + await expect(ObsidianProvider.create(mockRuntime, mockPort, mockToken)) + .rejects.toThrow('Failed to authenticate with Obsidian API'); + }); + + it('should reuse existing instance', async () => { + const instance1 = obsidianProvider; + const instance2 = await ObsidianProvider.create(mockRuntime, mockPort, mockToken); + expect(instance1).toBe(instance2); + }); + }); + + describe('vault operations', () => { + describe('listNotes', () => { + it('should return list of notes', async () => { + const mockNotes = ['note1.md', 'note2.md']; + fetchMock.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockNotes) + }); + + const notes = await obsidianProvider.listNotes(); + expect(notes).toEqual(mockNotes); + expect(fetchMock).toHaveBeenCalledWith( + 'http://127.0.0.1:27123/vault/', + expect.objectContaining({ + headers: { + Authorization: 'Bearer test-token', + accept: 'application/json' + } + }) + ); + }); + }); + + describe('getNote', () => { + it('should return note content', async () => { + const mockNote: NoteContent = { + content: 'Test content', + path: 'test.md', + tags: ['test'], + frontmatter: {}, + stat: { + ctime: Date.now(), + mtime: Date.now(), + size: 100 + } + }; + + fetchMock.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockNote) + }); + + const note = await obsidianProvider.getNote('test.md'); + expect(note).toEqual(mockNote); + }); + }); + + describe('getActiveNote', () => { + it('should return active note content', async () => { + const mockNote: NoteContent = { + content: 'Active note content', + path: 'active.md', + tags: ['active'], + frontmatter: {}, + stat: { + ctime: Date.now(), + mtime: Date.now(), + size: 100 + } + }; + + fetchMock.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockNote) + }); + + const note = await obsidianProvider.getActiveNote(); + expect(note).toEqual(mockNote); + }); + + it('should handle no active note', async () => { + fetchMock.mockResolvedValueOnce({ + ok: false, + status: 404, + json: () => Promise.reject(new Error('Not found')) + }); + + await expect(obsidianProvider.getActiveNote()) + .rejects.toThrow('No active file found in Obsidian'); + }); + }); + }); + + describe('file operations', () => { + describe('listFiles', () => { + it('should return list of files', async () => { + const mockFiles = { files: ['file1.md', 'file2.pdf'] }; + fetchMock.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockFiles) + }); + + const files = await obsidianProvider.listFiles(); + expect(files).toEqual(mockFiles.files); + }); + }); + + describe('listDirectoryFiles', () => { + it('should return files in directory', async () => { + const mockFiles = { files: ['dir/file1.md', 'dir/file2.md'] }; + fetchMock.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockFiles) + }); + + const files = await obsidianProvider.listDirectoryFiles('dir'); + expect(files).toEqual(mockFiles.files); + }); + }); + + describe('readFile', () => { + it('should return file content', async () => { + const mockContent = '# Test Content'; + fetchMock.mockResolvedValueOnce({ + ok: true, + text: () => Promise.resolve(mockContent) + }); + + const content = await obsidianProvider.readFile('test.md'); + expect(content).toBe(mockContent); + }); + }); + }); + + describe('command operations', () => { + describe('listCommands', () => { + it('should return list of commands', async () => { + const mockCommands = [ + { id: 'cmd1', name: 'Command 1' }, + { id: 'cmd2', name: 'Command 2' } + ]; + fetchMock.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockCommands) + }); + + const commands = await obsidianProvider.listCommands(); + expect(commands).toEqual(mockCommands); + }); + }); + }); + + describe('search operations', () => { + describe('search', () => { + it('should perform plaintext search', async () => { + const mockResults: ResultNoteApi[] = [{ + filename: 'test.md', + matches: [{ + context: 'test context', + match: { start: 0, end: 4 } + }], + score: 1.0 + }]; + + fetchMock.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockResults) + }); + + const results = await obsidianProvider.search('test', 'plaintext'); + expect(results).toEqual(mockResults); + }); + + it('should perform dataview search', async () => { + const mockResults: ResultNoteApi[] = [{ + filename: 'test.md', + matches: [{ + context: 'dataview result', + match: { start: 0, end: 8 } + }], + score: 1.0 + }]; + + fetchMock.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockResults) + }); + + const results = await obsidianProvider.search('TABLE field FROM "folder"', 'dataview'); + expect(results).toEqual(mockResults); + }); + + it('should perform jsonlogic search', async () => { + const mockResults: ResultNoteApi[] = [{ + filename: 'test.md', + matches: [{ + context: 'jsonlogic result', + match: { start: 0, end: 8 } + }], + score: 1.0 + }]; + + fetchMock.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockResults) + }); + + const results = await obsidianProvider.search({ var: 'field' }, 'jsonlogic'); + expect(results).toEqual(mockResults); + }); + }); + + describe('simpleSearch', () => { + it('should perform simple search with OR operator', async () => { + const mockResults1: ResultNoteApi[] = [{ + filename: 'test1.md', + matches: [{ + context: 'keyword1 result', + match: { start: 0, end: 8 } + }], + score: 1.0 + }]; + + const mockResults2: ResultNoteApi[] = [{ + filename: 'test2.md', + matches: [{ + context: 'keyword2 result', + match: { start: 0, end: 8 } + }], + score: 1.0 + }]; + + fetchMock + .mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockResults1) + }) + .mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockResults2) + }); + + const results = await obsidianProvider.searchKeywords('keyword1 OR keyword2'); + expect(results).toHaveLength(2); + expect(results[0].filename).toBe('test1.md'); + expect(results[1].filename).toBe('test2.md'); + }); + }); + }); + + describe('error handling', () => { + it('should handle HTTP errors', async () => { + fetchMock.mockResolvedValueOnce({ + ok: false, + status: 404, + json: () => Promise.reject(new Error('Not found')) + }); + + await expect(obsidianProvider.listNotes()) + .rejects.toThrow('HTTP error! status: 404'); + }); + + it('should handle network errors', async () => { + fetchMock.mockRejectedValueOnce(new Error('Network error')); + await expect(obsidianProvider.listNotes()) + .rejects.toThrow('Network error'); + }); + + it('should handle invalid query format errors', async () => { + await expect(async () => { + await obsidianProvider.search({}, 'dataview'); + }).rejects.toThrow('Dataview query must be a string'); + + await expect(async () => { + await obsidianProvider.search('test', 'jsonlogic'); + }).rejects.toThrow('JsonLogic query must be an object'); + }); + }); + + describe('utility methods', () => { + it('should check connection status', () => { + expect(obsidianProvider.isConnected()).toBe(true); + obsidianProvider.close(); + expect(obsidianProvider.isConnected()).toBe(false); + }); + }); +}); diff --git a/packages/plugin-obsidian/src/types/index.ts b/packages/plugin-obsidian/src/types/index.ts new file mode 100644 index 00000000000..774a01acf02 --- /dev/null +++ b/packages/plugin-obsidian/src/types/index.ts @@ -0,0 +1,141 @@ +import { z } from "zod"; + +export interface SearchMatchApi { + match: { + start: number; + end: number; + }; + context: string; +} + +export const noteSchema = z.object({ + tags: z.array(z.string()).optional(), + frontmatter: z.record(z.unknown()).optional(), + stat: z.object({ + ctime: z.number(), + mtime: z.number(), + size: z.number(), + }).nullable().optional(), + path: z.string(), + content: z.string().nullable().optional(), +}); + +export type NoteContent = z.infer; + +export const isValidNote = (note: unknown): note is NoteContent => { + return noteSchema.safeParse(note).success; +}; + +export const fileSchema = z.object({ + path: z.string(), + content: z.string().nullable().optional(), + stat: z.object({ + ctime: z.number(), + mtime: z.number(), + size: z.number(), + }).nullable().optional() +}); + +export type FileContent = z.infer; + +export const isValidFile = (file: unknown): file is FileContent => { + return fileSchema.safeParse(file).success; +}; + +export interface ResultNoteApi { + filename: string; + matches: SearchMatchApi[]; + score: number; +} + +export interface ResultNoteSearchApi { + filename: string; + result: boolean; +} + +export interface ServerInfo { + authenticated: boolean; + ok: boolean; + service: string; + versions: { + obsidian: string; + self: string; + }; +} + +export interface Command { + id: string; + name: string; +} + +export interface PatchContent { + content: string; + line: number; +} + +/* +export interface NoteHierarchy { + path: string; + content: string; + links: NoteHierarchy[]; +} +*/ + +export const noteHierarchySchema = z.object({ + path: z.string(), + content: z.string().nullable().optional(), + links: z.lazy(() => z.array(noteHierarchySchema)).nullable().optional() +}); + +export type NoteHierarchy = z.infer; + +export const isValidNoteHierarchy = (hierarchy: unknown): hierarchy is NoteHierarchy => { + return noteHierarchySchema.safeParse(hierarchy).success; +}; + +export const searchKeywordSchema = z.object({ + query: z.string().min(1).describe("The keywords to search for"), + options: z + .object({ + vault: z.string().optional(), + includeExcerpt: z.boolean().optional(), + limit: z.number().optional(), + }) + .optional(), +}); + +export type SearchKeyword = z.infer; + +export function isSearchKeyword(obj: any): obj is SearchKeyword { + return searchKeywordSchema.safeParse(obj).success; +} + +export type QueryFormat = 'plaintext' | 'dataview' | 'jsonlogic'; + +export interface SearchOptions { + contextLength?: number; + ignoreCase?: boolean; + searchIn?: string[] | null; +} + +export interface SearchQuery { + query?: string; + queryFormat?: QueryFormat; + options?: SearchOptions; +} + +export const searchOptionsSchema = z.object({ + contextLength: z.number().optional(), + ignoreCase: z.boolean().nullable().optional().default(true), + searchIn: z.array(z.string()).nullable().optional().default([]), +}); + +export const searchQuerySchema = z.object({ + query: z.union([z.string(), z.record(z.unknown())]).describe("The query to search for"), + queryFormat: z.enum(['plaintext', 'dataview', 'jsonlogic']).describe("The format of the query"), + options: searchOptionsSchema.optional().describe("Search options"), +}); + +export const isSearchQuery = (obj: unknown): obj is SearchQuery => { + return searchQuerySchema.safeParse(obj).success; +}; diff --git a/packages/plugin-obsidian/tsconfig.json b/packages/plugin-obsidian/tsconfig.json new file mode 100644 index 00000000000..265a5b9dc74 --- /dev/null +++ b/packages/plugin-obsidian/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "typeRoots": [ + "./node_modules/@types", + "./src/types" + ], + "declaration": true + }, + "include": [ + "src/**/*.ts" + ] +} \ No newline at end of file diff --git a/packages/plugin-obsidian/tsup.config.ts b/packages/plugin-obsidian/tsup.config.ts new file mode 100644 index 00000000000..b5e4388b214 --- /dev/null +++ b/packages/plugin-obsidian/tsup.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], // Ensure you're targeting CommonJS + external: [ + "dotenv", // Externalize dotenv to prevent bundling + "fs", // Externalize fs to use Node.js built-in module + "path", // Externalize other built-ins if necessary + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + "zod", + // Add other modules you want to externalize + ], +}); diff --git a/packages/plugin-solana/src/actions/fomo.ts b/packages/plugin-solana/src/actions/fomo.ts index aa4777b0ec3..e9713c62eb4 100644 --- a/packages/plugin-solana/src/actions/fomo.ts +++ b/packages/plugin-solana/src/actions/fomo.ts @@ -1,4 +1,4 @@ -import { generateImage } from "@elizaos/core"; +import { generateImage, elizaLogger } from "@elizaos/core"; import { Connection, Keypair, @@ -44,7 +44,7 @@ export interface CreateAndBuyContent extends Content { export function isCreateAndBuyContentForFomo( content: any ): content is CreateAndBuyContent { - console.log("Content for create & buy", content); + elizaLogger.log("Content for create & buy", content); return ( typeof content.tokenMetadata === "object" && content.tokenMetadata !== null && @@ -121,7 +121,7 @@ export const createAndBuyToken = async ({ preflightCommitment: "confirmed", }); - console.log("Transaction sent:", txid); + elizaLogger.log("Transaction sent:", txid); // Confirm transaction using the blockhash const confirmation = await connection.confirmTransaction( @@ -134,7 +134,7 @@ export const createAndBuyToken = async ({ ); if (!confirmation.value.err) { - console.log( + elizaLogger.log( "Success:", `https://fomo.fund/token/${mint.publicKey.toBase58()}` ); @@ -149,12 +149,12 @@ export const createAndBuyToken = async ({ ); const amount = balance.value.uiAmount; if (amount === null) { - console.log( + elizaLogger.log( `${deployer.publicKey.toBase58()}:`, "No Account Found" ); } else { - console.log(`${deployer.publicKey.toBase58()}:`, amount); + elizaLogger.log(`${deployer.publicKey.toBase58()}:`, amount); } return { @@ -163,7 +163,7 @@ export const createAndBuyToken = async ({ creator: deployer.publicKey.toBase58(), }; } else { - console.log("Create and Buy failed"); + elizaLogger.log("Create and Buy failed"); return { success: false, ca: mint.publicKey.toBase58(), @@ -231,7 +231,7 @@ export const buyToken = async ({ preflightCommitment: "confirmed", }); - console.log("Transaction sent:", txid); + elizaLogger.log("Transaction sent:", txid); // Confirm transaction using the blockhash const confirmation = await connection.confirmTransaction( @@ -244,7 +244,10 @@ export const buyToken = async ({ ); if (!confirmation.value.err) { - console.log("Success:", `https://fomo.fund/token/${mint.toBase58()}`); + elizaLogger.log( + "Success:", + `https://fomo.fund/token/${mint.toBase58()}` + ); const ata = getAssociatedTokenAddressSync( mint, buyer.publicKey, @@ -256,12 +259,15 @@ export const buyToken = async ({ ); const amount = balance.value.uiAmount; if (amount === null) { - console.log(`${buyer.publicKey.toBase58()}:`, "No Account Found"); + elizaLogger.log( + `${buyer.publicKey.toBase58()}:`, + "No Account Found" + ); } else { - console.log(`${buyer.publicKey.toBase58()}:`, amount); + elizaLogger.log(`${buyer.publicKey.toBase58()}:`, amount); } } else { - console.log("Buy failed"); + elizaLogger.log("Buy failed"); } }; @@ -324,7 +330,7 @@ export const sellToken = async ({ preflightCommitment: "confirmed", }); - console.log("Transaction sent:", txid); + elizaLogger.log("Transaction sent:", txid); // Confirm transaction using the blockhash const confirmation = await connection.confirmTransaction( @@ -337,7 +343,10 @@ export const sellToken = async ({ ); if (!confirmation.value.err) { - console.log("Success:", `https://fomo.fund/token/${mint.toBase58()}`); + elizaLogger.log( + "Success:", + `https://fomo.fund/token/${mint.toBase58()}` + ); const ata = getAssociatedTokenAddressSync( mint, seller.publicKey, @@ -349,12 +358,15 @@ export const sellToken = async ({ ); const amount = balance.value.uiAmount; if (amount === null) { - console.log(`${seller.publicKey.toBase58()}:`, "No Account Found"); + elizaLogger.log( + `${seller.publicKey.toBase58()}:`, + "No Account Found" + ); } else { - console.log(`${seller.publicKey.toBase58()}:`, amount); + elizaLogger.log(`${seller.publicKey.toBase58()}:`, amount); } } else { - console.log("Sell failed"); + elizaLogger.log("Sell failed"); } }; @@ -404,7 +416,7 @@ export default { _options: { [key: string]: unknown }, callback?: HandlerCallback ): Promise => { - console.log("Starting CREATE_AND_BUY_TOKEN handler..."); + elizaLogger.log("Starting CREATE_AND_BUY_TOKEN handler..."); // Compose state if not provided if (!state) { @@ -431,7 +443,9 @@ export default { // Validate the generated content if (!isCreateAndBuyContentForFomo(content)) { - console.error("Invalid content for CREATE_AND_BUY_TOKEN action."); + elizaLogger.error( + "Invalid content for CREATE_AND_BUY_TOKEN action." + ); return false; } @@ -451,11 +465,11 @@ export default { // Remove the "data:image/png;base64," prefix if present tokenMetadata.file = imageResult.data[0].replace(/^data:image\/[a-z]+;base64,/, ''); } else { - console.error("Failed to generate image:", imageResult.error); + elizaLogger.error("Failed to generate image:", imageResult.error); return false; } } catch (error) { - console.error("Error generating image:", error); + elizaLogger.error("Error generating image:", error); return false; } } */ @@ -511,7 +525,7 @@ export default { // Generate new mint keypair const mintKeypair = Keypair.generate(); - console.log( + elizaLogger.log( `Generated mint address: ${mintKeypair.publicKey.toBase58()}` ); @@ -527,14 +541,14 @@ export default { const createAndBuyConfirmation = await promptConfirmation(); if (!createAndBuyConfirmation) { - console.log("Create and buy token canceled by user"); + elizaLogger.log("Create and buy token canceled by user"); return false; } // Convert SOL to lamports (1 SOL = 1_000_000_000 lamports) const lamports = Math.floor(Number(buyAmountSol) * 1_000_000_000); - console.log("Executing create and buy transaction..."); + elizaLogger.log("Executing create and buy transaction..."); const result = await createAndBuyToken({ deployer: deployerKeypair, mint: mintKeypair, @@ -583,7 +597,7 @@ export default { */ // Log success message with token view URL const successMessage = `Token created and purchased successfully! View at: https://fomo.fund/token/${mintKeypair.publicKey.toBase58()}`; - console.log(successMessage); + elizaLogger.log(successMessage); return result.success; } catch (error) { if (callback) { diff --git a/packages/plugin-solana/src/actions/pumpfun.ts b/packages/plugin-solana/src/actions/pumpfun.ts index b563139e3b1..30d6f292375 100644 --- a/packages/plugin-solana/src/actions/pumpfun.ts +++ b/packages/plugin-solana/src/actions/pumpfun.ts @@ -17,6 +17,7 @@ import { generateObjectDeprecated, composeContext, type Action, + elizaLogger, } from "@elizaos/core"; import { walletProvider } from "../providers/wallet.ts"; @@ -35,7 +36,7 @@ export function isCreateAndBuyContent( runtime: IAgentRuntime, content: any ): content is CreateAndBuyContent { - console.log("Content for create & buy", content); + elizaLogger.log("Content for create & buy", content); return ( typeof content.tokenMetadata === "object" && content.tokenMetadata !== null && @@ -89,10 +90,10 @@ export const createAndBuyToken = async ({ commitment ); - console.log("Create Results: ", createResults); + elizaLogger.log("Create Results: ", createResults); if (createResults.success) { - console.log( + elizaLogger.log( "Success:", `https://pump.fun/${mint.publicKey.toBase58()}` ); @@ -107,12 +108,12 @@ export const createAndBuyToken = async ({ ); const amount = balance.value.uiAmount; if (amount === null) { - console.log( + elizaLogger.log( `${deployer.publicKey.toBase58()}:`, "No Account Found" ); } else { - console.log(`${deployer.publicKey.toBase58()}:`, amount); + elizaLogger.log(`${deployer.publicKey.toBase58()}:`, amount); } return { @@ -121,7 +122,7 @@ export const createAndBuyToken = async ({ creator: deployer.publicKey.toBase58(), }; } else { - console.log("Create and Buy failed"); + elizaLogger.log("Create and Buy failed"); return { success: false, ca: mint.publicKey.toBase58(), @@ -157,7 +158,7 @@ export const buyToken = async ({ priorityFee ); if (buyResults.success) { - console.log("Success:", `https://pump.fun/${mint.toBase58()}`); + elizaLogger.log("Success:", `https://pump.fun/${mint.toBase58()}`); const ata = getAssociatedTokenAddressSync( mint, buyer.publicKey, @@ -169,12 +170,15 @@ export const buyToken = async ({ ); const amount = balance.value.uiAmount; if (amount === null) { - console.log(`${buyer.publicKey.toBase58()}:`, "No Account Found"); + elizaLogger.log( + `${buyer.publicKey.toBase58()}:`, + "No Account Found" + ); } else { - console.log(`${buyer.publicKey.toBase58()}:`, amount); + elizaLogger.log(`${buyer.publicKey.toBase58()}:`, amount); } } else { - console.log("Buy failed"); + elizaLogger.log("Buy failed"); } }; @@ -205,7 +209,7 @@ export const sellToken = async ({ priorityFee ); if (sellResults.success) { - console.log("Success:", `https://pump.fun/${mint.toBase58()}`); + elizaLogger.log("Success:", `https://pump.fun/${mint.toBase58()}`); const ata = getAssociatedTokenAddressSync( mint, seller.publicKey, @@ -217,12 +221,15 @@ export const sellToken = async ({ ); const amount = balance.value.uiAmount; if (amount === null) { - console.log(`${seller.publicKey.toBase58()}:`, "No Account Found"); + elizaLogger.log( + `${seller.publicKey.toBase58()}:`, + "No Account Found" + ); } else { - console.log(`${seller.publicKey.toBase58()}:`, amount); + elizaLogger.log(`${seller.publicKey.toBase58()}:`, amount); } } else { - console.log("Sell failed"); + elizaLogger.log("Sell failed"); } }; @@ -283,7 +290,7 @@ export default { _options: { [key: string]: unknown }, callback?: HandlerCallback ): Promise => { - console.log("Starting CREATE_AND_BUY_TOKEN handler..."); + elizaLogger.log("Starting CREATE_AND_BUY_TOKEN handler..."); // Compose state if not provided if (!state) { @@ -310,7 +317,9 @@ export default { // Validate the generated content if (!isCreateAndBuyContent(runtime, content)) { - console.error("Invalid content for CREATE_AND_BUY_TOKEN action."); + elizaLogger.error( + "Invalid content for CREATE_AND_BUY_TOKEN action." + ); return false; } @@ -330,11 +339,11 @@ export default { // Remove the "data:image/png;base64," prefix if present tokenMetadata.file = imageResult.data[0].replace(/^data:image\/[a-z]+;base64,/, ''); } else { - console.error("Failed to generate image:", imageResult.error); + elizaLogger.error("Failed to generate image:", imageResult.error); return false; } } catch (error) { - console.error("Error generating image:", error); + elizaLogger.error("Error generating image:", error); return false; } } */ @@ -361,7 +370,7 @@ export default { `generated_image_${Date.now()}.txt` ); fs.writeFileSync(outputPath, base64Data); - console.log(`Base64 data saved to: ${outputPath}`); + elizaLogger.log(`Base64 data saved to: ${outputPath}`); const byteCharacters = atob(base64Data); const byteNumbers = new Array(byteCharacters.length); @@ -394,7 +403,7 @@ export default { // Generate new mint keypair const mintKeypair = Keypair.generate(); - console.log( + elizaLogger.log( `Generated mint address: ${mintKeypair.publicKey.toBase58()}` ); @@ -414,14 +423,14 @@ export default { const createAndBuyConfirmation = await promptConfirmation(); if (!createAndBuyConfirmation) { - console.log("Create and buy token canceled by user"); + elizaLogger.log("Create and buy token canceled by user"); return false; } // Convert SOL to lamports (1 SOL = 1_000_000_000 lamports) const lamports = Math.floor(Number(buyAmountSol) * 1_000_000_000); - console.log("Executing create and buy transaction..."); + elizaLogger.log("Executing create and buy transaction..."); const result = await createAndBuyToken({ deployer: deployerKeypair, mint: mintKeypair, @@ -469,7 +478,7 @@ export default { */ // Log success message with token view URL const successMessage = `Token created and purchased successfully! View at: https://pump.fun/${mintKeypair.publicKey.toBase58()}`; - console.log(successMessage); + elizaLogger.log(successMessage); return result.success; } catch (error) { if (callback) { diff --git a/packages/plugin-solana/src/actions/swap.ts b/packages/plugin-solana/src/actions/swap.ts index a0fd9c2b8bc..87006cb3773 100644 --- a/packages/plugin-solana/src/actions/swap.ts +++ b/packages/plugin-solana/src/actions/swap.ts @@ -9,6 +9,7 @@ import { settings, State, type Action, + elizaLogger, } from "@elizaos/core"; import { Connection, PublicKey, VersionedTransaction } from "@solana/web3.js"; import BigNumber from "bignumber.js"; @@ -32,7 +33,7 @@ async function swapToken( await getTokenDecimals(connection, inputTokenCA) ); - console.log("Decimals:", decimals.toString()); + elizaLogger.log("Decimals:", decimals.toString()); // Use BigNumber for adjustedAmount: amount * (10 ** decimals) const amountBN = new BigNumber(amount); @@ -40,7 +41,7 @@ async function swapToken( new BigNumber(10).pow(decimals) ); - console.log("Fetching quote with params:", { + elizaLogger.log("Fetching quote with params:", { inputMint: inputTokenCA, outputMint: outputTokenCA, amount: adjustedAmount, @@ -52,13 +53,13 @@ async function swapToken( const quoteData = await quoteResponse.json(); if (!quoteData || quoteData.error) { - console.error("Quote error:", quoteData); + elizaLogger.error("Quote error:", quoteData); throw new Error( `Failed to get quote: ${quoteData?.error || "Unknown error"}` ); } - console.log("Quote received:", quoteData); + elizaLogger.log("Quote received:", quoteData); const swapRequestBody = { quoteResponse: quoteData, @@ -67,11 +68,11 @@ async function swapToken( dynamicSlippage: true, priorityLevelWithMaxLamports: { maxLamports: 4000000, - priorityLevel: "veryHigh" - } + priorityLevel: "veryHigh", + }, }; - console.log("Requesting swap with body:", swapRequestBody); + elizaLogger.log("Requesting swap with body:", swapRequestBody); const swapResponse = await fetch("https://quote-api.jup.ag/v6/swap", { method: "POST", @@ -84,16 +85,16 @@ async function swapToken( const swapData = await swapResponse.json(); if (!swapData || !swapData.swapTransaction) { - console.error("Swap error:", swapData); + elizaLogger.error("Swap error:", swapData); throw new Error( `Failed to get swap transaction: ${swapData?.error || "No swap transaction returned"}` ); } - console.log("Swap transaction received"); + elizaLogger.log("Swap transaction received"); return swapData; } catch (error) { - console.error("Error in swapToken:", error); + elizaLogger.error("Error in swapToken:", error); throw error; } } @@ -162,7 +163,7 @@ async function getTokenFromWallet(runtime: IAgentRuntime, tokenSymbol: string) { return null; } } catch (error) { - console.error("Error checking token in wallet:", error); + elizaLogger.error("Error checking token in wallet:", error); return null; } } @@ -174,7 +175,7 @@ export const executeSwap: Action = { similes: ["SWAP_TOKENS", "TOKEN_SWAP", "TRADE_TOKENS", "EXCHANGE_TOKENS"], validate: async (runtime: IAgentRuntime, message: Memory) => { // Check if the necessary parameters are provided in the message - console.log("Message:", message); + elizaLogger.log("Message:", message); return true; }, description: "Perform a token swap.", @@ -207,7 +208,7 @@ export const executeSwap: Action = { modelClass: ModelClass.LARGE, }); - console.log("Response:", response); + elizaLogger.log("Response:", response); // const type = response.inputTokenSymbol?.toUpperCase() === "SOL" ? "buy" : "sell"; // Add SOL handling logic @@ -221,7 +222,7 @@ export const executeSwap: Action = { // if both contract addresses are set, lets execute the swap // TODO: try to resolve CA from symbol based on existing symbol in wallet if (!response.inputTokenCA && response.inputTokenSymbol) { - console.log( + elizaLogger.log( `Attempting to resolve CA for input token symbol: ${response.inputTokenSymbol}` ); response.inputTokenCA = await getTokenFromWallet( @@ -229,9 +230,13 @@ export const executeSwap: Action = { response.inputTokenSymbol ); if (response.inputTokenCA) { - console.log(`Resolved inputTokenCA: ${response.inputTokenCA}`); + elizaLogger.log( + `Resolved inputTokenCA: ${response.inputTokenCA}` + ); } else { - console.log("No contract addresses provided, skipping swap"); + elizaLogger.log( + "No contract addresses provided, skipping swap" + ); const responseMsg = { text: "I need the contract addresses to perform the swap", }; @@ -241,7 +246,7 @@ export const executeSwap: Action = { } if (!response.outputTokenCA && response.outputTokenSymbol) { - console.log( + elizaLogger.log( `Attempting to resolve CA for output token symbol: ${response.outputTokenSymbol}` ); response.outputTokenCA = await getTokenFromWallet( @@ -249,11 +254,13 @@ export const executeSwap: Action = { response.outputTokenSymbol ); if (response.outputTokenCA) { - console.log( + elizaLogger.log( `Resolved outputTokenCA: ${response.outputTokenCA}` ); } else { - console.log("No contract addresses provided, skipping swap"); + elizaLogger.log( + "No contract addresses provided, skipping swap" + ); const responseMsg = { text: "I need the contract addresses to perform the swap", }; @@ -263,7 +270,7 @@ export const executeSwap: Action = { } if (!response.amount) { - console.log("No amount provided, skipping swap"); + elizaLogger.log("No amount provided, skipping swap"); const responseMsg = { text: "I need the amount to perform the swap", }; @@ -273,7 +280,7 @@ export const executeSwap: Action = { // TODO: if response amount is half, all, etc, semantically retrieve amount and return as number if (!response.amount) { - console.log("Amount is not a number, skipping swap"); + elizaLogger.log("Amount is not a number, skipping swap"); const responseMsg = { text: "The amount must be a number", }; @@ -291,10 +298,10 @@ export const executeSwap: Action = { // const provider = new WalletProvider(connection, walletPublicKey); - console.log("Wallet Public Key:", walletPublicKey); - console.log("inputTokenSymbol:", response.inputTokenCA); - console.log("outputTokenSymbol:", response.outputTokenCA); - console.log("amount:", response.amount); + elizaLogger.log("Wallet Public Key:", walletPublicKey); + elizaLogger.log("inputTokenSymbol:", response.inputTokenCA); + elizaLogger.log("outputTokenSymbol:", response.outputTokenCA); + elizaLogger.log("amount:", response.amount); const swapResult = await swapToken( connection, @@ -304,7 +311,7 @@ export const executeSwap: Action = { response.amount as number ); - console.log("Deserializing transaction..."); + elizaLogger.log("Deserializing transaction..."); const transactionBuf = Buffer.from( swapResult.swapTransaction, "base64" @@ -312,9 +319,9 @@ export const executeSwap: Action = { const transaction = VersionedTransaction.deserialize(transactionBuf); - console.log("Preparing to sign transaction..."); + elizaLogger.log("Preparing to sign transaction..."); - console.log("Creating keypair..."); + elizaLogger.log("Creating keypair..."); const { keypair } = await getWalletKey(runtime, true); // Verify the public key matches what we expect if (keypair.publicKey.toBase58() !== walletPublicKey.toBase58()) { @@ -323,10 +330,10 @@ export const executeSwap: Action = { ); } - console.log("Signing transaction..."); + elizaLogger.log("Signing transaction..."); transaction.sign([keypair]); - console.log("Sending transaction..."); + elizaLogger.log("Sending transaction..."); const latestBlockhash = await connection.getLatestBlockhash(); @@ -336,7 +343,7 @@ export const executeSwap: Action = { preflightCommitment: "confirmed", }); - console.log("Transaction sent:", txid); + elizaLogger.log("Transaction sent:", txid); // Confirm transaction using the blockhash const confirmation = await connection.confirmTransaction( @@ -360,8 +367,8 @@ export const executeSwap: Action = { ); } - console.log("Swap completed successfully!"); - console.log(`Transaction ID: ${txid}`); + elizaLogger.log("Swap completed successfully!"); + elizaLogger.log(`Transaction ID: ${txid}`); const responseMsg = { text: `Swap completed successfully! Transaction ID: ${txid}`, @@ -371,7 +378,7 @@ export const executeSwap: Action = { return true; } catch (error) { - console.error("Error during token swap:", error); + elizaLogger.error("Error during token swap:", error); return false; } }, diff --git a/packages/plugin-solana/src/actions/swapDao.ts b/packages/plugin-solana/src/actions/swapDao.ts index 7a89d3f8272..0ebaa8569ec 100644 --- a/packages/plugin-solana/src/actions/swapDao.ts +++ b/packages/plugin-solana/src/actions/swapDao.ts @@ -3,6 +3,7 @@ import { IAgentRuntime, Memory, type Action, + elizaLogger, } from "@elizaos/core"; import { Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js"; import { getQuote } from "./swapUtils.ts"; @@ -53,7 +54,7 @@ export const executeSwapForDAO: Action = { name: "EXECUTE_SWAP_DAO", similes: ["SWAP_TOKENS_DAO", "TOKEN_SWAP_DAO"], validate: async (runtime: IAgentRuntime, message: Memory) => { - console.log("Message:", message); + elizaLogger.log("Message:", message); return true; }, description: "Perform a DAO token swap using execute_invoke.", @@ -88,11 +89,11 @@ export const executeSwapForDAO: Action = { outputToken as string, amount as number ); - console.log("Swap Quote:", quoteData); + elizaLogger.log("Swap Quote:", quoteData); const confirmSwap = await promptConfirmation(); if (!confirmSwap) { - console.log("Swap canceled by user"); + elizaLogger.log("Swap canceled by user"); return false; } @@ -113,12 +114,12 @@ export const executeSwapForDAO: Action = { instructionData ); - console.log("DAO Swap completed successfully!"); - console.log(`Transaction ID: ${txid}`); + elizaLogger.log("DAO Swap completed successfully!"); + elizaLogger.log(`Transaction ID: ${txid}`); return true; } catch (error) { - console.error("Error during DAO token swap:", error); + elizaLogger.error("Error during DAO token swap:", error); return false; } }, diff --git a/packages/plugin-solana/src/actions/swapUtils.ts b/packages/plugin-solana/src/actions/swapUtils.ts index b23cc939f46..64dcd713c6b 100644 --- a/packages/plugin-solana/src/actions/swapUtils.ts +++ b/packages/plugin-solana/src/actions/swapUtils.ts @@ -9,7 +9,7 @@ import { TokenAmount, VersionedTransaction, } from "@solana/web3.js"; -import { settings } from "@elizaos/core"; +import { settings, elizaLogger } from "@elizaos/core"; const solAddress = settings.SOL_ADDRESS; const SLIPPAGE = settings.SLIPPAGE; @@ -85,16 +85,16 @@ export const executeSwap = async ( "finalized" ); if (confirmation.value.err) { - console.log("Confirmation error", confirmation.value.err); + elizaLogger.log("Confirmation error", confirmation.value.err); throw new Error("Confirmation error"); } else { if (type === "buy") { - console.log( + elizaLogger.log( "Buy successful: https://solscan.io/tx/${signature}" ); } else { - console.log( + elizaLogger.log( "Sell successful: https://solscan.io/tx/${signature}" ); } @@ -102,7 +102,7 @@ export const executeSwap = async ( return signature; } catch (error) { - console.log(error); + elizaLogger.log(error); } }; @@ -120,13 +120,13 @@ export const Sell = async (baseMint: PublicKey, wallet: Keypair) => { ); if (!tokenBalInfo) { - console.log("Balance incorrect"); + elizaLogger.log("Balance incorrect"); return null; } const tokenBalance = tokenBalInfo.value.amount; if (tokenBalance === "0") { - console.warn( + elizaLogger.warn( `No token balance to sell with wallet ${wallet.publicKey}` ); } @@ -139,7 +139,7 @@ export const Sell = async (baseMint: PublicKey, wallet: Keypair) => { ); // simulate the transaction if (!sellTransaction) { - console.log("Failed to get sell transaction"); + elizaLogger.log("Failed to get sell transaction"); return null; } @@ -149,14 +149,14 @@ export const Sell = async (baseMint: PublicKey, wallet: Keypair) => { sellTransaction ); if (simulateResult.value.err) { - console.log("Sell Simulation failed", simulateResult.value.err); + elizaLogger.log("Sell Simulation failed", simulateResult.value.err); return null; } // execute the transaction return executeSwap(sellTransaction, "sell"); } catch (error) { - console.log(error); + elizaLogger.log(error); } }; @@ -174,13 +174,13 @@ export const Buy = async (baseMint: PublicKey, wallet: Keypair) => { ); if (!tokenBalInfo) { - console.log("Balance incorrect"); + elizaLogger.log("Balance incorrect"); return null; } const tokenBalance = tokenBalInfo.value.amount; if (tokenBalance === "0") { - console.warn( + elizaLogger.warn( `No token balance to sell with wallet ${wallet.publicKey}` ); } @@ -193,7 +193,7 @@ export const Buy = async (baseMint: PublicKey, wallet: Keypair) => { ); // simulate the transaction if (!buyTransaction) { - console.log("Failed to get buy transaction"); + elizaLogger.log("Failed to get buy transaction"); return null; } @@ -203,14 +203,14 @@ export const Buy = async (baseMint: PublicKey, wallet: Keypair) => { buyTransaction ); if (simulateResult.value.err) { - console.log("Buy Simulation failed", simulateResult.value.err); + elizaLogger.log("Buy Simulation failed", simulateResult.value.err); return null; } // execute the transaction return executeSwap(buyTransaction, "buy"); } catch (error) { - console.log(error); + elizaLogger.log(error); } }; @@ -230,7 +230,7 @@ export const getSwapTxWithWithJupiter = async ( return fetchSellTransaction(wallet, baseMint, amount); } } catch (error) { - console.log(error); + elizaLogger.log(error); } }; @@ -261,7 +261,7 @@ export const fetchBuyTransaction = async ( }) ).json(); if (!swapTransaction) { - console.log("Failed to get buy transaction"); + elizaLogger.log("Failed to get buy transaction"); return null; } @@ -274,7 +274,7 @@ export const fetchBuyTransaction = async ( transaction.sign([wallet]); return transaction; } catch (error) { - console.log("Failed to get buy transaction", error); + elizaLogger.log("Failed to get buy transaction", error); return null; } }; @@ -308,7 +308,7 @@ export const fetchSellTransaction = async ( }) ).json(); if (!swapTransaction) { - console.log("Failed to get sell transaction"); + elizaLogger.log("Failed to get sell transaction"); return null; } @@ -321,7 +321,7 @@ export const fetchSellTransaction = async ( transaction.sign([wallet]); return transaction; } catch (error) { - console.log("Failed to get sell transaction", error); + elizaLogger.log("Failed to get sell transaction", error); return null; } }; diff --git a/packages/plugin-solana/src/actions/takeOrder.ts b/packages/plugin-solana/src/actions/takeOrder.ts index 99b188b85d2..83e21c7daf3 100644 --- a/packages/plugin-solana/src/actions/takeOrder.ts +++ b/packages/plugin-solana/src/actions/takeOrder.ts @@ -4,9 +4,9 @@ import { Memory, Content, ModelClass, + composeContext, + generateText, } from "@elizaos/core"; -import { composeContext } from "@elizaos/core"; -import { generateText } from "@elizaos/core"; interface Order { userId: string; diff --git a/packages/plugin-solana/src/actions/transfer.ts b/packages/plugin-solana/src/actions/transfer.ts index 0769e6b9f70..4c0b40e339d 100644 --- a/packages/plugin-solana/src/actions/transfer.ts +++ b/packages/plugin-solana/src/actions/transfer.ts @@ -35,7 +35,7 @@ function isTransferContent( runtime: IAgentRuntime, content: any ): content is TransferContent { - console.log("Content for transfer", content); + elizaLogger.log("Content for transfer", content); return ( typeof content.tokenAddress === "string" && typeof content.recipient === "string" && @@ -74,21 +74,21 @@ export default { "PAY", ], validate: async (runtime: IAgentRuntime, message: Memory) => { - console.log("Validating transfer from user:", message.userId); + elizaLogger.log("Validating transfer from user:", message.userId); //add custom validate logic here /* const adminIds = runtime.getSetting("ADMIN_USER_IDS")?.split(",") || []; - //console.log("Admin IDs from settings:", adminIds); + //elizaLogger.log("Admin IDs from settings:", adminIds); const isAdmin = adminIds.includes(message.userId); if (isAdmin) { - //console.log(`Authorized transfer from user: ${message.userId}`); + //elizaLogger.log(`Authorized transfer from user: ${message.userId}`); return true; } else { - //console.log(`Unauthorized transfer attempt from user: ${message.userId}`); + //elizaLogger.log(`Unauthorized transfer attempt from user: ${message.userId}`); return false; } */ @@ -126,7 +126,7 @@ export default { // Validate transfer content if (!isTransferContent(runtime, content)) { - console.error("Invalid content for TRANSFER_TOKEN action."); + elizaLogger.error("Invalid content for TRANSFER_TOKEN action."); if (callback) { callback({ text: "Unable to process transfer request. Invalid content provided.", @@ -156,7 +156,7 @@ export default { const adjustedAmount = BigInt( Number(content.amount) * Math.pow(10, decimals) ); - console.log( + elizaLogger.log( `Transferring: ${content.amount} tokens (${adjustedAmount} base units)` ); @@ -210,7 +210,7 @@ export default { // Send transaction const signature = await connection.sendTransaction(transaction); - console.log("Transfer successful:", signature); + elizaLogger.log("Transfer successful:", signature); if (callback) { callback({ @@ -226,7 +226,7 @@ export default { return true; } catch (error) { - console.error("Error during token transfer:", error); + elizaLogger.error("Error during token transfer:", error); if (callback) { callback({ text: `Error transferring tokens: ${error.message}`, diff --git a/packages/plugin-solana/src/evaluators/trust.ts b/packages/plugin-solana/src/evaluators/trust.ts index d1b65a83984..0feadb653ac 100644 --- a/packages/plugin-solana/src/evaluators/trust.ts +++ b/packages/plugin-solana/src/evaluators/trust.ts @@ -80,7 +80,7 @@ Response should be a JSON object array inside a JSON markdown block. Correct res \`\`\``; async function handler(runtime: IAgentRuntime, message: Memory) { - console.log("Evaluating for trust"); + elizaLogger.log("Evaluating for trust"); const state = await runtime.composeState(message); // if the database type is postgres, we don't want to run this because it relies on sql queries that are currently specific to sqlite. This check can be removed once the trust score provider is updated to work with postgres. @@ -104,11 +104,11 @@ async function handler(runtime: IAgentRuntime, message: Memory) { }); if (!shouldProcess) { - console.log("Skipping process"); + elizaLogger.log("Skipping process"); return []; } - console.log("Processing recommendations"); + elizaLogger.log("Processing recommendations"); // Get recent recommendations const recommendationsManager = new MemoryManager({ @@ -135,7 +135,7 @@ async function handler(runtime: IAgentRuntime, message: Memory) { modelClass: ModelClass.LARGE, }); - console.log("recommendations", recommendations); + elizaLogger.log("recommendations", recommendations); if (!recommendations) { return []; @@ -186,7 +186,7 @@ async function handler(runtime: IAgentRuntime, message: Memory) { const tokenAddress = result?.baseToken?.address; rec.contractAddress = tokenAddress; if (!tokenAddress) { - console.warn("Could not find contract address for token"); + elizaLogger.warn("Could not find contract address for token"); continue; } } @@ -217,7 +217,7 @@ async function handler(runtime: IAgentRuntime, message: Memory) { }); if (!user) { - console.warn("Could not find user: ", rec.recommender); + elizaLogger.warn("Could not find user: ", rec.recommender); continue; } @@ -234,7 +234,7 @@ async function handler(runtime: IAgentRuntime, message: Memory) { await recommendationsManager.createMemory(recMemory, true); - console.log("recommendationsManager", rec); + elizaLogger.log("recommendationsManager", rec); // - from here we just need to make sure code is right @@ -253,7 +253,7 @@ async function handler(runtime: IAgentRuntime, message: Memory) { const shouldTrade = await tokenProvider.shouldTradeToken(); if (!shouldTrade) { - console.warn( + elizaLogger.warn( "There might be a problem with the token, not trading" ); continue; @@ -275,7 +275,7 @@ async function handler(runtime: IAgentRuntime, message: Memory) { case "sell": case "dont_sell": case "dont_buy": - console.warn("Not implemented"); + elizaLogger.warn("Not implemented"); break; } } diff --git a/packages/plugin-solana/src/keypairUtils.ts b/packages/plugin-solana/src/keypairUtils.ts index 4aa942ebed6..6dbacdb8414 100644 --- a/packages/plugin-solana/src/keypairUtils.ts +++ b/packages/plugin-solana/src/keypairUtils.ts @@ -1,7 +1,7 @@ import { Keypair, PublicKey } from "@solana/web3.js"; import { DeriveKeyProvider, TEEMode } from "@elizaos/plugin-tee"; import bs58 from "bs58"; -import { IAgentRuntime } from "@elizaos/core"; +import { IAgentRuntime, elizaLogger } from "@elizaos/core"; export interface KeypairResult { keypair?: Keypair; @@ -55,16 +55,16 @@ export async function getWalletKey( const secretKey = bs58.decode(privateKeyString); return { keypair: Keypair.fromSecretKey(secretKey) }; } catch (e) { - console.log("Error decoding base58 private key:", e); + elizaLogger.log("Error decoding base58 private key:", e); try { // Then try base64 - console.log("Try decoding base64 instead"); + elizaLogger.log("Try decoding base64 instead"); const secretKey = Uint8Array.from( Buffer.from(privateKeyString, "base64") ); return { keypair: Keypair.fromSecretKey(secretKey) }; } catch (e2) { - console.error("Error decoding private key: ", e2); + elizaLogger.error("Error decoding private key: ", e2); throw new Error("Invalid private key format"); } } diff --git a/packages/plugin-solana/src/providers/simulationSellingService.ts b/packages/plugin-solana/src/providers/simulationSellingService.ts index 3a189a2fdff..8c023569ed6 100644 --- a/packages/plugin-solana/src/providers/simulationSellingService.ts +++ b/packages/plugin-solana/src/providers/simulationSellingService.ts @@ -8,7 +8,7 @@ import { Connection, PublicKey } from "@solana/web3.js"; // Assuming TokenProvider and IAgentRuntime are available import { TokenProvider } from "./token.ts"; // import { settings } from "@elizaos/core"; -import { IAgentRuntime } from "@elizaos/core"; +import { IAgentRuntime, elizaLogger } from "@elizaos/core"; import { WalletProvider } from "./wallet.ts"; import * as amqp from "amqplib"; import { ProcessedTokenData } from "../types/token.ts"; @@ -60,11 +60,11 @@ export class SimulationSellingService { try { this.amqpConnection = await amqp.connect(amqpUrl); this.amqpChannel = await this.amqpConnection.createChannel(); - console.log("Connected to RabbitMQ"); + elizaLogger.log("Connected to RabbitMQ"); // Start consuming messages this.consumeMessages(); } catch (error) { - console.error("Failed to connect to RabbitMQ:", error); + elizaLogger.error("Failed to connect to RabbitMQ:", error); } } @@ -85,7 +85,7 @@ export class SimulationSellingService { }, { noAck: false } ); - console.log(`Listening for messages on queue: ${queue}`); + elizaLogger.log(`Listening for messages on queue: ${queue}`); } /** @@ -96,7 +96,7 @@ export class SimulationSellingService { try { const { tokenAddress, amount, sell_recommender_id } = JSON.parse(message); - console.log( + elizaLogger.log( `Received message for token ${tokenAddress} to sell ${amount}` ); @@ -113,7 +113,7 @@ export class SimulationSellingService { // Remove from running processes after completion this.runningProcesses.delete(tokenAddress); } catch (error) { - console.error("Error processing message:", error); + elizaLogger.error("Error processing message:", error); } } @@ -127,7 +127,7 @@ export class SimulationSellingService { const tokenAddress = tokenPerformance.tokenAddress; try { - console.log( + elizaLogger.log( `Executing sell for token ${tokenPerformance.symbol}: ${amountToSell}` ); @@ -153,7 +153,10 @@ export class SimulationSellingService { tokenProvider ); - console.log("Sell order executed successfully", sellDetailsData); + elizaLogger.log( + "Sell order executed successfully", + sellDetailsData + ); // check if balance is zero and remove token from running processes const balance = this.trustScoreDb.getTokenBalance(tokenAddress); @@ -163,7 +166,7 @@ export class SimulationSellingService { // stop the process in the sonar backend await this.stopProcessInTheSonarBackend(tokenAddress); } catch (error) { - console.error( + elizaLogger.error( `Error executing sell for token ${tokenAddress}:`, error ); @@ -183,13 +186,13 @@ export class SimulationSellingService { public async startService() { // starting the service - console.log("Starting SellingService..."); + elizaLogger.log("Starting SellingService..."); await this.startListeners(); } public async startListeners() { // scanning recommendations and selling - console.log("Scanning for token performances..."); + elizaLogger.log("Scanning for token performances..."); const tokenPerformances = await this.trustScoreDb.getAllTokenPerformancesWithBalance(); @@ -198,7 +201,7 @@ export class SimulationSellingService { private processTokenPerformances(tokenPerformances: TokenPerformance[]) { // To Do: logic when to sell and how much - console.log("Deciding when to sell and how much..."); + elizaLogger.log("Deciding when to sell and how much..."); const runningProcesses = this.runningProcesses; // remove running processes from tokenPerformances tokenPerformances = tokenPerformances.filter( @@ -246,7 +249,9 @@ export class SimulationSellingService { const runningProcesses = this.runningProcesses; // check if token is already being processed if (runningProcesses.has(tokenAddress)) { - console.log(`Token ${tokenAddress} is already being processed`); + elizaLogger.log( + `Token ${tokenAddress} is already being processed` + ); return; } const tokenPerformance = @@ -271,7 +276,7 @@ export class SimulationSellingService { this.runningProcesses.add(tokenAddress); } } catch (error) { - console.error( + elizaLogger.error( `Error getting token performance for token ${tokenAddress}:`, error ); @@ -306,19 +311,19 @@ export class SimulationSellingService { ); if (!response.ok) { - console.error( + elizaLogger.error( `Failed to send message to process token ${tokenAddress}` ); return; } const result = await response.json(); - console.log("Received response:", result); - console.log(`Sent message to process token ${tokenAddress}`); + elizaLogger.log("Received response:", result); + elizaLogger.log(`Sent message to process token ${tokenAddress}`); return result; } catch (error) { - console.error( + elizaLogger.error( `Error sending message to process token ${tokenAddress}:`, error ); @@ -337,7 +342,7 @@ export class SimulationSellingService { body: JSON.stringify({ tokenAddress }), }); } catch (error) { - console.error( + elizaLogger.error( `Error stopping process for token ${tokenAddress}:`, error ); @@ -437,7 +442,9 @@ export class SimulationSellingService { ): Promise { const processedData: ProcessedTokenData = await tokenProvider.getProcessedTokenData(); - console.log(`Fetched processed token data for token: ${tokenAddress}`); + elizaLogger.log( + `Fetched processed token data for token: ${tokenAddress}` + ); return processedData.tradeData.trade_24h_change_percent < -50; } @@ -478,15 +485,15 @@ export class SimulationSellingService { // If the request is successful, exit the loop return; } catch (error) { - console.error( + elizaLogger.error( `Attempt ${attempt} failed: Error creating trade in backend`, error ); if (attempt < retries) { - console.log(`Retrying in ${delayMs} ms...`); + elizaLogger.log(`Retrying in ${delayMs} ms...`); await this.delay(delayMs); // Wait for the specified delay before retrying } else { - console.error("All attempts failed."); + elizaLogger.error("All attempts failed."); } } } diff --git a/packages/plugin-solana/src/providers/token.ts b/packages/plugin-solana/src/providers/token.ts index b5fcc918a39..273185dffd4 100644 --- a/packages/plugin-solana/src/providers/token.ts +++ b/packages/plugin-solana/src/providers/token.ts @@ -1,5 +1,12 @@ -import { ICacheManager, settings } from "@elizaos/core"; -import { IAgentRuntime, Memory, Provider, State } from "@elizaos/core"; +import { + IAgentRuntime, + Memory, + Provider, + State, + elizaLogger, + ICacheManager, + settings, +} from "@elizaos/core"; import { DexScreenerData, DexScreenerPair, @@ -117,18 +124,18 @@ export class TokenProvider { const data = await response.json(); return data; } catch (error) { - console.error(`Attempt ${i + 1} failed:`, error); + elizaLogger.error(`Attempt ${i + 1} failed:`, error); lastError = error as Error; if (i < PROVIDER_CONFIG.MAX_RETRIES - 1) { const delay = PROVIDER_CONFIG.RETRY_DELAY * Math.pow(2, i); - console.log(`Waiting ${delay}ms before retrying...`); + elizaLogger.log(`Waiting ${delay}ms before retrying...`); await new Promise((resolve) => setTimeout(resolve, delay)); continue; } } } - console.error( + elizaLogger.error( "All attempts failed. Throwing the last error:", lastError ); @@ -154,7 +161,7 @@ export class TokenProvider { return null; } } catch (error) { - console.error("Error checking token in wallet:", error); + elizaLogger.error("Error checking token in wallet:", error); return null; } } @@ -164,7 +171,7 @@ export class TokenProvider { const cacheKey = `token_${this.tokenAddress}`; const cachedData = await this.getCachedData(cacheKey); if (cachedData) { - console.log( + elizaLogger.log( `Returning cached token data for ${this.tokenAddress}.` ); return cachedData; @@ -232,7 +239,7 @@ export class TokenProvider { isScam: token.isScam ? true : false, }; } catch (error) { - console.error( + elizaLogger.error( "Error fetching token data from Codex:", error.message ); @@ -245,7 +252,7 @@ export class TokenProvider { const cacheKey = "prices"; const cachedData = await this.getCachedData(cacheKey); if (cachedData) { - console.log("Returning cached prices."); + elizaLogger.log("Returning cached prices."); return cachedData; } const { SOL, BTC, ETH } = PROVIDER_CONFIG.TOKEN_ADDRESSES; @@ -276,13 +283,15 @@ export class TokenProvider { : "ethereum" ].usd = price; } else { - console.warn(`No price data available for token: ${token}`); + elizaLogger.warn( + `No price data available for token: ${token}` + ); } } this.setCachedData(cacheKey, prices); return prices; } catch (error) { - console.error("Error fetching prices:", error); + elizaLogger.error("Error fetching prices:", error); throw error; } } @@ -340,9 +349,10 @@ export class TokenProvider { async fetchTokenSecurity(): Promise { const cacheKey = `tokenSecurity_${this.tokenAddress}`; - const cachedData = await this.getCachedData(cacheKey); + const cachedData = + await this.getCachedData(cacheKey); if (cachedData) { - console.log( + elizaLogger.log( `Returning cached token security data for ${this.tokenAddress}.` ); return cachedData; @@ -363,7 +373,7 @@ export class TokenProvider { top10HolderPercent: data.data.top10HolderPercent, }; this.setCachedData(cacheKey, security); - console.log(`Token security data cached for ${this.tokenAddress}.`); + elizaLogger.log(`Token security data cached for ${this.tokenAddress}.`); return security; } @@ -372,7 +382,7 @@ export class TokenProvider { const cacheKey = `tokenTradeData_${this.tokenAddress}`; const cachedData = await this.getCachedData(cacheKey); if (cachedData) { - console.log( + elizaLogger.log( `Returning cached token trade data for ${this.tokenAddress}.` ); return cachedData; @@ -389,7 +399,7 @@ export class TokenProvider { const data = await fetch(url, options) .then((res) => res.json()) - .catch((err) => console.error(err)); + .catch((err) => elizaLogger.error(err)); if (!data?.success || !data?.data) { throw new Error("No token trade data available"); @@ -607,19 +617,19 @@ export class TokenProvider { const cacheKey = `dexScreenerData_${this.tokenAddress}`; const cachedData = await this.getCachedData(cacheKey); if (cachedData) { - console.log("Returning cached DexScreener data."); + elizaLogger.log("Returning cached DexScreener data."); return cachedData; } const url = `https://api.dexscreener.com/latest/dex/search?q=${this.tokenAddress}`; try { - console.log( + elizaLogger.log( `Fetching DexScreener data for token: ${this.tokenAddress}` ); const data = await fetch(url) .then((res) => res.json()) .catch((err) => { - console.error(err); + elizaLogger.error(err); }); if (!data || !data.pairs) { @@ -636,7 +646,7 @@ export class TokenProvider { return dexData; } catch (error) { - console.error(`Error fetching DexScreener data:`, error); + elizaLogger.error(`Error fetching DexScreener data:`, error); return { schemaVersion: "1.0.0", pairs: [], @@ -650,17 +660,17 @@ export class TokenProvider { const cacheKey = `dexScreenerData_search_${symbol}`; const cachedData = await this.getCachedData(cacheKey); if (cachedData) { - console.log("Returning cached search DexScreener data."); + elizaLogger.log("Returning cached search DexScreener data."); return this.getHighestLiquidityPair(cachedData); } const url = `https://api.dexscreener.com/latest/dex/search?q=${symbol}`; try { - console.log(`Fetching DexScreener data for symbol: ${symbol}`); + elizaLogger.log(`Fetching DexScreener data for symbol: ${symbol}`); const data = await fetch(url) .then((res) => res.json()) .catch((err) => { - console.error(err); + elizaLogger.error(err); return null; }); @@ -679,7 +689,7 @@ export class TokenProvider { // Return the pair with the highest liquidity and market cap return this.getHighestLiquidityPair(dexData); } catch (error) { - console.error(`Error fetching DexScreener data:`, error); + elizaLogger.error(`Error fetching DexScreener data:`, error); return null; } } @@ -748,7 +758,7 @@ export class TokenProvider { const cacheKey = `holderList_${this.tokenAddress}`; const cachedData = await this.getCachedData(cacheKey); if (cachedData) { - console.log("Returning cached holder list."); + elizaLogger.log("Returning cached holder list."); return cachedData; } @@ -758,7 +768,7 @@ export class TokenProvider { let cursor; //HELIOUS_API_KEY needs to be added const url = `https://mainnet.helius-rpc.com/?api-key=${settings.HELIUS_API_KEY || ""}`; - console.log({ url }); + elizaLogger.log({ url }); try { while (true) { @@ -771,7 +781,7 @@ export class TokenProvider { if (cursor != undefined) { params.cursor = cursor; } - console.log(`Fetching holders - Page ${page}`); + elizaLogger.log(`Fetching holders - Page ${page}`); if (page > 2) { break; } @@ -796,13 +806,13 @@ export class TokenProvider { !data.result.token_accounts || data.result.token_accounts.length === 0 ) { - console.log( + elizaLogger.log( `No more holders found. Total pages fetched: ${page - 1}` ); break; } - console.log( + elizaLogger.log( `Processing ${data.result.token_accounts.length} holders from page ${page}` ); @@ -830,14 +840,14 @@ export class TokenProvider { balance: balance.toString(), })); - console.log(`Total unique holders fetched: ${holders.length}`); + elizaLogger.log(`Total unique holders fetched: ${holders.length}`); // Cache the result this.setCachedData(cacheKey, holders); return holders; } catch (error) { - console.error("Error fetching holder list from Helius:", error); + elizaLogger.error("Error fetching holder list from Helius:", error); throw new Error("Failed to fetch holder list from Helius."); } } @@ -886,52 +896,54 @@ export class TokenProvider { ).length; return highSupplyHoldersCount; } catch (error) { - console.error("Error counting high supply holders:", error); + elizaLogger.error("Error counting high supply holders:", error); return 0; } } async getProcessedTokenData(): Promise { try { - console.log( + elizaLogger.log( `Fetching security data for token: ${this.tokenAddress}` ); const security = await this.fetchTokenSecurity(); const tokenCodex = await this.fetchTokenCodex(); - console.log(`Fetching trade data for token: ${this.tokenAddress}`); + elizaLogger.log( + `Fetching trade data for token: ${this.tokenAddress}` + ); const tradeData = await this.fetchTokenTradeData(); - console.log( + elizaLogger.log( `Fetching DexScreener data for token: ${this.tokenAddress}` ); const dexData = await this.fetchDexScreenerData(); - console.log( + elizaLogger.log( `Analyzing holder distribution for token: ${this.tokenAddress}` ); const holderDistributionTrend = await this.analyzeHolderDistribution(tradeData); - console.log( + elizaLogger.log( `Filtering high-value holders for token: ${this.tokenAddress}` ); const highValueHolders = await this.filterHighValueHolders(tradeData); - console.log( + elizaLogger.log( `Checking recent trades for token: ${this.tokenAddress}` ); const recentTrades = await this.checkRecentTrades(tradeData); - console.log( + elizaLogger.log( `Counting high-supply holders for token: ${this.tokenAddress}` ); const highSupplyHoldersCount = await this.countHighSupplyHolders(security); - console.log( + elizaLogger.log( `Determining DexScreener listing status for token: ${this.tokenAddress}` ); const isDexScreenerListed = dexData.pairs.length > 0; @@ -952,10 +964,10 @@ export class TokenProvider { tokenCodex, }; - // console.log("Processed token data:", processedData); + // elizaLogger.log("Processed token data:", processedData); return processedData; } catch (error) { - console.error("Error processing token data:", error); + elizaLogger.error("Error processing token data:", error); throw error; } } @@ -1012,7 +1024,7 @@ export class TokenProvider { isMarketCapTooLow ); } catch (error) { - console.error("Error processing token data:", error); + elizaLogger.error("Error processing token data:", error); throw error; } } @@ -1077,17 +1089,17 @@ export class TokenProvider { } output += `\n`; - console.log("Formatted token data:", output); + elizaLogger.log("Formatted token data:", output); return output; } async getFormattedTokenReport(): Promise { try { - console.log("Generating formatted token report..."); + elizaLogger.log("Generating formatted token report..."); const processedData = await this.getProcessedTokenData(); return this.formatTokenData(processedData); } catch (error) { - console.error("Error generating token report:", error); + elizaLogger.error("Error generating token report:", error); return "Unable to fetch token information. Please try again later."; } } @@ -1115,7 +1127,7 @@ const tokenProvider: Provider = { return provider.getFormattedTokenReport(); } catch (error) { - console.error("Error fetching token data:", error); + elizaLogger.error("Error fetching token data:", error); return "Unable to fetch token information. Please try again later."; } }, diff --git a/packages/plugin-solana/src/providers/tokenUtils.ts b/packages/plugin-solana/src/providers/tokenUtils.ts index 034dddc299e..8a717f4c41f 100644 --- a/packages/plugin-solana/src/providers/tokenUtils.ts +++ b/packages/plugin-solana/src/providers/tokenUtils.ts @@ -1,5 +1,6 @@ import { getAccount, getAssociatedTokenAddress } from "@solana/spl-token"; import { Connection, PublicKey } from "@solana/web3.js"; +import { elizaLogger } from "@elizaos/core"; export async function getTokenPriceInSol(tokenSymbol: string): Promise { const response = await fetch( @@ -24,7 +25,7 @@ async function getTokenBalance( const tokenAmount = tokenAccount.amount as unknown as number; return tokenAmount; } catch (error) { - console.error( + elizaLogger.error( `Error retrieving balance for token: ${tokenMintAddress.toBase58()}`, error ); diff --git a/packages/plugin-solana/src/providers/trustScoreProvider.ts b/packages/plugin-solana/src/providers/trustScoreProvider.ts index b9e046b0f9c..2cc40b09523 100644 --- a/packages/plugin-solana/src/providers/trustScoreProvider.ts +++ b/packages/plugin-solana/src/providers/trustScoreProvider.ts @@ -93,7 +93,7 @@ export class TrustScoreManager { const balance = parseFloat(tokenBalance); return balance; } catch (error) { - console.error("Error fetching balance", error); + elizaLogger.error("Error fetching balance", error); return 0; } } @@ -114,7 +114,9 @@ export class TrustScoreManager { }> { const processedData: ProcessedTokenData = await this.tokenProvider.getProcessedTokenData(); - console.log(`Fetched processed token data for token: ${tokenAddress}`); + elizaLogger.log( + `Fetched processed token data for token: ${tokenAddress}` + ); const recommenderMetrics = await this.trustScoreDb.getRecommenderMetrics(recommenderId); @@ -302,14 +304,18 @@ export class TrustScoreManager { const unique_wallet_24h = processedData.tradeData.unique_wallet_24h; const volume_24h = processedData.tradeData.volume_24h; const suspiciousVolume = unique_wallet_24h / volume_24h > 0.5; - console.log(`Fetched processed token data for token: ${tokenAddress}`); + elizaLogger.log( + `Fetched processed token data for token: ${tokenAddress}` + ); return suspiciousVolume; } async sustainedGrowth(tokenAddress: string): Promise { const processedData: ProcessedTokenData = await this.tokenProvider.getProcessedTokenData(); - console.log(`Fetched processed token data for token: ${tokenAddress}`); + elizaLogger.log( + `Fetched processed token data for token: ${tokenAddress}` + ); return processedData.tradeData.volume_24h_change_percent > 50; } @@ -317,7 +323,9 @@ export class TrustScoreManager { async isRapidDump(tokenAddress: string): Promise { const processedData: ProcessedTokenData = await this.tokenProvider.getProcessedTokenData(); - console.log(`Fetched processed token data for token: ${tokenAddress}`); + elizaLogger.log( + `Fetched processed token data for token: ${tokenAddress}` + ); return processedData.tradeData.trade_24h_change_percent < -50; } @@ -325,7 +333,9 @@ export class TrustScoreManager { async checkTrustScore(tokenAddress: string): Promise { const processedData: ProcessedTokenData = await this.tokenProvider.getProcessedTokenData(); - console.log(`Fetched processed token data for token: ${tokenAddress}`); + elizaLogger.log( + `Fetched processed token data for token: ${tokenAddress}` + ); return { ownerBalance: processedData.security.ownerBalance, @@ -493,15 +503,15 @@ export class TrustScoreManager { // If the request is successful, exit the loop return; } catch (error) { - console.error( + elizaLogger.error( `Attempt ${attempt} failed: Error creating trade in backend`, error ); if (attempt < retries) { - console.log(`Retrying in ${delayMs} ms...`); + elizaLogger.log(`Retrying in ${delayMs} ms...`); await this.delay(delayMs); // Wait for the specified delay before retrying } else { - console.error("All attempts failed."); + elizaLogger.error("All attempts failed."); } } } @@ -717,7 +727,7 @@ export const trustScoreProvider: Provider = { const userId = message.userId; if (!userId) { - console.error("User ID is missing from the message"); + elizaLogger.error("User ID is missing from the message"); return ""; } @@ -726,7 +736,10 @@ export const trustScoreProvider: Provider = { await trustScoreDb.getRecommenderMetrics(userId); if (!recommenderMetrics) { - console.error("No recommender metrics found for user:", userId); + elizaLogger.error( + "No recommender metrics found for user:", + userId + ); return ""; } @@ -740,7 +753,7 @@ export const trustScoreProvider: Provider = { return trustScoreString; } catch (error) { - console.error("Error in trust score provider:", error.message); + elizaLogger.error("Error in trust score provider:", error.message); return `Failed to fetch trust score: ${error instanceof Error ? error.message : "Unknown error"}`; } }, diff --git a/packages/plugin-solana/src/providers/wallet.ts b/packages/plugin-solana/src/providers/wallet.ts index 660631c8c86..d3912c8b0bd 100644 --- a/packages/plugin-solana/src/providers/wallet.ts +++ b/packages/plugin-solana/src/providers/wallet.ts @@ -1,4 +1,10 @@ -import { IAgentRuntime, Memory, Provider, State } from "@elizaos/core"; +import { + IAgentRuntime, + Memory, + Provider, + State, + elizaLogger, +} from "@elizaos/core"; import { Connection, PublicKey } from "@solana/web3.js"; import BigNumber from "bignumber.js"; import NodeCache from "node-cache"; @@ -91,7 +97,7 @@ export class WalletProvider { const data = await response.json(); return data; } catch (error) { - console.error(`Attempt ${i + 1} failed:`, error); + elizaLogger.error(`Attempt ${i + 1} failed:`, error); lastError = error; if (i < PROVIDER_CONFIG.MAX_RETRIES - 1) { const delay = PROVIDER_CONFIG.RETRY_DELAY * Math.pow(2, i); @@ -101,7 +107,7 @@ export class WalletProvider { } } - console.error( + elizaLogger.error( "All attempts failed. Throwing the last error:", lastError ); @@ -114,51 +120,83 @@ export class WalletProvider { const cachedValue = this.cache.get(cacheKey); if (cachedValue) { - console.log("Cache hit for fetchPortfolioValue"); + elizaLogger.log("Cache hit for fetchPortfolioValue"); return cachedValue; } - console.log("Cache miss for fetchPortfolioValue"); + elizaLogger.log("Cache miss for fetchPortfolioValue"); - const walletData = await this.fetchWithRetry( - runtime, - `${PROVIDER_CONFIG.BIRDEYE_API}/v1/wallet/token_list?wallet=${this.walletPublicKey.toBase58()}` - ); + // Check if Birdeye API key is available + const birdeyeApiKey = runtime.getSetting("BIRDEYE_API_KEY"); - if (!walletData?.success || !walletData?.data) { - console.error("No portfolio data available", walletData); - throw new Error("No portfolio data available"); + if (birdeyeApiKey) { + // Existing Birdeye API logic + const walletData = await this.fetchWithRetry( + runtime, + `${PROVIDER_CONFIG.BIRDEYE_API}/v1/wallet/token_list?wallet=${this.walletPublicKey.toBase58()}` + ); + + if (walletData?.success && walletData?.data) { + const data = walletData.data; + const totalUsd = new BigNumber(data.totalUsd.toString()); + const prices = await this.fetchPrices(runtime); + const solPriceInUSD = new BigNumber( + prices.solana.usd.toString() + ); + + const items = data.items.map((item: any) => ({ + ...item, + valueSol: new BigNumber(item.valueUsd || 0) + .div(solPriceInUSD) + .toFixed(6), + name: item.name || "Unknown", + symbol: item.symbol || "Unknown", + priceUsd: item.priceUsd || "0", + valueUsd: item.valueUsd || "0", + })); + + const portfolio = { + totalUsd: totalUsd.toString(), + totalSol: totalUsd.div(solPriceInUSD).toFixed(6), + items: items.sort((a, b) => + new BigNumber(b.valueUsd) + .minus(new BigNumber(a.valueUsd)) + .toNumber() + ), + }; + + this.cache.set(cacheKey, portfolio); + return portfolio; + } } - const data = walletData.data; - const totalUsd = new BigNumber(data.totalUsd.toString()); - const prices = await this.fetchPrices(runtime); - const solPriceInUSD = new BigNumber(prices.solana.usd.toString()); + // Fallback to basic token account info if no Birdeye API key or API call fails + const accounts = await this.getTokenAccounts( + this.walletPublicKey.toBase58() + ); - const items = data.items.map((item: any) => ({ - ...item, - valueSol: new BigNumber(item.valueUsd || 0) - .div(solPriceInUSD) - .toFixed(6), - name: item.name || "Unknown", - symbol: item.symbol || "Unknown", - priceUsd: item.priceUsd || "0", - valueUsd: item.valueUsd || "0", + const items = accounts.map((acc) => ({ + name: "Unknown", + address: acc.account.data.parsed.info.mint, + symbol: "Unknown", + decimals: acc.account.data.parsed.info.tokenAmount.decimals, + balance: acc.account.data.parsed.info.tokenAmount.amount, + uiAmount: + acc.account.data.parsed.info.tokenAmount.uiAmount.toString(), + priceUsd: "0", + valueUsd: "0", + valueSol: "0", })); - const totalSol = totalUsd.div(solPriceInUSD); const portfolio = { - totalUsd: totalUsd.toString(), - totalSol: totalSol.toFixed(6), - items: items.sort((a, b) => - new BigNumber(b.valueUsd) - .minus(new BigNumber(a.valueUsd)) - .toNumber() - ), + totalUsd: "0", + totalSol: "0", + items, }; + this.cache.set(cacheKey, portfolio); return portfolio; } catch (error) { - console.error("Error fetching portfolio:", error); + elizaLogger.error("Error fetching portfolio:", error); throw error; } } @@ -169,10 +207,10 @@ export class WalletProvider { const cachedValue = await this.cache.get(cacheKey); if (cachedValue) { - console.log("Cache hit for fetchPortfolioValue"); + elizaLogger.log("Cache hit for fetchPortfolioValue"); return cachedValue; } - console.log("Cache miss for fetchPortfolioValue"); + elizaLogger.log("Cache miss for fetchPortfolioValue"); const query = ` query Balances($walletId: String!, $cursor: String) { @@ -209,7 +247,7 @@ export class WalletProvider { const data = response.data?.data?.balances?.items; if (!data || data.length === 0) { - console.error("No portfolio data available", data); + elizaLogger.error("No portfolio data available", data); throw new Error("No portfolio data available"); } @@ -255,7 +293,7 @@ export class WalletProvider { return portfolio; } catch (error) { - console.error("Error fetching portfolio:", error); + elizaLogger.error("Error fetching portfolio:", error); throw error; } } @@ -266,10 +304,10 @@ export class WalletProvider { const cachedValue = this.cache.get(cacheKey); if (cachedValue) { - console.log("Cache hit for fetchPrices"); + elizaLogger.log("Cache hit for fetchPrices"); return cachedValue; } - console.log("Cache miss for fetchPrices"); + elizaLogger.log("Cache miss for fetchPrices"); const { SOL, BTC, ETH } = PROVIDER_CONFIG.TOKEN_ADDRESSES; const tokens = [SOL, BTC, ETH]; @@ -300,14 +338,16 @@ export class WalletProvider { : "ethereum" ].usd = price; } else { - console.warn(`No price data available for token: ${token}`); + elizaLogger.warn( + `No price data available for token: ${token}` + ); } } this.cache.set(cacheKey, prices); return prices; } catch (error) { - console.error("Error fetching prices:", error); + elizaLogger.error("Error fetching prices:", error); throw error; } } @@ -358,10 +398,28 @@ export class WalletProvider { return this.formatPortfolio(runtime, portfolio, prices); } catch (error) { - console.error("Error generating portfolio report:", error); + elizaLogger.error("Error generating portfolio report:", error); return "Unable to fetch wallet information. Please try again later."; } } + + private async getTokenAccounts(walletAddress: string) { + try { + const accounts = + await this.connection.getParsedTokenAccountsByOwner( + new PublicKey(walletAddress), + { + programId: new PublicKey( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + ), + } + ); + return accounts.value; + } catch (error) { + elizaLogger.error("Error fetching token accounts:", error); + return []; + } + } } const walletProvider: Provider = { @@ -374,14 +432,15 @@ const walletProvider: Provider = { const { publicKey } = await getWalletKey(runtime, false); const connection = new Connection( - runtime.getSetting("SOLANA_RPC_URL") || PROVIDER_CONFIG.DEFAULT_RPC + runtime.getSetting("SOLANA_RPC_URL") || + PROVIDER_CONFIG.DEFAULT_RPC ); const provider = new WalletProvider(connection, publicKey); return await provider.getFormattedPortfolio(runtime); } catch (error) { - console.error("Error in wallet provider:", error); + elizaLogger.error("Error in wallet provider:", error); return null; } }, diff --git a/packages/plugin-spheron/README.md b/packages/plugin-spheron/README.md new file mode 100644 index 00000000000..a7ad63d0526 --- /dev/null +++ b/packages/plugin-spheron/README.md @@ -0,0 +1,146 @@ +# Spheron Protocol Plugin for Eliza + +This plugin integrates the Spheron Protocol SDK into the Eliza ecosystem, providing functionality for managing deployments, escrow operations, and lease management. + +## Features + +- **Escrow Operations**: Manage token deposits, withdrawals, and balance checks +- **Deployment Management**: Create, update, and manage deployments using ICL YAML + +## Installation + +```bash +npm install @elizaos/plugin-spheron +``` + +## Configuration + +The plugin requires the following environment variables: + +```env +PRIVATE_KEY=your_private_key +PROVIDER_PROXY_URL=your_provider_proxy_url +WALLET_ADDRESS=your_wallet_address +``` + +## Usage + +1. Import and register the plugin: + +```typescript +import { spheronPlugin } from "@elizaos/plugin-spheron"; + +// Register with Eliza +eliza.registerPlugin(spheronPlugin); +``` + +2. Available Actions: + +- `ESCROW_OPERATION`: Handle token deposits and withdrawals +- `DEPLOYMENT_OPERATION`: Manage service deployments + +## Examples + +### Escrow Operations + +```typescript +// Deposit tokens +await runtime.executeAction("ESCROW_OPERATION", { + token: "USDT", + amount: 100, + operation: "deposit", +}); + +// Withdraw tokens +await runtime.executeAction("ESCROW_OPERATION", { + token: "USDC", + amount: 50, + operation: "withdraw", +}); +``` + +### Deployment Operations + +```typescript +// Create deployment +await runtime.executeAction("DEPLOYMENT_OPERATION", { + operation: "create", + template: "jupyter-notebook", + customizations: { + cpu: false, + resources: { + cpu: "4", + memory: "8Gi", + storage: "10Gi", + gpu: "1", + gpu_model: "rtx4090", + }, + duration: "1h", + token: "USDT", + }, +}); + +// Update deployment +await runtime.executeAction("DEPLOYMENT_OPERATION", { + operation: "update", + leaseId: "your_lease_id", + template: "jupyter-notebook", + customizations: { + cpu: false, + resources: { + cpu: "4", + memory: "8Gi", + storage: "10Gi", + gpu: "1", + gpu_model: "rtx4090", + }, + duration: "1h", + token: "USDT", + }, +}); + +// Close deployment +await runtime.executeAction("DEPLOYMENT_OPERATION", { + operation: "close", + leaseId: "your_lease_id", +}); +``` + +## Supported Templates + +- jupyter-notebook: Jupyter Notebook with or without Pytorch +- vscode: VSCode with or without Pytorch +- ollama: Ollama WebUI and API +- heurist-miner: Heurist Miner for mining heurist network + +## How it Works + +1. You can ask the eliza to deploy a template like `jupyter-notebook`, `vscode`, `ollama`, or `heurist-miner` for you with just natural language. +2. You can also customize the deployment with natural language. +3. You can also ask the eliza to close the deployment. +4. You can also ask the eliza to check the balance of your account. +5. You can also ask the eliza to deposit or withdraw tokens from your account. + +## Development + +1. Install dependencies: + +```bash +npm install +``` + +2. Build the plugin: + +```bash +npm run build +``` + +3. Run tests: + +```bash +npm test +``` + +## License + +This plugin is part of the Eliza project. See the main project repository for license information. diff --git a/packages/plugin-spheron/eslint.config.mjs b/packages/plugin-spheron/eslint.config.mjs new file mode 100644 index 00000000000..92fe5bbebef --- /dev/null +++ b/packages/plugin-spheron/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-spheron/package.json b/packages/plugin-spheron/package.json new file mode 100644 index 00000000000..ccd45ea27c1 --- /dev/null +++ b/packages/plugin-spheron/package.json @@ -0,0 +1,21 @@ +{ + "name": "@elizaos/plugin-spheron", + "version": "0.1.0", + "description": "Spheron Protocol Plugin for Eliza", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsup --format esm --dts", + "test": "jest", + "lint": "eslint --fix --cache ." + }, + "dependencies": { + "@elizaos/core": "workspace:*", + "@spheron/protocol-sdk": "^1.0.0", + "zod": "^3.22.4" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "typescript": "^5.0.0" + } +} diff --git a/packages/plugin-spheron/src/actions/deployment.ts b/packages/plugin-spheron/src/actions/deployment.ts new file mode 100644 index 00000000000..25048430cf2 --- /dev/null +++ b/packages/plugin-spheron/src/actions/deployment.ts @@ -0,0 +1,534 @@ +import { + Action, + ActionExample, + IAgentRuntime, + Memory, + State, + HandlerCallback, + elizaLogger, + composeContext, + ModelClass, + generateObjectDeprecated, +} from "@elizaos/core"; +import { validateSpheronConfig } from "../environment.ts"; +import { + getDeployment, + updateDeployment, + closeDeployment, + startDeployment, +} from "../utils/index.ts"; +import { DeploymentContent } from "../types/index.ts"; +import { AVAILABLE_GPU_MODELS } from "../utils/constants.ts"; +import { DEPLOYMENT_TEMPLATES } from "../utils/template.ts"; + +function isDeploymentContent(content: any): content is DeploymentContent { + elizaLogger.debug("Content for deployment operation:", content); + if ( + typeof content.operation !== "string" || + !["create", "update", "close"].includes(content.operation) + ) { + return false; + } + + switch (content.operation) { + case "create": + return ( + typeof content.template === "string" && + typeof content.customizations === "object" + ); + case "update": + return ( + typeof content.leaseId === "string" && + typeof content.template === "string" && + typeof content.customizations === "object" + ); + case "close": + return typeof content.leaseId === "string"; + default: + return false; + } +} + +// Generate template descriptions dynamically +const templateDescriptions = Object.entries(DEPLOYMENT_TEMPLATES) + .map(([key, template]) => `- ${key}: ${template.description}`) + .join("\n"); + +const deploymentTemplate = `Respond with a JSON markdown block containing only the extracted values for the requested deployment operation. + +Example responses for different operations: + +1. Creating a new deployment: +\`\`\`json +{ + "operation": "create", + "template": "", // One of: jupyter-notebook, ollama-webui, vscode-pytorch + "customizations": { + "cpu": , // Extract CPU-only preference from context or put a default value of false. eg. no gpu needed or something like that + "resources": { // Extract resource requirements from context + "cpu": "", // Extract cpu requirements from context or put a default value of 4 + "memory": "", // Extract memory requirements from context or put a default value of 8Gi + "storage": "", // Extract storage requirements from context or put a default value of 100Gi + "gpu": "", // Extract gpu requirements from context or put a default value of 1 + "gpu_model": "" // Extract gpu model requirements from context or put a default value of rtx4090 + }, + "duration": "" // Extract duration requirements from context or put a default value of 1h + "token": "" // Extract token requirements from context or put a default value of CST + "template": { + "heuristMinerAddress": "" // Extract heurist miner address requirements from context + } + } +} +\`\`\` + +2. Updating an existing deployment: +\`\`\`json +{ + "operation": "update", + "leaseId": "existing-lease-id", // Extract lease ID from context + "template": "", // One of: jupyter-notebook, ollama-webui, vscode-pytorch + "customizations": { + "cpu": , // Extract cpu-only preference from context or put a default value of false. eg. no gpu needed or something like that + "resources": { // Extract updated resource requirements from context + "cpu": "", // Extract cpu requirements from context or put a default value of 4 + "memory": "", // Extract memory requirements from context or put a default value of 8Gi + "storage": "", // Extract storage requirements from context or put a default value of 100Gi + "gpu": "", // Extract gpu requirements from context or put a default value of 1 + "gpu_model": "" // Extract gpu model requirements from context or put a default value of rtx4090 + }, + "duration": "" // Extract duration requirements from context or put a default value of 1h + "token": "" // Extract token requirements from context or put a default value of CST + } +} +\`\`\` + +3. Closing a deployment: +\`\`\`json +{ + "operation": "close", + "leaseId": "lease-id-to-close" +} +\`\`\` + +## Available Templates +${templateDescriptions} + +## Available GPU Models +${AVAILABLE_GPU_MODELS.map((gpu) => `- ${gpu}`).join("\n")} + +{{recentMessages}} + +Given the recent messages, extract the following information about the requested deployment: +- Desired template name from the context +- CPU-only requirement (if specified) from the context +- Any customization requirements GPU model and it's count, cpu and memory resources properly from the context +- Token (if specified) from the context +- Duration (if specified) from the context +- Lease ID (if updating or closing) from the context +- Operation (create, update, close) from the context + +Respond with a JSON markdown block containing only the extracted values.`; + +export default { + name: "DEPLOYMENT_OPERATION", + similes: [ + "CREATE_DEPLOYMENT", + "UPDATE_DEPLOYMENT", + "GET_DEPLOYMENT", + "CLOSE_DEPLOYMENT", + "DEPLOY_SERVICE", + "MANAGE_DEPLOYMENT", + "LAUNCH_SERVICE", + "START_DEPLOYMENT", + "SETUP_DEPLOYMENT", + ], + description: + "MUST use this action if the user requests to create, update, or manage a deployment. The request might vary, but it will always be related to deployment operations.", + validate: async (runtime: IAgentRuntime, _message: Memory) => { + await validateSpheronConfig(runtime); + return true; + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + _options: { [key: string]: unknown }, + callback?: HandlerCallback + ) => { + elizaLogger.log("Starting DEPLOYMENT_OPERATION handler..."); + + // Initialize or update state + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + // Filter only "just now" and last couple of user messages + state.recentMessages = state.recentMessages + .split("\n") + .filter( + (line) => line.includes("(just now)") || line.includes("(user)") + ) + .slice(-2) + .join("\n"); + + // Compose deployment context + const deploymentContext = composeContext({ + state, + template: deploymentTemplate, + }); + + // Generate deployment content + const content = await generateObjectDeprecated({ + runtime, + context: deploymentContext, + modelClass: ModelClass.SMALL, + }); + + // Validate deployment content + if (!isDeploymentContent(content)) { + elizaLogger.error( + "Invalid content for DEPLOYMENT_OPERATION action." + ); + callback?.({ + text: "Unable to process deployment request. Invalid content provided.", + content: { error: "Invalid deployment content" }, + }); + return false; + } + + try { + switch (content.operation) { + case "create": { + if ( + !content.template || + !DEPLOYMENT_TEMPLATES[content.template] + ) { + throw new Error( + `Unsupported template: ${content.template}. Available templates are: ${Object.keys(DEPLOYMENT_TEMPLATES).join(", ")}` + ); + } + + const computeConfig = DEPLOYMENT_TEMPLATES[ + content.template + ].config(content.customizations); + const result = await startDeployment( + runtime, + computeConfig + ); + + elizaLogger.log( + "Deployment created with lease ID:", + result.leaseId.toString() + ); + + const deploymentDetails = await getDeployment( + runtime, + result.leaseId.toString() + ); + const service = Object.values( + deploymentDetails.services + )[0]; + + // Get forwarded ports information + const ports = + deploymentDetails.forwarded_ports[service.name] || []; + const portInfo = ports + .map( + (p) => + `${p.host}:${p.externalPort} for Port ${p.port}` + ) + .join(", "); + + console.log("Final response:", { + text: `Deployment created and ready!\nLease ID: ${result.leaseId.toString()}\n${portInfo ? `Access URLs: ${portInfo}` : ""}`, + content: { + success: true, + leaseId: result.leaseId.toString(), + details: deploymentDetails, + ports: ports, + }, + }); + + callback?.({ + text: `Deployment created and ready!\nLease ID: ${result.leaseId.toString()}\n${portInfo ? `Access URLs: ${portInfo}` : ""}`, + content: { + success: true, + leaseId: result.leaseId.toString(), + details: deploymentDetails, + ports: ports, + }, + }); + break; + } + case "update": { + if ( + !content.leaseId || + !content.customizations || + !content.template + ) { + throw new Error( + "Lease ID, template, and customizations are required for deployment update" + ); + } + + if (!DEPLOYMENT_TEMPLATES[content.template]) { + throw new Error( + `Unsupported template: ${content.template}` + ); + } + + const computeConfig = DEPLOYMENT_TEMPLATES[ + content.template + ].config(content.customizations); + const result = await updateDeployment( + runtime, + content.leaseId.toString(), + computeConfig + ); + elizaLogger.log( + "Deployment updated with lease ID:", + result.leaseId.toString() + ); + + const newDetails = await getDeployment( + runtime, + content.leaseId.toString() + ); + callback?.({ + text: `Deployment ${content.leaseId.toString()} updated successfully`, + content: { + success: true, + details: newDetails, + }, + }); + break; + } + case "close": { + if (!content.leaseId) { + throw new Error( + "Lease ID is required for deployment closure" + ); + } + const result = await closeDeployment( + runtime, + content.leaseId.toString() + ); + elizaLogger.log( + "Deployment closed with lease ID:", + content.leaseId.toString() + ); + + callback?.({ + text: `Deployment ${content.leaseId.toString()} closed successfully`, + content: { + success: true, + transaction: result, + }, + }); + break; + } + } + return true; + } catch (error) { + console.log("Error:", error); + elizaLogger.error("Deployment operation failed:", error.message); + callback?.({ + text: "Deployment operation failed", + content: { + error: + error instanceof Error + ? error.message + : "Unknown error", + }, + }); + return false; + } + }, + examples: [ + // Create deployment examples with templates + [ + { + user: "{{user1}}", + content: { + text: "Deploy a Jupyter notebook with GPU", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Setting up your Jupyter notebook deployment with GPU support...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Create a CPU-only Jupyter notebook deployment", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Setting up your CPU-only Jupyter notebook deployment...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Deploy Jupyter notebook with A100 GPU and 32GB memory", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Setting up your Jupyter notebook deployment with A100 GPU and custom resources...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Deploy Ollama WebUI with RTX 4090", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Setting up Ollama WebUI with RTX 4090 GPU support...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Create a VS Code deployment with PyTorch and T4 GPU", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Setting up VS Code PyTorch environment with T4 GPU...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Deploy a Jupyter notebook with GPU and token USDT", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Setting up your Jupyter notebook deployment with GPU support and token USDT...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + // Update deployment examples + [ + { + user: "{{user1}}", + content: { + text: "Upgrade my deployment abc123 to use an A100 GPU", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Updating deployment abc123 to use A100 GPU...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Scale up the memory to 64GB for deployment xyz789", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Updating deployment resources...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Update my deployment abc123 to use an A100 GPU and token USDT", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Updating deployment abc123 to use A100 GPU and token USDT...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + // Close deployment examples + [ + { + user: "{{user1}}", + content: { + text: "Close deployment abc123", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Closing deployment abc123...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "I want to stop my deployment abc123", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Closing deployment abc123...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Stop my Jupyter notebook deployment xyz789", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Terminating Jupyter notebook deployment xyz789...", + action: "DEPLOYMENT_OPERATION", + }, + }, + ], + ] as ActionExample[][], +} as Action; diff --git a/packages/plugin-spheron/src/actions/escrow.ts b/packages/plugin-spheron/src/actions/escrow.ts new file mode 100644 index 00000000000..59b10040a07 --- /dev/null +++ b/packages/plugin-spheron/src/actions/escrow.ts @@ -0,0 +1,384 @@ +import { + Action, + ActionExample, + IAgentRuntime, + Memory, + State, + HandlerCallback, + elizaLogger, + composeContext, + generateObject, + ModelClass, + generateObjectDeprecated, +} from "@elizaos/core"; +import { validateSpheronConfig } from "../environment.ts"; +import { + depositBalance, + getUserBalance, + withdrawBalance, +} from "../utils/index.ts"; +import { EscrowContent } from "../types/index.ts"; +import { SUPPORTED_TOKENS } from "../utils/constants.ts"; + +function isEscrowContent(content: any): content is EscrowContent { + console.log("Content for escrow operation:", content); + return ( + typeof content.token === "string" && + (content.operation === "deposit" || content.operation === "withdraw" + ? typeof content.amount === "number" && content.amount > 0 + : content.operation === "check") && + (content.operation === "deposit" || + content.operation === "withdraw" || + content.operation === "check") + ); +} + +const escrowTemplate = `Respond with a JSON markdown block containing only the extracted values +- Use null for any values that cannot be determined. +- Token must be one of the supported tokens. +- Amount must be a positive number. + +Example response for checking balance for : +\`\`\`json +{ + "token": "", // can be USDT, USDC, DAI, WETH, CST + "operation": "check" +} +\`\`\` + +Example response for depositing : +\`\`\`json +{ + "token": "", // can be USDT, USDC, DAI, WETH, CST + "amount": , // must be a positive number + "operation": "deposit" +} +\`\`\` + +Example response for withdrawing : +\`\`\`json +{ + "token": "", // can be USDT, USDC, DAI, WETH, CST + "amount": , // must be a positive number + "operation": "withdraw" // must be one of the supported operations +} +\`\`\` + +## Supported Tokens +${Object.entries(SUPPORTED_TOKENS) + .map(([key, _]) => `- ${key}`) + .join("\n")} + +{{recentMessages}} + +Given the recent messages, extract the following information about the requested escrow operation: +- Token symbol (must be one of the supported tokens) +- Amount to deposit/withdraw (must be a positive number) +- Operation type (deposit or withdraw) +- Don't mention multiple operations in the same json block + +Respond with a JSON markdown block containing only the extracted values.`; + +export default { + name: "ESCROW_OPERATION", + similes: [ + "DEPOSIT_TOKEN", + "WITHDRAW_TOKEN", + "CHECK_BALANCE", + "GET_BALANCE", + "DEPOSIT_FUNDS", + "WITHDRAW_FUNDS", + "ADD_FUNDS", + "REMOVE_FUNDS", + "TRANSFER_TO_ESCROW", + "TRANSFER_FROM_ESCROW", + "FUND_ACCOUNT", + "WITHDRAW_FROM_ACCOUNT", + ], + description: + "MUST use this action if the user requests to deposit or withdraw tokens from escrow. The request might vary, but it will always be related to escrow operations.", + validate: async (runtime: IAgentRuntime, _message: Memory) => { + await validateSpheronConfig(runtime); + return true; + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + _options: { [key: string]: unknown }, + callback?: HandlerCallback + ) => { + elizaLogger.log("Starting ESCROW_OPERATION handler..."); + + // Initialize or update state + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + // Filter only "just now" and last couple of user messages + state.recentMessages = state.recentMessages + .split("\n") + .filter( + (line) => line.includes("(just now)") || line.includes("(user)") + ) + .slice(-2) + .join("\n"); + + // Compose escrow context + const escrowContext = composeContext({ + state, + template: escrowTemplate, + }); + + // Generate escrow content + const content = await generateObjectDeprecated({ + runtime, + context: escrowContext, + modelClass: ModelClass.SMALL, + }); + + // Validate escrow content + if (!isEscrowContent(content)) { + elizaLogger.error("Invalid content for ESCROW_OPERATION action."); + callback?.({ + text: "Unable to process escrow request. Invalid content provided.", + content: { error: "Invalid escrow content" }, + }); + return false; + } + + try { + const config = await validateSpheronConfig(runtime); + const balance = await getUserBalance( + runtime, + content.token, + config.WALLET_ADDRESS + ); + elizaLogger.log(`Current ${content.token} balance:`, balance); + + if (content.operation === "check") { + const formattedAvailableBalance = + Number(balance.unlockedBalance) / + 10 ** Number(balance.token.decimal); + const formattedLockedBalance = + Number(balance.lockedBalance) / + 10 ** Number(balance.token.decimal); + callback?.({ + text: `Current ${content.token.toUpperCase()} Balance for ${config.WALLET_ADDRESS}\n Available balance: ${formattedAvailableBalance.toFixed(2)} ${content.token.toUpperCase()}\n Locked balance: ${formattedLockedBalance.toFixed(2)} ${content.token.toUpperCase()}`, + content: { + success: true, + unlockedBalance: formattedAvailableBalance, + lockedBalance: formattedLockedBalance, + token: balance.token, + walletAddress: config.WALLET_ADDRESS, + }, + }); + } else if (content.operation === "deposit") { + try { + const result = await depositBalance( + runtime, + content.token, + content.amount + ); + callback?.({ + text: `Successfully deposited ${content.amount} ${content.token.toUpperCase()} into Spheron Escrow for ${config.WALLET_ADDRESS}`, + content: { + success: true, + transaction: result, + operation: "deposit", + token: content.token, + amount: content.amount, + newBalance: await getUserBalance( + runtime, + content.token, + config.WALLET_ADDRESS + ), + walletAddress: config.WALLET_ADDRESS, + }, + }); + } catch (error) { + elizaLogger.error("Deposit operation failed:", error); + callback?.({ + text: `Failed to deposit ${content.amount} ${content.token.toUpperCase()}: ${error instanceof Error ? error.message : "Unknown error"}`, + content: { + success: false, + operation: "deposit", + token: content.token, + amount: content.amount, + error: + error instanceof Error + ? error.message + : "Unknown error", + }, + }); + return false; + } + } else if (content.operation === "withdraw") { + try { + const result = await withdrawBalance( + runtime, + content.token, + content.amount + ); + callback?.({ + text: `Successfully withdrew ${content.amount} ${content.token.toUpperCase()} from Spheron Escrow for ${config.WALLET_ADDRESS}`, + content: { + success: true, + transaction: result, + operation: "withdraw", + token: content.token, + amount: content.amount, + newBalance: await getUserBalance( + runtime, + content.token, + config.WALLET_ADDRESS + ), + walletAddress: config.WALLET_ADDRESS, + }, + }); + } catch (error) { + elizaLogger.error("Withdraw operation failed:", error); + callback?.({ + text: `Failed to withdraw ${content.amount} ${content.token.toUpperCase()}: ${error instanceof Error ? error.message : "Unknown error"}`, + content: { + success: false, + operation: "withdraw", + token: content.token, + amount: content.amount, + error: + error instanceof Error + ? error.message + : "Unknown error", + }, + }); + return false; + } + } else { + throw new Error("Invalid operation"); + } + + return true; + } catch (error) { + elizaLogger.error("Escrow operation failed:", error); + callback?.({ + text: "Escrow operation failed", + content: { + error: + error instanceof Error + ? error.message + : "Unknown error", + }, + }); + return false; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "Deposit 100 USDT into escrow", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Processing your deposit of 100 USDT...", + action: "ESCROW_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Withdraw 50 USDC from my balance", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Processing your withdrawal of 50 USDC...", + action: "ESCROW_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Add 200 DAI to my account", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Processing your deposit of 200 DAI...", + action: "ESCROW_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Check agent's escrow USDT balance", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Checking your USDT balance...", + action: "ESCROW_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "How much DAI do I have in agent's escrow?", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Let me check your DAI balance...", + action: "ESCROW_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Transfer 75 USDC to escrow", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Processing your deposit of 75 USDC...", + action: "ESCROW_OPERATION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "I want to remove 150 DAI from escrow", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Processing your withdrawal of 150 DAI...", + action: "ESCROW_OPERATION", + }, + }, + ], + ] as ActionExample[][], +} as Action; diff --git a/packages/plugin-spheron/src/environment.ts b/packages/plugin-spheron/src/environment.ts new file mode 100644 index 00000000000..66e6a0bc898 --- /dev/null +++ b/packages/plugin-spheron/src/environment.ts @@ -0,0 +1,52 @@ +import { IAgentRuntime } from "@elizaos/core"; +import { z } from "zod"; + +export const spheronEnvSchema = z.object({ + PRIVATE_KEY: z.string().min(1, "Private key is required"), + PROVIDER_PROXY_URL: z + .string() + .url("Provider proxy URL must be a valid URL"), + WALLET_ADDRESS: z.string().min(1, "Wallet address is required"), + SPHERON_PROXY_PORT: z.string().optional(), +}); + +export const requiredEnvVars = [ + "SPHERON_PRIVATE_KEY", + "SPHERON_WALLET_ADDRESS", + "SPHERON_PROVIDER_PROXY_URL", +] as const; + +export type SpheronConfig = z.infer; + +export async function validateSpheronConfig( + runtime: IAgentRuntime +): Promise { + try { + const config = { + PRIVATE_KEY: + runtime.getSetting("PRIVATE_KEY") || + process.env.SPHERON_PRIVATE_KEY || + process.env.PRIVATE_KEY, + PROVIDER_PROXY_URL: + runtime.getSetting("PROVIDER_PROXY_URL") || + process.env.SPHERON_PROVIDER_PROXY_URL || + process.env.PROVIDER_PROXY_URL, + WALLET_ADDRESS: + runtime.getSetting("WALLET_ADDRESS") || + process.env.SPHERON_WALLET_ADDRESS || + process.env.WALLET_ADDRESS, + }; + + return spheronEnvSchema.parse(config); + } catch (error) { + if (error instanceof z.ZodError) { + const errorMessages = error.errors + .map((err) => `${err.path.join(".")}: ${err.message}`) + .join("\n"); + throw new Error( + `Spheron configuration validation failed:\n${errorMessages}` + ); + } + throw error; + } +} diff --git a/packages/plugin-spheron/src/index.ts b/packages/plugin-spheron/src/index.ts new file mode 100644 index 00000000000..bb2fcc3d86f --- /dev/null +++ b/packages/plugin-spheron/src/index.ts @@ -0,0 +1,31 @@ +import { Plugin } from "@elizaos/core"; +import escrow from "./actions/escrow.ts"; +import deployment from "./actions/deployment.ts"; +import { tokensProvider } from "./providers/tokens.ts"; +import { deploymentProvider } from "./providers/deployment.ts"; +import { + SUPPORTED_TOKENS, + DEPLOYMENT_CONFIGS, + LEASE_STATES, +} from "./utils/constants.ts"; + +export const CONFIG = { + SUPPORTED_TOKENS, + DEPLOYMENT_CONFIGS, + LEASE_STATES, +}; + +export const spheronPlugin: Plugin = { + name: "spheron", + description: "Spheron Protocol Plugin for Eliza", + actions: [escrow, deployment], + evaluators: [], + providers: [tokensProvider, deploymentProvider], +}; + +export default spheronPlugin; + +// Export types +export * from "./types/index.ts"; +export * from "./environment.ts"; +export * from "./utils/index.ts"; diff --git a/packages/plugin-spheron/src/providers/deployment.ts b/packages/plugin-spheron/src/providers/deployment.ts new file mode 100644 index 00000000000..a2a066e4d90 --- /dev/null +++ b/packages/plugin-spheron/src/providers/deployment.ts @@ -0,0 +1,18 @@ +import { + IAgentRuntime, + Memory, + Provider, + State, + elizaLogger, +} from "@elizaos/core"; +import { DEPLOYMENT_CONFIGS } from "../utils/constants.ts"; + +export const deploymentProvider: Provider = { + get: async (_runtime: IAgentRuntime, _message: Memory, _state?: State) => { + elizaLogger.debug("deploymentProvider::get"); + const configs = Object.entries(DEPLOYMENT_CONFIGS) + .map(([key, value]) => `${key}: ${value}`) + .join("\n"); + return `The deployment configuration settings are:\n${configs}`; + }, +}; diff --git a/packages/plugin-spheron/src/providers/tokens.ts b/packages/plugin-spheron/src/providers/tokens.ts new file mode 100644 index 00000000000..d44a55b9e05 --- /dev/null +++ b/packages/plugin-spheron/src/providers/tokens.ts @@ -0,0 +1,18 @@ +import { + IAgentRuntime, + Memory, + Provider, + State, + elizaLogger, +} from "@elizaos/core"; +import { SUPPORTED_TOKENS } from "../utils/constants.ts"; + +export const tokensProvider: Provider = { + get: async (_runtime: IAgentRuntime, _message: Memory, _state?: State) => { + elizaLogger.debug("tokensProvider::get"); + const tokens = Object.entries(SUPPORTED_TOKENS) + .map(([key, value]) => `${key}: ${value}`) + .join("\n"); + return `The supported tokens for Spheron operations are:\n${tokens}`; + }, +}; diff --git a/packages/plugin-spheron/src/types/index.ts b/packages/plugin-spheron/src/types/index.ts new file mode 100644 index 00000000000..489c5050255 --- /dev/null +++ b/packages/plugin-spheron/src/types/index.ts @@ -0,0 +1,94 @@ +import { Content } from "@elizaos/core"; + +export interface SpheronComputeConfig { + name: string; + image: string; + replicas?: number; + ports?: Array<{ + containerPort: number; + servicePort: number; + }>; + env?: Array<{ + name: string; + value: string; + }>; + computeResources?: { + cpu: number; + memory: string; + storage: string; + gpu?: { + count: number; + model: string; + }; + }; + duration?: string; + mode?: string; + token?: string; +} + +export interface EscrowContent extends Content { + token: string; + amount: number; + operation: "deposit" | "withdraw" | "check"; +} + +export interface DeploymentContent extends Content { + operation: "create" | "update" | "close"; + template?: string; + customizations?: Customizations; + leaseId?: string; +} + +export interface Customizations { + cpu: boolean; + resources: { + cpu: number; + memory: string; + storage: string; + gpu: number; + gpu_model: string; + }; + duration: string; + token: string; + template?: { + heuristMinerAddress: string; + }; +} +export interface TokenInfo { + name: string; + symbol: string; + decimal: number; +} + +export interface BalanceInfo { + lockedBalance: string; + unlockedBalance: string; + token: TokenInfo; +} + +export interface DeploymentDetails { + services: { + [key: string]: { + name: string; + available: number; + total: number; + observed_generation: number; + replicas: number; + updated_replicas: number; + ready_replicas: number; + available_replicas: number; + container_statuses: any[]; + creationTimestamp: string; + }; + }; + forwarded_ports: { + [key: string]: Array<{ + host: string; + port: number; + externalPort: number; + proto: string; + name: string; + }>; + }; + ips: null | object; +} \ No newline at end of file diff --git a/packages/plugin-spheron/src/utils/constants.ts b/packages/plugin-spheron/src/utils/constants.ts new file mode 100644 index 00000000000..bba90ad136b --- /dev/null +++ b/packages/plugin-spheron/src/utils/constants.ts @@ -0,0 +1,34 @@ +export const SUPPORTED_TOKENS = { + USDT: "USDT", + USDC: "USDC", + DAI: "DAI", + WETH: "WETH", + CST: "CST", +} as const; + +export const DEPLOYMENT_CONFIGS = { + DEFAULT_PROVIDER_PROXY_URL: "http://localhost:3040", + NETWORK: "testnet", +} as const; + +export const LEASE_STATES = { + ACTIVE: "ACTIVE", + TERMINATED: "TERMINATED", +} as const; + +export const DEFAULT_PAGE_SIZE = 10; + +export const AVAILABLE_GPU_MODELS = [ + "rtx4090", + "h100", + "rtx3090", + "t4", + "rtx4070tisuper", + "rtx4070", + "rtx4070ti", + "rtx6000-ada", + "t1000", + "a100", + "v100", + "p4", +]; diff --git a/packages/plugin-spheron/src/utils/index.ts b/packages/plugin-spheron/src/utils/index.ts new file mode 100644 index 00000000000..a129b771d77 --- /dev/null +++ b/packages/plugin-spheron/src/utils/index.ts @@ -0,0 +1,371 @@ +import { IAgentRuntime, elizaLogger } from "@elizaos/core"; +import { SpheronSDK } from "@spheron/protocol-sdk"; +import { validateSpheronConfig } from "../environment.ts"; +import { + BalanceInfo, + DeploymentDetails, + SpheronComputeConfig, +} from "../types/index.ts"; + +export const getSDKInstance = async ( + runtime: IAgentRuntime +): Promise => { + const config = await validateSpheronConfig(runtime); + return new SpheronSDK("testnet", config.PRIVATE_KEY); +}; + +// Escrow Operations +export const getUserBalance = async ( + runtime: IAgentRuntime, + token: string, + walletAddress?: string +): Promise => { + const sdk = await getSDKInstance(runtime); + return await sdk.escrow.getUserBalance(token, walletAddress); +}; + +export const depositBalance = async ( + runtime: IAgentRuntime, + token: string, + amount: number +): Promise => { + const sdk = await getSDKInstance(runtime); + return await sdk.escrow.depositBalance({ + token, + amount, + onFailureCallback: (error) => { + elizaLogger.error("Deposit failed: ", error); + throw error; + }, + }); +}; + +export const withdrawBalance = async ( + runtime: IAgentRuntime, + token: string, + amount: number +): Promise => { + const sdk = await getSDKInstance(runtime); + return await sdk.escrow.withdrawBalance({ + token, + amount, + onFailureCallback: (error) => { + elizaLogger.error("Withdrawal failed:", error); + throw error; + }, + }); +}; + +// Deployment Operations +export const startDeployment = async ( + runtime: IAgentRuntime, + computeConfig: SpheronComputeConfig +): Promise => { + // Check balance before deployment + const token = computeConfig.token || "CST"; + const balance = await getUserBalance(runtime, token); + + // Ensure unlockedBalance and decimals exist and are valid + if (!balance.unlockedBalance || !balance.token?.decimal) { + throw new Error("Invalid balance info structure"); + } + + const unlockedBalance = BigInt(balance.unlockedBalance); + const decimal = BigInt(balance.token.decimal); + const divisor = BigInt(10) ** decimal; + + // Calculate withdrawal amount and convert to string with proper decimal places + const balanceAmount = Number(unlockedBalance) / Number(divisor); + + const requiredAmount = + calculateGPUPrice(computeConfig.computeResources?.gpu) * + (computeConfig.duration ? parseDuration(computeConfig.duration) : 1); + + if (balanceAmount < requiredAmount) { + throw new Error( + `Insufficient balance. Available: ${balanceAmount} ${token}, Required: ${requiredAmount} ${token}` + ); + } + + const result = await createOrder(runtime, generateICLYaml(computeConfig)); + // Wait for new deployment to be ready + let isReady = false; + const maxAttempts = 10; // 10 times with 10-second intervals + let attempts = 0; + + while (!isReady && attempts < maxAttempts) { + const status = await getDeploymentStatus( + runtime, + result.leaseId.toString() + ); + elizaLogger.debug( + `Deployment status (attempt ${attempts + 1}/${maxAttempts}):`, + status + ); + + if (status) { + isReady = true; + } else { + await new Promise((resolve) => setTimeout(resolve, 10000)); // Wait 10 seconds between checks + attempts++; + } + } + + if (isReady) { + elizaLogger.log("Deployment ready"); + } else { + elizaLogger.error(`Deployment not ready after ${maxAttempts} attempts`); + throw new Error("Deployment timeout"); + } + return result; +}; + +export const updateDeployment = async ( + runtime: IAgentRuntime, + leaseId: string, + computeConfig: SpheronComputeConfig +): Promise => { + // Check balance before deployment update + const token = computeConfig.token || "CST"; + const balance = await getUserBalance(runtime, token); + + // Ensure unlockedBalance and decimals exist and are valid + if (!balance.unlockedBalance || !balance.token?.decimal) { + throw new Error("Invalid balance info structure"); + } + + const unlockedBalance = BigInt(balance.unlockedBalance); + const decimal = BigInt(balance.token.decimal); + const divisor = BigInt(10) ** decimal; + + // Calculate withdrawal amount and convert to string with proper decimal places + const balanceAmount = Number(unlockedBalance) / Number(divisor); + + const requiredAmount = + calculateGPUPrice(computeConfig.computeResources?.gpu) * + (computeConfig.duration ? parseDuration(computeConfig.duration) : 1); + + if (balanceAmount < requiredAmount) { + throw new Error( + `Insufficient balance. Available: ${balanceAmount} ${token}, Required: ${requiredAmount} ${token}` + ); + } + + const result = await updateOrder( + runtime, + leaseId.toString(), + generateICLYaml(computeConfig) + ); + + // Wait for new deployment to be ready + let isReady = false; + const maxAttempts = 10; // 10 times with 10-second intervals + let attempts = 0; + + while (!isReady && attempts < maxAttempts) { + const status = await getDeploymentStatus(runtime, leaseId.toString()); + elizaLogger.debug( + `Deployment status (attempt ${attempts + 1}/${maxAttempts}):`, + status + ); + + if (status) { + isReady = true; + } else { + await new Promise((resolve) => setTimeout(resolve, 10000)); // Wait 10 seconds between checks + attempts++; + } + } + + if (isReady) { + elizaLogger.log("Deployment ready"); + } else { + elizaLogger.error(`Deployment not ready after ${maxAttempts} attempts`); + throw new Error("Deployment timeout"); + } + return result; +}; + +export const createOrder = async ( + runtime: IAgentRuntime, + iclYaml: string +): Promise<{ leaseId: string; transaction: any }> => { + elizaLogger.debug("Creating order with iclYaml:", iclYaml); + const sdk = await getSDKInstance(runtime); + const config = await validateSpheronConfig(runtime); + return await sdk.deployment.createDeployment( + iclYaml, + config.PROVIDER_PROXY_URL + ); +}; + +export const updateOrder = async ( + runtime: IAgentRuntime, + leaseId: string, + iclYaml: string +): Promise<{ providerAddress: string }> => { + const sdk = await getSDKInstance(runtime); + const config = await validateSpheronConfig(runtime); + return await sdk.deployment.updateDeployment( + leaseId, + iclYaml, + config.PROVIDER_PROXY_URL + ); +}; + +export const getDeployment = async ( + runtime: IAgentRuntime, + leaseId: string +): Promise => { + elizaLogger.debug("Getting deployment with lease ID:", leaseId); + const sdk = await getSDKInstance(runtime); + const config = await validateSpheronConfig(runtime); + return await sdk.deployment.getDeployment( + leaseId, + config.PROVIDER_PROXY_URL + ); +}; + +export const closeDeployment = async ( + runtime: IAgentRuntime, + leaseId: string +): Promise => { + const sdk = await getSDKInstance(runtime); + return await sdk.deployment.closeDeployment(leaseId); +}; + +export async function getDeploymentStatus( + runtime: IAgentRuntime, + deploymentId: string +): Promise { + try { + const deployment = await getDeployment(runtime, deploymentId); + const service = Object.values(deployment.services)[0]; + return service.ready_replicas === service.total; + } catch (error: any) { + throw new Error(`Failed to get deployment status: ${error.message}`); + } +} + +function calculateGPUPrice(gpu?: { model?: string; count?: number }): number { + if (!gpu) return 1; + + const basePrice = (() => { + switch (gpu.model?.toLowerCase()) { + // Consumer GPUs + case "rtx4090": + return 0.7; + case "rtx3090": + return 0.5; + case "rtx3080": + return 0.4; + case "rtx3070": + return 0.3; + // Data Center GPUs + case "h100": + return 3.0; + case "a100": + return 1.5; + case "a40": + return 1.2; + case "a30": + return 1.2; + case "a16": + return 1.0; + // Default case + default: + return 0.5; + } + })(); + + return basePrice * (gpu.count || 1); +} + +export function generateICLYaml(config: SpheronComputeConfig): string { + return `version: "1.0" +services: + ${config.name}: + image: ${config.image} + ${ + config.ports + ? `expose: + ${config.ports + .map( + (p) => `- port: ${p.containerPort} + as: ${p.servicePort} + to: + - global: true` + ) + .join("\n ")}` + : "" + } + ${ + config.env + ? `env: + ${config.env.map((e) => `- ${e.name}=${e.value}`).join("\n ")}` + : "" + } +profiles: + name: ${config.name} + duration: ${config.duration || "24h"} + mode: ${config.mode || "provider"} + tier: + - community + compute: + ${config.name}: + resources: + cpu: + units: ${config.computeResources?.cpu || 2} + memory: + size: ${config.computeResources?.memory || "2Gi"} + storage: + - size: ${config.computeResources?.storage || "10Gi"} + ${ + config.computeResources?.gpu + ? `gpu: + units: ${config.computeResources?.gpu?.count || 1} + attributes: + vendor: + nvidia: + - model: ${config.computeResources?.gpu?.model || "rtx4090"}` + : "" + } + placement: + westcoast: + pricing: + ${config.name}: + token: ${config.token || "CST"} + amount: ${calculateGPUPrice(config.computeResources?.gpu)} +deployment: + ${config.name}: + westcoast: + profile: ${config.name} + count: ${config.replicas || 1}`; +} + +function parseDuration(duration: string): number { + const match = duration.match(/^(\d*\.?\d+)(h|d|w|m)$/); + if (!match) { + throw new Error( + "Invalid duration format. Expected format: number (can include decimals) followed by h(hours), d(days), w(weeks), or m(months)" + ); + } + + const [, value, unit] = match; + const numValue = parseFloat(value); + + switch (unit) { + case "min": + return numValue / 60; + case "h": + return numValue; + case "d": + return numValue * 24; + case "w": + return numValue * 7 * 24; + case "m": + return numValue * 30 * 24; + default: + return 1; + } +} diff --git a/packages/plugin-spheron/src/utils/template.ts b/packages/plugin-spheron/src/utils/template.ts new file mode 100644 index 00000000000..7ff0fb6c77a --- /dev/null +++ b/packages/plugin-spheron/src/utils/template.ts @@ -0,0 +1,143 @@ +import { Customizations, SpheronComputeConfig } from "../types/index.ts"; + +interface TemplateDefinition { + description: string; + config: (customizations?: any) => SpheronComputeConfig; +} + +export const DEPLOYMENT_TEMPLATES: Record = { + "jupyter-notebook": { + description: "Jupyter Notebook environment for AI development", + config: (customizations: Customizations) => ({ + name: "jupyter", + image: customizations.cpu + ? "jupyter/minimal-notebook:latest" + : "quay.io/jupyter/pytorch-notebook:cuda12-pytorch-2.4.1", + ports: [ + { + containerPort: 8888, + servicePort: 8888, + }, + ], + env: [ + { + name: "JUPYTER_TOKEN", + value: "spheron", + }, + ], + computeResources: { + cpu: customizations.resources?.cpu || 4, + memory: customizations.resources?.memory || "8Gi", + storage: customizations.resources?.storage || "10Gi", + ...(!customizations.cpu && { + gpu: { + count: customizations.resources?.gpu || 1, + model: customizations.resources?.gpu_model || "rtx4090", + }, + }), + }, + duration: customizations.duration || "1d", + token: customizations.token || "CST", + }), + }, + "ollama-webui": { + description: "Ollama Web UI for managing and interacting with LLMs", + config: (customizations: Customizations) => ({ + name: "ollama-webui", + image: "ghcr.io/open-webui/open-webui:ollama", + ports: [ + { + containerPort: 8080, + servicePort: 8080, + }, + { + containerPort: 11434, + servicePort: 11434, + }, + ], + computeResources: { + cpu: customizations.resources?.cpu || 4, + memory: customizations.resources?.memory || "8Gi", + storage: customizations.resources?.storage || "20Gi", + ...(!customizations.cpu && { + gpu: { + count: customizations.resources?.gpu || 1, + model: customizations.resources?.gpu_model || "rtx4090", + }, + }), + }, + duration: customizations.duration || "1d", + token: customizations.token || "CST", + }), + }, + "vscode-pytorch": { + description: "VS Code Server with PyTorch development environment", + config: (customizations: Customizations) => ({ + name: "vscode", + image: customizations.cpu + ? "lscr.io/linuxserver/code-server" + : "spheronnetwork/vscode-pytorch:latest", + ports: [ + { + containerPort: 8443, + servicePort: 8443, + }, + ], + env: [ + { + name: "PASSWORD", + value: "spheron", + }, + ], + computeResources: { + cpu: customizations.resources?.cpu || 4, + memory: customizations.resources?.memory || "8Gi", + storage: customizations.resources?.storage || "20Gi", + ...(!customizations.cpu && { + gpu: { + count: customizations.resources?.gpu || 1, + model: customizations.resources?.gpu_model || "rtx4090", + }, + }), + }, + duration: customizations.duration || "1d", + token: customizations.token || "CST", + }), + }, + "heurist-miner": { + description: "Heurist Miner for mining Heurist network", + config: (customizations: Customizations) => ({ + name: "heurist-miner", + image: "spheronnetwork/heurist-miner:latest", + ports: [ + { + containerPort: 8888, + servicePort: 8888, + }, + ], + env: [ + { + name: "MINER_ID_0", + value: customizations.template?.heuristMinerAddress || "", + }, + { + name: "LOG_LEVEL", + value: "INFO", + }, + ], + computeResources: { + cpu: customizations.resources?.cpu || 8, + memory: customizations.resources?.memory || "16Gi", + storage: customizations.resources?.storage || "200Gi", + ...(!customizations.cpu && { + gpu: { + count: customizations.resources?.gpu || 1, + model: customizations.resources?.gpu_model || "rtx4090", + }, + }), + }, + duration: customizations.duration || "1d", + token: customizations.token || "CST", + }), + }, +}; diff --git a/packages/plugin-spheron/tsconfig.json b/packages/plugin-spheron/tsconfig.json new file mode 100644 index 00000000000..005fbac9d36 --- /dev/null +++ b/packages/plugin-spheron/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src/**/*.ts"] +} diff --git a/packages/plugin-spheron/tsup.config.ts b/packages/plugin-spheron/tsup.config.ts new file mode 100644 index 00000000000..1a55f7a745f --- /dev/null +++ b/packages/plugin-spheron/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], // Ensure you're targeting CommonJS + external: [], +}); diff --git a/packages/plugin-thirdweb/.npmignore b/packages/plugin-thirdweb/.npmignore new file mode 100644 index 00000000000..078562eceab --- /dev/null +++ b/packages/plugin-thirdweb/.npmignore @@ -0,0 +1,6 @@ +* + +!dist/** +!package.json +!readme.md +!tsup.config.ts \ No newline at end of file diff --git a/packages/plugin-thirdweb/README.md b/packages/plugin-thirdweb/README.md new file mode 100644 index 00000000000..f4d220a0f81 --- /dev/null +++ b/packages/plugin-thirdweb/README.md @@ -0,0 +1,62 @@ +# `ai16z/plugin-thirdweb` + +This plugin provides access to thirdweb's Nebula AI interface: [https://portal.thirdweb.com/nebula](https://portal.thirdweb.com/nebula). + +## Configuration + +### Default Setup + +By default, \*_thirdweb plugin_ is enabled. To use it, simply add your secret key to the `.env` file: + +```env +THIRDWEB_SECRET_KEY=your-thirdweb-secret-key-here +``` + +--- + +## Actions + +### Chat + +Interact with the thirdweb Nebula natural language interface to perform any of the following: + +- Analyze any smart contract's functionality and features +- Explain contract interfaces and supported standards +- Read contract data and state +- Help you understand function behaviors and parameters +- Decode complex contract interactions +- Retrieve detailed contract metadata and source code analysis +- Provide real-time network status and gas prices +- Explain block and transaction details +- Help you understand blockchain network specifications +- Offer insights about different blockchain networks +- Track transaction status and history +- Access detailed chain metadata including RPC endpoints +- Look up token information across different networks +- Track token prices and market data +- Explain token standards and implementations +- Help you understand token bridges and cross-chain aspects +- Monitor trading pairs and liquidity +- Fetch token metadata and current exchange rates +- Retrieve detailed transaction information using transaction hashes +- Provide wallet balance and transaction history + +**Example usage:** + +```env +What is the ETH balance for 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 +``` + +```env +What is the total NFT supply for 0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D? +``` + +```env +Does 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 hold USDC on Base? +``` + +```env +What is the address of USDC on Ethereum? +``` + +--- diff --git a/packages/plugin-thirdweb/eslint.config.mjs b/packages/plugin-thirdweb/eslint.config.mjs new file mode 100644 index 00000000000..92fe5bbebef --- /dev/null +++ b/packages/plugin-thirdweb/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-thirdweb/package.json b/packages/plugin-thirdweb/package.json new file mode 100644 index 00000000000..125d7fd14e6 --- /dev/null +++ b/packages/plugin-thirdweb/package.json @@ -0,0 +1,20 @@ +{ + "name": "@elizaos/plugin-thirdweb", + "version": "0.1.7-alpha.2", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@elizaos/core": "workspace:*", + "thirdweb": "^5.80.0", + "tsup": "8.3.5" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "lint": "eslint --fix --cache ." + }, + "peerDependencies": { + "whatwg-url": "7.1.0" + } +} diff --git a/packages/plugin-thirdweb/src/actions/chat.ts b/packages/plugin-thirdweb/src/actions/chat.ts new file mode 100644 index 00000000000..16d558a4e19 --- /dev/null +++ b/packages/plugin-thirdweb/src/actions/chat.ts @@ -0,0 +1,214 @@ +import { + elizaLogger, + HandlerCallback, + IAgentRuntime, + Memory, + State, + type Action, +} from "@elizaos/core"; + +const BASE_URL = "https://nebula-api.thirdweb.com"; + +// If chat is a stream, wait for stream to complete before returning response +async function handleStreamResponse( + response: Response +): Promise { + elizaLogger.log("Starting stream response handling"); + const reader = response.body?.getReader(); + if (!reader) { + elizaLogger.error("No readable stream available"); + throw new Error("No readable stream available"); + } + + return new ReadableStream({ + async start(controller) { + try { + while (true) { + const { done, value } = await reader.read(); + if (done) { + elizaLogger.log("Stream reading completed"); + break; + } + + const events = new TextDecoder() + .decode(value) + .split("\n\n"); + elizaLogger.debug( + `Processing ${events.length} stream events` + ); + for (const event of events) { + if (!event.trim()) continue; + controller.enqueue(event); + } + } + } finally { + reader.releaseLock(); + controller.close(); + elizaLogger.log("Stream controller closed"); + } + }, + }); +} + +// Process & return a response to the current message with thirdweb Nebula +export const blockchainChatAction: Action = { + name: "BLOCKCHAIN_CHAT", + similes: [ + "QUERY_BLOCKCHAIN", + "CHECK_BLOCKCHAIN", + "BLOCKCHAIN_SEARCH", + "CRYPTO_LOOKUP", + "WEB3_SEARCH", + "BLOCKCHAIN_HISTORY_EXPLORER", + "UNIVERSAL_BLOCKCHAIN_TRANSALTOR", + "BLOCKCHAIN_DATA_PROVIDER", + "HISTORICAL_BLOCKCHAIN_DATA", + "TRACK_BLOCKCHAIN_TRANSACTIONS", + "BLOCKCHAIN_INTERPRETER", + "BLOCKCHAIN_TRANSACTION_DETAILS", + ], + validate: async ( + runtime: IAgentRuntime, + _message: Memory + ): Promise => { + const secretKey = + runtime.getSetting("THIRDWEB_SECRET_KEY") ?? + process.env.THIRDWEB_SECRET_KEY; + return Boolean(secretKey); + }, + description: + "Query blockchain data and execute transactions through natural language interaction with the Nebula API", + handler: async ( + runtime: IAgentRuntime, + message: Memory, + _state: State, + _options: any, + callback: HandlerCallback + ): Promise => { + try { + elizaLogger.log("Starting blockchain chat handler"); + const secretKey = + runtime.getSetting("THIRDWEB_SECRET_KEY") ?? + process.env.THIRDWEB_SECRET_KEY; + + if (!secretKey) { + elizaLogger.error("THIRDWEB_SECRET_KEY not configured"); + throw new Error("THIRDWEB_SECRET_KEY is not configured"); + } + + const request = { + message: message.content.text, + stream: false, + }; + + elizaLogger.log("NEBULA CHAT REQUEST: ", request); + + elizaLogger.debug("Sending request to Nebula API"); + const response = await fetch(`${BASE_URL}/chat`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-secret-key": secretKey, + }, + body: JSON.stringify(request), + }); + elizaLogger.debug("Received response from Nebula API"); + + if (!request.stream) { + const text = await response.text(); + elizaLogger.debug("Raw response text:", text); + + try { + const cleanedText = text.trim().split("\n").pop() || text; + const parsed = JSON.parse(cleanedText); + elizaLogger.log("Successfully parsed response:", parsed); + + console.log(parsed.message); + + await callback({ text: parsed.message }); + + return parsed; + } catch (parseError) { + elizaLogger.error("Parse error details:", parseError); + elizaLogger.error( + "Failed to parse JSON response. Raw text:", + text + ); + return { text: text }; + } + } + + elizaLogger.log("Handling streaming response"); + return handleStreamResponse(response); + } catch (error) { + elizaLogger.error("Blockchain chat failed:", error); + throw new Error(`Blockchain chat failed: ${error.message}`); + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "What's the ETH balance of vitalik.eth?", + action: "BLOCKCHAIN_CHAT", + }, + }, + { + user: "{{user2}}", + content: { + text: "The current ETH balance of vitalik.eth (0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045) is 1,123.45 ETH", + action: "BLOCKCHAIN_CHAT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "send 0.1 ETH to 0x742d35Cc6634C0532925a3b844Bc454e4438f44e", + action: "BLOCKCHAIN_CHAT", + }, + }, + { + user: "{{user2}}", + content: { + text: "I'll help you send 0.1 ETH. Please review and sign the transaction.", + action: "BLOCKCHAIN_CHAT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Show me the floor price of BAYC", + action: "BLOCKCHAIN_CHAT", + }, + }, + { + user: "{{user2}}", + content: { + text: "The current floor price for BAYC is 32.5 ETH with 3 sales in the last 24h", + action: "BLOCKCHAIN_CHAT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Show me my recent transactions", + action: "BLOCKCHAIN_CHAT", + }, + }, + { + user: "{{user2}}", + content: { + text: "Here are your recent transactions: 1. Sent 1.5 ETH 2. Swapped tokens on Uniswap 3. Received 0.5 ETH", + action: "BLOCKCHAIN_CHAT", + }, + }, + ], + ], +} as Action; diff --git a/packages/plugin-thirdweb/src/actions/index.ts b/packages/plugin-thirdweb/src/actions/index.ts new file mode 100644 index 00000000000..5ea161c6e4a --- /dev/null +++ b/packages/plugin-thirdweb/src/actions/index.ts @@ -0,0 +1 @@ +export * from "./chat.ts"; diff --git a/packages/plugin-thirdweb/src/index.ts b/packages/plugin-thirdweb/src/index.ts new file mode 100644 index 00000000000..49bbe528abb --- /dev/null +++ b/packages/plugin-thirdweb/src/index.ts @@ -0,0 +1,12 @@ +import { Plugin } from "@elizaos/core"; +import { blockchainChatAction } from "./actions/chat"; +export * as actions from "./actions/index.ts"; + +export const thirdwebPlugin: Plugin = { + name: "PROVIDE_BLOCKCHAIN_DATA", + description: + "Search the blockchain with thirdweb Nebula for information about wallet addresses, token prices, token owners, transactions and their details.", + actions: [blockchainChatAction], + evaluators: [], + providers: [], +}; diff --git a/packages/plugin-thirdweb/tsconfig.json b/packages/plugin-thirdweb/tsconfig.json new file mode 100644 index 00000000000..834c4dce269 --- /dev/null +++ b/packages/plugin-thirdweb/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": [ + "node" + ] + }, + "include": [ + "src/**/*.ts" + ] +} \ No newline at end of file diff --git a/packages/plugin-thirdweb/tsup.config.ts b/packages/plugin-thirdweb/tsup.config.ts new file mode 100644 index 00000000000..e42bf4efeae --- /dev/null +++ b/packages/plugin-thirdweb/tsup.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], // Ensure you're targeting CommonJS + external: [ + "dotenv", // Externalize dotenv to prevent bundling + "fs", // Externalize fs to use Node.js built-in module + "path", // Externalize other built-ins if necessary + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + // Add other modules you want to externalize + ], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 399b437dc1f..902089d10ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,10 +78,10 @@ importers: version: 9.1.7 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.10.5) + version: 29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0) lerna: specifier: 8.1.5 - version: 8.1.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(encoding@0.1.13) + version: 8.1.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13) only-allow: specifier: 1.2.1 version: 1.2.1 @@ -90,7 +90,7 @@ importers: version: 3.4.1 ts-jest: specifier: ^29.1.1 - version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.10.5))(typescript@5.6.3) + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0))(typescript@5.6.3) turbo: specifier: 2.3.3 version: 2.3.3 @@ -112,9 +112,6 @@ importers: agent: dependencies: - '@ai16z/plugin-cosmos': - specifier: workspace:* - version: link:../packages/plugin-cosmos '@elizaos/adapter-pglite': specifier: workspace:* version: link:../packages/adapter-pglite @@ -163,6 +160,9 @@ importers: '@elizaos/plugin-abstract': specifier: workspace:* version: link:../packages/plugin-abstract + '@elizaos/plugin-allora': + specifier: workspace:* + version: link:../packages/plugin-allora '@elizaos/plugin-aptos': specifier: workspace:* version: link:../packages/plugin-aptos @@ -190,9 +190,15 @@ importers: '@elizaos/plugin-conflux': specifier: workspace:* version: link:../packages/plugin-conflux + '@elizaos/plugin-cosmos': + specifier: workspace:* + version: link:../packages/plugin-cosmos '@elizaos/plugin-cronoszkevm': specifier: workspace:* version: link:../packages/plugin-cronoszkevm + '@elizaos/plugin-depin': + specifier: workspace:* + version: link:../packages/plugin-depin '@elizaos/plugin-echochambers': specifier: workspace:* version: link:../packages/plugin-echochambers @@ -226,6 +232,9 @@ importers: '@elizaos/plugin-intiface': specifier: workspace:* version: link:../packages/plugin-intiface + '@elizaos/plugin-movement': + specifier: workspace:* + version: link:../packages/plugin-movement '@elizaos/plugin-multiversx': specifier: workspace:* version: link:../packages/plugin-multiversx @@ -238,6 +247,9 @@ importers: '@elizaos/plugin-node': specifier: workspace:* version: link:../packages/plugin-node + '@elizaos/plugin-obsidian': + specifier: workspace:* + version: link:../packages/plugin-obsidian '@elizaos/plugin-open-weather': specifier: workspace:* version: link:../packages/plugin-open-weather @@ -265,6 +277,9 @@ importers: '@elizaos/plugin-tee-marlin': specifier: workspace:* version: link:../packages/plugin-tee-marlin + '@elizaos/plugin-thirdweb': + specifier: workspace:* + version: link:../packages/plugin-thirdweb '@elizaos/plugin-ton': specifier: workspace:* version: link:../packages/plugin-ton @@ -292,16 +307,16 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + version: 29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) ts-jest: specifier: ^29.2.5 - version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)))(typescript@5.6.3) + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)))(typescript@5.7.2) ts-node: specifier: 10.9.2 - version: 10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3) + version: 10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) client: dependencies: @@ -401,25 +416,25 @@ importers: dependencies: '@docusaurus/core': specifier: 3.6.3 - version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/plugin-content-blog': specifier: 3.6.3 - version: 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/plugin-content-docs': specifier: 3.6.3 - version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/plugin-ideal-image': specifier: 3.6.3 - version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/preset-classic': specifier: 3.6.3 - version: 3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/theme-common': specifier: 3.6.3 - version: 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + version: 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/theme-mermaid': specifier: 3.6.3 - version: 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@mdx-js/react': specifier: 3.0.1 version: 3.0.1(@types/react@18.3.12)(react@18.3.1) @@ -428,7 +443,7 @@ importers: version: 2.1.1 docusaurus-lunr-search: specifier: 3.5.0 - version: 3.5.0(@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 3.5.0(@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) dotenv: specifier: ^16.4.7 version: 16.4.7 @@ -456,13 +471,13 @@ importers: version: 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) docusaurus-plugin-typedoc: specifier: 1.0.5 - version: 1.0.5(typedoc-plugin-markdown@4.2.10(typedoc@0.26.11(typescript@5.6.3))) + version: 1.0.5(typedoc-plugin-markdown@4.2.10(typedoc@0.26.11(typescript@5.7.2))) typedoc: specifier: 0.26.11 - version: 0.26.11(typescript@5.6.3) + version: 0.26.11(typescript@5.7.2) typedoc-plugin-markdown: specifier: 4.2.10 - version: 4.2.10(typedoc@0.26.11(typescript@5.6.3)) + version: 4.2.10(typedoc@0.26.11(typescript@5.7.2)) packages/adapter-pglite: dependencies: @@ -478,7 +493,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/adapter-postgres: dependencies: @@ -494,7 +509,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/adapter-redis: dependencies: @@ -513,7 +528,7 @@ importers: version: 5.0.0 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/adapter-sqlite: dependencies: @@ -535,7 +550,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/adapter-sqljs: dependencies: @@ -557,7 +572,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/adapter-supabase: dependencies: @@ -573,7 +588,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/client-auto: dependencies: @@ -604,7 +619,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/client-direct: dependencies: @@ -647,7 +662,7 @@ importers: version: 1.4.12 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/client-discord: dependencies: @@ -684,7 +699,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) vitest: specifier: 1.2.1 version: 1.2.1(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) @@ -696,11 +711,11 @@ importers: version: link:../core '@neynar/nodejs-sdk': specifier: ^2.0.3 - version: 2.7.1(bufferutil@4.0.9)(class-transformer@0.5.1)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + version: 2.7.1(bufferutil@4.0.9)(class-transformer@0.5.1)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) devDependencies: tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/client-github: dependencies: @@ -725,7 +740,7 @@ importers: version: 8.1.0 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/client-lens: dependencies: @@ -744,7 +759,7 @@ importers: devDependencies: tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/client-slack: dependencies: @@ -790,13 +805,13 @@ importers: version: 18.19.70 jest: specifier: ^29.5.0 - version: 29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) + version: 29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) rimraf: specifier: ^5.0.0 version: 5.0.10 ts-jest: specifier: ^29.1.0 - version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)))(typescript@5.6.3) + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)))(typescript@5.6.3) ts-node: specifier: ^10.9.1 version: 10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3) @@ -824,7 +839,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) vitest: specifier: 1.2.1 version: 1.2.1(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) @@ -837,6 +852,9 @@ importers: agent-twitter-client: specifier: 0.0.18 version: 0.0.18(bufferutil@4.0.9)(utf-8-validate@5.0.10) + discord.js: + specifier: 14.16.3 + version: 14.16.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) glob: specifier: 11.0.0 version: 11.0.0 @@ -847,9 +865,15 @@ importers: specifier: 3.23.8 version: 3.23.8 devDependencies: + '@vitest/coverage-v8': + specifier: 1.1.3 + version: 1.1.3(vitest@1.1.3(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) + vitest: + specifier: 1.1.3 + version: 1.1.3(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) packages/core: dependencies: @@ -985,13 +1009,13 @@ importers: version: 8.16.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.6.3) '@vitest/coverage-v8': specifier: 2.1.5 - version: 2.1.5(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + version: 2.1.5(vitest@2.1.8(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) dotenv: specifier: 16.4.5 version: 16.4.5 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + version: 29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) lint-staged: specifier: 15.2.10 version: 15.2.10 @@ -1009,7 +1033,7 @@ importers: version: 2.79.2 ts-jest: specifier: 29.2.5 - version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3) + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3) @@ -1040,7 +1064,7 @@ importers: version: 2.4.0 unbuild: specifier: 2.0.0 - version: 2.0.0(typescript@5.6.3) + version: 2.0.0(typescript@5.7.2) packages/plugin-0g: dependencies: @@ -1055,7 +1079,7 @@ importers: version: 6.13.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/plugin-3d-generation: dependencies: @@ -1064,7 +1088,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1076,10 +1100,49 @@ importers: version: link:../core tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) web3: specifier: ^4.15.0 - version: 4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + version: 4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) + whatwg-url: + specifier: 7.1.0 + version: 7.1.0 + + packages/plugin-allora: + dependencies: + '@alloralabs/allora-sdk': + specifier: 0.0.4 + version: 0.0.4 + '@elizaos/core': + specifier: workspace:* + version: link:../core + node-cache: + specifier: 5.1.2 + version: 5.1.2 + tsup: + specifier: 8.3.5 + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) + vitest: + specifier: 2.1.8 + version: 2.1.8(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + whatwg-url: + specifier: 7.1.0 + version: 7.1.0 + + packages/plugin-anyone: + dependencies: + '@anyone-protocol/anyone-client': + specifier: ^0.4.3 + version: 0.4.3 + '@elizaos/core': + specifier: workspace:* + version: link:../core + axios: + specifier: ^1.7.9 + version: 1.7.9(debug@4.4.0) + tsup: + specifier: 8.3.5 + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1103,7 +1166,7 @@ importers: version: 5.1.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) vitest: specifier: 2.1.4 version: 2.1.4(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) @@ -1118,10 +1181,10 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) viem: specifier: 2.21.58 - version: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + version: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) devDependencies: whatwg-url: specifier: 7.1.0 @@ -1144,7 +1207,7 @@ importers: version: 20.17.9 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/plugin-avalanche: dependencies: @@ -1157,7 +1220,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/plugin-binance: dependencies: @@ -1176,7 +1239,7 @@ importers: version: 20.17.9 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/plugin-bootstrap: dependencies: @@ -1185,7 +1248,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1216,7 +1279,7 @@ importers: version: 20.17.9 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/plugin-coinprice: dependencies: @@ -1232,7 +1295,7 @@ importers: devDependencies: tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/plugin-conflux: dependencies: @@ -1241,7 +1304,7 @@ importers: version: link:../core cive: specifier: 0.7.1 - version: 0.7.1(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 0.7.1(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10) packages/plugin-cosmos: dependencies: @@ -1266,12 +1329,19 @@ importers: chain-registry: specifier: ^1.69.68 version: 1.69.86 + interchain: + specifier: ^1.10.4 + version: 1.10.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) zod: specifier: 3.23.8 version: 3.23.8 + devDependencies: + '@chain-registry/types': + specifier: ^0.50.44 + version: 0.50.45 packages/plugin-cronoszkevm: dependencies: @@ -1280,13 +1350,28 @@ importers: version: link:../core tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) web3: specifier: ^4.15.0 - version: 4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + version: 4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) web3-plugin-zksync: specifier: ^1.0.8 - version: 1.0.8(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1)) + version: 1.0.8(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1)) + whatwg-url: + specifier: 7.1.0 + version: 7.1.0 + + packages/plugin-depin: + dependencies: + '@elizaos/core': + specifier: workspace:* + version: link:../core + axios: + specifier: ^1.7.9 + version: 1.7.9(debug@4.4.0) + tsup: + specifier: 8.3.5 + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1313,13 +1398,13 @@ importers: version: 5.15.5 '@lifi/sdk': specifier: 3.4.1 - version: 3.4.1(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(typescript@5.6.3)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1)) + version: 3.4.1(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(typescript@5.7.2)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1)) '@lifi/types': specifier: 16.3.0 version: 16.3.0 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1371,7 +1456,7 @@ importers: version: 10.0.0 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) vitest: specifier: 2.1.4 version: 2.1.4(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) @@ -1389,7 +1474,7 @@ importers: version: 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) vitest: specifier: 2.1.4 version: 2.1.4(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) @@ -1404,10 +1489,10 @@ importers: version: link:../core genlayer-js: specifier: 0.4.7 - version: 0.4.7(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + version: 0.4.7(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/plugin-giphy: dependencies: @@ -1419,7 +1504,7 @@ importers: version: 1.7.9(debug@4.4.0) tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) zod: specifier: ^3.22.4 version: 3.23.8 @@ -1431,7 +1516,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) packages/plugin-goat: dependencies: @@ -1446,19 +1531,19 @@ importers: version: 0.4.0 '@goat-sdk/plugin-erc20': specifier: 0.2.2 - version: 0.2.2(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) + version: 0.2.2(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8)) '@goat-sdk/plugin-kim': specifier: 0.1.2 - version: 0.1.2(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) + version: 0.1.2(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8)) '@goat-sdk/wallet-evm': specifier: 0.2.0 - version: 0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10) '@goat-sdk/wallet-viem': specifier: 0.2.0 - version: 0.2.0(@goat-sdk/wallet-evm@0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10))(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) + version: 0.2.0(@goat-sdk/wallet-evm@0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10))(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8)) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1470,7 +1555,7 @@ importers: version: link:../core tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) ws: specifier: ^8.18.0 version: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -1505,7 +1590,7 @@ importers: version: 29.5.14 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@22.10.5) + version: 29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0) tsup: specifier: 8.3.5 version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) @@ -1520,7 +1605,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1538,10 +1623,44 @@ importers: version: 1.0.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) + whatwg-url: + specifier: 7.1.0 + version: 7.1.0 + + packages/plugin-movement: + dependencies: + '@aptos-labs/ts-sdk': + specifier: ^1.26.0 + version: 1.33.1 + '@elizaos/core': + specifier: workspace:* + version: link:../core + bignumber: + specifier: 1.1.0 + version: 1.1.0 + bignumber.js: + specifier: 9.1.2 + version: 9.1.2 + form-data: + specifier: 4.0.1 + version: 4.0.1 + node-cache: + specifier: 5.1.2 + version: 5.1.2 whatwg-url: specifier: 7.1.0 version: 7.1.0 + devDependencies: + tsup: + specifier: 8.3.5 + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + typescript: + specifier: ^5.0.0 + version: 5.6.3 + vitest: + specifier: 2.1.4 + version: 2.1.4(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) packages/plugin-multiversx: dependencies: @@ -1565,7 +1684,7 @@ importers: version: 2.1.1 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) vitest: specifier: 2.1.5 version: 2.1.5(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) @@ -1595,7 +1714,7 @@ importers: version: 5.1.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1625,7 +1744,7 @@ importers: version: 0.9.2(@metaplex-foundation/umi@0.9.2)(@solana/web3.js@1.95.5(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(encoding@0.1.13) '@solana-developers/helpers': specifier: ^2.5.6 - version: 2.5.6(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 2.5.6(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': specifier: 1.95.5 version: 1.95.5(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -1640,7 +1759,7 @@ importers: version: 5.1.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1754,7 +1873,7 @@ importers: version: 5.1.2 node-llama-cpp: specifier: 3.1.1 - version: 3.1.1(typescript@5.6.3) + version: 3.1.1(typescript@5.7.2) nodejs-whisper: specifier: 0.1.18 version: 0.1.18 @@ -1772,10 +1891,10 @@ importers: version: 5.4.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) puppeteer-extra: specifier: 3.3.6 - version: 3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)) + version: 3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)) puppeteer-extra-plugin-capsolver: specifier: 2.0.1 - version: 2.0.1(bufferutil@4.0.9)(encoding@0.1.13)(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10))(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 2.0.1(bufferutil@4.0.9)(encoding@0.1.13)(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(typescript@5.7.2)(utf-8-validate@5.0.10) sharp: specifier: 0.33.5 version: 0.33.5 @@ -1818,7 +1937,25 @@ importers: version: 22.8.4 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) + + packages/plugin-obsidian: + dependencies: + '@elizaos/core': + specifier: workspace:* + version: link:../core + file-type-checker: + specifier: ^1.1.2 + version: 1.1.2 + mrmime: + specifier: ^2.0.0 + version: 2.0.0 + tsup: + specifier: 8.3.5 + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) + whatwg-url: + specifier: 7.1.0 + version: 7.1.0 packages/plugin-open-weather: dependencies: @@ -1827,7 +1964,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1851,7 +1988,7 @@ importers: version: link:../plugin-trustdb '@solana/spl-token': specifier: 0.4.9 - version: 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': specifier: 1.95.8 version: 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -1863,7 +2000,7 @@ importers: version: 6.0.0 fomo-sdk-solana: specifier: 1.3.2 - version: 1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) form-data: specifier: 4.0.1 version: 4.0.1 @@ -1872,10 +2009,10 @@ importers: version: 5.1.2 pumpdotfun-sdk: specifier: 1.3.2 - version: 1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(rollup@4.30.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(rollup@4.30.1)(typescript@5.7.2)(utf-8-validate@5.0.10) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) vitest: specifier: 2.1.4 version: 2.1.4(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) @@ -1899,7 +2036,7 @@ importers: version: link:../plugin-trustdb '@solana/spl-token': specifier: 0.4.9 - version: 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': specifier: 1.95.8 version: 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -1914,7 +2051,7 @@ importers: version: 6.0.0 fomo-sdk-solana: specifier: 1.3.2 - version: 1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) form-data: specifier: 4.0.1 version: 4.0.1 @@ -1923,13 +2060,13 @@ importers: version: 5.1.2 pumpdotfun-sdk: specifier: 1.3.2 - version: 1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(rollup@4.30.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(rollup@4.30.1)(typescript@5.7.2)(utf-8-validate@5.0.10) solana-agent-kit: specifier: ^1.2.0 - version: 1.3.7(@noble/hashes@1.7.0)(@swc/core@1.10.4(@swc/helpers@0.5.15))(axios@1.7.9)(borsh@2.0.0)(buffer@6.0.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(handlebars@4.7.8)(jiti@2.4.2)(react@18.3.1)(sodium-native@3.4.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 1.3.7(@noble/hashes@1.7.0)(@swc/core@1.10.4(@swc/helpers@0.5.15))(axios@1.7.9)(borsh@2.0.0)(buffer@6.0.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(handlebars@4.7.8)(jiti@2.4.2)(react@18.3.1)(sodium-native@3.4.1)(typescript@5.7.2)(utf-8-validate@5.0.10) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) vitest: specifier: 2.1.4 version: 2.1.4(@types/node@20.17.9)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) @@ -1937,6 +2074,25 @@ importers: specifier: 7.1.0 version: 7.1.0 + packages/plugin-spheron: + dependencies: + '@elizaos/core': + specifier: workspace:* + version: link:../core + '@spheron/protocol-sdk': + specifier: ^1.0.0 + version: 1.2.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + zod: + specifier: ^3.22.4 + version: 3.23.8 + devDependencies: + '@types/node': + specifier: ^20.0.0 + version: 20.17.9 + typescript: + specifier: ^5.0.0 + version: 5.6.3 + packages/plugin-stargaze: dependencies: '@elizaos/core': @@ -1947,7 +2103,7 @@ importers: version: 1.7.9(debug@4.4.0) tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) zod: specifier: ^3.22.4 version: 3.23.8 @@ -1971,7 +2127,7 @@ importers: version: 6.18.0(encoding@0.1.13) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) unruggable-sdk: specifier: 1.4.0 version: 1.4.0(starknet@6.18.0(encoding@0.1.13)) @@ -1992,10 +2148,10 @@ importers: version: 2.1.0 '@story-protocol/core-sdk': specifier: 1.2.0-rc.3 - version: 1.2.0-rc.3(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + version: 1.2.0-rc.3(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -2011,7 +2167,7 @@ importers: version: link:../core '@mysten/sui': specifier: ^1.16.0 - version: 1.18.0(typescript@5.6.3) + version: 1.18.0(typescript@5.7.2) bignumber.js: specifier: 9.1.2 version: 9.1.2 @@ -2023,7 +2179,7 @@ importers: version: 5.1.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) vitest: specifier: 2.1.4 version: 2.1.4(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) @@ -2038,10 +2194,10 @@ importers: version: link:../core '@phala/dstack-sdk': specifier: 0.1.7 - version: 0.1.7(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + version: 0.1.7(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) '@solana/spl-token': specifier: 0.4.9 - version: 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': specifier: 1.95.8 version: 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -2056,10 +2212,10 @@ importers: version: 5.1.2 pumpdotfun-sdk: specifier: 1.3.2 - version: 1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(rollup@4.30.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(rollup@4.30.1)(typescript@5.7.2)(utf-8-validate@5.0.10) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -2071,7 +2227,22 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) + whatwg-url: + specifier: 7.1.0 + version: 7.1.0 + + packages/plugin-thirdweb: + dependencies: + '@elizaos/core': + specifier: workspace:* + version: link:../core + thirdweb: + specifier: ^5.80.0 + version: 5.82.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(bufferutil@4.0.9)(encoding@0.1.13)(ethers@6.13.4(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ioredis@5.4.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) + tsup: + specifier: 8.3.5 + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -2095,7 +2266,7 @@ importers: version: 5.1.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -2110,7 +2281,7 @@ importers: version: 3.2.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) uuid: specifier: 11.0.3 version: 11.0.3 @@ -2135,7 +2306,11 @@ importers: version: 0.0.18(bufferutil@4.0.9)(utf-8-validate@5.0.10) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) + devDependencies: + vitest: + specifier: ^1.0.0 + version: 1.2.1(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) packages/plugin-video-generation: dependencies: @@ -2144,7 +2319,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -2156,7 +2331,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -2184,10 +2359,10 @@ importers: version: 8.16.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.6.3) jest: specifier: 29.7.0 - version: 29.7.0(@types/node@20.17.9) + version: 29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) ts-jest: specifier: 29.2.5 - version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.9))(typescript@5.6.3) + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0))(typescript@5.6.3) typescript: specifier: 5.6.3 version: 5.6.3 @@ -2199,13 +2374,13 @@ importers: version: link:../core tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) web3: specifier: ^4.15.0 - version: 4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + version: 4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) web3-plugin-zksync: specifier: ^1.0.8 - version: 1.0.8(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1)) + version: 1.0.8(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1)) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -2523,6 +2698,10 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@alloralabs/allora-sdk@0.0.4': + resolution: {integrity: sha512-QlpXJAnN5I6QHnNP+j96Cim05ztBfsKV/Ecn79+2KE2Wt71PJQj3ZGJ5SmbICJdQe5FrkpgthBkK0xOoYMYhWQ==} + engines: {node: '>=18'} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -2557,6 +2736,10 @@ packages: resolution: {integrity: sha512-IQD9wkVReKAhsEAbDjh/0KrBGTEXelqZLpOBRDaIRvlzZ9sjmUP+gKbpvzyJnei2JHQiE8JAgj7YcNloINbGBw==} engines: {node: '>= 10'} + '@anyone-protocol/anyone-client@0.4.3': + resolution: {integrity: sha512-+JfuYFmjh2Yz3E3tPgoCXJAz5LoRUGq30eJOiCQBvXWwz3agjS2pwX4L4T+uvcWNFlRCjUHsmbsqKVDa7kf3Rw==} + hasBin: true + '@aptos-labs/aptos-cli@1.0.2': resolution: {integrity: sha512-PYPsd0Kk3ynkxNfe3S4fanI3DiUICCoh4ibQderbvjPFL5A0oK6F4lPEO2t0MDsQySTk2t4vh99Xjy6Bd9y+aQ==} hasBin: true @@ -3499,6 +3682,9 @@ packages: '@coinbase/coinbase-sdk@0.10.0': resolution: {integrity: sha512-sqLH7dE/0XSn5jHddjVrC1PR77sQUEytYcQAlH2d8STqRARcvddxVAByECUIL32MpbdJY7Wca3KfSa6qo811Mg==} + '@coinbase/wallet-sdk@4.2.4': + resolution: {integrity: sha512-wJ9QOXOhRdGermKAoJSr4JgGqZm/Um0m+ecywzEC9qSOu3TXuVcG3k0XXTXW11UBgjdoPRuf5kAwRX3T9BynFA==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -3626,6 +3812,9 @@ packages: peerDependencies: '@solana/web3.js': ^1.68.0 + '@cosmjs/amino@0.32.2': + resolution: {integrity: sha512-lcK5RCVm4OfdAooxKcF2+NwaDVVpghOq6o/A40c2mHXDUzUoRZ33VAHjVJ9Me6vOFxshrw/XEFn1f4KObntjYA==} + '@cosmjs/amino@0.32.4': resolution: {integrity: sha512-zKYOt6hPy8obIFtLie/xtygCkH9ZROiQ12UHfKsOkWaZfPQUvVbtgmu6R4Kn1tFLI/SRkw7eqhaogmW/3NYu/Q==} @@ -3644,24 +3833,36 @@ packages: '@cosmjs/math@0.32.4': resolution: {integrity: sha512-++dqq2TJkoB8zsPVYCvrt88oJWsy1vMOuSOKcdlnXuOA/ASheTJuYy4+oZlTQ3Fr8eALDLGGPhJI02W2HyAQaw==} + '@cosmjs/proto-signing@0.32.2': + resolution: {integrity: sha512-UV4WwkE3W3G3s7wwU9rizNcUEz2g0W8jQZS5J6/3fiN0mRPwtPKQ6EinPN9ASqcAJ7/VQH4/9EPOw7d6XQGnqw==} + '@cosmjs/proto-signing@0.32.4': resolution: {integrity: sha512-QdyQDbezvdRI4xxSlyM1rSVBO2st5sqtbEIl3IX03uJ7YiZIQHyv6vaHVf1V4mapusCqguiHJzm4N4gsFdLBbQ==} '@cosmjs/socket@0.32.4': resolution: {integrity: sha512-davcyYziBhkzfXQTu1l5NrpDYv0K9GekZCC9apBRvL1dvMc9F/ygM7iemHjUA+z8tJkxKxrt/YPjJ6XNHzLrkw==} + '@cosmjs/stargate@0.32.2': + resolution: {integrity: sha512-AsJa29fT7Jd4xt9Ai+HMqhyj7UQu7fyYKdXj/8+/9PD74xe6lZSYhQPcitUmMLJ1ckKPgXSk5Dd2LbsQT0IhZg==} + '@cosmjs/stargate@0.32.4': resolution: {integrity: sha512-usj08LxBSsPRq9sbpCeVdyLx2guEcOHfJS9mHGCLCXpdAPEIEQEtWLDpEUc0LEhWOx6+k/ChXTc5NpFkdrtGUQ==} '@cosmjs/stream@0.32.4': resolution: {integrity: sha512-Gih++NYHEiP+oyD4jNEUxU9antoC0pFSg+33Hpp0JlHwH0wXhtD3OOKnzSfDB7OIoEbrzLJUpEjOgpCp5Z+W3A==} + '@cosmjs/tendermint-rpc@0.32.2': + resolution: {integrity: sha512-DXyJHDmcAfCix4H/7/dKR0UMdshP01KxJOXHdHxBCbLIpck94BsWD3B2ZTXwfA6sv98so9wOzhp7qGQa5malxg==} + '@cosmjs/tendermint-rpc@0.32.4': resolution: {integrity: sha512-MWvUUno+4bCb/LmlMIErLypXxy7ckUuzEmpufYYYd9wgbdCXaTaO08SZzyFM5PI8UJ/0S2AmUrgWhldlbxO8mw==} '@cosmjs/utils@0.32.4': resolution: {integrity: sha512-D1Yc+Zy8oL/hkUkFUL/bwxvuDBzRGpc4cF7/SkdhxX4iHpSLgdOuTt1mhCh9+kl6NQREy9t7SYZ6xeW5gFe60w==} + '@cosmology/lcd@0.13.5': + resolution: {integrity: sha512-CI8KFsJcgp0RINF8wHpv3Y9yR4Fb9ZnGucyoUICjtX2XT4NVBK+fvZuRFj5TP34km8TpEOb+WV2T7IN/pZsD7Q==} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -4270,6 +4471,60 @@ packages: '@emnapi/wasi-threads@1.0.1': resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==} + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/is-prop-valid@1.3.1': + resolution: {integrity: sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==} + + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + peerDependencies: + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + + '@emotion/styled@11.14.0': + resolution: {integrity: sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==} + peerDependencies: + '@emotion/react': ^11.0.0-rc.0 + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + peerDependencies: + react: '>=16.8.0' + + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + '@es-joy/jsdoccomment@0.41.0': resolution: {integrity: sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==} engines: {node: '>=16'} @@ -5174,6 +5429,10 @@ packages: resolution: {integrity: sha512-pJSUG3r5QIvCFNfkz7/y7kEqvEJaVAk0jZbZoKbcPCRUnXaUeAq7p8I0oklqetGyxbUcZ2FOGpt+Y+4uIltVPg==} engines: {node: '>=18.0.0'} + '@google/model-viewer@2.1.1': + resolution: {integrity: sha512-5umyLoD5vMxlSVQwtmUXeNCNWs9dzmWykGm1qrHe/pCYrj/1lyJIgJRw+IxoMNodGqtcHEtfDhdNjRDM9yo/TA==} + engines: {node: '>=6.0.0'} + '@gql.tada/cli-utils@1.6.3': resolution: {integrity: sha512-jFFSY8OxYeBxdKi58UzeMXG1tdm4FVjXa8WHIi66Gzu9JWtCE6mqom3a8xkmSw+mVaybFW5EN2WXf1WztJVNyQ==} peerDependencies: @@ -6722,6 +6981,9 @@ packages: resolution: {integrity: sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==} engines: {node: '>= 10.0.0'} + '@passwordless-id/webauthn@2.1.2': + resolution: {integrity: sha512-Ahj+A3O0gP3EsLV4FRXjfhbzzP895d8CnHKmhT1hkAz1zLSBCRE/iXJsasL1kwGoriDFLJ+YtO6x1rok4SZH2g==} + '@peculiar/asn1-schema@2.3.15': resolution: {integrity: sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==} @@ -6998,6 +7260,9 @@ packages: '@radix-ui/primitive@1.1.0': resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} + '@radix-ui/primitive@1.1.1': + resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} + '@radix-ui/react-arrow@1.1.0': resolution: {integrity: sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==} peerDependencies: @@ -7011,6 +7276,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-arrow@1.1.1': + resolution: {integrity: sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-compose-refs@1.1.0': resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} peerDependencies: @@ -7020,6 +7298,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-compose-refs@1.1.1': + resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-context@1.1.0': resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==} peerDependencies: @@ -7051,6 +7338,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-dialog@1.1.3': + resolution: {integrity: sha512-ujGvqQNkZ0J7caQyl8XuZRj2/TIrYcOGwqz5TeD1OMcCdfBuEMP0D12ve+8J5F9XuNUth3FAKFWo/wt0E/GJrQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-dismissable-layer@1.1.1': resolution: {integrity: sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==} peerDependencies: @@ -7064,6 +7364,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-dismissable-layer@1.1.2': + resolution: {integrity: sha512-kEHnlhv7wUggvhuJPkyw4qspXLJOdYoAP4dO2c8ngGuXTq1w/HZp1YeVB+NQ2KbH1iEG+pvOCGYSqh9HZOz6hg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-focus-guards@1.1.1': resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} peerDependencies: @@ -7086,6 +7399,24 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-focus-scope@1.1.1': + resolution: {integrity: sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-icons@1.3.2': + resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==} + peerDependencies: + react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc + '@radix-ui/react-id@1.1.0': resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} peerDependencies: @@ -7108,6 +7439,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-popper@1.2.1': + resolution: {integrity: sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-portal@1.1.2': resolution: {integrity: sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==} peerDependencies: @@ -7121,6 +7465,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-portal@1.1.3': + resolution: {integrity: sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-presence@1.1.1': resolution: {integrity: sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==} peerDependencies: @@ -7134,6 +7491,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-presence@1.1.2': + resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-primitive@2.0.0': resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==} peerDependencies: @@ -7147,6 +7517,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-primitive@2.0.1': + resolution: {integrity: sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-separator@1.1.0': resolution: {integrity: sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==} peerDependencies: @@ -7169,6 +7552,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-slot@1.1.1': + resolution: {integrity: sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-tooltip@1.1.4': resolution: {integrity: sha512-QpObUH/ZlpaO4YgHSaYzrLO2VuO+ZBFFgGzjMUPwtiYnAzzNNDPJeEGRrT7qNOrWm/Jr08M1vlp+vTHtnSQ0Uw==} peerDependencies: @@ -7182,6 +7574,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-tooltip@1.1.5': + resolution: {integrity: sha512-IucoQPcK5nwUuztaxBQvudvYwH58wtRcJlv1qvaMSyIbL9dEBfFN0vRf/D8xDbu6HmAJLlNGty4z8Na+vIqe9Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-use-callback-ref@1.1.0': resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} peerDependencies: @@ -7249,6 +7654,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-visually-hidden@1.1.1': + resolution: {integrity: sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/rect@1.1.0': resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} @@ -8159,6 +8577,9 @@ packages: '@solana/web3.js@1.98.0': resolution: {integrity: sha512-nz3Q5OeyGFpFCR+erX2f6JPt3sKhzhYcSycBCSPkWjzSVDh/Rr1FqTVMRe58FKO16/ivTUcuJjeS5MyBvpkbzA==} + '@spheron/protocol-sdk@1.2.3': + resolution: {integrity: sha512-aZ7A/D3MuhTHiV5nfavnxOkmO61APkVZiJoLm0+EgsS0z1fFMSO9O6QdW0VCA6T75ajyAagXPJgr8U/VVRVp3w==} + '@spruceid/siwe-parser@1.1.3': resolution: {integrity: sha512-oQ8PcwDqjGWJvLmvAF2yzd6iniiWxK0Qtz+Dw+gLD/W5zOQJiKIUXwslHOm8VB8OOOKW9vfR3dnPBhHaZDvRsw==} @@ -8435,11 +8856,19 @@ packages: '@tanstack/query-core@5.60.6': resolution: {integrity: sha512-tI+k0KyCo1EBJ54vxK1kY24LWj673ujTydCZmzEZKAew4NqZzTaVQJEuaG1qKj2M03kUHN46rchLRd+TxVq/zQ==} + '@tanstack/query-core@5.62.7': + resolution: {integrity: sha512-fgpfmwatsrUal6V+8EC2cxZIQVl9xvL7qYa03gsdsCy985UTUlS4N+/3hCzwR0PclYDqisca2AqR1BVgJGpUDA==} + '@tanstack/react-query@5.61.0': resolution: {integrity: sha512-SBzV27XAeCRBOQ8QcC94w2H1Md0+LI0gTWwc3qRJoaGuewKn5FNW4LSqwPFJZVEItfhMfGT7RpZuSFXjTi12pQ==} peerDependencies: react: ^18 || ^19 + '@tanstack/react-query@5.62.7': + resolution: {integrity: sha512-+xCtP4UAFDTlRTYyEjLx0sRtWyr5GIk7TZjZwBu4YaNahi3Rt2oMyRqfpfVrtwsqY2sayP4iXVCwmC+ZqqFmuw==} + peerDependencies: + react: ^18 || ^19 + '@tavily/core@0.0.2': resolution: {integrity: sha512-UabYbp57bdjEloA4efW9zTSzv+FZp13JVDHcfutUNR5XUZ+aDGupe2wpfABECnD+b7Ojp9v9zguZcm1o+h0//w==} @@ -8941,6 +9370,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/unzipper@0.10.10': + resolution: {integrity: sha512-jKJdNxhmCHTZsaKW5x0qjn6rB+gHk0w5VFbEKsw84i+RJqXZyfTmGnpjDcKqzMpjz7VVLsUBMtO5T3mVidpt0g==} + '@types/uuid@10.0.0': resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} @@ -9115,6 +9547,11 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 + '@vitest/coverage-v8@1.1.3': + resolution: {integrity: sha512-Uput7t3eIcbSTOTQBzGtS+0kah96bX+szW9qQrLeGe3UmgL2Akn8POnyC2lH7XsnREZOds9aCUTxgXf+4HX5RA==} + peerDependencies: + vitest: ^1.0.0 + '@vitest/coverage-v8@2.1.5': resolution: {integrity: sha512-/RoopB7XGW7UEkUndRXF87A9CwkoZAJW01pj8/3pgmDVsjMH2IKy6H1A38po9tmUlwhSyYs0az82rbKd9Yaynw==} peerDependencies: @@ -9139,6 +9576,9 @@ packages: vitest: optional: true + '@vitest/expect@1.1.3': + resolution: {integrity: sha512-MnJqsKc1Ko04lksF9XoRJza0bGGwTtqfbyrsYv5on4rcEkdo+QgUdITenBQBUltKzdxW7K3rWh+nXRULwsdaVg==} + '@vitest/expect@1.2.1': resolution: {integrity: sha512-/bqGXcHfyKgFWYwIgFr1QYDaR9e64pRKxgBNWNXPefPFRhgm+K3+a/dS0cUGEreWngets3dlr8w8SBRw2fCfFQ==} @@ -9148,6 +9588,9 @@ packages: '@vitest/expect@2.1.5': resolution: {integrity: sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==} + '@vitest/expect@2.1.8': + resolution: {integrity: sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==} + '@vitest/mocker@2.1.4': resolution: {integrity: sha512-Ky/O1Lc0QBbutJdW0rqLeFNbuLEyS+mIPiNdlVlp2/yhJ0SbyYqObS5IHdhferJud8MbbwMnexg4jordE5cCoQ==} peerDependencies: @@ -9170,6 +9613,17 @@ packages: vite: optional: true + '@vitest/mocker@2.1.8': + resolution: {integrity: sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/pretty-format@2.1.4': resolution: {integrity: sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==} @@ -9179,6 +9633,9 @@ packages: '@vitest/pretty-format@2.1.8': resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} + '@vitest/runner@1.1.3': + resolution: {integrity: sha512-Va2XbWMnhSdDEh/OFxyUltgQuuDRxnarK1hW5QNN4URpQrqq6jtt8cfww/pQQ4i0LjoYxh/3bYWvDFlR9tU73g==} + '@vitest/runner@1.2.1': resolution: {integrity: sha512-zc2dP5LQpzNzbpaBt7OeYAvmIsRS1KpZQw4G3WM/yqSV1cQKNKwLGmnm79GyZZjMhQGlRcSFMImLjZaUQvNVZQ==} @@ -9188,6 +9645,12 @@ packages: '@vitest/runner@2.1.5': resolution: {integrity: sha512-pKHKy3uaUdh7X6p1pxOkgkVAFW7r2I818vHDthYLvUyjRfkKOU6P45PztOch4DZarWQne+VOaIMwA/erSSpB9g==} + '@vitest/runner@2.1.8': + resolution: {integrity: sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==} + + '@vitest/snapshot@1.1.3': + resolution: {integrity: sha512-U0r8pRXsLAdxSVAyGNcqOU2H3Z4Y2dAAGGelL50O0QRMdi1WWeYHdrH/QWpN1e8juWfVKsb8B+pyJwTC+4Gy9w==} + '@vitest/snapshot@1.2.1': resolution: {integrity: sha512-Tmp/IcYEemKaqAYCS08sh0vORLJkMr0NRV76Gl8sHGxXT5151cITJCET20063wk0Yr/1koQ6dnmP6eEqezmd/Q==} @@ -9197,6 +9660,12 @@ packages: '@vitest/snapshot@2.1.5': resolution: {integrity: sha512-zmYw47mhfdfnYbuhkQvkkzYroXUumrwWDGlMjpdUr4jBd3HZiV2w7CQHj+z7AAS4VOtWxI4Zt4bWt4/sKcoIjg==} + '@vitest/snapshot@2.1.8': + resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} + + '@vitest/spy@1.1.3': + resolution: {integrity: sha512-Ec0qWyGS5LhATFQtldvChPTAHv08yHIOZfiNcjwRQbFPHpkih0md9KAbs7TfeIfL7OFKoe7B/6ukBTqByubXkQ==} + '@vitest/spy@1.2.1': resolution: {integrity: sha512-vG3a/b7INKH7L49Lbp0IWrG6sw9j4waWAucwnksPB1r1FTJgV7nkBByd9ufzu6VWya/QTvQW4V9FShZbZIB2UQ==} @@ -9206,6 +9675,12 @@ packages: '@vitest/spy@2.1.5': resolution: {integrity: sha512-aWZF3P0r3w6DiYTVskOYuhBc7EMc3jvn1TkBg8ttylFFRqNN2XGD7V5a4aQdk6QiUzZQ4klNBSpCLJgWNdIiNw==} + '@vitest/spy@2.1.8': + resolution: {integrity: sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==} + + '@vitest/utils@1.1.3': + resolution: {integrity: sha512-Dyt3UMcdElTll2H75vhxfpZu03uFpXRCHxWnzcrFjZxT1kTbq8ALUYIeBgGolo1gldVdI0YSlQRacsqxTwNqwg==} + '@vitest/utils@1.2.1': resolution: {integrity: sha512-bsH6WVZYe/J2v3+81M5LDU8kW76xWObKIURpPrOXm2pjBniBu2MERI/XP60GpS4PHU3jyK50LUutOwrx4CyHUg==} @@ -9215,6 +9690,9 @@ packages: '@vitest/utils@2.1.5': resolution: {integrity: sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg==} + '@vitest/utils@2.1.8': + resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} + '@vladfrangu/async_event_emitter@2.4.6': resolution: {integrity: sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} @@ -9947,6 +10425,10 @@ packages: resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + babel-plugin-polyfill-corejs2@0.4.12: resolution: {integrity: sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==} peerDependencies: @@ -10148,6 +10630,9 @@ packages: engines: {node: '>= 0.8.0'} hasBin: true + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + bn.js@4.11.6: resolution: {integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==} @@ -10979,6 +11464,9 @@ packages: convert-source-map@1.1.3: resolution: {integrity: sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==} + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -11047,6 +11535,10 @@ packages: resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==} engines: {node: '>=8'} + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + cosmiconfig@8.1.3: resolution: {integrity: sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==} engines: {node: '>=14'} @@ -12625,6 +13117,9 @@ packages: peerDependencies: webpack: ^4.0.0 || ^5.0.0 + file-type-checker@1.1.2: + resolution: {integrity: sha512-HodBNiinBQNHQfXhXzAuHkU2udHF3LFS6PAOEZqxW+BjotZVCaMR7ckpTTnvLi718dbzRavnjRX0kbSb5pJG3g==} + file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} @@ -12663,6 +13158,9 @@ packages: resolution: {integrity: sha512-x+1gcT3k+7ipx8chx1Z7cViSdeQ/RBwDk+6GiWnMTO0+YtGFrahToxarIZM6TzDZ9UFfYPUGpBf/85v5GpBXKA==} hasBin: true + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + find-up@2.1.0: resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} engines: {node: '>=4'} @@ -12877,6 +13375,10 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + fuse.js@7.0.0: + resolution: {integrity: sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==} + engines: {node: '>=10'} + gauge@3.0.2: resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} engines: {node: '>=10'} @@ -13655,6 +14157,12 @@ packages: inline-style-parser@0.2.4: resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} + input-otp@1.4.2: + resolution: {integrity: sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + inquirer@8.2.6: resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==} engines: {node: '>=12.0.0'} @@ -13666,6 +14174,9 @@ packages: int64-buffer@0.1.10: resolution: {integrity: sha512-v7cSY1J8ydZ0GyjUHqF+1bshJ6cnEVLo9EnjB8p+4HDRPZc9N5jjmvUV7NvEsqQOKyH0pmIBFWXVQbiS0+OBbA==} + interchain@1.10.4: + resolution: {integrity: sha512-tyJ3mfcuYqwLb3iZyuXDMOwMjWYptgiZrl6tu50pSSYoWrPN/9B6ztEC4IkYT1oKmWVOAiacNYuSRNmMUuWsmA==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -15495,6 +16006,14 @@ packages: resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} engines: {node: '>= 18'} + mipd@0.0.7: + resolution: {integrity: sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + mitt@3.0.0: resolution: {integrity: sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==} @@ -16157,6 +16676,14 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + ox@0.4.2: + resolution: {integrity: sha512-X3Ho21mTtJiCU2rWmfaheh2b0CG70Adre7Da/XQ0ECy+QppI6pLqdbGAJHiu/cTjumVXfwDGfv48APqePCU+ow==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + ox@0.4.4: resolution: {integrity: sha512-oJPEeCDs9iNiPs6J0rTx+Y0KGeCGyCAA3zo94yZhm8G5WpOxrwUtn2Ie/Y8IyARSqqY/j9JTKA3Fc1xs1DvFnw==} peerDependencies: @@ -18934,6 +19461,9 @@ packages: peerDependencies: postcss: ^8.4.31 + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + stylis@4.3.4: resolution: {integrity: sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==} @@ -19136,9 +19666,67 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + thirdweb@5.82.0: + resolution: {integrity: sha512-VB2+TK5BKTBZLkQkXHMS2JMA5RNDaZbjlSTOOYJxLNhcoJfXUloMufvrkeiKbZzrW0h87bdDMy79nLMODFHlDA==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@aws-sdk/client-kms': '*' + '@aws-sdk/client-lambda': ^3 + '@aws-sdk/credential-providers': ^3 + '@coinbase/wallet-mobile-sdk': ^1 + '@mobile-wallet-protocol/client': 0.1.1 + '@react-native-async-storage/async-storage': ^1 || ^2 + ethers: ^5 || ^6 + expo-linking: ^6 + expo-web-browser: ^13 || ^14 + react: ^18 || ^19 + react-native: '*' + react-native-aes-gcm-crypto: ^0.2 + react-native-passkey: ^3 + react-native-quick-crypto: '>=0.7.0-rc.6 || >=0.7' + react-native-svg: ^15 + typescript: '>=5.0.4' + peerDependenciesMeta: + '@aws-sdk/client-kms': + optional: true + '@aws-sdk/client-lambda': + optional: true + '@aws-sdk/credential-providers': + optional: true + '@coinbase/wallet-mobile-sdk': + optional: true + '@mobile-wallet-protocol/client': + optional: true + '@react-native-async-storage/async-storage': + optional: true + ethers: + optional: true + expo-linking: + optional: true + expo-web-browser: + optional: true + react: + optional: true + react-native: + optional: true + react-native-aes-gcm-crypto: + optional: true + react-native-passkey: + optional: true + react-native-quick-crypto: + optional: true + react-native-svg: + optional: true + typescript: + optional: true + thread-stream@0.15.2: resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==} + three@0.146.0: + resolution: {integrity: sha512-1lvNfLezN6OJ9NaFAhfX4sm5e9YCzHtaRgZ1+B4C+Hv6TibRMsuBAM5/wVKzxjpYIlMymvgsHEFrrigEfXnb2A==} + throttleit@2.1.0: resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} engines: {node: '>=18'} @@ -19657,6 +20245,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + u3@0.1.1: resolution: {integrity: sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w==} @@ -19926,6 +20519,9 @@ packages: resolution: {integrity: sha512-eL/8PlhLcMmlMDtNPKhyyz9kEBDS3Uk4yMu/ewlkT2WFbtzScjHWPJLdQLmaGPUKjXzwe9MumOtOgc4Fro96Kg==} hasBin: true + unzipper@0.12.3: + resolution: {integrity: sha512-PZ8hTS+AqcGxsaQntl3IRBw65QrBI6lxzqDEL7IAo/XCEqRTKGfOX56Vea5TH9SZczRVxuzk1re04z/YjuYCJA==} + upath@2.0.1: resolution: {integrity: sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==} engines: {node: '>=4'} @@ -19940,6 +20536,9 @@ packages: resolution: {integrity: sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==} engines: {node: '>=14.16'} + uqr@0.1.2: + resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -20131,6 +20730,11 @@ packages: typescript: optional: true + vite-node@1.1.3: + resolution: {integrity: sha512-BLSO72YAkIUuNrOx+8uznYICJfTEbvBAmWClY3hpath5+h1mbPS5OMn42lrTxXuyCazVyZoDkSRnju78GiVCqA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + vite-node@1.2.1: resolution: {integrity: sha512-fNzHmQUSOY+y30naohBvSW7pPn/xn3Ib/uqm+5wAJQJiqQsU0NBR78XdRJb04l4bOFKjpTWld0XAfkKlrDbySg==} engines: {node: ^18.0.0 || >=20.0.0} @@ -20146,6 +20750,11 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true + vite-node@2.1.8: + resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + vite-plugin-top-level-await@1.4.4: resolution: {integrity: sha512-QyxQbvcMkgt+kDb12m2P8Ed35Sp6nXP+l8ptGrnHV9zgYDUpraO0CPdlqLSeBqvY2DToR52nutDG7mIHuysdiw==} peerDependencies: @@ -20187,6 +20796,31 @@ packages: terser: optional: true + vitest@1.1.3: + resolution: {integrity: sha512-2l8om1NOkiA90/Y207PsEvJLYygddsOyr81wLQ20Ra8IlLKbyQncWsGZjnbkyG2KwwuTXLQjEPOJuxGMG8qJBQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': ^1.0.0 + '@vitest/ui': ^1.0.0 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vitest@1.2.1: resolution: {integrity: sha512-TRph8N8rnSDa5M2wKWJCMnztCZS9cDcgVTQ6tsTFTG/odHJ4l5yNVqvbeDJYJRZ6is3uxaEpFs8LL6QM+YFSdA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -20262,6 +20896,31 @@ packages: jsdom: optional: true + vitest@2.1.8: + resolution: {integrity: sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.8 + '@vitest/ui': 2.1.8 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vizion@2.2.1: resolution: {integrity: sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww==} engines: {node: '>=4.0'} @@ -20871,11 +21530,11 @@ snapshots: optionalDependencies: graphql: 16.10.0 - '@0no-co/graphqlsp@1.12.16(graphql@16.10.0)(typescript@5.6.3)': + '@0no-co/graphqlsp@1.12.16(graphql@16.10.0)(typescript@5.7.2)': dependencies: - '@gql.tada/internal': 1.0.8(graphql@16.10.0)(typescript@5.6.3) + '@gql.tada/internal': 1.0.8(graphql@16.10.0)(typescript@5.7.2) graphql: 16.10.0 - typescript: 5.6.3 + typescript: 5.7.2 '@acuminous/bitsyntax@0.1.2': dependencies: @@ -21264,6 +21923,11 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@alloralabs/allora-sdk@0.0.4': + dependencies: + '@types/node': 22.10.5 + typescript: 5.7.2 + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -21303,6 +21967,20 @@ snapshots: '@anush008/tokenizers-linux-x64-gnu': 0.0.0 '@anush008/tokenizers-win32-x64-msvc': 0.0.0 + '@anyone-protocol/anyone-client@0.4.3': + dependencies: + '@types/node': 20.17.9 + '@types/unzipper': 0.10.10 + axios: 1.7.9(debug@4.4.0) + chalk: 4.1.2 + net: 1.0.2 + socks-proxy-agent: 8.0.5 + typescript: 5.6.3 + unzipper: 0.12.3 + transitivePeerDependencies: + - debug + - supports-color + '@aptos-labs/aptos-cli@1.0.2': dependencies: commander: 12.1.0 @@ -22822,13 +23500,13 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@bigmi/core@0.0.4(bitcoinjs-lib@7.0.0-rc.0(typescript@5.6.3))(bs58@6.0.0)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1))': + '@bigmi/core@0.0.4(bitcoinjs-lib@7.0.0-rc.0(typescript@5.7.2))(bs58@6.0.0)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1))': dependencies: '@noble/hashes': 1.7.0 bech32: 2.0.0 - bitcoinjs-lib: 7.0.0-rc.0(typescript@5.6.3) + bitcoinjs-lib: 7.0.0-rc.0(typescript@5.7.2) bs58: 6.0.0 - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) '@binance/connector@3.6.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: @@ -22846,12 +23524,12 @@ snapshots: bs58: 5.0.0 buffer: 6.0.3 - '@bonfida/spl-name-service@3.0.7(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@bonfida/spl-name-service@3.0.7(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@bonfida/sns-records': 0.0.1(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@noble/curves': 1.8.0 '@scure/base': 1.2.1 - '@solana/spl-token': 0.4.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.4.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) borsh: 2.0.0 buffer: 6.0.3 @@ -22894,12 +23572,12 @@ snapshots: '@chevrotain/utils@11.0.3': {} - '@cks-systems/manifest-sdk@0.1.59(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(jiti@2.4.2)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@cks-systems/manifest-sdk@0.1.59(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(jiti@2.4.2)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@metaplex-foundation/beet': 0.7.2 '@metaplex-foundation/rustbin': 0.3.5 '@metaplex-foundation/solita': 0.12.2(bufferutil@4.0.9)(encoding@0.1.13)(jiti@2.4.2)(utf-8-validate@5.0.10) - '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) bn.js: 5.2.1 borsh: 0.7.0 @@ -22911,7 +23589,7 @@ snapshots: percentile: 1.6.0 prom-client: 15.1.3 rimraf: 5.0.10 - typedoc: 0.26.11(typescript@5.6.3) + typedoc: 0.26.11(typescript@5.7.2) ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) zstddec: 0.0.2 transitivePeerDependencies: @@ -22976,6 +23654,13 @@ snapshots: - utf-8-validate - zod + '@coinbase/wallet-sdk@4.2.4': + dependencies: + '@noble/hashes': 1.7.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + preact: 10.25.4 + '@colors/colors@1.5.0': optional: true @@ -23216,6 +23901,13 @@ snapshots: bn.js: 5.2.1 buffer-layout: 1.2.2 + '@cosmjs/amino@0.32.2': + dependencies: + '@cosmjs/crypto': 0.32.4 + '@cosmjs/encoding': 0.32.4 + '@cosmjs/math': 0.32.4 + '@cosmjs/utils': 0.32.4 + '@cosmjs/amino@0.32.4': dependencies: '@cosmjs/crypto': 0.32.4 @@ -23265,6 +23957,15 @@ snapshots: dependencies: bn.js: 5.2.1 + '@cosmjs/proto-signing@0.32.2': + dependencies: + '@cosmjs/amino': 0.32.4 + '@cosmjs/crypto': 0.32.4 + '@cosmjs/encoding': 0.32.4 + '@cosmjs/math': 0.32.4 + '@cosmjs/utils': 0.32.4 + cosmjs-types: 0.9.0 + '@cosmjs/proto-signing@0.32.4': dependencies: '@cosmjs/amino': 0.32.4 @@ -23284,6 +23985,23 @@ snapshots: - bufferutil - utf-8-validate + '@cosmjs/stargate@0.32.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@confio/ics23': 0.6.8 + '@cosmjs/amino': 0.32.4 + '@cosmjs/encoding': 0.32.4 + '@cosmjs/math': 0.32.4 + '@cosmjs/proto-signing': 0.32.4 + '@cosmjs/stream': 0.32.4 + '@cosmjs/tendermint-rpc': 0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmjs/utils': 0.32.4 + cosmjs-types: 0.9.0 + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + '@cosmjs/stargate@0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@confio/ics23': 0.6.8 @@ -23305,6 +24023,23 @@ snapshots: dependencies: xstream: 11.14.0 + '@cosmjs/tendermint-rpc@0.32.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@cosmjs/crypto': 0.32.4 + '@cosmjs/encoding': 0.32.4 + '@cosmjs/json-rpc': 0.32.4 + '@cosmjs/math': 0.32.4 + '@cosmjs/socket': 0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmjs/stream': 0.32.4 + '@cosmjs/utils': 0.32.4 + axios: 1.7.9(debug@4.4.0) + readonly-date: 1.0.0 + xstream: 11.14.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + '@cosmjs/tendermint-rpc@0.32.4(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@cosmjs/crypto': 0.32.4 @@ -23324,6 +24059,12 @@ snapshots: '@cosmjs/utils@0.32.4': {} + '@cosmology/lcd@0.13.5': + dependencies: + axios: 1.7.4 + transitivePeerDependencies: + - debug + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -23739,7 +24480,7 @@ snapshots: transitivePeerDependencies: - '@algolia/client-search' - '@docusaurus/babel@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/babel@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)': dependencies: '@babel/core': 7.26.0 '@babel/generator': 7.26.3 @@ -23752,7 +24493,7 @@ snapshots: '@babel/runtime-corejs3': 7.26.0 '@babel/traverse': 7.26.4 '@docusaurus/logger': 3.6.3 - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) babel-plugin-dynamic-import-node: 2.3.3 fs-extra: 11.2.0 tslib: 2.8.1 @@ -23767,14 +24508,14 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/bundler@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/bundler@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)': dependencies: '@babel/core': 7.26.0 - '@docusaurus/babel': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/babel': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/cssnano-preset': 3.6.3 '@docusaurus/logger': 3.6.3 '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) babel-loader: 9.2.1(@babel/core@7.26.0)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) clean-css: 5.3.3 copy-webpack-plugin: 11.0.0(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) @@ -23786,9 +24527,9 @@ snapshots: mini-css-extract-plugin: 2.9.2(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) null-loader: 4.0.1(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) postcss: 8.4.49 - postcss-loader: 7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) + postcss-loader: 7.3.4(postcss@8.4.49)(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) postcss-preset-env: 10.1.3(postcss@8.4.49) - react-dev-utils: 12.0.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) + react-dev-utils: 12.0.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) terser-webpack-plugin: 5.3.11(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) tslib: 2.8.1 url-loader: 4.1.1(file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))))(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) @@ -23812,15 +24553,15 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/babel': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/bundler': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/babel': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) + '@docusaurus/bundler': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/logger': 3.6.3 - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@mdx-js/react': 3.0.1(@types/react@18.3.12)(react@18.3.1) boxen: 6.2.1 chalk: 4.1.2 @@ -23842,7 +24583,7 @@ snapshots: p-map: 4.0.0 prompts: 2.4.2 react: 18.3.1 - react-dev-utils: 12.0.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) + react-dev-utils: 12.0.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) react-dom: 18.3.1(react@18.3.1) react-helmet-async: 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-loadable: '@docusaurus/react-loadable@6.0.0(react@18.3.1)' @@ -23902,11 +24643,11 @@ snapshots: transitivePeerDependencies: - webpack - '@docusaurus/mdx-loader@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/mdx-loader@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)': dependencies: '@docusaurus/logger': 3.6.3 - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@mdx-js/mdx': 3.1.0(acorn@8.14.0) '@slorber/remark-comment': 1.0.0 escape-html: 1.0.3 @@ -23958,17 +24699,17 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/plugin-content-blog@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-content-blog@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/logger': 3.6.3 - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) + '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) cheerio: 1.0.0-rc.12 feed: 4.2.2 fs-extra: 11.2.0 @@ -24002,17 +24743,17 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/logger': 3.6.3 - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@types/react-router-config': 5.0.11 combine-promises: 1.2.0 fs-extra: 11.2.0 @@ -24044,13 +24785,13 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-pages@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-content-pages@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -24077,11 +24818,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-debug@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-debug@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -24108,11 +24849,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-analytics@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-google-analytics@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) tslib: 2.8.1 @@ -24137,11 +24878,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-gtag@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-google-gtag@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@types/gtag.js': 0.0.12 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -24167,11 +24908,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-tag-manager@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-google-tag-manager@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) tslib: 2.8.1 @@ -24196,14 +24937,14 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-ideal-image@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-ideal-image@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/lqip-loader': 3.6.3(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) '@docusaurus/responsive-loader': 1.7.0(sharp@0.32.6) '@docusaurus/theme-translations': 3.6.3 '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@slorber/react-ideal-image': 0.0.12(prop-types@15.8.1)(react-waypoint@10.3.0(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -24233,14 +24974,14 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-sitemap@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-sitemap@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/logger': 3.6.3 '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -24267,20 +25008,20 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/preset-classic@3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10)': - dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-content-blog': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-content-pages': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-debug': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-google-analytics': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-google-gtag': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-google-tag-manager': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-sitemap': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/theme-classic': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/theme-search-algolia': 3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/preset-classic@3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.7.2)(utf-8-validate@5.0.10)': + dependencies: + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/plugin-content-blog': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/plugin-content-pages': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/plugin-debug': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/plugin-google-analytics': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/plugin-google-gtag': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/plugin-google-tag-manager': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/plugin-sitemap': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/theme-classic': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) + '@docusaurus/theme-search-algolia': 3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -24319,21 +25060,21 @@ snapshots: optionalDependencies: sharp: 0.32.6 - '@docusaurus/theme-classic@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/theme-classic@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/logger': 3.6.3 - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/plugin-content-blog': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-content-pages': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-content-blog': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/plugin-content-pages': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/theme-translations': 3.6.3 '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@mdx-js/react': 3.0.1(@types/react@18.3.12)(react@18.3.1) clsx: 2.1.1 copy-text-to-clipboard: 3.2.0 @@ -24370,12 +25111,12 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/theme-common@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/theme-common@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)': dependencies: - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/history': 4.7.11 '@types/react': 18.3.12 @@ -24396,13 +25137,13 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/theme-mermaid@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/theme-mermaid@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) mermaid: 11.4.1 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -24429,16 +25170,16 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/theme-search-algolia@3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/theme-search-algolia@3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@docsearch/react': 3.8.2(@algolia/client-search@5.18.0)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3) - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) '@docusaurus/logger': 3.6.3 - '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/theme-translations': 3.6.3 - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) algoliasearch: 4.24.0 algoliasearch-helper: 3.22.6(algoliasearch@4.24.0) clsx: 2.1.1 @@ -24513,10 +25254,10 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils-validation@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/utils-validation@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)': dependencies: '@docusaurus/logger': 3.6.3 - '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2) '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) fs-extra: 11.2.0 joi: 17.13.3 @@ -24534,12 +25275,12 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/utils@3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)': dependencies: '@docusaurus/logger': 3.6.3 '@docusaurus/types': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@svgr/webpack': 8.1.0(typescript@5.6.3) + '@svgr/webpack': 8.1.0(typescript@5.7.2) escape-string-regexp: 4.0.0 file-loader: 6.2.0(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) fs-extra: 11.2.0 @@ -24614,6 +25355,89 @@ snapshots: dependencies: tslib: 2.8.1 + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.25.9 + '@babel/runtime': 7.26.0 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/hash@0.9.2': {} + + '@emotion/is-prop-valid@1.3.1': + dependencies: + '@emotion/memoize': 0.9.0 + + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.0 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + transitivePeerDependencies: + - supports-color + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.1.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.0 + '@emotion/babel-plugin': 11.13.5 + '@emotion/is-prop-valid': 1.3.1 + '@emotion/react': 11.14.0(@types/react@18.3.12)(react@18.3.1) + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) + '@emotion/utils': 1.4.2 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + transitivePeerDependencies: + - supports-color + + '@emotion/unitless@0.10.0': {} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + '@es-joy/jsdoccomment@0.41.0': dependencies: comment-parser: 1.4.1 @@ -25509,43 +26333,43 @@ snapshots: reflect-metadata: 0.2.2 zod: 3.23.8 - '@goat-sdk/plugin-erc20@0.2.2(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))': + '@goat-sdk/plugin-erc20@0.2.2(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8))': dependencies: '@goat-sdk/core': 0.4.0 - '@goat-sdk/wallet-evm': 0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10) - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + '@goat-sdk/wallet-evm': 0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8) zod: 3.23.8 transitivePeerDependencies: - bufferutil - typescript - utf-8-validate - '@goat-sdk/plugin-kim@0.1.2(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))': + '@goat-sdk/plugin-kim@0.1.2(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8))': dependencies: '@goat-sdk/core': 0.4.0 - '@goat-sdk/wallet-evm': 0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10) - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + '@goat-sdk/wallet-evm': 0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8) zod: 3.23.8 transitivePeerDependencies: - bufferutil - typescript - utf-8-validate - '@goat-sdk/wallet-evm@0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@goat-sdk/wallet-evm@0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@goat-sdk/core': 0.4.0 - abitype: 1.0.8(typescript@5.6.3)(zod@3.23.8) - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + abitype: 1.0.8(typescript@5.7.2)(zod@3.23.8) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8) zod: 3.23.8 transitivePeerDependencies: - bufferutil - typescript - utf-8-validate - '@goat-sdk/wallet-viem@0.2.0(@goat-sdk/wallet-evm@0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10))(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))': + '@goat-sdk/wallet-viem@0.2.0(@goat-sdk/wallet-evm@0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10))(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8))': dependencies: - '@goat-sdk/wallet-evm': 0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10) - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + '@goat-sdk/wallet-evm': 0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8) '@google-cloud/vertexai@1.9.2(encoding@0.1.13)': dependencies: @@ -25554,18 +26378,23 @@ snapshots: - encoding - supports-color - '@gql.tada/cli-utils@1.6.3(@0no-co/graphqlsp@1.12.16(graphql@16.10.0)(typescript@5.6.3))(graphql@16.10.0)(typescript@5.6.3)': + '@google/model-viewer@2.1.1': dependencies: - '@0no-co/graphqlsp': 1.12.16(graphql@16.10.0)(typescript@5.6.3) - '@gql.tada/internal': 1.0.8(graphql@16.10.0)(typescript@5.6.3) + lit: 2.8.0 + three: 0.146.0 + + '@gql.tada/cli-utils@1.6.3(@0no-co/graphqlsp@1.12.16(graphql@16.10.0)(typescript@5.7.2))(graphql@16.10.0)(typescript@5.7.2)': + dependencies: + '@0no-co/graphqlsp': 1.12.16(graphql@16.10.0)(typescript@5.7.2) + '@gql.tada/internal': 1.0.8(graphql@16.10.0)(typescript@5.7.2) graphql: 16.10.0 - typescript: 5.6.3 + typescript: 5.7.2 - '@gql.tada/internal@1.0.8(graphql@16.10.0)(typescript@5.6.3)': + '@gql.tada/internal@1.0.8(graphql@16.10.0)(typescript@5.7.2)': dependencies: '@0no-co/graphql.web': 1.0.13(graphql@16.10.0) graphql: 16.10.0 - typescript: 5.6.3 + typescript: 5.7.2 '@graphql-typed-document-node/core@3.2.0(graphql@16.10.0)': dependencies: @@ -25746,7 +26575,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3))': + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -25760,7 +26589,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -25781,7 +26610,7 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3))': + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -25795,7 +26624,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -25816,7 +26645,7 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3))': + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -25830,7 +26659,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -26261,7 +27090,7 @@ snapshots: tslib: 2.8.1 zod: 3.23.8 - '@lerna/create@8.1.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(encoding@0.1.13)(typescript@5.6.3)': + '@lerna/create@8.1.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13)(typescript@5.6.3)': dependencies: '@npmcli/arborist': 7.5.3 '@npmcli/package-json': 5.2.0 @@ -26280,7 +27109,7 @@ snapshots: conventional-changelog-core: 5.0.1 conventional-recommended-bump: 7.0.1 cosmiconfig: 8.3.6(typescript@5.6.3) - dedent: 1.5.3 + dedent: 1.5.3(babel-plugin-macros@3.1.0) execa: 5.0.0 fs-extra: 11.2.0 get-stream: 6.0.0 @@ -26346,28 +27175,28 @@ snapshots: dependencies: '@lifi/types': 16.3.0 - '@lifi/sdk@3.4.1(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(typescript@5.6.3)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1))': + '@lifi/sdk@3.4.1(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(typescript@5.7.2)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1))': dependencies: - '@bigmi/core': 0.0.4(bitcoinjs-lib@7.0.0-rc.0(typescript@5.6.3))(bs58@6.0.0)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1)) + '@bigmi/core': 0.0.4(bitcoinjs-lib@7.0.0-rc.0(typescript@5.7.2))(bs58@6.0.0)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1)) '@lifi/types': 16.3.0 '@noble/curves': 1.8.0 '@noble/hashes': 1.7.0 '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) bech32: 2.0.0 - bitcoinjs-lib: 7.0.0-rc.0(typescript@5.6.3) + bitcoinjs-lib: 7.0.0-rc.0(typescript@5.7.2) bs58: 6.0.0 - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) transitivePeerDependencies: - typescript '@lifi/types@16.3.0': {} - '@lightprotocol/compressed-token@0.17.1(@lightprotocol/stateless.js@0.17.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@lightprotocol/compressed-token@0.17.1(@lightprotocol/stateless.js@0.17.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@lightprotocol/stateless.js': 0.17.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@solana/spl-token': 0.4.8(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.4.8(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) buffer: 6.0.3 tweetnacl: 1.0.3 @@ -26412,7 +27241,7 @@ snapshots: '@lit-protocol/misc-browser': 2.1.62(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@lit-protocol/types': 2.1.62 '@lit-protocol/uint8arrays': 2.1.62 - '@walletconnect/ethereum-provider': 2.17.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@walletconnect/ethereum-provider': 2.17.3(@types/react@18.3.12)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.4.2)(react@18.3.1)(utf-8-validate@5.0.10) ethers: 5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) lit-connect-modal: 0.1.11 lit-siwe: 1.1.8(@ethersproject/contracts@5.7.0)(@ethersproject/hash@5.7.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@ethersproject/wallet@5.7.0) @@ -26528,7 +27357,7 @@ snapshots: '@lit-protocol/nacl': 2.1.62 '@lit-protocol/types': 2.1.62 '@lit-protocol/uint8arrays': 2.1.62 - '@walletconnect/ethereum-provider': 2.17.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@walletconnect/ethereum-provider': 2.17.3(@types/react@18.3.12)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.4.2)(react@18.3.1)(utf-8-validate@5.0.10) ethers: 5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) jszip: 3.10.1 lit-connect-modal: 0.1.11 @@ -26711,12 +27540,12 @@ snapshots: '@metaplex-foundation/cusper@0.0.2': {} - '@metaplex-foundation/mpl-auction-house@2.5.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@metaplex-foundation/mpl-auction-house@2.5.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@metaplex-foundation/beet': 0.6.1 '@metaplex-foundation/beet-solana': 0.3.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@metaplex-foundation/cusper': 0.0.2 - '@solana/spl-token': 0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) bn.js: 5.2.1 transitivePeerDependencies: @@ -26727,12 +27556,12 @@ snapshots: - typescript - utf-8-validate - '@metaplex-foundation/mpl-bubblegum@0.7.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@metaplex-foundation/mpl-bubblegum@0.7.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@metaplex-foundation/beet': 0.7.1 '@metaplex-foundation/beet-solana': 0.4.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@metaplex-foundation/cusper': 0.0.2 - '@metaplex-foundation/mpl-token-metadata': 2.13.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@metaplex-foundation/mpl-token-metadata': 2.13.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/spl-account-compression': 0.1.10(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@solana/spl-token': 0.1.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -26751,12 +27580,12 @@ snapshots: '@msgpack/msgpack': 3.0.0-beta2 '@noble/hashes': 1.7.0 - '@metaplex-foundation/mpl-token-metadata@2.13.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@metaplex-foundation/mpl-token-metadata@2.13.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@metaplex-foundation/beet': 0.7.1 '@metaplex-foundation/beet-solana': 0.4.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@metaplex-foundation/cusper': 0.0.2 - '@solana/spl-token': 0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) bn.js: 5.2.1 debug: 4.4.0(supports-color@8.1.1) @@ -27024,7 +27853,7 @@ snapshots: dependencies: bs58: 6.0.0 - '@mysten/sui@1.18.0(typescript@5.6.3)': + '@mysten/sui@1.18.0(typescript@5.7.2)': dependencies: '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) '@mysten/bcs': 1.2.0 @@ -27035,7 +27864,7 @@ snapshots: '@simplewebauthn/typescript-types': 7.4.0 '@suchipi/femver': 1.0.0 bech32: 2.0.0 - gql.tada: 1.8.10(graphql@16.10.0)(typescript@5.6.3) + gql.tada: 1.8.10(graphql@16.10.0)(typescript@5.7.2) graphql: 16.10.0 jose: 5.9.6 poseidon-lite: 0.2.1 @@ -27179,11 +28008,11 @@ snapshots: transitivePeerDependencies: - encoding - '@neynar/nodejs-sdk@2.7.1(bufferutil@4.0.9)(class-transformer@0.5.1)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1)': + '@neynar/nodejs-sdk@2.7.1(bufferutil@4.0.9)(class-transformer@0.5.1)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1)': dependencies: '@openapitools/openapi-generator-cli': 2.15.3(class-transformer@0.5.1)(encoding@0.1.13) semver: 7.6.3 - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) transitivePeerDependencies: - '@nestjs/microservices' - '@nestjs/platform-express' @@ -28138,18 +28967,18 @@ snapshots: '@opentelemetry/api@1.9.0': {} - '@orca-so/common-sdk@0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3)': + '@orca-so/common-sdk@0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3)': dependencies: - '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) decimal.js: 10.4.3 tiny-invariant: 1.3.3 - '@orca-so/whirlpools-sdk@0.13.13(@coral-xyz/anchor@0.29.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(@orca-so/common-sdk@0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3))(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3)': + '@orca-so/whirlpools-sdk@0.13.13(@coral-xyz/anchor@0.29.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(@orca-so/common-sdk@0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3))(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3)': dependencies: '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@orca-so/common-sdk': 0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3) - '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@orca-so/common-sdk': 0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3) + '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) decimal.js: 10.4.3 tiny-invariant: 1.3.3 @@ -28214,6 +29043,8 @@ snapshots: '@parcel/watcher-win32-ia32': 2.5.0 '@parcel/watcher-win32-x64': 2.5.0 + '@passwordless-id/webauthn@2.1.2': {} + '@peculiar/asn1-schema@2.3.15': dependencies: asn1js: 3.0.5 @@ -28232,9 +29063,9 @@ snapshots: tslib: 2.8.1 webcrypto-core: 1.8.1 - '@phala/dstack-sdk@0.1.7(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1)': + '@phala/dstack-sdk@0.1.7(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1)': optionalDependencies: - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) transitivePeerDependencies: - bufferutil - typescript @@ -28653,7 +29484,7 @@ snapshots: '@protobufjs/utf8@1.1.0': {} - '@puppeteer/browsers@0.5.0(typescript@5.6.3)': + '@puppeteer/browsers@0.5.0(typescript@5.7.2)': dependencies: debug: 4.3.4 extract-zip: 2.0.1 @@ -28664,7 +29495,7 @@ snapshots: unbzip2-stream: 1.4.3 yargs: 17.7.1 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -28707,6 +29538,8 @@ snapshots: '@radix-ui/primitive@1.1.0': {} + '@radix-ui/primitive@1.1.1': {} + '@radix-ui/react-arrow@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -28716,12 +29549,27 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 + '@radix-ui/react-arrow@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.12)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: '@types/react': 18.3.12 + '@radix-ui/react-compose-refs@1.1.1(@types/react@18.3.12)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + '@radix-ui/react-context@1.1.0(@types/react@18.3.12)(react@18.3.1)': dependencies: react: 18.3.1 @@ -28756,6 +29604,28 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 + '@radix-ui/react-dialog@1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.12)(react@18.3.1) + aria-hidden: 1.2.4 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.6.0(@types/react@18.3.12)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@radix-ui/react-dismissable-layer@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -28769,6 +29639,19 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 + '@radix-ui/react-dismissable-layer@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@radix-ui/react-focus-guards@1.1.1(@types/react@18.3.12)(react@18.3.1)': dependencies: react: 18.3.1 @@ -28786,6 +29669,21 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 + '@radix-ui/react-focus-scope@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-icons@1.3.2(react@18.3.1)': + dependencies: + react: 18.3.1 + '@radix-ui/react-id@1.1.0(@types/react@18.3.12)(react@18.3.1)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1) @@ -28811,6 +29709,24 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 + '@radix-ui/react-popper@1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-arrow': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-rect': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/rect': 1.1.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@radix-ui/react-portal@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -28821,6 +29737,16 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 + '@radix-ui/react-portal@1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@radix-ui/react-presence@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1) @@ -28831,6 +29757,16 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 + '@radix-ui/react-presence@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-slot': 1.1.0(@types/react@18.3.12)(react@18.3.1) @@ -28840,6 +29776,15 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 + '@radix-ui/react-primitive@2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@radix-ui/react-separator@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -28856,6 +29801,13 @@ snapshots: optionalDependencies: '@types/react': 18.3.12 + '@radix-ui/react-slot@1.1.1(@types/react@18.3.12)(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + '@radix-ui/react-tooltip@1.1.4(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -28876,6 +29828,26 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 + '@radix-ui/react-tooltip@1.1.5(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.12)(react@18.3.1)': dependencies: react: 18.3.1 @@ -28925,12 +29897,21 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 + '@radix-ui/react-visually-hidden@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@radix-ui/rect@1.1.0': {} - '@raydium-io/raydium-sdk-v2@0.1.82-alpha(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@raydium-io/raydium-sdk-v2@0.1.82-alpha(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 - '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) axios: 1.7.9(debug@4.4.0) big.js: 6.2.2 @@ -28948,10 +29929,10 @@ snapshots: - typescript - utf-8-validate - '@raydium-io/raydium-sdk-v2@0.1.95-alpha(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@raydium-io/raydium-sdk-v2@0.1.95-alpha(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 - '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) axios: 1.7.9(debug@4.4.0) big.js: 6.2.2 @@ -29862,10 +30843,10 @@ snapshots: '@smithy/types': 4.0.0 tslib: 2.8.1 - '@solana-developers/helpers@2.5.6(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@solana-developers/helpers@2.5.6(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) bs58: 6.0.0 dotenv: 16.4.7 @@ -29895,20 +30876,20 @@ snapshots: dependencies: '@solana/errors': 2.0.0-preview.2 - '@solana/codecs-core@2.0.0-preview.4(typescript@5.6.3)': + '@solana/codecs-core@2.0.0-preview.4(typescript@5.7.2)': dependencies: - '@solana/errors': 2.0.0-preview.4(typescript@5.6.3) - typescript: 5.6.3 + '@solana/errors': 2.0.0-preview.4(typescript@5.7.2) + typescript: 5.7.2 '@solana/codecs-core@2.0.0-rc.1(typescript@4.9.5)': dependencies: '@solana/errors': 2.0.0-rc.1(typescript@4.9.5) typescript: 4.9.5 - '@solana/codecs-core@2.0.0-rc.1(typescript@5.6.3)': + '@solana/codecs-core@2.0.0-rc.1(typescript@5.7.2)': dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.6.3) - typescript: 5.6.3 + '@solana/errors': 2.0.0-rc.1(typescript@5.7.2) + typescript: 5.7.2 '@solana/codecs-data-structures@2.0.0-preview.2': dependencies: @@ -29916,12 +30897,12 @@ snapshots: '@solana/codecs-numbers': 2.0.0-preview.2 '@solana/errors': 2.0.0-preview.2 - '@solana/codecs-data-structures@2.0.0-preview.4(typescript@5.6.3)': + '@solana/codecs-data-structures@2.0.0-preview.4(typescript@5.7.2)': dependencies: - '@solana/codecs-core': 2.0.0-preview.4(typescript@5.6.3) - '@solana/codecs-numbers': 2.0.0-preview.4(typescript@5.6.3) - '@solana/errors': 2.0.0-preview.4(typescript@5.6.3) - typescript: 5.6.3 + '@solana/codecs-core': 2.0.0-preview.4(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-preview.4(typescript@5.7.2) + '@solana/errors': 2.0.0-preview.4(typescript@5.7.2) + typescript: 5.7.2 '@solana/codecs-data-structures@2.0.0-rc.1(typescript@4.9.5)': dependencies: @@ -29930,23 +30911,23 @@ snapshots: '@solana/errors': 2.0.0-rc.1(typescript@4.9.5) typescript: 4.9.5 - '@solana/codecs-data-structures@2.0.0-rc.1(typescript@5.6.3)': + '@solana/codecs-data-structures@2.0.0-rc.1(typescript@5.7.2)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.6.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.6.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.6.3) - typescript: 5.6.3 + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.7.2) + '@solana/errors': 2.0.0-rc.1(typescript@5.7.2) + typescript: 5.7.2 '@solana/codecs-numbers@2.0.0-preview.2': dependencies: '@solana/codecs-core': 2.0.0-preview.2 '@solana/errors': 2.0.0-preview.2 - '@solana/codecs-numbers@2.0.0-preview.4(typescript@5.6.3)': + '@solana/codecs-numbers@2.0.0-preview.4(typescript@5.7.2)': dependencies: - '@solana/codecs-core': 2.0.0-preview.4(typescript@5.6.3) - '@solana/errors': 2.0.0-preview.4(typescript@5.6.3) - typescript: 5.6.3 + '@solana/codecs-core': 2.0.0-preview.4(typescript@5.7.2) + '@solana/errors': 2.0.0-preview.4(typescript@5.7.2) + typescript: 5.7.2 '@solana/codecs-numbers@2.0.0-rc.1(typescript@4.9.5)': dependencies: @@ -29954,11 +30935,11 @@ snapshots: '@solana/errors': 2.0.0-rc.1(typescript@4.9.5) typescript: 4.9.5 - '@solana/codecs-numbers@2.0.0-rc.1(typescript@5.6.3)': + '@solana/codecs-numbers@2.0.0-rc.1(typescript@5.7.2)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.6.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.6.3) - typescript: 5.6.3 + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.7.2) + '@solana/errors': 2.0.0-rc.1(typescript@5.7.2) + typescript: 5.7.2 '@solana/codecs-strings@2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22)': dependencies: @@ -29967,13 +30948,13 @@ snapshots: '@solana/errors': 2.0.0-preview.2 fastestsmallesttextencoderdecoder: 1.0.22 - '@solana/codecs-strings@2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/codecs-strings@2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs-core': 2.0.0-preview.4(typescript@5.6.3) - '@solana/codecs-numbers': 2.0.0-preview.4(typescript@5.6.3) - '@solana/errors': 2.0.0-preview.4(typescript@5.6.3) + '@solana/codecs-core': 2.0.0-preview.4(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-preview.4(typescript@5.7.2) + '@solana/errors': 2.0.0-preview.4(typescript@5.7.2) fastestsmallesttextencoderdecoder: 1.0.22 - typescript: 5.6.3 + typescript: 5.7.2 '@solana/codecs-strings@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@4.9.5)': dependencies: @@ -29983,13 +30964,13 @@ snapshots: fastestsmallesttextencoderdecoder: 1.0.22 typescript: 4.9.5 - '@solana/codecs-strings@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/codecs-strings@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.6.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.6.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.6.3) + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.7.2) + '@solana/errors': 2.0.0-rc.1(typescript@5.7.2) fastestsmallesttextencoderdecoder: 1.0.22 - typescript: 5.6.3 + typescript: 5.7.2 '@solana/codecs@2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22)': dependencies: @@ -30001,14 +30982,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/codecs@2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/codecs@2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs-core': 2.0.0-preview.4(typescript@5.6.3) - '@solana/codecs-data-structures': 2.0.0-preview.4(typescript@5.6.3) - '@solana/codecs-numbers': 2.0.0-preview.4(typescript@5.6.3) - '@solana/codecs-strings': 2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) - '@solana/options': 2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) - typescript: 5.6.3 + '@solana/codecs-core': 2.0.0-preview.4(typescript@5.7.2) + '@solana/codecs-data-structures': 2.0.0-preview.4(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-preview.4(typescript@5.7.2) + '@solana/codecs-strings': 2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/options': 2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + typescript: 5.7.2 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -30023,14 +31004,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/codecs@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/codecs@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.6.3) - '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.6.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.6.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) - '@solana/options': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) - typescript: 5.6.3 + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/options': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + typescript: 5.7.2 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -30039,11 +31020,11 @@ snapshots: chalk: 5.4.1 commander: 12.1.0 - '@solana/errors@2.0.0-preview.4(typescript@5.6.3)': + '@solana/errors@2.0.0-preview.4(typescript@5.7.2)': dependencies: chalk: 5.4.1 commander: 12.1.0 - typescript: 5.6.3 + typescript: 5.7.2 '@solana/errors@2.0.0-rc.1(typescript@4.9.5)': dependencies: @@ -30051,25 +31032,25 @@ snapshots: commander: 12.1.0 typescript: 4.9.5 - '@solana/errors@2.0.0-rc.1(typescript@5.6.3)': + '@solana/errors@2.0.0-rc.1(typescript@5.7.2)': dependencies: chalk: 5.4.1 commander: 12.1.0 - typescript: 5.6.3 + typescript: 5.7.2 '@solana/options@2.0.0-preview.2': dependencies: '@solana/codecs-core': 2.0.0-preview.2 '@solana/codecs-numbers': 2.0.0-preview.2 - '@solana/options@2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/options@2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs-core': 2.0.0-preview.4(typescript@5.6.3) - '@solana/codecs-data-structures': 2.0.0-preview.4(typescript@5.6.3) - '@solana/codecs-numbers': 2.0.0-preview.4(typescript@5.6.3) - '@solana/codecs-strings': 2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) - '@solana/errors': 2.0.0-preview.4(typescript@5.6.3) - typescript: 5.6.3 + '@solana/codecs-core': 2.0.0-preview.4(typescript@5.7.2) + '@solana/codecs-data-structures': 2.0.0-preview.4(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-preview.4(typescript@5.7.2) + '@solana/codecs-strings': 2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/errors': 2.0.0-preview.4(typescript@5.7.2) + typescript: 5.7.2 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -30084,14 +31065,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/options@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/options@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.6.3) - '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.6.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.6.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.6.3) - typescript: 5.6.3 + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/errors': 2.0.0-rc.1(typescript@5.7.2) + typescript: 5.7.2 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -30126,34 +31107,34 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/spl-token-group@0.0.5(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/spl-token-group@0.0.5(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs': 2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/codecs': 2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/spl-type-length-value': 0.1.0 '@solana/web3.js': 1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: - fastestsmallesttextencoderdecoder - typescript - '@solana/spl-token-group@0.0.7(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/spl-token-group@0.0.7(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: - fastestsmallesttextencoderdecoder - typescript - '@solana/spl-token-group@0.0.7(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/spl-token-group@0.0.7(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: - fastestsmallesttextencoderdecoder - typescript - '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -30167,17 +31148,17 @@ snapshots: - fastestsmallesttextencoderdecoder - typescript - '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: - fastestsmallesttextencoderdecoder - typescript - '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -30210,11 +31191,11 @@ snapshots: - typescript - utf-8-validate - '@solana/spl-token@0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@solana/spl-token@0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) buffer: 6.0.3 transitivePeerDependencies: @@ -30224,12 +31205,12 @@ snapshots: - typescript - utf-8-validate - '@solana/spl-token@0.4.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@solana/spl-token@0.4.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@solana/spl-token-group': 0.0.4(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22) - '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) buffer: 6.0.3 transitivePeerDependencies: @@ -30239,12 +31220,12 @@ snapshots: - typescript - utf-8-validate - '@solana/spl-token@0.4.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@solana/spl-token@0.4.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@solana/spl-token-group': 0.0.4(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22) - '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) buffer: 6.0.3 transitivePeerDependencies: @@ -30254,12 +31235,12 @@ snapshots: - typescript - utf-8-validate - '@solana/spl-token@0.4.8(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@solana/spl-token@0.4.8(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@solana/spl-token-group': 0.0.5(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) - '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/spl-token-group': 0.0.5(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.95.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) buffer: 6.0.3 transitivePeerDependencies: @@ -30269,12 +31250,12 @@ snapshots: - typescript - utf-8-validate - '@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@solana/spl-token-group': 0.0.7(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) - '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/spl-token-group': 0.0.7(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) buffer: 6.0.3 transitivePeerDependencies: @@ -30284,12 +31265,12 @@ snapshots: - typescript - utf-8-validate - '@solana/spl-token@0.4.9(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@solana/spl-token@0.4.9(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@solana/spl-token-group': 0.0.7(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) - '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + '@solana/spl-token-group': 0.0.7(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) buffer: 6.0.3 transitivePeerDependencies: @@ -30320,7 +31301,7 @@ snapshots: dependencies: '@babel/runtime': 7.26.0 '@noble/curves': 1.8.0 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.7.0 '@solana/buffer-layout': 4.0.1 agentkeepalive: 4.6.0 bigint-buffer: 1.1.5 @@ -30404,6 +31385,15 @@ snapshots: - encoding - utf-8-validate + '@spheron/protocol-sdk@1.2.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + base64-js: 1.5.1 + ethers: 6.13.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) + js-yaml: 4.1.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@spruceid/siwe-parser@1.1.3': dependencies: apg-js: 4.4.0 @@ -30497,14 +31487,14 @@ snapshots: '@starknet-io/types-js@0.7.10': {} - '@story-protocol/core-sdk@1.2.0-rc.3(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1)': + '@story-protocol/core-sdk@1.2.0-rc.3(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1)': dependencies: - abitype: 0.10.3(typescript@5.6.3)(zod@3.24.1) + abitype: 0.10.3(typescript@5.7.2)(zod@3.24.1) axios: 1.7.9(debug@4.4.0) bs58: 6.0.0 dotenv: 16.4.7 multiformats: 9.9.0 - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) transitivePeerDependencies: - bufferutil - debug @@ -30631,12 +31621,12 @@ snapshots: '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.26.0) '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.26.0) - '@svgr/core@8.1.0(typescript@5.6.3)': + '@svgr/core@8.1.0(typescript@5.7.2)': dependencies: '@babel/core': 7.26.0 '@svgr/babel-preset': 8.1.0(@babel/core@7.26.0) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.6.3) + cosmiconfig: 8.3.6(typescript@5.7.2) snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -30647,35 +31637,35 @@ snapshots: '@babel/types': 7.26.3 entities: 4.5.0 - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.6.3))': + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.7.2))': dependencies: '@babel/core': 7.26.0 '@svgr/babel-preset': 8.1.0(@babel/core@7.26.0) - '@svgr/core': 8.1.0(typescript@5.6.3) + '@svgr/core': 8.1.0(typescript@5.7.2) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: - supports-color - '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.6.3))(typescript@5.6.3)': + '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.7.2))(typescript@5.7.2)': dependencies: - '@svgr/core': 8.1.0(typescript@5.6.3) - cosmiconfig: 8.3.6(typescript@5.6.3) + '@svgr/core': 8.1.0(typescript@5.7.2) + cosmiconfig: 8.3.6(typescript@5.7.2) deepmerge: 4.3.1 svgo: 3.3.2 transitivePeerDependencies: - typescript - '@svgr/webpack@8.1.0(typescript@5.6.3)': + '@svgr/webpack@8.1.0(typescript@5.7.2)': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-constant-elements': 7.25.9(@babel/core@7.26.0) '@babel/preset-env': 7.26.0(@babel/core@7.26.0) '@babel/preset-react': 7.26.3(@babel/core@7.26.0) '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) - '@svgr/core': 8.1.0(typescript@5.6.3) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.6.3)) - '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.6.3))(typescript@5.6.3) + '@svgr/core': 8.1.0(typescript@5.7.2) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.7.2)) + '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.7.2))(typescript@5.7.2) transitivePeerDependencies: - supports-color - typescript @@ -30747,11 +31737,18 @@ snapshots: '@tanstack/query-core@5.60.6': {} + '@tanstack/query-core@5.62.7': {} + '@tanstack/react-query@5.61.0(react@18.3.1)': dependencies: '@tanstack/query-core': 5.60.6 react: 18.3.1 + '@tanstack/react-query@5.62.7(react@18.3.1)': + dependencies: + '@tanstack/query-core': 5.62.7 + react: 18.3.1 + '@tavily/core@0.0.2': dependencies: axios: 1.7.9(debug@4.4.0) @@ -30761,13 +31758,13 @@ snapshots: '@telegraf/types@7.1.0': {} - '@tensor-hq/tensor-common@8.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@tensor-hq/tensor-common@8.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.26.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@metaplex-foundation/mpl-auction-house': 2.5.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@metaplex-foundation/mpl-bubblegum': 0.7.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@metaplex-foundation/mpl-auction-house': 2.5.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@metaplex-foundation/mpl-bubblegum': 0.7.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/spl-account-compression': 0.1.10(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@solana/spl-token': 0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) axios: 0.28.1 big.js: 6.2.2 @@ -30786,14 +31783,14 @@ snapshots: - typescript - utf-8-validate - '@tensor-oss/tensorswap-sdk@4.5.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@tensor-oss/tensorswap-sdk@4.5.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.26.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@msgpack/msgpack': 2.8.0 '@saberhq/solana-contrib': 1.15.0(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bn.js@5.2.1) - '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@tensor-hq/tensor-common': 8.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@tensor-hq/tensor-common': 8.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@types/bn.js': 5.1.6 big.js: 6.2.2 bn.js: 5.2.1 @@ -31406,6 +32403,10 @@ snapshots: '@types/unist@3.0.3': {} + '@types/unzipper@0.10.10': + dependencies: + '@types/node': 20.17.9 + '@types/uuid@10.0.0': {} '@types/uuid@8.3.4': {} @@ -31699,7 +32700,26 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@2.1.5(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@vitest/coverage-v8@1.1.3(vitest@1.1.3(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 0.2.3 + debug: 4.4.0(supports-color@8.1.1) + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + magic-string: 0.30.17 + magicast: 0.3.5 + picocolors: 1.1.1 + std-env: 3.8.0 + test-exclude: 6.0.0 + v8-to-istanbul: 9.3.0 + vitest: 1.1.3(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + transitivePeerDependencies: + - supports-color + + '@vitest/coverage-v8@2.1.5(vitest@2.1.8(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 @@ -31713,7 +32733,7 @@ snapshots: std-env: 3.8.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + vitest: 2.1.8(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) transitivePeerDependencies: - supports-color @@ -31725,6 +32745,12 @@ snapshots: typescript: 5.6.3 vitest: 2.1.5(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + '@vitest/expect@1.1.3': + dependencies: + '@vitest/spy': 1.1.3 + '@vitest/utils': 1.1.3 + chai: 4.5.0 + '@vitest/expect@1.2.1': dependencies: '@vitest/spy': 1.2.1 @@ -31745,6 +32771,13 @@ snapshots: chai: 5.1.2 tinyrainbow: 1.2.0 + '@vitest/expect@2.1.8': + dependencies: + '@vitest/spy': 2.1.8 + '@vitest/utils': 2.1.8 + chai: 5.1.2 + tinyrainbow: 1.2.0 + '@vitest/mocker@2.1.4(vite@5.4.11(@types/node@22.10.5)(terser@5.37.0))': dependencies: '@vitest/spy': 2.1.4 @@ -31761,6 +32794,14 @@ snapshots: optionalDependencies: vite: 5.4.11(@types/node@22.10.5)(terser@5.37.0) + '@vitest/mocker@2.1.8(vite@5.4.11(@types/node@22.10.5)(terser@5.37.0))': + dependencies: + '@vitest/spy': 2.1.8 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 5.4.11(@types/node@22.10.5)(terser@5.37.0) + '@vitest/pretty-format@2.1.4': dependencies: tinyrainbow: 1.2.0 @@ -31773,6 +32814,12 @@ snapshots: dependencies: tinyrainbow: 1.2.0 + '@vitest/runner@1.1.3': + dependencies: + '@vitest/utils': 1.1.3 + p-limit: 5.0.0 + pathe: 1.1.2 + '@vitest/runner@1.2.1': dependencies: '@vitest/utils': 1.2.1 @@ -31789,6 +32836,17 @@ snapshots: '@vitest/utils': 2.1.5 pathe: 1.1.2 + '@vitest/runner@2.1.8': + dependencies: + '@vitest/utils': 2.1.8 + pathe: 1.1.2 + + '@vitest/snapshot@1.1.3': + dependencies: + magic-string: 0.30.17 + pathe: 1.1.2 + pretty-format: 29.7.0 + '@vitest/snapshot@1.2.1': dependencies: magic-string: 0.30.17 @@ -31807,6 +32865,16 @@ snapshots: magic-string: 0.30.17 pathe: 1.1.2 + '@vitest/snapshot@2.1.8': + dependencies: + '@vitest/pretty-format': 2.1.8 + magic-string: 0.30.17 + pathe: 1.1.2 + + '@vitest/spy@1.1.3': + dependencies: + tinyspy: 2.2.1 + '@vitest/spy@1.2.1': dependencies: tinyspy: 2.2.1 @@ -31819,6 +32887,17 @@ snapshots: dependencies: tinyspy: 3.0.2 + '@vitest/spy@2.1.8': + dependencies: + tinyspy: 3.0.2 + + '@vitest/utils@1.1.3': + dependencies: + diff-sequences: 29.6.3 + estree-walker: 3.0.3 + loupe: 2.3.7 + pretty-format: 29.7.0 + '@vitest/utils@1.2.1': dependencies: diff-sequences: 29.6.3 @@ -31838,6 +32917,12 @@ snapshots: loupe: 3.1.2 tinyrainbow: 1.2.0 + '@vitest/utils@2.1.8': + dependencies: + '@vitest/pretty-format': 2.1.8 + loupe: 3.1.2 + tinyrainbow: 1.2.0 + '@vladfrangu/async_event_emitter@2.4.6': {} '@vue/compiler-core@3.5.13': @@ -31945,7 +33030,7 @@ snapshots: dependencies: tslib: 1.14.1 - '@walletconnect/ethereum-provider@2.17.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)': + '@walletconnect/ethereum-provider@2.17.3(@types/react@18.3.12)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.4.2)(react@18.3.1)(utf-8-validate@5.0.10)': dependencies: '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) '@walletconnect/jsonrpc-provider': 1.0.14 @@ -31955,7 +33040,7 @@ snapshots: '@walletconnect/modal': 2.7.0(@types/react@18.3.12)(react@18.3.1) '@walletconnect/sign-client': 2.17.3(bufferutil@4.0.9)(ioredis@5.4.2)(utf-8-validate@5.0.10) '@walletconnect/types': 2.17.3(ioredis@5.4.2) - '@walletconnect/universal-provider': 2.17.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.17.3(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.4.2)(utf-8-validate@5.0.10) '@walletconnect/utils': 2.17.3(ioredis@5.4.2) events: 3.3.0 transitivePeerDependencies: @@ -32166,7 +33251,7 @@ snapshots: - ioredis - uploadthing - '@walletconnect/universal-provider@2.17.3(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)': + '@walletconnect/universal-provider@2.17.3(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.4.2)(utf-8-validate@5.0.10)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) @@ -32366,35 +33451,45 @@ snapshots: fs-extra: 10.1.0 yargs: 17.7.2 - abitype@0.10.3(typescript@5.6.3)(zod@3.24.1): + abitype@0.10.3(typescript@5.7.2)(zod@3.24.1): optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 zod: 3.24.1 - abitype@0.7.1(typescript@5.6.3)(zod@3.24.1): + abitype@0.7.1(typescript@5.7.2)(zod@3.24.1): dependencies: - typescript: 5.6.3 + typescript: 5.7.2 optionalDependencies: zod: 3.24.1 - abitype@1.0.7(typescript@5.6.3)(zod@3.23.8): + abitype@1.0.7(typescript@5.6.3)(zod@3.24.1): optionalDependencies: typescript: 5.6.3 + zod: 3.24.1 + + abitype@1.0.7(typescript@5.7.2)(zod@3.23.8): + optionalDependencies: + typescript: 5.7.2 zod: 3.23.8 - abitype@1.0.7(typescript@5.6.3)(zod@3.24.1): + abitype@1.0.7(typescript@5.7.2)(zod@3.24.1): optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 zod: 3.24.1 - abitype@1.0.8(typescript@5.6.3)(zod@3.23.8): + abitype@1.0.8(typescript@5.6.3)(zod@3.24.1): optionalDependencies: typescript: 5.6.3 + zod: 3.24.1 + + abitype@1.0.8(typescript@5.7.2)(zod@3.23.8): + optionalDependencies: + typescript: 5.7.2 zod: 3.23.8 - abitype@1.0.8(typescript@5.6.3)(zod@3.24.1): + abitype@1.0.8(typescript@5.7.2)(zod@3.24.1): optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 zod: 3.24.1 abort-controller@3.0.0: @@ -33003,6 +34098,12 @@ snapshots: '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.6 + babel-plugin-macros@3.1.0: + dependencies: + '@babel/runtime': 7.26.0 + cosmiconfig: 7.1.0 + resolve: 1.22.10 + babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.26.0): dependencies: '@babel/compat-data': 7.26.3 @@ -33229,14 +34330,14 @@ snapshots: dependencies: '@noble/hashes': 1.3.0 - bitcoinjs-lib@7.0.0-rc.0(typescript@5.6.3): + bitcoinjs-lib@7.0.0-rc.0(typescript@5.7.2): dependencies: '@noble/hashes': 1.7.0 bech32: 2.0.0 bip174: 3.0.0-rc.1 bs58check: 4.0.0 uint8array-tools: 0.0.9 - valibot: 0.38.0(typescript@5.6.3) + valibot: 0.38.0(typescript@5.7.2) varuint-bitcoin: 2.0.0 transitivePeerDependencies: - typescript @@ -33260,6 +34361,8 @@ snapshots: blessed@0.1.81: {} + bluebird@3.7.2: {} + bn.js@4.11.6: {} bn.js@4.12.1: {} @@ -33906,13 +35009,13 @@ snapshots: dependencies: consola: 3.3.3 - cive@0.7.1(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10): + cive@0.7.1(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: '@noble/curves': 1.8.0 '@noble/hashes': 1.7.0 '@scure/bip32': 1.6.1 '@scure/bip39': 1.5.1 - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8) zod: 3.23.8 transitivePeerDependencies: - bufferutil @@ -34312,6 +35415,8 @@ snapshots: convert-source-map@1.1.3: {} + convert-source-map@1.9.0: {} + convert-source-map@2.0.0: {} cookie-es@1.2.2: {} @@ -34376,6 +35481,14 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + cosmiconfig@8.1.3: dependencies: import-fresh: 3.3.0 @@ -34392,6 +35505,15 @@ snapshots: optionalDependencies: typescript: 5.6.3 + cosmiconfig@8.3.6(typescript@5.7.2): + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.7.2 + cosmjs-types@0.9.0: {} crc-32@1.2.2: {} @@ -34418,13 +35540,13 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 - create-jest@29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)): + create-jest@29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -34433,13 +35555,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@20.17.9): + create-jest@29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -34448,13 +35570,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)): + create-jest@29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -34463,28 +35585,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@22.10.5): + create-jest@29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@22.10.5) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - - create-jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -35064,7 +36171,9 @@ snapshots: dependencies: mimic-response: 3.1.0 - dedent@1.5.3: {} + dedent@1.5.3(babel-plugin-macros@3.1.0): + optionalDependencies: + babel-plugin-macros: 3.1.0 deep-eql@4.1.4: dependencies: @@ -35273,9 +36382,9 @@ snapshots: dependencies: esutils: 2.0.3 - docusaurus-lunr-search@3.5.0(@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + docusaurus-lunr-search@3.5.0(@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.4(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10) autocomplete.js: 0.37.1 clsx: 1.2.1 gauge: 3.0.2 @@ -35293,9 +36402,9 @@ snapshots: unified: 9.2.2 unist-util-is: 4.1.0 - docusaurus-plugin-typedoc@1.0.5(typedoc-plugin-markdown@4.2.10(typedoc@0.26.11(typescript@5.6.3))): + docusaurus-plugin-typedoc@1.0.5(typedoc-plugin-markdown@4.2.10(typedoc@0.26.11(typescript@5.7.2))): dependencies: - typedoc-plugin-markdown: 4.2.10(typedoc@0.26.11(typescript@5.6.3)) + typedoc-plugin-markdown: 4.2.10(typedoc@0.26.11(typescript@5.7.2)) dom-converter@0.2.0: dependencies: @@ -36545,6 +37654,8 @@ snapshots: schema-utils: 3.3.0 webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15)) + file-type-checker@1.1.2: {} + file-uri-to-path@1.0.0: {} filelist@1.0.4: @@ -36595,6 +37706,8 @@ snapshots: - jiti - supports-color + find-root@1.1.0: {} + find-up@2.1.0: dependencies: locate-path: 2.0.0 @@ -36623,12 +37736,12 @@ snapshots: semver-regex: 4.0.5 super-regex: 1.0.0 - flash-sdk@2.24.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10): + flash-sdk@2.24.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: '@coral-xyz/anchor': 0.27.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@pythnetwork/client': 2.22.0(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@pythnetwork/price-service-client': 1.9.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@solana/spl-token': 0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@types/node': 20.17.9 bignumber.js: 9.1.2 @@ -36639,7 +37752,7 @@ snapshots: jsbi: 4.3.0 node-fetch: 3.3.2 rimraf: 5.0.10 - ts-node: 10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3) + ts-node: 10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2) tweetnacl: 1.0.3 transitivePeerDependencies: - '@swc/core' @@ -36681,11 +37794,11 @@ snapshots: optionalDependencies: debug: 4.4.0(supports-color@8.1.1) - fomo-sdk-solana@1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10): + fomo-sdk-solana@1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: '@coral-xyz/anchor': 0.30.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@raydium-io/raydium-sdk-v2': 0.1.82-alpha(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@raydium-io/raydium-sdk-v2': 0.1.82-alpha(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) bs58: 6.0.0 coral-xyz3: '@coral-xyz/anchor@0.29.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)' @@ -36716,7 +37829,7 @@ snapshots: forever-agent@0.6.1: {} - fork-ts-checker-webpack-plugin@6.5.3(eslint@9.17.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))): + fork-ts-checker-webpack-plugin@6.5.3(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))): dependencies: '@babel/code-frame': 7.26.2 '@types/json-schema': 7.0.15 @@ -36731,7 +37844,7 @@ snapshots: schema-utils: 2.7.0 semver: 7.6.3 tapable: 1.1.3 - typescript: 5.6.3 + typescript: 5.7.2 webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15)) optionalDependencies: eslint: 9.17.0(jiti@2.4.2) @@ -36883,6 +37996,8 @@ snapshots: functions-have-names@1.2.3: {} + fuse.js@7.0.0: {} + gauge@3.0.2: dependencies: aproba: 2.0.0 @@ -36933,11 +38048,11 @@ snapshots: dependencies: is-property: 1.0.2 - genlayer-js@0.4.7(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1): + genlayer-js@0.4.7(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(bufferutil@4.0.9)(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1): dependencies: eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.17.0(jiti@2.4.2)) typescript-parsec: 0.3.4 - viem: 2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) transitivePeerDependencies: - '@typescript-eslint/parser' - bufferutil @@ -37267,13 +38382,13 @@ snapshots: p-cancelable: 3.0.0 responselike: 3.0.0 - gql.tada@1.8.10(graphql@16.10.0)(typescript@5.6.3): + gql.tada@1.8.10(graphql@16.10.0)(typescript@5.7.2): dependencies: '@0no-co/graphql.web': 1.0.13(graphql@16.10.0) - '@0no-co/graphqlsp': 1.12.16(graphql@16.10.0)(typescript@5.6.3) - '@gql.tada/cli-utils': 1.6.3(@0no-co/graphqlsp@1.12.16(graphql@16.10.0)(typescript@5.6.3))(graphql@16.10.0)(typescript@5.6.3) - '@gql.tada/internal': 1.0.8(graphql@16.10.0)(typescript@5.6.3) - typescript: 5.6.3 + '@0no-co/graphqlsp': 1.12.16(graphql@16.10.0)(typescript@5.7.2) + '@gql.tada/cli-utils': 1.6.3(@0no-co/graphqlsp@1.12.16(graphql@16.10.0)(typescript@5.7.2))(graphql@16.10.0)(typescript@5.7.2) + '@gql.tada/internal': 1.0.8(graphql@16.10.0)(typescript@5.7.2) + typescript: 5.7.2 transitivePeerDependencies: - '@gql.tada/svelte-support' - '@gql.tada/vue-support' @@ -37376,7 +38491,7 @@ snapshots: hard-rejection@2.1.0: {} - hardhat@2.22.17(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10): + hardhat@2.22.17(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: '@ethersproject/abi': 5.7.0 '@metamask/eth-sig-util': 4.0.1 @@ -37423,8 +38538,8 @@ snapshots: uuid: 8.3.2 ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: - ts-node: 10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.6.3) - typescript: 5.6.3 + ts-node: 10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.7.2) + typescript: 5.7.2 transitivePeerDependencies: - bufferutil - c-kzg @@ -37969,6 +39084,11 @@ snapshots: inline-style-parser@0.2.4: {} + input-otp@1.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + inquirer@8.2.6: dependencies: ansi-escapes: 4.3.2 @@ -38002,6 +39122,18 @@ snapshots: int64-buffer@0.1.10: {} + interchain@1.10.4(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + '@cosmjs/amino': 0.32.2 + '@cosmjs/proto-signing': 0.32.2 + '@cosmjs/stargate': 0.32.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmjs/tendermint-rpc': 0.32.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@cosmology/lcd': 0.13.5 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -38494,7 +39626,7 @@ snapshots: jest-util: 29.7.0 p-limit: 3.1.0 - jest-circus@29.7.0: + jest-circus@29.7.0(babel-plugin-macros@3.1.0): dependencies: '@jest/environment': 29.7.0 '@jest/expect': 29.7.0 @@ -38503,7 +39635,7 @@ snapshots: '@types/node': 20.17.9 chalk: 4.1.2 co: 4.6.0 - dedent: 1.5.3 + dedent: 1.5.3(babel-plugin-macros@3.1.0) is-generator-fn: 2.1.0 jest-each: 29.7.0 jest-matcher-utils: 29.7.0 @@ -38520,16 +39652,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)): + jest-cli@29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) + create-jest: 29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -38539,16 +39671,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.17.9): + jest-cli@29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.9) + create-jest: 29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -38558,16 +39690,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)): + jest-cli@29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + create-jest: 29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -38577,16 +39709,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@22.10.5): + jest-cli@29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.10.5) + create-jest: 29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.10.5) + jest-config: 29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -38596,26 +39728,7 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - - jest-config@29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)): + jest-config@29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -38626,7 +39739,7 @@ snapshots: deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 29.7.0 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) jest-environment-node: 29.7.0 jest-get-type: 29.6.3 jest-regex-util: 29.6.3 @@ -38646,7 +39759,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)): + jest-config@29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -38657,7 +39770,7 @@ snapshots: deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 29.7.0 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) jest-environment-node: 29.7.0 jest-get-type: 29.6.3 jest-regex-util: 29.6.3 @@ -38677,7 +39790,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)): + jest-config@29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -38688,7 +39801,7 @@ snapshots: deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 29.7.0 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) jest-environment-node: 29.7.0 jest-get-type: 29.6.3 jest-regex-util: 29.6.3 @@ -38703,12 +39816,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.17.9 - ts-node: 10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3) + ts-node: 10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): + jest-config@29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -38719,7 +39832,7 @@ snapshots: deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 29.7.0 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) jest-environment-node: 29.7.0 jest-get-type: 29.6.3 jest-regex-util: 29.6.3 @@ -38739,7 +39852,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@22.10.5): + jest-config@29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -38750,7 +39863,7 @@ snapshots: deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 29.7.0 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) jest-environment-node: 29.7.0 jest-get-type: 29.6.3 jest-regex-util: 29.6.3 @@ -38769,7 +39882,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): + jest-config@29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -38780,7 +39893,7 @@ snapshots: deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 29.7.0 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) jest-environment-node: 29.7.0 jest-get-type: 29.6.3 jest-regex-util: 29.6.3 @@ -38802,7 +39915,7 @@ snapshots: jest-diff@29.7.0: dependencies: - chalk: 4.1.0 + chalk: 4.1.2 diff-sequences: 29.6.3 jest-get-type: 29.6.3 pretty-format: 29.7.0 @@ -39021,60 +40134,48 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)): + jest@29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) + jest-cli: 29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest@29.7.0(@types/node@20.17.9): + jest@29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.9) + jest-cli: 29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)): + jest@29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + jest-cli: 29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0) transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest@29.7.0(@types/node@22.10.5): + jest@29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.10.5) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - - jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) - '@jest/types': 29.6.3 - import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest-cli: 29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -39462,9 +40563,9 @@ snapshots: leac@0.6.0: {} - lerna@8.1.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(encoding@0.1.13): + lerna@8.1.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13): dependencies: - '@lerna/create': 8.1.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(encoding@0.1.13)(typescript@5.6.3) + '@lerna/create': 8.1.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13)(typescript@5.6.3) '@npmcli/arborist': 7.5.3 '@npmcli/package-json': 5.2.0 '@npmcli/run-script': 8.1.0 @@ -39483,7 +40584,7 @@ snapshots: conventional-changelog-core: 5.0.1 conventional-recommended-bump: 7.0.1 cosmiconfig: 8.3.6(typescript@5.6.3) - dedent: 1.5.3 + dedent: 1.5.3(babel-plugin-macros@3.1.0) envinfo: 7.13.0 execa: 5.0.0 fs-extra: 11.2.0 @@ -40705,6 +41806,10 @@ snapshots: minipass: 7.1.2 rimraf: 5.0.10 + mipd@0.0.7(typescript@5.7.2): + optionalDependencies: + typescript: 5.7.2 + mitt@3.0.0: {} mixin-object@2.0.1: @@ -40724,7 +41829,7 @@ snapshots: mkdirp@3.0.1: {} - mkdist@1.6.0(typescript@5.6.3): + mkdist@1.6.0(typescript@5.7.2): dependencies: autoprefixer: 10.4.20(postcss@8.4.49) citty: 0.1.6 @@ -40740,7 +41845,7 @@ snapshots: semver: 7.6.3 tinyglobby: 0.2.10 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 mlly@1.7.3: dependencies: @@ -41100,7 +42205,7 @@ snapshots: process: 0.11.10 uuid: 9.0.1 - node-llama-cpp@3.1.1(typescript@5.6.3): + node-llama-cpp@3.1.1(typescript@5.7.2): dependencies: '@huggingface/jinja': 0.3.2 async-retry: 1.3.3 @@ -41144,7 +42249,7 @@ snapshots: '@node-llama-cpp/win-x64': 3.1.1 '@node-llama-cpp/win-x64-cuda': 3.1.1 '@node-llama-cpp/win-x64-vulkan': 3.1.1 - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -41307,7 +42412,7 @@ snapshots: '@yarnpkg/parsers': 3.0.0-rc.46 '@zkochan/js-yaml': 0.0.7 axios: 1.7.9(debug@4.4.0) - chalk: 4.1.0 + chalk: 4.1.2 cli-cursor: 3.1.0 cli-spinners: 2.6.1 cliui: 8.0.1 @@ -41594,7 +42699,7 @@ snapshots: ora@5.3.0: dependencies: bl: 4.1.0 - chalk: 4.1.0 + chalk: 4.1.2 cli-cursor: 3.1.0 cli-spinners: 2.6.1 is-interactive: 1.0.0 @@ -41640,31 +42745,59 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - ox@0.4.4(typescript@5.6.3)(zod@3.23.8): + ox@0.4.2(typescript@5.7.2)(zod@3.24.1): + dependencies: + '@adraffy/ens-normalize': 1.11.0 + '@noble/curves': 1.8.0 + '@noble/hashes': 1.7.0 + '@scure/bip32': 1.6.1 + '@scure/bip39': 1.5.1 + abitype: 1.0.8(typescript@5.7.2)(zod@3.24.1) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.7.2 + transitivePeerDependencies: + - zod + + ox@0.4.4(typescript@5.6.3)(zod@3.24.1): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/curves': 1.7.0 '@noble/hashes': 1.6.1 '@scure/bip32': 1.6.0 '@scure/bip39': 1.5.0 - abitype: 1.0.7(typescript@5.6.3)(zod@3.23.8) + abitype: 1.0.7(typescript@5.6.3)(zod@3.24.1) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - zod - ox@0.4.4(typescript@5.6.3)(zod@3.24.1): + ox@0.4.4(typescript@5.7.2)(zod@3.23.8): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/curves': 1.7.0 '@noble/hashes': 1.6.1 '@scure/bip32': 1.6.0 '@scure/bip39': 1.5.0 - abitype: 1.0.7(typescript@5.6.3)(zod@3.24.1) + abitype: 1.0.7(typescript@5.7.2)(zod@3.23.8) eventemitter3: 5.0.1 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 + transitivePeerDependencies: + - zod + + ox@0.4.4(typescript@5.7.2)(zod@3.24.1): + dependencies: + '@adraffy/ens-normalize': 1.11.0 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.7(typescript@5.7.2)(zod@3.24.1) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.7.2 transitivePeerDependencies: - zod @@ -42459,9 +43592,9 @@ snapshots: tsx: 4.19.2 yaml: 2.7.0 - postcss-loader@7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))): + postcss-loader@7.3.4(postcss@8.4.49)(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))): dependencies: - cosmiconfig: 8.3.6(typescript@5.6.3) + cosmiconfig: 8.3.6(typescript@5.7.2) jiti: 1.21.7 postcss: 8.4.49 semver: 7.6.3 @@ -43113,11 +44246,11 @@ snapshots: end-of-stream: 1.4.4 once: 1.4.0 - pumpdotfun-sdk@1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(rollup@4.30.1)(typescript@5.6.3)(utf-8-validate@5.0.10): + pumpdotfun-sdk@1.3.2(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(rollup@4.30.1)(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: '@coral-xyz/anchor': 0.30.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@rollup/plugin-json': 6.1.0(rollup@4.30.1) - '@solana/spl-token': 0.4.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.4.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil @@ -43137,9 +44270,9 @@ snapshots: dependencies: escape-goat: 4.0.0 - puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10): + puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: - '@puppeteer/browsers': 0.5.0(typescript@5.6.3) + '@puppeteer/browsers': 0.5.0(typescript@5.7.2) chromium-bidi: 0.4.7(devtools-protocol@0.0.1107588) cross-fetch: 3.1.5(encoding@0.1.13) debug: 4.3.4 @@ -43151,20 +44284,20 @@ snapshots: unbzip2-stream: 1.4.3 ws: 8.13.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - bufferutil - encoding - supports-color - utf-8-validate - puppeteer-extra-plugin-capsolver@2.0.1(bufferutil@4.0.9)(encoding@0.1.13)(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10))(typescript@5.6.3)(utf-8-validate@5.0.10): + puppeteer-extra-plugin-capsolver@2.0.1(bufferutil@4.0.9)(encoding@0.1.13)(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: axios: 1.7.9(debug@4.4.0) capsolver-npm: 2.0.2 - puppeteer: 19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10) - puppeteer-extra: 3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)) - puppeteer-extra-plugin: 3.2.3(puppeteer-extra@3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10))) + puppeteer: 19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10) + puppeteer-extra: 3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)) + puppeteer-extra-plugin: 3.2.3(puppeteer-extra@3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))) transitivePeerDependencies: - '@types/puppeteer' - bufferutil @@ -43176,35 +44309,35 @@ snapshots: - typescript - utf-8-validate - puppeteer-extra-plugin@3.2.3(puppeteer-extra@3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10))): + puppeteer-extra-plugin@3.2.3(puppeteer-extra@3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))): dependencies: '@types/debug': 4.1.12 debug: 4.4.0(supports-color@8.1.1) merge-deep: 3.0.3 optionalDependencies: - puppeteer-extra: 3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)) + puppeteer-extra: 3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)) transitivePeerDependencies: - supports-color - puppeteer-extra@3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)): + puppeteer-extra@3.3.6(puppeteer-core@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)): dependencies: '@types/debug': 4.1.12 debug: 4.4.0(supports-color@8.1.1) deepmerge: 4.3.1 optionalDependencies: - puppeteer: 19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10) - puppeteer-core: 19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10) + puppeteer: 19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10) + puppeteer-core: 19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10) transitivePeerDependencies: - supports-color - puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10): + puppeteer@19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: - '@puppeteer/browsers': 0.5.0(typescript@5.6.3) + '@puppeteer/browsers': 0.5.0(typescript@5.7.2) cosmiconfig: 8.1.3 https-proxy-agent: 5.0.1 progress: 2.0.3 proxy-from-env: 1.1.0 - puppeteer-core: 19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10) + puppeteer-core: 19.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil - encoding @@ -43298,7 +44431,7 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-dev-utils@12.0.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))): + react-dev-utils@12.0.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))): dependencies: '@babel/code-frame': 7.26.2 address: 1.2.2 @@ -43309,7 +44442,7 @@ snapshots: escape-string-regexp: 4.0.0 filesize: 8.0.7 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.17.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))) global-modules: 2.0.0 globby: 11.1.0 gzip-size: 6.0.0 @@ -43326,7 +44459,7 @@ snapshots: text-table: 0.2.0 webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15)) optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - eslint - supports-color @@ -43919,11 +45052,11 @@ snapshots: robust-predicates@3.0.2: {} - rollup-plugin-dts@6.1.1(rollup@3.29.5)(typescript@5.6.3): + rollup-plugin-dts@6.1.1(rollup@3.29.5)(typescript@5.7.2): dependencies: magic-string: 0.30.17 rollup: 3.29.5 - typescript: 5.6.3 + typescript: 5.7.2 optionalDependencies: '@babel/code-frame': 7.26.2 @@ -44505,17 +45638,17 @@ snapshots: typedarray-to-buffer: 3.1.5 xsalsa20: 1.2.0 - solana-agent-kit@1.3.7(@noble/hashes@1.7.0)(@swc/core@1.10.4(@swc/helpers@0.5.15))(axios@1.7.9)(borsh@2.0.0)(buffer@6.0.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(handlebars@4.7.8)(jiti@2.4.2)(react@18.3.1)(sodium-native@3.4.1)(typescript@5.6.3)(utf-8-validate@5.0.10): + solana-agent-kit@1.3.7(@noble/hashes@1.7.0)(@swc/core@1.10.4(@swc/helpers@0.5.15))(axios@1.7.9)(borsh@2.0.0)(buffer@6.0.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(handlebars@4.7.8)(jiti@2.4.2)(react@18.3.1)(sodium-native@3.4.1)(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: '@ai-sdk/openai': 1.0.13(zod@3.24.1) - '@bonfida/spl-name-service': 3.0.7(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@cks-systems/manifest-sdk': 0.1.59(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(jiti@2.4.2)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@bonfida/spl-name-service': 3.0.7(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@cks-systems/manifest-sdk': 0.1.59(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(jiti@2.4.2)(typescript@5.7.2)(utf-8-validate@5.0.10) '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@langchain/core': 0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) '@langchain/groq': 0.1.2(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) '@langchain/langgraph': 0.2.39(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1))) '@langchain/openai': 0.3.16(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) - '@lightprotocol/compressed-token': 0.17.1(@lightprotocol/stateless.js@0.17.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@lightprotocol/compressed-token': 0.17.1(@lightprotocol/stateless.js@0.17.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@lightprotocol/stateless.js': 0.17.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@metaplex-foundation/mpl-core': 1.1.1(@metaplex-foundation/umi@0.9.2)(@noble/hashes@1.7.0) '@metaplex-foundation/mpl-token-metadata': 3.3.0(@metaplex-foundation/umi@0.9.2) @@ -44524,13 +45657,13 @@ snapshots: '@metaplex-foundation/umi-bundle-defaults': 0.9.2(@metaplex-foundation/umi@0.9.2)(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(encoding@0.1.13) '@metaplex-foundation/umi-web3js-adapters': 0.9.2(@metaplex-foundation/umi@0.9.2)(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@onsol/tldparser': 0.6.7(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bn.js@5.2.1)(borsh@2.0.0)(buffer@6.0.3)(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@orca-so/common-sdk': 0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3) - '@orca-so/whirlpools-sdk': 0.13.13(@coral-xyz/anchor@0.29.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(@orca-so/common-sdk@0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3))(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3) + '@orca-so/common-sdk': 0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10))(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3) + '@orca-so/whirlpools-sdk': 0.13.13(@coral-xyz/anchor@0.29.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(@orca-so/common-sdk@0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3))(@solana/spl-token@0.4.9(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(decimal.js@10.4.3) '@pythnetwork/hermes-client': 1.3.0(axios@1.7.9) - '@raydium-io/raydium-sdk-v2': 0.1.95-alpha(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@solana/spl-token': 0.4.9(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@raydium-io/raydium-sdk-v2': 0.1.95-alpha(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.4.9(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@tensor-oss/tensorswap-sdk': 4.5.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@tensor-oss/tensorswap-sdk': 4.5.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@tiplink/api': 0.3.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(sodium-native@3.4.1)(utf-8-validate@5.0.10) ai: 4.0.27(react@18.3.1)(zod@3.24.1) bn.js: 5.2.1 @@ -44538,11 +45671,11 @@ snapshots: chai: 5.1.2 decimal.js: 10.4.3 dotenv: 16.4.7 - flash-sdk: 2.24.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + flash-sdk: 2.24.3(@swc/core@1.10.4(@swc/helpers@0.5.15))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) form-data: 4.0.1 langchain: 0.3.10(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(@langchain/groq@0.1.2(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13))(axios@1.7.9)(encoding@0.1.13)(handlebars@4.7.8)(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) openai: 4.77.3(encoding@0.1.13)(zod@3.24.1) - typedoc: 0.27.6(typescript@5.6.3) + typedoc: 0.27.6(typescript@5.7.2) zod: 3.24.1 transitivePeerDependencies: - '@langchain/anthropic' @@ -44961,6 +46094,8 @@ snapshots: postcss: 8.4.49 postcss-selector-parser: 6.1.2 + stylis@4.2.0: {} + stylis@4.3.4: {} subarg@1.0.0: @@ -45215,10 +46350,67 @@ snapshots: dependencies: any-promise: 1.3.0 + thirdweb@5.82.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(bufferutil@4.0.9)(encoding@0.1.13)(ethers@6.13.4(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ioredis@5.4.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1): + dependencies: + '@coinbase/wallet-sdk': 4.2.4 + '@emotion/react': 11.14.0(@types/react@18.3.12)(react@18.3.1) + '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react@18.3.1) + '@google/model-viewer': 2.1.1 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@passwordless-id/webauthn': 2.1.2 + '@radix-ui/react-dialog': 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-icons': 1.3.2(react@18.3.1) + '@radix-ui/react-tooltip': 1.1.5(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-query': 5.62.7(react@18.3.1) + '@walletconnect/ethereum-provider': 2.17.3(@types/react@18.3.12)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.4.2)(react@18.3.1)(utf-8-validate@5.0.10) + '@walletconnect/sign-client': 2.17.3(bufferutil@4.0.9)(ioredis@5.4.2)(utf-8-validate@5.0.10) + abitype: 1.0.7(typescript@5.7.2)(zod@3.24.1) + cross-spawn: 7.0.6 + fuse.js: 7.0.0 + input-otp: 1.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + mipd: 0.0.7(typescript@5.7.2) + ox: 0.4.2(typescript@5.7.2)(zod@3.24.1) + uqr: 0.1.2 + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) + optionalDependencies: + ethers: 6.13.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) + react: 18.3.1 + typescript: 5.7.2 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@types/react' + - '@types/react-dom' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react-dom + - supports-color + - uploadthing + - utf-8-validate + - zod + thread-stream@0.15.2: dependencies: real-require: 0.1.0 + three@0.146.0: {} + throttleit@2.1.0: {} through2@2.0.5: @@ -45395,18 +46587,18 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)))(typescript@5.6.3): + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)))(typescript@5.7.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + jest: 29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.6.3 - typescript: 5.6.3 + typescript: 5.7.2 yargs-parser: 21.1.1 optionalDependencies: '@babel/core': 7.26.0 @@ -45415,12 +46607,12 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.26.0) esbuild: 0.24.2 - ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)))(typescript@5.6.3): + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.19.70)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) + jest: 29.7.0(@types/node@18.19.70)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@18.19.70)(typescript@5.6.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -45434,12 +46626,12 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.0) - ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.9))(typescript@5.6.3): + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.9) + jest: 29.7.0(@types/node@20.17.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -45453,12 +46645,12 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.0) - ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.10.5))(typescript@5.6.3): + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.10.5) + jest: 29.7.0(@types/node@22.10.5)(babel-plugin-macros@3.1.0) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -45472,12 +46664,12 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.0) - ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3): + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest: 29.7.0(@types/node@22.8.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -45515,7 +46707,7 @@ snapshots: optionalDependencies: '@swc/core': 1.10.4(@swc/helpers@0.5.15) - ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3): + ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.7.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -45529,13 +46721,13 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.6.3 + typescript: 5.7.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: '@swc/core': 1.10.4(@swc/helpers@0.5.15) - ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.6.3): + ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.7.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -45549,7 +46741,7 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.6.3 + typescript: 5.7.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: @@ -45631,6 +46823,34 @@ snapshots: - tsx - yaml + tsup@8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0): + dependencies: + bundle-require: 5.1.0(esbuild@0.24.2) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.3.3 + debug: 4.4.0(supports-color@8.1.1) + esbuild: 0.24.2 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.7.0) + resolve-from: 5.0.0 + rollup: 4.30.1 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.10 + tree-kill: 1.2.2 + optionalDependencies: + '@swc/core': 1.10.4(@swc/helpers@0.5.15) + postcss: 8.4.49 + typescript: 5.7.2 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + tsx@4.19.2: dependencies: esbuild: 0.23.1 @@ -45783,9 +47003,9 @@ snapshots: typedarray@0.0.6: {} - typedoc-plugin-markdown@4.2.10(typedoc@0.26.11(typescript@5.6.3)): + typedoc-plugin-markdown@4.2.10(typedoc@0.26.11(typescript@5.7.2)): dependencies: - typedoc: 0.26.11(typescript@5.6.3) + typedoc: 0.26.11(typescript@5.7.2) typedoc@0.26.11(typescript@5.6.3): dependencies: @@ -45796,13 +47016,22 @@ snapshots: typescript: 5.6.3 yaml: 2.7.0 - typedoc@0.27.6(typescript@5.6.3): + typedoc@0.26.11(typescript@5.7.2): + dependencies: + lunr: 2.3.9 + markdown-it: 14.1.0 + minimatch: 9.0.5 + shiki: 1.26.1 + typescript: 5.7.2 + yaml: 2.7.0 + + typedoc@0.27.6(typescript@5.7.2): dependencies: '@gerrit0/mini-shiki': 1.26.1 lunr: 2.3.9 markdown-it: 14.1.0 minimatch: 9.0.5 - typescript: 5.6.3 + typescript: 5.7.2 yaml: 2.7.0 typeforce@1.18.0: {} @@ -45826,6 +47055,8 @@ snapshots: typescript@5.6.3: {} + typescript@5.7.2: {} + u3@0.1.1: {} uc.micro@2.1.0: {} @@ -45855,7 +47086,7 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - unbuild@2.0.0(typescript@5.6.3): + unbuild@2.0.0(typescript@5.7.2): dependencies: '@rollup/plugin-alias': 5.1.1(rollup@3.29.5) '@rollup/plugin-commonjs': 25.0.8(rollup@3.29.5) @@ -45872,17 +47103,17 @@ snapshots: hookable: 5.5.3 jiti: 1.21.7 magic-string: 0.30.17 - mkdist: 1.6.0(typescript@5.6.3) + mkdist: 1.6.0(typescript@5.7.2) mlly: 1.7.3 pathe: 1.1.2 pkg-types: 1.3.0 pretty-bytes: 6.1.1 rollup: 3.29.5 - rollup-plugin-dts: 6.1.1(rollup@3.29.5)(typescript@5.6.3) + rollup-plugin-dts: 6.1.1(rollup@3.29.5)(typescript@5.7.2) scule: 1.3.0 untyped: 1.5.2 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - sass - supports-color @@ -46087,6 +47318,14 @@ snapshots: transitivePeerDependencies: - supports-color + unzipper@0.12.3: + dependencies: + bluebird: 3.7.2 + duplexer2: 0.1.4 + fs-extra: 11.2.0 + graceful-fs: 4.2.11 + node-int64: 0.4.0 + upath@2.0.1: {} update-browserslist-db@1.1.1(browserslist@4.24.3): @@ -46112,6 +47351,8 @@ snapshots: semver-diff: 4.0.0 xdg-basedir: 5.1.0 + uqr@0.1.2: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -46210,9 +47451,9 @@ snapshots: valibot@0.36.0: {} - valibot@0.38.0(typescript@5.6.3): + valibot@0.38.0(typescript@5.7.2): optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 valid-url@1.0.9: {} @@ -46276,15 +47517,15 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8): + viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1): dependencies: '@noble/curves': 1.7.0 '@noble/hashes': 1.6.1 '@scure/bip32': 1.6.0 '@scure/bip39': 1.5.0 - abitype: 1.0.7(typescript@5.6.3)(zod@3.23.8) + abitype: 1.0.7(typescript@5.6.3)(zod@3.24.1) isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.4.4(typescript@5.6.3)(zod@3.23.8) + ox: 0.4.4(typescript@5.6.3)(zod@3.24.1) webauthn-p256: 0.0.10 ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: @@ -46294,24 +47535,60 @@ snapshots: - utf-8-validate - zod - viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1): + viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8): dependencies: '@noble/curves': 1.7.0 '@noble/hashes': 1.6.1 '@scure/bip32': 1.6.0 '@scure/bip39': 1.5.0 - abitype: 1.0.7(typescript@5.6.3)(zod@3.24.1) + abitype: 1.0.7(typescript@5.7.2)(zod@3.23.8) isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.4.4(typescript@5.6.3)(zod@3.24.1) + ox: 0.4.4(typescript@5.7.2)(zod@3.23.8) webauthn-p256: 0.0.10 ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - bufferutil - utf-8-validate - zod + viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1): + dependencies: + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.7(typescript@5.7.2)(zod@3.24.1) + isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + ox: 0.4.4(typescript@5.7.2)(zod@3.24.1) + webauthn-p256: 0.0.10 + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.7.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + vite-node@1.1.3(@types/node@22.10.5)(terser@5.37.0): + dependencies: + cac: 6.7.14 + debug: 4.4.0(supports-color@8.1.1) + pathe: 1.1.2 + picocolors: 1.1.1 + vite: 5.4.11(@types/node@22.10.5)(terser@5.37.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vite-node@1.2.1(@types/node@22.10.5)(terser@5.37.0): dependencies: cac: 6.7.14 @@ -46382,7 +47659,25 @@ snapshots: - supports-color - terser - vite-node@2.1.5(@types/node@22.8.4)(terser@5.37.0): + vite-node@2.1.8(@types/node@22.10.5)(terser@5.37.0): + dependencies: + cac: 6.7.14 + debug: 4.4.0(supports-color@8.1.1) + es-module-lexer: 1.6.0 + pathe: 1.1.2 + vite: 5.4.11(@types/node@22.10.5)(terser@5.37.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite-node@2.1.8(@types/node@22.8.4)(terser@5.37.0): dependencies: cac: 6.7.14 debug: 4.4.0(supports-color@8.1.1) @@ -46444,6 +47739,42 @@ snapshots: fsevents: 2.3.3 terser: 5.37.0 + vitest@1.1.3(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0): + dependencies: + '@vitest/expect': 1.1.3 + '@vitest/runner': 1.1.3 + '@vitest/snapshot': 1.1.3 + '@vitest/spy': 1.1.3 + '@vitest/utils': 1.1.3 + acorn-walk: 8.3.4 + cac: 6.7.14 + chai: 4.5.0 + debug: 4.4.0(supports-color@8.1.1) + execa: 8.0.1 + local-pkg: 0.5.1 + magic-string: 0.30.17 + pathe: 1.1.2 + picocolors: 1.1.1 + std-env: 3.8.0 + strip-literal: 1.3.0 + tinybench: 2.9.0 + tinypool: 0.8.4 + vite: 5.4.11(@types/node@22.10.5)(terser@5.37.0) + vite-node: 1.1.3(@types/node@22.10.5)(terser@5.37.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.10.5 + jsdom: 25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10) + transitivePeerDependencies: + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vitest@1.2.1(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0): dependencies: '@vitest/expect': 1.2.1 @@ -46588,15 +47919,51 @@ snapshots: - supports-color - terser - vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0): + vitest@2.1.8(@types/node@22.10.5)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0): dependencies: - '@vitest/expect': 2.1.5 - '@vitest/mocker': 2.1.5(vite@5.4.11(@types/node@22.10.5)(terser@5.37.0)) + '@vitest/expect': 2.1.8 + '@vitest/mocker': 2.1.8(vite@5.4.11(@types/node@22.10.5)(terser@5.37.0)) '@vitest/pretty-format': 2.1.8 - '@vitest/runner': 2.1.5 - '@vitest/snapshot': 2.1.5 - '@vitest/spy': 2.1.5 - '@vitest/utils': 2.1.5 + '@vitest/runner': 2.1.8 + '@vitest/snapshot': 2.1.8 + '@vitest/spy': 2.1.8 + '@vitest/utils': 2.1.8 + chai: 5.1.2 + debug: 4.4.0(supports-color@8.1.1) + expect-type: 1.1.0 + magic-string: 0.30.17 + pathe: 1.1.2 + std-env: 3.8.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.0.2 + tinyrainbow: 1.2.0 + vite: 5.4.11(@types/node@22.10.5)(terser@5.37.0) + vite-node: 2.1.8(@types/node@22.10.5)(terser@5.37.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.10.5 + jsdom: 25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10) + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vitest@2.1.8(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0): + dependencies: + '@vitest/expect': 2.1.8 + '@vitest/mocker': 2.1.8(vite@5.4.11(@types/node@22.10.5)(terser@5.37.0)) + '@vitest/pretty-format': 2.1.8 + '@vitest/runner': 2.1.8 + '@vitest/snapshot': 2.1.8 + '@vitest/spy': 2.1.8 + '@vitest/utils': 2.1.8 chai: 5.1.2 debug: 4.4.0(supports-color@8.1.1) expect-type: 1.1.0 @@ -46608,7 +47975,7 @@ snapshots: tinypool: 1.0.2 tinyrainbow: 1.2.0 vite: 5.4.11(@types/node@22.8.4)(terser@5.37.0) - vite-node: 2.1.5(@types/node@22.8.4)(terser@5.37.0) + vite-node: 2.1.8(@types/node@22.8.4)(terser@5.37.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.8.4 @@ -46730,9 +48097,9 @@ snapshots: dependencies: web3-types: 1.10.0 - web3-eth-abi@4.4.1(typescript@5.6.3)(zod@3.24.1): + web3-eth-abi@4.4.1(typescript@5.7.2)(zod@3.24.1): dependencies: - abitype: 0.7.1(typescript@5.6.3)(zod@3.24.1) + abitype: 0.7.1(typescript@5.7.2)(zod@3.24.1) web3-errors: 1.3.1 web3-types: 1.10.0 web3-utils: 4.3.3 @@ -46751,13 +48118,13 @@ snapshots: web3-utils: 4.3.3 web3-validator: 2.0.6 - web3-eth-contract@4.7.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1): + web3-eth-contract@4.7.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1): dependencies: '@ethereumjs/rlp': 5.0.2 web3-core: 4.7.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) web3-errors: 1.3.1 - web3-eth: 4.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) - web3-eth-abi: 4.4.1(typescript@5.6.3)(zod@3.24.1) + web3-eth: 4.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) + web3-eth-abi: 4.4.1(typescript@5.7.2)(zod@3.24.1) web3-types: 1.10.0 web3-utils: 4.3.3 web3-validator: 2.0.6 @@ -46768,13 +48135,13 @@ snapshots: - utf-8-validate - zod - web3-eth-ens@4.4.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1): + web3-eth-ens@4.4.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1): dependencies: '@adraffy/ens-normalize': 1.11.0 web3-core: 4.7.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) web3-errors: 1.3.1 - web3-eth: 4.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) - web3-eth-contract: 4.7.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + web3-eth: 4.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) + web3-eth-contract: 4.7.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) web3-net: 4.1.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) web3-types: 1.10.0 web3-utils: 4.3.3 @@ -46793,10 +48160,10 @@ snapshots: web3-utils: 4.3.3 web3-validator: 2.0.6 - web3-eth-personal@4.1.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1): + web3-eth-personal@4.1.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1): dependencies: web3-core: 4.7.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - web3-eth: 4.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + web3-eth: 4.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) web3-rpc-methods: 1.3.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) web3-types: 1.10.0 web3-utils: 4.3.3 @@ -46808,12 +48175,12 @@ snapshots: - utf-8-validate - zod - web3-eth@4.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1): + web3-eth@4.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1): dependencies: setimmediate: 1.0.5 web3-core: 4.7.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) web3-errors: 1.3.1 - web3-eth-abi: 4.4.1(typescript@5.6.3)(zod@3.24.1) + web3-eth-abi: 4.4.1(typescript@5.7.2)(zod@3.24.1) web3-eth-accounts: 4.3.1 web3-net: 4.1.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) web3-providers-ws: 4.0.8(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -46839,11 +48206,11 @@ snapshots: - encoding - utf-8-validate - web3-plugin-zksync@1.0.8(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1)): + web3-plugin-zksync@1.0.8(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1)): dependencies: ethereum-cryptography: 2.2.1 - hardhat: 2.22.17(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10) - web3: 4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + hardhat: 2.22.17(bufferutil@4.0.9)(ts-node@10.9.2(@swc/core@1.10.4(@swc/helpers@0.5.15))(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)(utf-8-validate@5.0.10) + web3: 4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) transitivePeerDependencies: - bufferutil - c-kzg @@ -46932,17 +48299,17 @@ snapshots: web3-types: 1.10.0 zod: 3.23.8 - web3@4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1): + web3@4.16.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1): dependencies: web3-core: 4.7.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) web3-errors: 1.3.1 - web3-eth: 4.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) - web3-eth-abi: 4.4.1(typescript@5.6.3)(zod@3.24.1) + web3-eth: 4.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) + web3-eth-abi: 4.4.1(typescript@5.7.2)(zod@3.24.1) web3-eth-accounts: 4.3.1 - web3-eth-contract: 4.7.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) - web3-eth-ens: 4.4.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + web3-eth-contract: 4.7.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) + web3-eth-ens: 4.4.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) web3-eth-iban: 4.0.7 - web3-eth-personal: 4.1.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1) + web3-eth-personal: 4.1.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.24.1) web3-net: 4.1.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) web3-providers-http: 4.2.0(encoding@0.1.13) web3-providers-ws: 4.0.8(bufferutil@4.0.9)(utf-8-validate@5.0.10) diff --git a/scripts/jsdoc-automation/src/AIService.ts b/scripts/jsdoc-automation/src/AIService.ts deleted file mode 100644 index 1d3838aa3fd..00000000000 --- a/scripts/jsdoc-automation/src/AIService.ts +++ /dev/null @@ -1,835 +0,0 @@ -import { ChatOpenAI } from "@langchain/openai"; -import dotenv from "dotenv"; -import { - ActionMetadata, - ASTQueueItem, - EnvUsage, - OrganizedDocs, - PluginDocumentation, - TodoItem, - TodoSection, -} from "./types/index.js"; -import path from "path"; -import { promises as fs } from "fs"; -import { Configuration } from "./Configuration.js"; -import { TypeScriptParser } from "./TypeScriptParser.js"; -import { PROMPT_TEMPLATES } from "./utils/prompts.js"; - -dotenv.config(); - -interface FileDocsGroup { - filePath: string; - classes: ASTQueueItem[]; - methods: ASTQueueItem[]; - interfaces: ASTQueueItem[]; - types: ASTQueueItem[]; - functions: ASTQueueItem[]; -} - -/** - * Service for interacting with OpenAI chat API. - */ -export class AIService { - private chatModel: ChatOpenAI; - private typeScriptParser: TypeScriptParser; - - /** - * Constructor for initializing the ChatOpenAI instance. - * - * @param {Configuration} configuration - The configuration instance to be used - * @throws {Error} If OPENAI_API_KEY environment variable is not set - */ - constructor(private configuration: Configuration) { - if (!process.env.OPENAI_API_KEY) { - throw new Error("OPENAI_API_KEY is not set"); - } - this.chatModel = new ChatOpenAI({ apiKey: process.env.OPENAI_API_KEY }); - this.typeScriptParser = new TypeScriptParser(); - } - - /** - * Generates a comment based on the specified prompt by invoking the chat model. - * @param {string} prompt - The prompt for which to generate a comment - * @returns {Promise} The generated comment - */ - public async generateComment(prompt: string): Promise { - try { - // First try with generous limit - let finalPrompt = this.truncateCodeBlock(prompt, 8000); - - // Only append language instruction if not English - const normalizedLanguage = this.configuration.language - .toLowerCase() - .trim(); - if (normalizedLanguage !== "english") { - finalPrompt += `\n\nEverything except the JSDoc conventions and code should be in ${this.configuration.language}`; - } - - console.log( - `Generating comment for prompt of length: ${finalPrompt.length}` - ); - - try { - const response = await this.chatModel.invoke(finalPrompt); - return response.content as string; - } catch (error) { - if ( - error instanceof Error && - error.message.includes("maximum context length") - ) { - console.warn( - "Token limit exceeded, attempting with further truncation..." - ); - // Try with more aggressive truncation - finalPrompt = this.truncateCodeBlock(prompt, 4000); - try { - const response = - await this.chatModel.invoke(finalPrompt); - return response.content as string; - } catch (retryError) { - if ( - retryError instanceof Error && - retryError.message.includes( - "maximum context length" - ) - ) { - console.warn( - "Still exceeding token limit, using minimal context..." - ); - // Final attempt with minimal context - finalPrompt = this.truncateCodeBlock(prompt, 2000); - const response = - await this.chatModel.invoke(finalPrompt); - return response.content as string; - } - throw retryError; - } - } - throw error; - } - } catch (error) { - this.handleAPIError(error as Error); - return ""; - } - } - - public async generatePluginDocumentation({ - existingDocs, - packageJson, - todoItems, - envUsages, - }: { - existingDocs: ASTQueueItem[]; - packageJson: any; - todoItems: TodoItem[]; - envUsages: EnvUsage[]; - }): Promise { - const organizedDocs = this.organizeDocumentation(existingDocs); - - // Read the index.ts file - // Read the index.ts file - const indexPath = path.join( - this.configuration.absolutePath, - "src", - "index.ts" - ); - const exports = this.typeScriptParser.extractExports(indexPath); - - // Extract actions, providers, and evaluators from the index.ts content - // Generate documentation for actions - const actionsDocumentation = await this.generateActionsDocumentation( - exports.actions - ); - - // Generate documentation for providers - const providersDocumentation = - await this.generateProvidersDocumentation(exports.providers); - - // Generate documentation for evaluators - const evaluatorsDocumentation = - await this.generateEvaluatorsDocumentation(exports.evaluators); - - const [ - overview, - installation, - configuration, - usage, - apiRef, - troubleshooting, - todoSection, - ] = await Promise.all([ - this.generateOverview(organizedDocs, packageJson), - this.generateInstallation(packageJson), - this.generateConfiguration(envUsages), - this.generateUsage(organizedDocs, packageJson), - this.generateApiReference(organizedDocs), - this.generateTroubleshooting(organizedDocs, packageJson), - this.generateTodoSection(todoItems), - ]); - - return { - overview, - installation, - configuration, - usage, - apiReference: apiRef, - troubleshooting, - todos: todoSection.todos, - actionsDocumentation, // Added actions documentation - providersDocumentation, // Added providers documentation - evaluatorsDocumentation, // Added evaluators documentation - }; - } - - private async generateOverview( - docs: OrganizedDocs, - packageJson: any - ): Promise { - const prompt = PROMPT_TEMPLATES.overview(packageJson, docs); - try { - const overview = await this.generateComment(prompt); - return overview; - } catch (error) { - console.error("Error generating overview:", error); - return `# ${packageJson.name}\n\nNo overview available. Please check package documentation.`; - } - } - - private async generateInstallation(packageJson: any): Promise { - const indexPath = path.join( - this.configuration.absolutePath, - "src/index.ts" - ); - let mainExport = "plugin"; - let exportName = packageJson.name.split("/").pop() + "Plugin"; - - try { - const indexContent = await fs.readFile(indexPath, { - encoding: "utf8", - }); - const exportMatch = indexContent.match(/export const (\w+):/); - if (exportMatch) { - exportName = exportMatch[1]; - } - - const prompt = `Generate installation and integration instructions for this ElizaOS plugin: - - Plugin name: ${packageJson.name} - Main export: ${exportName} - Index file exports: - ${indexContent} - Dependencies: ${JSON.stringify(packageJson.dependencies || {}, null, 2)} - Peer dependencies: ${JSON.stringify(packageJson.peerDependencies || {}, null, 2)} - - This is a plugin for the ElizaOS agent system. Generate comprehensive installation instructions that include: - - 1. How to add the plugin to your ElizaOS project: - - First, explain that users need to add the following to their agent/package.json dependencies: - \`\`\`json - { - "dependencies": { - "${packageJson.name}": "workspace:*" - } - } - \`\`\` - - Then, explain they need to: - 1. cd into the agent/ directory - 2. Run pnpm install to install the new dependency - 3. Run pnpm build to build the project with the new plugin - - 2. After installation, show how to import and use the plugin: - - Import syntax using: import { ${exportName} } from "${packageJson.name}"; - - How to add it to the AgentRuntime plugins array - - 3. Integration example showing the complete setup: - \`\`\`typescript - import { ${exportName} } from "${packageJson.name}"; - - return new AgentRuntime({ - // other configuration... - plugins: [ - ${exportName}, - // other plugins... - ], - }); - \`\`\` - - 4. Verification steps to ensure successful integration - - for this step just tell the user to ensure they see ["✓ Registering action: "] in the console - - Format the response in markdown, with clear section headers and step-by-step instructions. Emphasize that this is a workspace package that needs to be added to agent/package.json and then built.`; - - return await this.generateComment(prompt); - } catch (error) { - console.error("Error reading index.ts:", error); - return this.generateBasicInstallPrompt(packageJson); - } - } - - private async generateBasicInstallPrompt( - packageJson: any - ): Promise { - console.log( - "AIService::generateInstallation threw an error, generating basic install prompt" - ); - const prompt = `Generate basic installation instructions for this ElizaOS plugin: - - Plugin name: ${packageJson.name} - Dependencies: ${JSON.stringify(packageJson.dependencies || {}, null, 2)} - Peer dependencies: ${JSON.stringify(packageJson.peerDependencies || {}, null, 2)} - - This is a plugin for the ElizaOS agent system. Include basic setup instructions.`; - - return await this.generateComment(prompt); - } - - private async generateConfiguration( - envUsages: EnvUsage[] - ): Promise { - const prompt = `Generate configuration documentation based on these environment variable usages: - ${envUsages - .map( - (item) => ` - Environment Variable: ${item.code} - Full Context: ${item.fullContext} - ` - ) - .join("\n")} - Create comprehensive configuration documentation that: - 1. Lists all required environment variables and their purpose - 2. Return a full .env example file - - Inform the user that the configuration is done in the .env file. - And to ensure the .env is set in the .gitignore file so it is not committed to the repository. - - Format the response in markdown with proper headings and code blocks.`; - - return await this.generateComment(prompt); - } - - private async generateUsage( - docs: OrganizedDocs, - packageJson: any - ): Promise { - const fileGroups = this.groupDocsByFile(docs); - const sections: string[] = []; - - // Generate documentation for each file without individual intros - for (const fileGroup of fileGroups) { - const fileDoc = await this.generateFileUsageDoc(fileGroup); - if (fileDoc.trim()) { - sections.push(fileDoc); - } - } - - return sections.join("\n\n"); - } - - private async generateApiReference(docs: OrganizedDocs): Promise { - const fileGroups = this.groupDocsByFile(docs); - const sections: string[] = []; - - for (const fileGroup of fileGroups) { - const fileDoc = await this.generateFileApiDoc(fileGroup); - if (fileDoc.trim()) { - sections.push(fileDoc); - } - } - - return sections.join("\n"); - } - - /** - * Generates troubleshooting guide based on documentation and common patterns - */ - // toDo - integrate w/ @Jin's discord scraper to pull solutions for known issues - private async generateTroubleshooting( - docs: OrganizedDocs, - packageJson: any - ): Promise { - const prompt = `${PROMPT_TEMPLATES.troubleshooting}\n\nFor package: ${packageJson.name}\n\nWith content:\n${JSON.stringify(docs, null, 2)}`; - return await this.generateComment(prompt); - } - - /** - * Generates TODO section documentation from found TODO comments - */ - // toDo - integrate w/ @Jin's discord scraper to auto create GH issues/bounties - private async generateTodoSection( - todoItems: TodoItem[] - ): Promise { - if (todoItems.length === 0) { - return { todos: "No TODO items found.", todoCount: 0 }; - } - - const prompt = `${PROMPT_TEMPLATES.todos}\n\nWith items:\n${todoItems - .map( - (item) => - `- Comment: ${item.comment}\n Context: ${item.fullContext}` - ) - .join("\n")}`; - - const todos = await this.generateComment(prompt); - return { todos, todoCount: todoItems.length }; - } - - // should be moved to utils - private organizeDocumentation(docs: ASTQueueItem[]): OrganizedDocs { - return docs.reduce( - (acc: OrganizedDocs, doc) => { - // Use nodeType to determine the category - switch (doc.nodeType) { - case "ClassDeclaration": - acc.classes.push(doc); - break; - case "MethodDefinition": - case "TSMethodSignature": - acc.methods.push(doc); - break; - case "TSInterfaceDeclaration": - acc.interfaces.push(doc); - break; - case "TSTypeAliasDeclaration": - acc.types.push(doc); - break; - case "FunctionDeclaration": - acc.functions.push(doc); - break; - } - return acc; - }, - { - classes: [], - methods: [], - interfaces: [], - types: [], - functions: [], - } - ); - } - - private async generateActionsDocumentation( - actionsFiles: string[] - ): Promise { - let documentation = ""; - - for (const file of actionsFiles) { - // Remove ./ prefix and ensure path includes src directory and .ts extension - const relativePath = file.replace(/^\.\//, ""); - const filePath = path.join( - this.configuration.absolutePath, - "src", - relativePath + ".ts" - ); - - try { - const ast = this.typeScriptParser.parse(filePath); - const bounds = this.typeScriptParser.findActionBounds(ast); - - if (!bounds) { - console.warn(`No action bounds found in ${filePath}`); - continue; - } - - const actionCode = this.typeScriptParser.extractActionCode( - filePath, - bounds - ); - - // Use PROMPT_TEMPLATES.actionDoc - const prompt = `${PROMPT_TEMPLATES.actionDoc}\n\nWith content:\n\`\`\`typescript\n${actionCode}\n\`\`\``; - - const actionDocumentation = await this.generateComment(prompt); - if (actionDocumentation.trim()) { - documentation += actionDocumentation + "\n\n"; - } - } catch (error) { - console.warn( - `Warning: Could not process action file ${filePath}:`, - error - ); - continue; - } - } - - if (!documentation.trim()) { - return "No actions documentation available."; - } - - return documentation; - } - - private async generateProvidersDocumentation( - providersFiles: string[] - ): Promise { - let documentation = ""; - - for (const file of providersFiles) { - // Remove ./ prefix and ensure path includes src directory and .ts extension - const relativePath = file.replace(/^\.\//, ""); - const filePath = path.join( - this.configuration.absolutePath, - "src", - relativePath + ".ts" - ); - - try { - const content = await fs.readFile(filePath, "utf-8"); - // Create a provider object with relevant information - const provider = { - fileName: relativePath, - content: content, - // Extract provider properties - name: relativePath.split("/").pop()?.replace(".ts", ""), - }; - - const providerDocumentation = - await this.generateProviderDoc(provider); - if (providerDocumentation.trim()) { - documentation += providerDocumentation + "\n\n"; - } - } catch (error) { - console.warn( - `Warning: Could not read provider file ${filePath}:`, - error - ); - continue; - } - } - - if (!documentation.trim()) { - return "No providers documentation available."; - } - - return documentation; - } - - private async generateEvaluatorsDocumentation( - evaluatorsFiles: string[] - ): Promise { - let documentation = ""; - - for (const file of evaluatorsFiles) { - // Remove ./ prefix and ensure path includes src directory and .ts extension - const relativePath = file.replace(/^\.\//, ""); - const filePath = path.join( - this.configuration.absolutePath, - "src", - relativePath + ".ts" - ); - - try { - const content = await fs.readFile(filePath, "utf-8"); - const prompt = `Generate documentation for the following Evaluator: - \`\`\`typescript - ${content} - \`\`\` - - Provide an overview of the evaluator's purpose and functionality. - Format in markdown without adding any additional headers.`; - - const evaluatorDocumentation = - await this.generateComment(prompt); - if (evaluatorDocumentation.trim()) { - documentation += `### ${relativePath}\n\n${evaluatorDocumentation}\n\n`; - } - } catch (error) { - console.warn( - `Warning: Could not read evaluator file ${filePath}:`, - error - ); - continue; - } - } - - if (!documentation.trim()) { - return "No evaluators documentation available."; - } - - return documentation; - } - - private groupDocsByFile(docs: OrganizedDocs): FileDocsGroup[] { - // Get unique file paths - const filePaths = new Set(); - [ - ...docs.classes, - ...docs.methods, - ...docs.interfaces, - ...docs.types, - ...docs.functions, - ].forEach((item) => filePaths.add(item.filePath)); - - // Create groups for each file path - return Array.from(filePaths).map((filePath) => { - return { - filePath, - classes: docs.classes.filter((c) => c.filePath === filePath), - methods: docs.methods.filter((m) => m.filePath === filePath), - interfaces: docs.interfaces.filter( - (i) => i.filePath === filePath - ), - types: docs.types.filter((t) => t.filePath === filePath), - functions: docs.functions.filter( - (f) => f.filePath === filePath - ), - }; - }); - } - - private formatFilePath(filePath: string): string { - // Get relative path from src directory - const srcIndex = filePath.indexOf("/src/"); - if (srcIndex === -1) return filePath; - - const relativePath = filePath.slice(srcIndex + 5); // +5 to skip '/src/' - return relativePath; - } - - private async generateFileUsageDoc( - fileGroup: FileDocsGroup - ): Promise { - const filePath = this.formatFilePath(fileGroup.filePath); - const prompt = `${PROMPT_TEMPLATES.fileUsageDoc}\n\nFor file: ${filePath}\n\nWith components:\n${this.formatComponents(fileGroup)}`; - const doc = await this.generateComment(prompt); - return `### ${filePath}\n\n${doc}`; - } - - private async generateFileApiDoc( - fileGroup: FileDocsGroup - ): Promise { - const filePath = this.formatFilePath(fileGroup.filePath); - const formattedDocs = this.formatApiComponents(fileGroup); - // Add TypeScript code block for the file path to indicate it's a TypeScript module - return formattedDocs - ? `### File: \`${filePath}\`\n${formattedDocs}` - : ""; - } - - private formatApiComponents(fileGroup: FileDocsGroup): string { - const sections: string[] = []; - - // Classes - if (fileGroup.classes.length > 0) { - sections.push("#### Classes"); - fileGroup.classes.forEach((c) => { - sections.push(`##### \`${c.name}\``); - if (c.jsDoc) sections.push(this.formatJSDoc(c.jsDoc, c.code)); - - // Add any methods belonging to this class - const classMethods = fileGroup.methods.filter( - (m) => m.className === c.name - ); - if (classMethods.length > 0) { - sections.push("**Methods:**"); - classMethods.forEach((m) => { - sections.push( - `###### \`${m.name}\`${m.jsDoc ? `\n${this.formatJSDoc(m.jsDoc, m.code)}` : ""}` - ); - }); - } - }); - } - - // Interfaces - if (fileGroup.interfaces.length > 0) { - sections.push("#### Interfaces"); - fileGroup.interfaces.forEach((i) => { - sections.push(`##### \`${i.name}\``); - if (i.jsDoc) sections.push(this.formatJSDoc(i.jsDoc, i.code)); - }); - } - - // Types - if (fileGroup.types.length > 0) { - sections.push("#### Types"); - fileGroup.types.forEach((t) => { - sections.push(`##### \`${t.name}\``); - if (t.jsDoc) sections.push(this.formatJSDoc(t.jsDoc, t.code)); - }); - } - - // Standalone Functions - if (fileGroup.functions.length > 0) { - sections.push("#### Functions"); - fileGroup.functions.forEach((f) => { - sections.push(`##### \`${f.name}\``); - if (f.jsDoc) sections.push(this.formatJSDoc(f.jsDoc, f.code)); - }); - } - - // Standalone Methods - const standaloneMethods = fileGroup.methods.filter((m) => !m.className); - if (standaloneMethods.length > 0) { - sections.push("#### Methods"); - standaloneMethods.forEach((m) => { - sections.push(`##### \`${m.name}\``); - if (m.jsDoc) sections.push(this.formatJSDoc(m.jsDoc, m.code)); - }); - } - - return sections.join("\n\n"); - } - - private formatJSDoc(jsDoc: string, code?: string): string { - // Clean up the JSDoc - let cleanDoc = jsDoc - .replace(/^```\s*\n?/gm, "") - .replace(/\n?```\s*$/gm, ""); - cleanDoc = cleanDoc.trim().replace(/\n{3,}/g, "\n\n"); - - // Format JSDoc with typescript declaration - const docSection = "```typescript\n" + cleanDoc + "\n```"; - - // If we have the actual code, include it after the JSDoc - // if (code) { - // const cleanCode = code.trim().replace(/^```\s*\n?/gm, '').replace(/\n?```\s*$/gm, ''); - // return `${docSection}\n\n**Implementation:**\n\n\`\`\`typescript\n${cleanCode}\n\`\`\``; - // } - - return docSection; - } - - private formatComponents(fileGroup: FileDocsGroup): string { - const sections: string[] = []; - - if (fileGroup.classes.length > 0) { - sections.push( - "Classes:", - fileGroup.classes - .map((c) => `- ${c.name}: ${c.jsDoc}`) - .join("\n") - ); - } - - if (fileGroup.methods.length > 0) { - sections.push( - "Methods:", - fileGroup.methods - .map((m) => `- ${m.name}: ${m.jsDoc}`) - .join("\n") - ); - } - - if (fileGroup.interfaces.length > 0) { - sections.push( - "Interfaces:", - fileGroup.interfaces - .map((i) => `- ${i.name}: ${i.jsDoc}`) - .join("\n") - ); - } - - if (fileGroup.types.length > 0) { - sections.push( - "Types:", - fileGroup.types.map((t) => `- ${t.name}: ${t.jsDoc}`).join("\n") - ); - } - - if (fileGroup.functions.length > 0) { - sections.push( - "Functions:", - fileGroup.functions - .map((f) => `- ${f.name}: ${f.jsDoc}`) - .join("\n") - ); - } - - return sections.join("\n\n"); - } - - private async generateProviderDoc(provider: any): Promise { - const prompt = `${PROMPT_TEMPLATES.providerDoc}\n\nWith content:\n${JSON.stringify(provider, null, 2)}`; - return await this.generateComment(prompt); - } - /** - * Handle API errors by logging the error message and throwing the error. - * - * - * @param {Error} error The error object to handle - * @returns {void} - */ - public handleAPIError(error: Error): void { - console.error("API Error:", error.message); - throw error; - } - - private truncateCodeBlock(code: string, maxLength: number = 8000): string { - if (code.length <= maxLength) return code; - - // Extract code blocks - const codeBlockRegex = /```[\s\S]*?```/g; - const codeBlocks = code.match(codeBlockRegex) || []; - - // If no code blocks found, truncate the text directly - if (codeBlocks.length === 0) { - return code.slice(0, maxLength) + "... (truncated)"; - } - - // Calculate maximum length per block to stay under total limit - const nonCodeLength = code.replace(codeBlockRegex, "").length; - const maxLengthPerBlock = Math.floor( - (maxLength - nonCodeLength) / codeBlocks.length - ); - - for (let i = 0; i < codeBlocks.length; i++) { - const block = codeBlocks[i]; - if (block.length > maxLengthPerBlock) { - const lines = block.split("\n"); - const header = lines[0]; // Keep the ```typescript or similar - const footer = lines[lines.length - 1]; // Keep the closing ``` - - // Calculate how many lines we can keep - const maxLinesPerSection = Math.floor( - (maxLengthPerBlock - header.length - footer.length) / 3 - ); - - // Take fewer lines but ensure we get the most important parts - const codeStart = lines.slice(1, maxLinesPerSection).join("\n"); - - // For the middle section, focus on the important parts - const middleIndex = Math.floor(lines.length / 2); - const middleStart = Math.max( - maxLinesPerSection, - middleIndex - Math.floor(maxLinesPerSection / 2) - ); - const middleEnd = Math.min( - lines.length - maxLinesPerSection, - middleIndex + Math.floor(maxLinesPerSection / 2) - ); - const codeMiddle = lines - .slice(middleStart, middleEnd) - .join("\n"); - - // Take the end section - const codeEnd = lines - .slice(lines.length - maxLinesPerSection, -1) - .join("\n"); - - const truncatedBlock = `${header}\n${codeStart}\n// ... truncated [${lines.length - maxLinesPerSection * 2} lines] ...\n${codeMiddle}\n// ... truncated ...\n${codeEnd}\n${footer}`; - code = code.replace(block, truncatedBlock); - } - } - - // Final safety check - if still too long, do a hard truncate - if (code.length > maxLength) { - const blocks = code.split("```"); - const truncatedBlocks = blocks.map((block, index) => { - // Every odd index is a code block - if (index % 2 === 1) { - const lines = block.split("\n"); - const maxLines = 10; // Keep only first few lines of each block - return ( - lines.slice(0, maxLines).join("\n") + - "\n// ... remaining code truncated ...\n" - ); - } - return block.slice(0, 500); // Limit non-code text - }); - code = truncatedBlocks.join("```"); - } - - return code; - } -} diff --git a/scripts/jsdoc-automation/src/AIService/AIService.ts b/scripts/jsdoc-automation/src/AIService/AIService.ts new file mode 100644 index 00000000000..ee6582766c0 --- /dev/null +++ b/scripts/jsdoc-automation/src/AIService/AIService.ts @@ -0,0 +1,114 @@ +import { ChatOpenAI } from "@langchain/openai"; +import dotenv from "dotenv"; +import { Configuration } from "../Configuration.js"; +import { TypeScriptParser } from "../TypeScriptParser.js"; +import { CodeFormatter } from "./utils/CodeFormatter.js"; +import { DocumentOrganizer } from "./utils/DocumentOrganizer.js"; + +dotenv.config(); + +/** + * Service for interacting with OpenAI chat API. + */ +export class AIService { + private chatModel: ChatOpenAI; + private codeFormatter: CodeFormatter; + private chatModelFAQ: ChatOpenAI; + + /** + * Constructor for initializing the ChatOpenAI instance. + * + * @param {Configuration} configuration - The configuration instance to be used + * @throws {Error} If OPENAI_API_KEY environment variable is not set + */ + constructor(private configuration: Configuration) { + if (!process.env.OPENAI_API_KEY) { + throw new Error("OPENAI_API_KEY is not set"); + } + this.chatModel = new ChatOpenAI({ apiKey: process.env.OPENAI_API_KEY }); + this.chatModelFAQ = new ChatOpenAI({ + apiKey: process.env.OPENAI_API_KEY, + model: "gpt-4o", + }); + this.codeFormatter = new CodeFormatter(); + } + + + /** + * Generates a comment based on the specified prompt by invoking the chat model. + * @param {string} prompt - The prompt for which to generate a comment + * @returns {Promise} The generated comment + */ + public async generateComment(prompt: string, isFAQ: boolean = false): Promise { + try { + // First try with generous limit + let finalPrompt = prompt; + if (!isFAQ) { + finalPrompt = this.codeFormatter.truncateCodeBlock(prompt, 8000); + } + + console.log( + `Generating comment for prompt of length: ${finalPrompt.length}` + ); + + try { + let response; + if (isFAQ) { + response = await this.chatModelFAQ.invoke(finalPrompt); + } else { + response = await this.chatModel.invoke(finalPrompt); + } + return response.content as string; + } catch (error) { + if ( + error instanceof Error && + error.message.includes("maximum context length") + ) { + console.warn( + "Token limit exceeded, attempting with further truncation..." + ); + // Try with more aggressive truncation + finalPrompt = this.codeFormatter.truncateCodeBlock(prompt, 4000); + try { + const response = + await this.chatModel.invoke(finalPrompt); + return response.content as string; + } catch (retryError) { + if ( + retryError instanceof Error && + retryError.message.includes( + "maximum context length" + ) + ) { + console.warn( + "Still exceeding token limit, using minimal context..." + ); + // Final attempt with minimal context + finalPrompt = this.codeFormatter.truncateCodeBlock(prompt, 2000); + const response = + await this.chatModel.invoke(finalPrompt); + return response.content as string; + } + throw retryError; + } + } + throw error; + } + } catch (error) { + this.handleAPIError(error as Error); + return ""; + } + } + + /** + * Handle API errors by logging the error message and throwing the error. + * + * + * @param {Error} error The error object to handle + * @returns {void} + */ + public handleAPIError(error: Error): void { + console.error("API Error:", error.message); + throw error; + } +} diff --git a/scripts/jsdoc-automation/src/AIService/generators/FullDocumentationGenerator.ts b/scripts/jsdoc-automation/src/AIService/generators/FullDocumentationGenerator.ts new file mode 100644 index 00000000000..2adc503f643 --- /dev/null +++ b/scripts/jsdoc-automation/src/AIService/generators/FullDocumentationGenerator.ts @@ -0,0 +1,520 @@ +import { ASTQueueItem, EnvUsage, PluginDocumentation, TodoItem, TodoSection } from "../../types"; +import { Configuration } from "../../Configuration.js"; +import { TypeScriptParser } from "../../TypeScriptParser.js"; +import { CodeFormatter } from "../utils/CodeFormatter.js"; +import { DocumentOrganizer } from "../utils/DocumentOrganizer.js"; +import path from "path"; +import { PROMPT_TEMPLATES } from "../../utils/prompts"; +import { FileDocsGroup, OrganizedDocs } from "../types"; +import { AIService } from "../AIService.js"; +import { promises as fs } from "fs"; + +interface FAQ { + question: string; + answer: string; +} + +interface TroubleshootingIssue { + issue: string; + cause: string; + solution: string; +} + +interface Troubleshooting { + commonIssues: TroubleshootingIssue[]; + debuggingTips: string[]; +} + +export class FullDocumentationGenerator { + private typeScriptParser: TypeScriptParser; + private codeFormatter: CodeFormatter; + private documentOrganizer: DocumentOrganizer; + private aiService: AIService; + + /** + * Constructor for initializing the ChatOpenAI instance. + * + * @param {Configuration} configuration - The configuration instance to be used + * @throws {Error} If OPENAI_API_KEY environment variable is not set + */ + constructor(private configuration: Configuration) { + this.typeScriptParser = new TypeScriptParser(); + this.codeFormatter = new CodeFormatter(); + this.documentOrganizer = new DocumentOrganizer(); + this.aiService = new AIService(configuration); + } + + public async generatePluginDocumentation({ + existingDocs, + packageJson, + todoItems, + envUsages, + }: { + existingDocs: ASTQueueItem[]; + packageJson: any; + todoItems: TodoItem[]; + envUsages: EnvUsage[]; + }): Promise { + const organizedDocs = this.documentOrganizer.organizeDocumentation(existingDocs); + const organizedDocsPath = path.join(this.configuration.absolutePath, "organizedDocs.json"); + await fs.writeFile(organizedDocsPath, JSON.stringify(organizedDocs, null, 2)); + + const indexPath = path.join( + this.configuration.absolutePath, + "src", + "index.ts" + ); + const exports = this.typeScriptParser.extractExports(indexPath); + + const actionsDocumentation = await this.generateActionsDocumentation( + exports.actions + ); + const providersDocumentation = await this.generateProvidersDocumentation(exports.providers); + const evaluatorsDocumentation = await this.generateEvaluatorsDocumentation(exports.evaluators); + + // Generate overview, FAQ, and troubleshooting together + const overviewResponse = await this.generateOverview(organizedDocs, packageJson); + const parsedOverview = JSON.parse(overviewResponse); + + const [ + installation, + configuration, + usage, + apiRef, + todoSection, + ] = await Promise.all([ + this.generateInstallation(packageJson), + this.generateConfiguration(envUsages), + this.generateUsage(organizedDocs, packageJson), + this.generateApiReference(organizedDocs), + this.generateTodoSection(todoItems), + ]); + + // Format the FAQ and troubleshooting sections + const formattedFAQ = this.formatFAQSection(parsedOverview.faq); + const formattedTroubleshooting = this.formatTroubleshootingSection(parsedOverview.troubleshooting); + + return { + overview: this.formatOverviewSection(parsedOverview.overview), + installation, + configuration, + usage, + apiReference: apiRef, + troubleshooting: formattedTroubleshooting, + faq: formattedFAQ, + todos: todoSection.todos, + actionsDocumentation, + providersDocumentation, + evaluatorsDocumentation, + }; + } + + private formatOverviewSection(overview: any): string { + return `### Purpose\n${overview.purpose}\n\n### Key Features\n${overview.keyFeatures}`; + } + + private formatFAQSection(faq: FAQ[]): string { + if (!Array.isArray(faq)) { + console.warn('FAQ data is not an array, returning empty string'); + return ''; + } + + return faq + .filter(item => item.question && item.answer) // Filter out invalid items + .map(item => `### Q: ${item.question}\n${item.answer}`) + .join('\n\n'); + } + + private formatTroubleshootingSection(troubleshooting: Troubleshooting): string { + if (!troubleshooting?.commonIssues || !troubleshooting?.debuggingTips) { + console.warn('Troubleshooting data is missing required fields, returning empty string'); + return ''; + } + const issues = troubleshooting.commonIssues + .filter((issue: { issue: string; cause: string; solution: string }) => issue.issue && issue.cause && issue.solution) + .map((issue: { issue: string; cause: string; solution: string }) => `### ${issue.issue}\n- Cause: ${issue.cause}\n- Solution: ${issue.solution}`) + .join('\n\n'); + + const tips = troubleshooting.debuggingTips.length > 0 + ? `### Debugging Tips\n${troubleshooting.debuggingTips.map(tip => `- ${tip}`).join('\n')}` + : ''; + + return issues + (tips ? `\n\n${tips}` : ''); + } + + private async generateOverview( + docs: OrganizedDocs, + packageJson: any + ): Promise { + const prompt = PROMPT_TEMPLATES.overview(packageJson, docs); + try { + const overview = await this.aiService.generateComment(prompt, true); + return this.cleanJSONResponse(overview); + } catch (error) { + console.error("Error generating overview:", error); + return `# ${packageJson.name}\n\nNo overview available. Please check package documentation.`; + } + } + + private cleanJSONResponse(response: string): string { + // Remove markdown code block syntax if present + return response + .replace(/^```json\n/, '') // Remove opening ```json + .replace(/\n```$/, '') // Remove closing ``` + .trim(); // Remove any extra whitespace + } + + private async generateInstallation(packageJson: any): Promise { + const indexPath = path.join( + this.configuration.absolutePath, + "src/index.ts" + ); + let mainExport = "plugin"; + let exportName = packageJson.name.split("/").pop() + "Plugin"; + + try { + const indexContent = await fs.readFile(indexPath, { + encoding: "utf8", + }); + const exportMatch = indexContent.match(/export const (\w+):/); + if (exportMatch) { + exportName = exportMatch[1]; + } + + const prompt = `Generate installation and integration instructions for this ElizaOS plugin: + + Plugin name: ${packageJson.name} + Main export: ${exportName} + Index file exports: + ${indexContent} + Dependencies: ${JSON.stringify(packageJson.dependencies || {}, null, 2)} + Peer dependencies: ${JSON.stringify(packageJson.peerDependencies || {}, null, 2)} + + This is a plugin for the ElizaOS agent system. Generate comprehensive installation instructions that include: + + 1. How to add the plugin to your ElizaOS project: + - First, explain that users need to add the following to their agent/package.json dependencies: + \`\`\`json + { + "dependencies": { + "${packageJson.name}": "workspace:*" + } + } + \`\`\` + - Then, explain they need to: + 1. cd into the agent/ directory + 2. Run pnpm install to install the new dependency + 3. Run pnpm build to build the project with the new plugin + + 2. After installation, show how to import and use the plugin: + - Import syntax using: import { ${exportName} } from "${packageJson.name}"; + - How to add it to the AgentRuntime plugins array + + 3. Integration example showing the complete setup: + \`\`\`typescript + import { ${exportName} } from "${packageJson.name}"; + + return new AgentRuntime({ + // other configuration... + plugins: [ + ${exportName}, + // other plugins... + ], + }); + \`\`\` + + 4. Verification steps to ensure successful integration + - for this step just tell the user to ensure they see ["✓ Registering action: "] in the console + + Format the response in markdown, with clear section headers and step-by-step instructions. Emphasize that this is a workspace package that needs to be added to agent/package.json and then built.`; + + return await this.aiService.generateComment(prompt); + } catch (error) { + console.error("Error reading index.ts:", error); + return this.generateBasicInstallPrompt(packageJson); + } + } + + private async generateBasicInstallPrompt( + packageJson: any + ): Promise { + console.log( + "AIService::generateInstallation threw an error, generating basic install prompt" + ); + const prompt = `Generate basic installation instructions for this ElizaOS plugin: + + Plugin name: ${packageJson.name} + Dependencies: ${JSON.stringify(packageJson.dependencies || {}, null, 2)} + Peer dependencies: ${JSON.stringify(packageJson.peerDependencies || {}, null, 2)} + + This is a plugin for the ElizaOS agent system. Include basic setup instructions.`; + + return await this.aiService.generateComment(prompt); + } + + private async generateConfiguration( + envUsages: EnvUsage[] + ): Promise { + const prompt = `Generate configuration documentation based on these environment variable usages: + ${envUsages + .map( + (item) => ` + Environment Variable: ${item.code} + Full Context: ${item.fullContext} + ` + ) + .join("\n")} + Create comprehensive configuration documentation that: + 1. Lists all required environment variables and their purpose + 2. Return a full .env example file + + Inform the user that the configuration is done in the .env file. + And to ensure the .env is set in the .gitignore file so it is not committed to the repository. + + Format the response in markdown with proper headings and code blocks.`; + + return await this.aiService.generateComment(prompt); + } + + private async generateUsage( + docs: OrganizedDocs, + packageJson: any + ): Promise { + const fileGroups = this.documentOrganizer.groupDocsByFile(docs); + // write fileGroups to a json file + const fileGroupsPath = path.join(this.configuration.absolutePath, "fileGroups.json"); + await fs.writeFile(fileGroupsPath, JSON.stringify(fileGroups, null, 2)); + const sections: string[] = []; + + // Generate documentation for each file without individual intros + for (const fileGroup of fileGroups) { + const fileDoc = await this.generateFileUsageDoc(fileGroup); + if (fileDoc.trim()) { + sections.push(fileDoc); + } + } + + return sections.join("\n\n"); + } + + private async generateApiReference(docs: OrganizedDocs): Promise { + const fileGroups = this.documentOrganizer.groupDocsByFile(docs); + const sections: string[] = []; + + for (const fileGroup of fileGroups) { + const fileDoc = await this.generateFileApiDoc(fileGroup); + if (fileDoc.trim()) { + sections.push(fileDoc); + } + } + + return sections.join("\n"); + } + + /** + * Generates troubleshooting guide based on documentation and common patterns + */ + // toDo - integrate w/ @Jin's discord scraper to pull solutions for known issues + private async generateTroubleshooting( + docs: OrganizedDocs, + packageJson: any + ): Promise { + const prompt = `${PROMPT_TEMPLATES.troubleshooting}\n\nFor package: ${packageJson.name}\n\nWith content:\n${JSON.stringify(docs, null, 2)}`; + return await this.aiService.generateComment(prompt); + } + + private async generateFileUsageDoc( + fileGroup: FileDocsGroup + ): Promise { + const filePath = this.codeFormatter.formatFilePath(fileGroup.filePath); + const prompt = `${PROMPT_TEMPLATES.fileUsageDoc}\n\nFor file: ${filePath}\n\nWith components:\n${this.codeFormatter.formatComponents(fileGroup)}`; + const doc = await this.aiService.generateComment(prompt); + return `### ${filePath}\n\n${doc}`; + } + + private async generateFileApiDoc( + fileGroup: FileDocsGroup + ): Promise { + const filePath = this.codeFormatter.formatFilePath(fileGroup.filePath); + const formattedDocs = this.codeFormatter.formatApiComponents(fileGroup); + // Add TypeScript code block for the file path to indicate it's a TypeScript module + return formattedDocs + ? `### File: \`${filePath}\`\n${formattedDocs}` + : ""; + } + + private async generateProviderDoc(provider: any): Promise { + const prompt = `${PROMPT_TEMPLATES.providerDoc}\n\nWith content:\n${JSON.stringify(provider, null, 2)}`; + return await this.aiService.generateComment(prompt); + } + + /** + * Generates TODO section documentation from found TODO comments + */ + // toDo - integrate w/ @Jin's discord scraper to auto create GH issues/bounties + private async generateTodoSection( + todoItems: TodoItem[] + ): Promise { + if (todoItems.length === 0) { + return { todos: "No TODO items found.", todoCount: 0 }; + } + + const prompt = `${PROMPT_TEMPLATES.todos}\n\nWith items:\n${todoItems + .map( + (item) => + `- Comment: ${item.comment}\n Context: ${item.fullContext}` + ) + .join("\n")}`; + + const todos = await this.aiService.generateComment(prompt); + return { todos, todoCount: todoItems.length }; + } + + private resolveTypeScriptFilePath(file: string): string { + // Remove leading ./ if present + const relativePath = file.replace(/^\.\//, ""); + + // Ensure the path has .ts extension + const pathWithExtension = this.codeFormatter.ensureTypeScriptExtension(relativePath); + + // Join with the absolute path and src directory + return path.join( + this.configuration.absolutePath, + "src", + pathWithExtension + ); + } + + /////////////////////////////// + /// Eliza Specific Constructs// + /////////////////////////////// + + private async generateActionsDocumentation( + actionsFiles: string[] + ): Promise { + let documentation = ""; + + for (const file of actionsFiles) { + // Remove ./ prefix and ensure path includes src directory and .ts extension + const filePath = this.resolveTypeScriptFilePath(file); + + try { + const ast = this.typeScriptParser.parse(filePath); + const bounds = this.typeScriptParser.findActionBounds(ast); + + if (!bounds) { + console.warn(`No action bounds found in ${filePath}`); + continue; + } + + const actionCode = this.typeScriptParser.extractActionCode( + filePath, + bounds + ); + + // Use PROMPT_TEMPLATES.actionDoc + const prompt = `${PROMPT_TEMPLATES.actionDoc}\n\nWith content:\n\`\`\`typescript\n${actionCode}\n\`\`\``; + + const actionDocumentation = await this.aiService.generateComment(prompt); + if (actionDocumentation.trim()) { + documentation += actionDocumentation + "\n\n"; + } + } catch (error) { + console.warn( + `Warning: Could not process action file ${filePath}:`, + error + ); + continue; + } + } + + if (!documentation.trim()) { + return "No actions documentation available."; + } + + return documentation; + } + + private async generateProvidersDocumentation( + providersFiles: string[] + ): Promise { + let documentation = ""; + + for (const file of providersFiles) { + // Remove ./ prefix and ensure path includes src directory and .ts extension + const relativePath = file.replace(/^\.\//, ""); + const filePath = this.resolveTypeScriptFilePath(file); + + try { + const content = await fs.readFile(filePath, "utf-8"); + // Create a provider object with relevant information + const provider = { + fileName: relativePath, + content: content, + // Extract provider properties + name: relativePath.split("/").pop()?.replace(".ts", ""), + }; + + const providerDocumentation = + await this.generateProviderDoc(provider); + if (providerDocumentation.trim()) { + documentation += providerDocumentation + "\n\n"; + } + } catch (error) { + console.warn( + `Warning: Could not read provider file ${filePath}:`, + error + ); + continue; + } + } + + if (!documentation.trim()) { + return "No providers documentation available."; + } + + return documentation; + } + + private async generateEvaluatorsDocumentation( + evaluatorsFiles: string[] + ): Promise { + let documentation = ""; + + for (const file of evaluatorsFiles) { + // Remove ./ prefix and ensure path includes src directory and .ts extension + const relativePath = file.replace(/^\.\//, ""); + const filePath = this.resolveTypeScriptFilePath(file); + + try { + const content = await fs.readFile(filePath, "utf-8"); + const prompt = `Generate documentation for the following Evaluator: + \`\`\`typescript + ${content} + \`\`\` + + Provide an overview of the evaluator's purpose and functionality. + + Format in markdown without adding any additional headers.`; + + const evaluatorDocumentation = + await this.aiService.generateComment(prompt); + if (evaluatorDocumentation.trim()) { + documentation += `### ${relativePath}\n\n${evaluatorDocumentation}\n\n`; + } + } catch (error) { + console.warn( + `Warning: Could not read evaluator file ${filePath}:`, + error + ); + continue; + } + } + + if (!documentation.trim()) { + return "No evaluators documentation available."; + } + + return documentation; + } +} \ No newline at end of file diff --git a/scripts/jsdoc-automation/src/AIService/index.ts b/scripts/jsdoc-automation/src/AIService/index.ts new file mode 100644 index 00000000000..bd9948075a4 --- /dev/null +++ b/scripts/jsdoc-automation/src/AIService/index.ts @@ -0,0 +1,2 @@ +export * from './AIService.js'; +export * from './types'; \ No newline at end of file diff --git a/scripts/jsdoc-automation/src/AIService/types/index.ts b/scripts/jsdoc-automation/src/AIService/types/index.ts new file mode 100644 index 00000000000..060c2fffb56 --- /dev/null +++ b/scripts/jsdoc-automation/src/AIService/types/index.ts @@ -0,0 +1,19 @@ +import { ASTQueueItem } from "../../types"; + +export interface FileDocsGroup { + filePath: string; + classes: ASTQueueItem[]; + methods: ASTQueueItem[]; + interfaces: ASTQueueItem[]; + types: ASTQueueItem[]; + functions: ASTQueueItem[]; +} + +export interface OrganizedDocs { + classes: ASTQueueItem[]; + methods: ASTQueueItem[]; + interfaces: ASTQueueItem[]; + types: ASTQueueItem[]; + functions: ASTQueueItem[]; + variables: ASTQueueItem[]; +} diff --git a/scripts/jsdoc-automation/src/AIService/utils/CodeFormatter.ts b/scripts/jsdoc-automation/src/AIService/utils/CodeFormatter.ts new file mode 100644 index 00000000000..6fb7cfac9d3 --- /dev/null +++ b/scripts/jsdoc-automation/src/AIService/utils/CodeFormatter.ts @@ -0,0 +1,234 @@ +import { FileDocsGroup } from "../types"; + +export class CodeFormatter { + + public ensureTypeScriptExtension(filePath: string): string { + // If the path already ends with .ts, return it as is + if (filePath.endsWith('.ts')) { + return filePath; + } + // Otherwise, append .ts + return `${filePath}.ts`; + } + + public formatApiComponents(fileGroup: FileDocsGroup): string { + const sections: string[] = []; + + // Classes + if (fileGroup.classes.length > 0) { + sections.push("#### Classes"); + fileGroup.classes.forEach((c) => { + sections.push(`##### \`${c.name}\``); + if (c.jsDoc) sections.push(this.formatJSDoc(c.jsDoc, c.code)); + + // Add any methods belonging to this class + const classMethods = fileGroup.methods.filter( + (m) => m.className === c.name + ); + if (classMethods.length > 0) { + sections.push("**Methods:**"); + classMethods.forEach((m) => { + sections.push( + `###### \`${m.name}\`${m.jsDoc ? `\n${this.formatJSDoc(m.jsDoc, m.code)}` : ""}` + ); + }); + } + }); + } + + // Interfaces + if (fileGroup.interfaces.length > 0) { + sections.push("#### Interfaces"); + fileGroup.interfaces.forEach((i) => { + sections.push(`##### \`${i.name}\``); + if (i.jsDoc) sections.push(this.formatJSDoc(i.jsDoc, i.code)); + }); + } + + // Types + if (fileGroup.types.length > 0) { + sections.push("#### Types"); + fileGroup.types.forEach((t) => { + sections.push(`##### \`${t.name}\``); + if (t.jsDoc) sections.push(this.formatJSDoc(t.jsDoc, t.code)); + }); + } + + // Standalone Functions + if (fileGroup.functions.length > 0) { + sections.push("#### Functions"); + fileGroup.functions.forEach((f) => { + sections.push(`##### \`${f.name}\``); + if (f.jsDoc) sections.push(this.formatJSDoc(f.jsDoc, f.code)); + }); + } + + // Standalone Methods + const standaloneMethods = fileGroup.methods.filter((m) => !m.className); + if (standaloneMethods.length > 0) { + sections.push("#### Methods"); + standaloneMethods.forEach((m) => { + sections.push(`##### \`${m.name}\``); + if (m.jsDoc) sections.push(this.formatJSDoc(m.jsDoc, m.code)); + }); + } + + return sections.join("\n\n"); + } + + public formatComponents(fileGroup: FileDocsGroup): string { + const sections: string[] = []; + + if (fileGroup.classes.length > 0) { + sections.push( + "Classes:", + fileGroup.classes + .map((c) => `- ${c.name}: ${c.jsDoc}`) + .join("\n") + ); + } + + if (fileGroup.methods.length > 0) { + sections.push( + "Methods:", + fileGroup.methods + .map((m) => `- ${m.name}: ${m.jsDoc}`) + .join("\n") + ); + } + + if (fileGroup.interfaces.length > 0) { + sections.push( + "Interfaces:", + fileGroup.interfaces + .map((i) => `- ${i.name}: ${i.jsDoc}`) + .join("\n") + ); + } + + if (fileGroup.types.length > 0) { + sections.push( + "Types:", + fileGroup.types.map((t) => `- ${t.name}: ${t.jsDoc}`).join("\n") + ); + } + + if (fileGroup.functions.length > 0) { + sections.push( + "Functions:", + fileGroup.functions + .map((f) => `- ${f.name}: ${f.jsDoc}`) + .join("\n") + ); + } + + return sections.join("\n\n"); + } + + + public formatFilePath(filePath: string): string { + // Get relative path from src directory + const srcIndex = filePath.indexOf("/src/"); + if (srcIndex === -1) return filePath; + + const relativePath = filePath.slice(srcIndex + 5); // +5 to skip '/src/' + return relativePath; + } + + public formatJSDoc(jsDoc: string, code?: string): string { + // Clean up the JSDoc + let cleanDoc = jsDoc + .replace(/^```\s*\n?/gm, "") + .replace(/\n?```\s*$/gm, ""); + cleanDoc = cleanDoc.trim().replace(/\n{3,}/g, "\n\n"); + + // Format JSDoc with typescript declaration + const docSection = "```typescript\n" + cleanDoc + "\n```"; + + // If we have the actual code, include it after the JSDoc + // if (code) { + // const cleanCode = code.trim().replace(/^```\s*\n?/gm, '').replace(/\n?```\s*$/gm, ''); + // return `${docSection}\n\n**Implementation:**\n\n\`\`\`typescript\n${cleanCode}\n\`\`\``; + // } + + return docSection; + } + + public truncateCodeBlock(code: string, maxLength: number = 8000): string { + if (code.length <= maxLength) return code; + + // Extract code blocks + const codeBlockRegex = /```[\s\S]*?```/g; + const codeBlocks = code.match(codeBlockRegex) || []; + + // If no code blocks found, truncate the text directly + if (codeBlocks.length === 0) { + return code.slice(0, maxLength) + "... (truncated)"; + } + + // Calculate maximum length per block to stay under total limit + const nonCodeLength = code.replace(codeBlockRegex, "").length; + const maxLengthPerBlock = Math.floor( + (maxLength - nonCodeLength) / codeBlocks.length + ); + + for (let i = 0; i < codeBlocks.length; i++) { + const block = codeBlocks[i]; + if (block.length > maxLengthPerBlock) { + const lines = block.split("\n"); + const header = lines[0]; // Keep the ```typescript or similar + const footer = lines[lines.length - 1]; // Keep the closing ``` + + // Calculate how many lines we can keep + const maxLinesPerSection = Math.floor( + (maxLengthPerBlock - header.length - footer.length) / 3 + ); + + // Take fewer lines but ensure we get the most important parts + const codeStart = lines.slice(1, maxLinesPerSection).join("\n"); + + // For the middle section, focus on the important parts + const middleIndex = Math.floor(lines.length / 2); + const middleStart = Math.max( + maxLinesPerSection, + middleIndex - Math.floor(maxLinesPerSection / 2) + ); + const middleEnd = Math.min( + lines.length - maxLinesPerSection, + middleIndex + Math.floor(maxLinesPerSection / 2) + ); + const codeMiddle = lines + .slice(middleStart, middleEnd) + .join("\n"); + + // Take the end section + const codeEnd = lines + .slice(lines.length - maxLinesPerSection, -1) + .join("\n"); + + const truncatedBlock = `${header}\n${codeStart}\n// ... truncated [${lines.length - maxLinesPerSection * 2} lines] ...\n${codeMiddle}\n// ... truncated ...\n${codeEnd}\n${footer}`; + code = code.replace(block, truncatedBlock); + } + } + + // Final safety check - if still too long, do a hard truncate + if (code.length > maxLength) { + const blocks = code.split("```"); + const truncatedBlocks = blocks.map((block, index) => { + // Every odd index is a code block + if (index % 2 === 1) { + const lines = block.split("\n"); + const maxLines = 10; // Keep only first few lines of each block + return ( + lines.slice(0, maxLines).join("\n") + + "\n// ... remaining code truncated ...\n" + ); + } + return block.slice(0, 500); // Limit non-code text + }); + code = truncatedBlocks.join("```"); + } + + return code; + } +} \ No newline at end of file diff --git a/scripts/jsdoc-automation/src/AIService/utils/DocumentOrganizer.ts b/scripts/jsdoc-automation/src/AIService/utils/DocumentOrganizer.ts new file mode 100644 index 00000000000..9b0c78c00de --- /dev/null +++ b/scripts/jsdoc-automation/src/AIService/utils/DocumentOrganizer.ts @@ -0,0 +1,76 @@ +import { ASTQueueItem } from "../../types"; +import { FileDocsGroup, OrganizedDocs } from "../types"; + +export class DocumentOrganizer { + + public organizeDocumentation(docs: ASTQueueItem[]): OrganizedDocs { + return docs.reduce( + (acc: OrganizedDocs, doc) => { + // Use nodeType to determine the category + switch (doc.nodeType) { + case "ClassDeclaration": + acc.classes.push(doc); + break; + case "MethodDefinition": + case "TSMethodSignature": + acc.methods.push(doc); + break; + case "TSInterfaceDeclaration": + acc.interfaces.push(doc); + break; + case "TSTypeAliasDeclaration": + acc.types.push(doc); + break; + case "FunctionDeclaration": + acc.functions.push(doc); + break; + case "VariableDeclaration": + acc.variables.push(doc); + break; + } + return acc; + }, + { + classes: [], + methods: [], + interfaces: [], + types: [], + functions: [], + variables: [], + } + ); + } + + public groupDocsByFile(docs: OrganizedDocs): FileDocsGroup[] { + // Get unique file paths + const filePaths = new Set(); + [ + ...docs.classes, + ...docs.methods, + ...docs.interfaces, + ...docs.types, + ...docs.functions, + ...docs.variables, + ].forEach((item) => filePaths.add(item.filePath)); + + // Create groups for each file path + return Array.from(filePaths).map((filePath) => { + return { + filePath, + classes: docs.classes.filter((c) => c.filePath === filePath), + methods: docs.methods.filter((m) => m.filePath === filePath), + interfaces: docs.interfaces.filter( + (i) => i.filePath === filePath + ), + types: docs.types.filter((t) => t.filePath === filePath), + functions: docs.functions.filter( + (f) => f.filePath === filePath + ), + variables: docs.variables.filter( + (v) => v.filePath === filePath + ), + }; + }); + } + +} diff --git a/scripts/jsdoc-automation/src/Configuration.ts b/scripts/jsdoc-automation/src/Configuration.ts index c8f2dd3dcc9..f8f4de5803d 100644 --- a/scripts/jsdoc-automation/src/Configuration.ts +++ b/scripts/jsdoc-automation/src/Configuration.ts @@ -29,7 +29,6 @@ interface ConfigurationData { excludedFiles: string[]; generateJsDoc: boolean; generateReadme: boolean; - language: string; } /** @@ -40,9 +39,8 @@ export class Configuration implements Omit { private _rootDirectory!: ConfigurationData["rootDirectory"]; private readonly repoRoot: string; private _branch: string = "develop"; - private _language: string = "English"; private _generateJsDoc: boolean = true; - private _generateReadme: boolean = true; + private _generateReadme: boolean = false; public excludedDirectories: string[] = []; public repository: Repository = { @@ -63,14 +61,6 @@ export class Configuration implements Omit { this.loadConfiguration(); } - get language(): string { - return this._language; - } - - set language(value: string) { - this._language = value; - } - get generateJsDoc(): boolean { return this._generateJsDoc; } @@ -109,8 +99,6 @@ export class Configuration implements Omit { private loadConfiguration(): void { // First try to get from environment variables - this._language = process.env.INPUT_LANGUAGE || "English"; - console.log("Using language:", this._language); const rootDirectory = process.env.INPUT_ROOT_DIRECTORY; this._generateJsDoc = process.env.INPUT_JSDOC ? process.env.INPUT_JSDOC.toUpperCase() === "T" diff --git a/scripts/jsdoc-automation/src/DocumentationGenerator.ts b/scripts/jsdoc-automation/src/DocumentationGenerator.ts index be8b1416e07..275019f516a 100644 --- a/scripts/jsdoc-automation/src/DocumentationGenerator.ts +++ b/scripts/jsdoc-automation/src/DocumentationGenerator.ts @@ -14,7 +14,7 @@ import { GitManager } from "./GitManager.js"; import fs from "fs"; import { Configuration } from "./Configuration.js"; import path from "path"; -import { AIService } from "./AIService.js"; +import { AIService } from "./AIService/AIService.js"; import { PluginDocumentationGenerator } from "./PluginDocumentationGenerator.js"; import { JSDocValidator } from "./JSDocValidator.js"; diff --git a/scripts/jsdoc-automation/src/JSDocValidator.ts b/scripts/jsdoc-automation/src/JSDocValidator.ts index 85a47d56ef3..fdba99b8e6e 100644 --- a/scripts/jsdoc-automation/src/JSDocValidator.ts +++ b/scripts/jsdoc-automation/src/JSDocValidator.ts @@ -1,5 +1,5 @@ import { parse, ParserOptions } from "@typescript-eslint/parser"; -import { AIService } from "./AIService.js"; +import { AIService } from "./AIService/AIService.js"; export class JSDocValidator { private parserOptions: ParserOptions = { diff --git a/scripts/jsdoc-automation/src/JsDocAnalyzer.ts b/scripts/jsdoc-automation/src/JsDocAnalyzer.ts index cadb9ba46f7..4915ece1869 100644 --- a/scripts/jsdoc-automation/src/JsDocAnalyzer.ts +++ b/scripts/jsdoc-automation/src/JsDocAnalyzer.ts @@ -1,7 +1,6 @@ import type { TSESTree } from "@typescript-eslint/types"; import { TypeScriptParser } from "./TypeScriptParser.js"; import { ASTQueueItem, EnvUsage, TodoItem } from "./types/index.js"; -import { ASTQueueItem, EnvUsage, TodoItem } from "./types/index.js"; type AST_NODE_TYPES = { ClassDeclaration: "ClassDeclaration"; @@ -14,6 +13,7 @@ type AST_NODE_TYPES = { TSPropertySignature: "TSPropertySignature"; ExportNamedDeclaration: "ExportNamedDeclaration"; Identifier: "Identifier"; + VariableDeclaration: "VariableDeclaration"; }; const AST_NODE_TYPES = { @@ -27,6 +27,7 @@ const AST_NODE_TYPES = { TSPropertySignature: "TSPropertySignature", ExportNamedDeclaration: "ExportNamedDeclaration", Identifier: "Identifier", + VariableDeclaration: "VariableDeclaration", } as const; type DocumentableNodeType = @@ -37,7 +38,8 @@ type DocumentableNodeType = | "MethodDefinition" | "TSMethodSignature" | "TSInterfaceDeclaration" - | "TSPropertySignature"; + | "TSPropertySignature" + | "VariableDeclaration"; interface Location { start: number; @@ -57,8 +59,57 @@ export class JsDocAnalyzer { AST_NODE_TYPES.TSMethodSignature, AST_NODE_TYPES.TSPropertySignature, AST_NODE_TYPES.TSInterfaceDeclaration, + AST_NODE_TYPES.VariableDeclaration, ]); + /** + * Type guard to check if a node is a VariableDeclaration + */ + private isVariableDeclaration(node: TSESTree.Node): node is TSESTree.VariableDeclaration { + return node.type === 'VariableDeclaration'; + } + + /** + * Checks if a node is a const declaration + */ + private isConstDeclaration(node: TSESTree.Node): boolean { + return this.isVariableDeclaration(node) && node.kind === 'const'; + } + + /** + * Checks if a node spans more than the specified number of lines + */ + private isLongEnough(node: TSESTree.Node, minLines: number = 10): boolean { + if (!node.loc) return false; + return (node.loc.end.line - node.loc.start.line) > minLines; + } + + /** + * Checks if a node is an export declaration + */ + private isExportDeclaration(node: TSESTree.Node): node is TSESTree.ExportNamedDeclaration { + return node.type === 'ExportNamedDeclaration'; + } + + /** + * Checks if a variable declaration is a significant constant + * @param node The variable declaration node to check + * @returns True if the node is an exported constant with significant complexity + */ + private isSignificantConstant(node: TSESTree.VariableDeclaration): boolean { + // Must be const declaration + if (node.kind !== 'const') return false; + + // Must be exported + const parent = node.parent; + if (!parent || !this.isExportNamedDeclaration(parent)) return false; + + // Must span multiple lines (at least 10) + if (!node.loc) return false; + const lineCount = node.loc.end.line - node.loc.start.line; + return lineCount >= 10; + } + /** * Type guard to check if a node is a ClassDeclaration */ @@ -151,6 +202,14 @@ export class JsDocAnalyzer { private getNodeName(node: TSESTree.Node): string | undefined { const actualNode = this.getActualNode(node); + // Handle variable declarations (constants) + if (this.isVariableDeclaration(actualNode) && actualNode.declarations.length > 0) { + const declaration = actualNode.declarations[0]; + if (this.isIdentifier(declaration.id)) { + return declaration.id.name; + } + } + if (this.isMethodDefinition(actualNode)) { return this.getMethodName(actualNode); } @@ -238,6 +297,17 @@ export class JsDocAnalyzer { */ public shouldHaveJSDoc(node: TSESTree.Node): boolean { const actualNode = this.getActualNode(node); + + // Special handling for const declarations + if (this.isConstDeclaration(actualNode)) { + return this.isLongEnough(actualNode); + } + + // Handle export const declarations + if (this.isExportDeclaration(node) && node.declaration && this.isConstDeclaration(node.declaration)) { + return this.isLongEnough(node.declaration); + } + return this.documentableTypes.has( actualNode.type as DocumentableNodeType ); diff --git a/scripts/jsdoc-automation/src/JsDocGenerator.ts b/scripts/jsdoc-automation/src/JsDocGenerator.ts index 5dd44439314..164c8cc9285 100644 --- a/scripts/jsdoc-automation/src/JsDocGenerator.ts +++ b/scripts/jsdoc-automation/src/JsDocGenerator.ts @@ -1,4 +1,4 @@ -import { AIService } from "./AIService.js"; +import { AIService } from "./AIService/AIService.js"; import { ASTQueueItem } from "./types/index.js"; /** @@ -50,7 +50,7 @@ export class JsDocGenerator { \`\`\`typescript ${queueItem.code} \`\`\` - + Only return the JSDoc comment, not the code itself. `; } @@ -61,7 +61,7 @@ export class JsDocGenerator { Class name: ${queueItem.code.match(/class (\w+)/)?.[1]} Only return the JSDoc for the Class itself, not the methods or anything in the class. - + Only return the JSDoc comment for the class, no other text or code. Example: diff --git a/scripts/jsdoc-automation/src/PluginDocumentationGenerator.ts b/scripts/jsdoc-automation/src/PluginDocumentationGenerator.ts index f277727eaf1..ac81b624fbd 100644 --- a/scripts/jsdoc-automation/src/PluginDocumentationGenerator.ts +++ b/scripts/jsdoc-automation/src/PluginDocumentationGenerator.ts @@ -4,9 +4,10 @@ import { TodoItem, EnvUsage, } from "./types/index.js"; -import { AIService } from "./AIService.js"; +import { AIService } from "./AIService/AIService.js"; import { GitManager } from "./GitManager.js"; import { Configuration } from "./Configuration.js"; +import { FullDocumentationGenerator } from "./AIService/generators/FullDocumentationGenerator.js"; import fs from "fs"; import path from "path"; @@ -14,11 +15,14 @@ import path from "path"; * Generates comprehensive plugin documentation based on existing JSDoc comments */ export class PluginDocumentationGenerator { + private fullDocumentationGenerator: FullDocumentationGenerator; constructor( private aiService: AIService, private gitManager: GitManager, private configuration: Configuration - ) {} + ) { + this.fullDocumentationGenerator = new FullDocumentationGenerator(configuration); + } /** * Generates comprehensive plugin documentation @@ -45,7 +49,7 @@ export class PluginDocumentationGenerator { console.error("package.json not found"); } // Generate documentation - const documentation = await this.aiService.generatePluginDocumentation({ + const documentation = await this.fullDocumentationGenerator.generatePluginDocumentation({ existingDocs, packageJson, todoItems, @@ -109,15 +113,15 @@ ${docs.evaluatorsDocumentation} ## Usage Examples ${docs.usage} -## API Reference -${docs.apiReference} +## FAQ +${docs.faq} ## Development ### TODO Items ${docs.todos} -### Troubleshooting +## Troubleshooting Guide ${docs.troubleshooting}`; } } diff --git a/scripts/jsdoc-automation/src/TypeScriptParser.ts b/scripts/jsdoc-automation/src/TypeScriptParser.ts index d900c8f0cf3..db36fc86338 100644 --- a/scripts/jsdoc-automation/src/TypeScriptParser.ts +++ b/scripts/jsdoc-automation/src/TypeScriptParser.ts @@ -87,6 +87,9 @@ export class TypeScriptParser { let endLine: number | null = null; let actionNameStartLine: number | null = null; + // write ast to json file + // fs.writeFileSync("ast.json", JSON.stringify(ast, null, 2)); + const findActionTypeAnnotation = (node: any) => { // Look for Action type annotation if ( diff --git a/scripts/jsdoc-automation/src/index.ts b/scripts/jsdoc-automation/src/index.ts index 320273c9370..571cb78a52b 100644 --- a/scripts/jsdoc-automation/src/index.ts +++ b/scripts/jsdoc-automation/src/index.ts @@ -4,7 +4,7 @@ import { JsDocAnalyzer } from "./JsDocAnalyzer.js"; import { JsDocGenerator } from "./JsDocGenerator.js"; import { DocumentationGenerator } from "./DocumentationGenerator.js"; import { Configuration } from "./Configuration.js"; -import { AIService } from "./AIService.js"; +import { AIService } from "./AIService/AIService.js"; import { GitManager } from "./GitManager.js"; import { PluginDocumentationGenerator } from "./PluginDocumentationGenerator.js"; diff --git a/scripts/jsdoc-automation/src/types/index.ts b/scripts/jsdoc-automation/src/types/index.ts index 2762f850d12..4453630f38f 100644 --- a/scripts/jsdoc-automation/src/types/index.ts +++ b/scripts/jsdoc-automation/src/types/index.ts @@ -1,7 +1,5 @@ import { TSESTree } from "@typescript-eslint/types"; -import { TSESTree } from "@typescript-eslint/types"; - export interface ASTQueueItem { name: string; filePath: string; @@ -32,14 +30,6 @@ export interface PrModeFileChange extends FullModeFileChange { contents_url: string; } -export interface OrganizedDocs { - classes: ASTQueueItem[]; - methods: ASTQueueItem[]; - interfaces: ASTQueueItem[]; - types: ASTQueueItem[]; - functions: ASTQueueItem[]; -} - export interface TodoSection { todos: string; todoCount: number; @@ -86,6 +76,7 @@ export interface PluginDocumentation { actionsDocumentation: string; providersDocumentation: string; evaluatorsDocumentation: string; + faq: string; } export interface ActionMetadata { diff --git a/scripts/jsdoc-automation/src/utils/prompts.ts b/scripts/jsdoc-automation/src/utils/prompts.ts index 17ae441ba30..f1b35e5368c 100644 --- a/scripts/jsdoc-automation/src/utils/prompts.ts +++ b/scripts/jsdoc-automation/src/utils/prompts.ts @@ -1,59 +1,107 @@ -import { OrganizedDocs } from "../types"; +import { OrganizedDocs } from "../AIService/types"; export const PROMPT_TEMPLATES = { overview: (packageJson: any, docs: OrganizedDocs) => ` - Create an overview for ${packageJson.name} with the following structure and details: - -### Purpose -[Write a comprehensive paragraph explaining the main purpose based on the package details below] - -Package Information: -- Name: ${packageJson.name} -- Description: ${packageJson.description || "N/A"} -- Version: ${packageJson.version || "N/A"} -- Keywords: ${(packageJson.keywords || []).join(", ")} - -### Key Features - -Code Components: -${ - docs.classes.length > 0 - ? ` -Classes: -${docs.classes.map((c) => `- ${c.name}: ${c.jsDoc}`).join("\n")}` - : "" -} - -${ - docs.interfaces.length > 0 - ? ` -Interfaces: -${docs.interfaces.map((i) => `- ${i.name}: ${i.jsDoc}`).join("\n")}` - : "" -} - -${ - docs.types.length > 0 - ? ` -Types: -${docs.types.map((t) => `- ${t.name}: ${t.jsDoc}`).join("\n")}` - : "" -} - -${ - docs.functions.length > 0 - ? ` -Functions: -${docs.functions.map((f) => `- ${f.name}: ${f.jsDoc}`).join("\n")}` - : "" -} - -Based on the above components, list the key features and capabilities of this plugin: -- Feature 1: Brief description -- Feature 2: Brief description -[List key features with brief descriptions] - -Format in markdown without adding any additional headers.`, + Using the provided JSDoc as context, create a comprehensive documentation overview, FAQ, and Troubleshooting section for ${packageJson.name}. Return the response in the following JSON structure: + { + "overview": { + "purpose": "A comprehensive paragraph explaining the main purpose", + "keyFeatures": "List of key features and capabilities" + }, + "faq": [ + { + "question": "Common question based on the code structure and functionality", + "answer": "Detailed answer with examples if applicable" + } + ], + "troubleshooting": { + "commonIssues": [ + { + "issue": "Potential issue based on code structure", + "cause": "Likely cause", + "solution": "How to solve it" + } + ], + "debuggingTips": [ + "Relevant debugging tips based on the codebase" + ] + } + } + + Base your response on the following package and code information: + + Package Information: + - Name: ${packageJson.name} + - Description: ${packageJson.description || "N/A"} + + Code Components: + ${docs.classes.length > 0 ? ` + Classes: + ${docs.classes.map((c) => `- ${c.name}: ${c.jsDoc}`).join("\n")}` : ""} + + ${docs.interfaces.length > 0 ? ` + Interfaces: + ${docs.interfaces.map((i) => `- ${i.name}: ${i.jsDoc}`).join("\n")}` : ""} + + ${docs.types.length > 0 ? ` + Types: + ${docs.types.map((t) => `- ${t.name}: ${t.jsDoc}`).join("\n")}` : ""} + + ${docs.functions.length > 0 ? ` + Functions: + ${docs.functions.map((f) => `- ${f.name}: ${f.jsDoc}`).join("\n")}` : ""} + + ${docs.variables.length > 0 ? ` + Variables: + ${docs.variables.map((v) => `- ${v.name}: ${v.jsDoc}`).join("\n")}` : ""} + + Based on the above components, generate: + 1. A comprehensive overview that explains the plugin's purpose and key features + 2. FAQ entries that cover the following aspects of the code: + - Action questions: Can the Action do this? + - Capability questions: For example, Can the Action, Provider, or Evaluator do this in its current state? + - Integration questions: For example, How to extend this aspect of the code? + - Common use-case questions: For example, How do I accomplish specific tasks with the code as it stands today? + 3. Troubleshooting guide that anticipates potential issues based on the code structure + + Always include one FAQ pair that states: + Q: "My action is registered, but the agent is not calling it" + A: "Ensure that action's name clearly aligns with the task, and ensure you give a detailed description of the conditions that should trigger the action" + + Heres some content from this codebases documentation to help you provide a more accurate Overview, FAQ, and Troubleshooting: + + Providers are core modules that inject dynamic context and real-time information into agent interactions. They serve as a bridge between the agent and various external systems, enabling access to market data, wallet information, sentiment analysis, and temporal context. + Overview + A provider's primary purpose is to: + Supply dynamic contextual information + Integrate with the agent runtime + Format information for conversation templates + Maintain consistent data access + + Actions are core building blocks in Eliza that define how agents respond to and interact with messages. They allow agents to interact with external systems, modify their behavior, and perform tasks beyond simple message responses. + Overview + Each Action consists of: + name: Unique identifier for the action + similes: Array of alternative names/variations + description: Detailed explanation of the action's purpose + validate: Function that checks if action is appropriate + handler: Implementation of the action's behavior + examples: Array of example usage patterns + + Evaluators are core components that assess and extract information from conversations. They integrate with the AgentRuntime's evaluation system. + Overview + Evaluators enable agents to: + Build long-term memory + Track goal progress + Extract facts and insights + Maintain contextual awareness + + + Create your FAQ and Troubleshooting based on likely questions and issues that users will have based on the documentation provided above. + Format the response as a valid JSON object. For the FAQ try and have at least 5-6 questions and answers. + + IMPORTANT: Return only the raw JSON object without any markdown formatting or code blocks. + `, installation: `Create installation instructions with the following structure: @@ -108,12 +156,7 @@ Format in markdown without adding any additional headers.`, [Brief description of the provider] #### Methods -[Focus on the get() method and its functionality.] - -#### Usage -\`\`\`typescript -[Example usage code] -\`\`\` +[Textual description of the get() method and its functionality.] Format in markdown without adding any additional headers.`, @@ -185,9 +228,5 @@ Format in markdown without adding any additional headers.`, - [Second debugging tip] - Ask your questions at https://eliza.gg/ 🚀 or in our discord -### FAQ -Q: [Common question] -A: [Answer with example if applicable] - Format in markdown without adding any additional headers.`, };