├── .github ├── ISSUE_TEMPLATE │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE │ ├── default.md │ └── plugin.md ├── pr-labeler-config.yml └── workflows │ ├── pr-labeler.yml │ └── validate-new-plugin-metadata.yml ├── .gitignore ├── .npmignore ├── .nvmrc ├── CONTRIBUTION_GUIDE.md ├── LICENSE ├── README.md ├── docs └── imgs │ ├── GAME-framework.jpeg │ ├── game-cloud-json.png │ ├── new_sdk_visual.png │ └── old_sdk_visual.png ├── examples ├── .env.example ├── README.md ├── chat-agent-example │ ├── chatAgent.ts │ ├── discord-with-chatAgent.ts │ └── telegram-with-chatAgent-example.ts ├── package-lock.json ├── package.json ├── state-management │ ├── README.md │ ├── agent.ts │ ├── functions.ts │ ├── index.ts │ └── worker.ts ├── telegram-example │ └── tg.ts ├── tsconfig.json └── twitter-example │ └── twitter.ts ├── game-starter ├── .dockerignore ├── .env.example ├── .gitignore ├── Dockerfile ├── README.md ├── docker-compose.yml ├── package-lock.json ├── package.json ├── rofl-compose.yml ├── rofl.yaml ├── src │ ├── agent.ts │ ├── functions.ts │ ├── index.ts │ └── worker.ts └── tsconfig.json ├── package-lock.json ├── package.json ├── plugins ├── adNetworkPlugin │ ├── .gitignore │ ├── .npmignore │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── adNetworkPlugin.ts │ │ ├── example.ts │ │ └── index.ts │ └── tsconfig.json ├── alchemyPlugin │ ├── .env.example │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── plugin_metadata.yml │ ├── src │ │ ├── alchemyPlugin.ts │ │ ├── example.ts │ │ └── index.ts │ └── tsconfig.json ├── alloraPlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── alloraPlugin.ts │ │ ├── example.ts │ │ └── index.ts │ └── tsconfig.json ├── attpsPlugin │ ├── .env.example │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── attpsPlugin.ts │ │ ├── index.ts │ │ └── types.ts │ ├── test │ │ └── index.test.ts │ ├── tsconfig.json │ └── vite.config.ts ├── coingeckoMaopPlugin │ ├── README.md │ ├── package.json │ └── src │ │ ├── coingeckoMaopPlugin.ts │ │ ├── example.coinDataByID.ts │ │ ├── example.coinPricesByAddress.ts │ │ ├── example.coinPricesByIDs.ts │ │ ├── example.coinsCategoriesList.ts │ │ ├── example.coinsListWithMarketData.ts │ │ ├── example.newPoolsByNetwork.ts │ │ ├── example.specificPoolData.ts │ │ ├── example.tokenInfoByAddress.ts │ │ ├── example.tokenPriceByAddresses.ts │ │ ├── example.topGainersLosersConfig.ts │ │ ├── example.trendingPoolsByNetwork.ts │ │ ├── example.trendingPoolsList.ts │ │ ├── example.trendingSearchList.ts │ │ ├── example.ts │ │ ├── index.ts │ │ └── utils.ts ├── d.a.t.aPlugin │ ├── .env.example │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── d.a.t.aPlugin.ts │ │ ├── example.ts │ │ └── index.ts │ └── tsconfig.json ├── deskExchangePlugin │ ├── .env.example │ ├── .gitignore │ ├── README.md │ ├── __test__ │ │ ├── deskExchangePlugin.test.ts │ │ └── log.ts │ ├── eslint.config.mjs │ ├── jest.config.js │ ├── jest.setup.js │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ ├── constants.ts │ │ ├── deskExchangePlugin.ts │ │ ├── index.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── discordPlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── __test__ │ │ └── DiscordPlugin.test.ts │ ├── jest.config.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── discordPlugin.ts │ │ ├── example.ts │ │ └── index.ts │ └── tsconfig.json ├── dpsnPlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── __test__ │ │ ├── __mocks__ │ │ │ └── dpsn-client.ts │ │ ├── dpsnPlugin.test.ts │ │ ├── integration.test.ts │ │ ├── mocks │ │ │ ├── dpsnClient.mock.ts │ │ │ └── gameAgent.mock.ts │ │ └── setup.ts │ ├── coverage │ │ ├── lcov-report │ │ │ ├── base.css │ │ │ ├── block-navigation.js │ │ │ ├── dpsnPlugin.ts.html │ │ │ ├── favicon.png │ │ │ ├── index.html │ │ │ ├── prettify.css │ │ │ ├── prettify.js │ │ │ ├── sort-arrow-sprite.png │ │ │ └── sorter.js │ │ └── lcov.info │ ├── jest.config.js │ ├── package-lock.json │ ├── package.json │ ├── plugin_metadata.yml │ ├── src │ │ ├── dpsnPlugin.ts │ │ ├── example.ts │ │ └── index.ts │ └── tsconfig.json ├── echochambersPlugin │ ├── LICENSE │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── echochambersPlugin.ts │ │ ├── example.ts │ │ ├── example_mock.ts │ │ ├── index.ts │ │ └── types.ts │ └── tsconfig.json ├── elfaAiPlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── __test__ │ │ └── ElfaAiPlugin.test.ts │ ├── jest.config.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── elfaAiPlugin.ts │ │ ├── example.ts │ │ └── index.ts │ └── tsconfig.json ├── ensoPlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── .env.example │ │ ├── constants.ts │ │ ├── ensoPlugin.ts │ │ ├── example.ts │ │ ├── index.ts │ │ └── utils.ts │ └── tsconfig.json ├── evalEnginePlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── evalEngine.ts │ │ ├── example.ts │ │ ├── index.ts │ │ ├── tweet │ │ │ ├── fetch-tweet.ts │ │ │ ├── get-tweet.ts │ │ │ └── tweet.ts │ │ └── twitterPlugin.ts │ └── tsconfig.json ├── farcasterPlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── farcasterPlugin.ts │ │ └── index.ts │ └── tsconfig.json ├── imageGenPlugin │ ├── README.md │ ├── package.json │ └── src │ │ ├── example.ts │ │ ├── imageGenPlugin.ts │ │ └── index.ts ├── mindNetworkPlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── cache.ts │ │ ├── example.ts │ │ ├── index.ts │ │ └── mindNetworkPlugin.ts │ └── tsconfig.json ├── onChainActionsPlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── .env.example │ │ ├── example.ts │ │ ├── index.ts │ │ └── onChainActionsPlugin.ts │ └── tsconfig.json ├── plugin_metadata_template.yml ├── recallStoragePlugin │ ├── .env.example │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── example.ts │ │ ├── index.ts │ │ └── recallStoragePlugin.ts │ └── tsconfig.json ├── rss3Plugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ ├── example.ts │ │ ├── index.ts │ │ └── rss3Plugin.ts │ └── tsconfig.json ├── s3Plugin │ ├── .env.example │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── example.ts │ │ ├── index.ts │ │ └── s3Plugin.ts │ └── tsconfig.json ├── stateofmikaPlugin │ ├── .gitignore │ ├── README.md │ ├── __tests__ │ │ ├── integration.test.ts │ │ └── stateMikaPlugin.test.ts │ ├── jest.config.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── stateMikaPlugin.ts │ └── tsconfig.json ├── telegramPlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── __test__ │ │ └── TelegramPlugin.test.ts │ ├── jest.config.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── example.ts │ │ ├── index.ts │ │ └── telegramPlugin.ts │ └── tsconfig.json ├── twitterPlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── example │ │ ├── .env.example │ │ ├── index.ts │ │ ├── media_file.png │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── test_game_twitter_client.ts │ │ └── virtuals-logo.png │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── bin.ts │ │ ├── index.ts │ │ └── twitterPlugin.ts │ └── tsconfig.json └── zytronPlugin │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── package.json │ ├── src │ ├── constants.ts │ ├── example.ts │ ├── index.ts │ ├── utils.ts │ ├── zytronPlugin.ts │ └── zytronWallet.ts │ └── tsconfig.json ├── src ├── agent.ts ├── api.ts ├── apiV2.ts ├── chatAgent.ts ├── function.ts ├── index.ts ├── interface │ └── GameClient.ts └── worker.ts ├── tools ├── README.md └── cloud-to-sdk │ ├── README.md │ ├── generateAgent.ts │ ├── generateFunctions.ts │ ├── generateWorker.ts │ ├── index.ts │ ├── package.json │ └── types.ts └── tsconfig.json /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Click the `Preview` tab and select a PR template: 2 | 3 | - [Default Template](?expand=1&template=default.md) 4 | - [Plugin](?expand=1&template=plugin.md) 5 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/default.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | One-liner - what does this change? 4 | 5 | ## Changes 6 | 7 | (Answer where applicable) 8 | 9 | - Important links (Jira/Notion/GitHub Issues): 10 | - Why this PR is needed? 11 | - What does this add? 12 | - What does this deprecate? 13 | - What does this improve? 14 | 15 | ## Related Changes 16 | 17 | - Does this have a dependant PR? Eg. link to original PR if this is a bug fix PR. 18 | 19 | (Use table to list all related PRs if done in parts) 20 | 21 | | Description | PR | 22 | | --- | --- | 23 | | [Part 1] This PR | ⬅️ | 24 | | [Part 2] Another PR | link | 25 | | [Part 3] Another PR | link | 26 | 27 | ## Dev Testing 28 | 29 | (Include where applicable) 30 | 31 | - Screenshots 32 | - Video Recordings 33 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/plugin.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | One-liner – What does this plugin contribution add or change? 4 | 5 | ## Links 6 | 7 | - Plugin documentation: 8 | - Issue link (if applicable): 9 | - Other useful links: 10 | 11 | ## Plugin Documentation Checklist 12 | 13 | - README Validation 14 | - [ ] `README.md` file exists in the plugin root folder 15 | - [ ] Clear installation instructions 16 | - [ ] Usage examples with code snippets 17 | - [ ] List of features and capabilities 18 | - [ ] Troubleshooting guide (if applicable) 19 | - [ ] Contribution guidelines (if applicable) 20 | 21 | - Metadata Validation 22 | - [ ] `plugin_metadata.yml` file exists in the plugin root folder 23 | - [ ] Complete metadata provided in reference to [plugin metadata template](../.././plugins/plugin_metadata_template.yml) 24 | 25 | ## Dev Testing 26 | 27 | (Include where applicable) 28 | 29 | - Screenshots/GIFs 30 | - Video Demonstrations 31 | - Logs or Console Outputs 32 | - Testing steps for the plugin 33 | 34 | ## Additional Notes 35 | 36 | - Any considerations for future updates or enhancements. 37 | - Known issues or limitations with this plugin contribution. 38 | -------------------------------------------------------------------------------- /.github/pr-labeler-config.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | appendOnly: true 3 | labels: 4 | - label: "bugfix" 5 | title: "(?i)fix|bug" 6 | - label: "documentation" 7 | title: "(?i)docs|documentation" 8 | - label: "enhancement" 9 | title: "(?i)feat|feature|enhance|improve" 10 | - label: "plugin" 11 | title: "(?i)plugin" 12 | - label: "test" 13 | title: "(?i)test" 14 | -------------------------------------------------------------------------------- /.github/workflows/pr-labeler.yml: -------------------------------------------------------------------------------- 1 | name: Auto Label PR 2 | 3 | on: 4 | pull_request: 5 | branches: [ "main" ] 6 | types: [ opened, edited, reopened, synchronize ] 7 | 8 | jobs: 9 | label-plugin-pr: 10 | permissions: 11 | contents: read 12 | pull-requests: write 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Auto Apply Labels 16 | uses: srvaroa/labeler@master 17 | with: 18 | config_path: .github/pr-labeler-config.yml 19 | env: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | .env 4 | *.lock 5 | 6 | # JetBrains IDEs 7 | .idea/ 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v18.18.2 2 | -------------------------------------------------------------------------------- /CONTRIBUTION_GUIDE.md: -------------------------------------------------------------------------------- 1 | # Contributing to GAME SDK 2 | 3 | There are various ways you can contribute to the GAME SDK, whether it's fixing bugs, adding new plugins, or improving the documentation. 4 | 5 | ### Submitting Code (e.g. plugins) 6 | 1. **Fork** the repository and clone it to your local machine. 7 | 2. **Create a Branch** for your changes. 8 | 3. **Make Changes** to address the issue or add the feature. 9 | 4. **Ensure Compliance** with the relevant contribution requirements: 10 | - For **general PRs**, follow the [default PR template](./.github/PULL_REQUEST_TEMPLATE/default.md). 11 | - For **plugin contributions**, ensure your PR follows the [plugin PR template](./.github/PULL_REQUEST_TEMPLATE/plugin.md). 12 | 5. **Commit** with a message that clearly explains your change. 13 | 6. **Push** the branch to your fork and submit a pull request. 14 | 7. **Label** the pull request appropriately based on the [label definitions](#label-definitions). 15 | 16 | ### General Contribution Guidelines 17 | If you are contributing to the core SDK, ensure the following: 18 | - The code is well-documented. 19 | - Your PR follows the [default PR template](./.github/PULL_REQUEST_TEMPLATE/default.md). 20 | - Screenshots, video demonstrations, or logs showcasing the changes are included (if applicable). 21 | 22 | ### Plugin Contribution Guidelines 23 | If you are adding a new plugin, ensure the following: 24 | - A `README.md` file exists in the plugin root directory and includes: 25 | - Installation instructions 26 | - Usage examples with code snippets 27 | - List of features and capabilities 28 | - Troubleshooting guide (if applicable) 29 | - Contribution guidelines (if applicable) 30 | - A `plugin_metadata.yml` file exists in the plugin root directory with complete metadata as per the [plugin metadata template](./plugins/plugin_metadata_template.yml). 31 | - Your PR follows the [plugin PR template](./.github/PULL_REQUEST_TEMPLATE/plugin.md). 32 | - Screenshots, video demonstrations, or logs showcasing the plugin functionality are included (if applicable). 33 | 34 | ### Reporting Bugs 35 | - Open an issue in the [Issues](https://github.com/game-by-virtuals/game-node/issues) tab and tag it as a `bug`. 36 | 37 | ### Suggesting Enhancements 38 | - Open an issue in the [Issues](https://github.com/game-by-virtuals/game-node/issues) tab and tag it as an `enhancement`. 39 | 40 | ## Label Definitions 41 | Please tag issues and pull requests appropriately, based on the definition below: 42 | - **plugin**: A plugin contribution. 43 | - **bug**: A problem that needs fixing. 44 | - **enhancement**: A requested enhancement. 45 | - **help wanted**: A task that is open for anyone to work on. 46 | - **documentation**: Documentation changes. 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025, Virtuals Protocol 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /docs/imgs/GAME-framework.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game-by-virtuals/game-node/0d991ce28db65a5a0e2d4046bc05d8d3bfcab3df/docs/imgs/GAME-framework.jpeg -------------------------------------------------------------------------------- /docs/imgs/game-cloud-json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game-by-virtuals/game-node/0d991ce28db65a5a0e2d4046bc05d8d3bfcab3df/docs/imgs/game-cloud-json.png -------------------------------------------------------------------------------- /docs/imgs/new_sdk_visual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game-by-virtuals/game-node/0d991ce28db65a5a0e2d4046bc05d8d3bfcab3df/docs/imgs/new_sdk_visual.png -------------------------------------------------------------------------------- /docs/imgs/old_sdk_visual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game-by-virtuals/game-node/0d991ce28db65a5a0e2d4046bc05d8d3bfcab3df/docs/imgs/old_sdk_visual.png -------------------------------------------------------------------------------- /examples/.env.example: -------------------------------------------------------------------------------- 1 | API_KEY=YOUR_GAME_SDK_API_KEY -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | This directory contains example implementations showing how to use the library with different platforms. 4 | 5 | ## Running the Examples 6 | 7 | 1. Create a `.env` file in each example directory (telegram-example and twitter-example) using the `.env.example` as template 8 | 9 | 2. Run the examples using: 10 | 11 | npm run telegram-example # for telegram bot 12 | npm run twitter-example # for twitter bot -------------------------------------------------------------------------------- /examples/chat-agent-example/discord-with-chatAgent.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from "@virtuals-protocol/game"; 2 | import DiscordPlugin from "../../plugins/discordPlugin/src/discordPlugin"; 3 | import { ChatAgent } from "../../src/chatAgent"; 4 | 5 | const discordPlugin = new DiscordPlugin({ 6 | credentials: { 7 | botToken: process.env.DISCORD_BOT_TOKEN || "" 8 | }, 9 | }); 10 | 11 | const chatAgent = new ChatAgent(process.env.GAME_API_KEY || "", "You are a helpful assistant"); 12 | 13 | 14 | (async () => { 15 | // Track active chats using a Map 16 | const activeChats = new Map(); 17 | 18 | discordPlugin.onMessage(async (msg) => { 19 | // Skip messages from bots 20 | if (msg.author.bot) { 21 | console.log('This message is from a bot.'); 22 | return; 23 | } 24 | 25 | // Log guild information if available 26 | if (msg.guild) { 27 | console.log(`Guild Name: ${msg.guild.name}, Guild ID: ${msg.guild.id}`); 28 | } else { 29 | console.log('This message is not from a guild (e.g., DM).'); 30 | } 31 | 32 | // Get or create chat for this user 33 | let chat = activeChats.get(msg.author.id); 34 | if (!chat) { 35 | chat = await chatAgent.createChat({ 36 | partnerId: msg.author.id, 37 | partnerName: msg.author.username, 38 | actionSpace: [ 39 | discordPlugin.sendMessageFunction, 40 | discordPlugin.addReactionFunction, 41 | discordPlugin.pinMessageFunction, 42 | discordPlugin.deleteMessageFunction, 43 | // Add other Discord-specific functions here 44 | ], 45 | }); 46 | activeChats.set(msg.author.id, chat); 47 | } 48 | 49 | const userMessage = msg.content; 50 | const response = await chat.next(userMessage); 51 | 52 | if (response.functionCall) { 53 | console.log(`Function call: ${response.functionCall.fn_name}`); 54 | // The function will be automatically executed by the agent 55 | } 56 | 57 | if (response.message) { 58 | await discordPlugin.sendMessageFunction.executable({ 59 | channel_id: msg.channelId, 60 | content: response.message 61 | }, console.log); 62 | } 63 | 64 | if (response.isFinished) { 65 | await discordPlugin.sendMessageFunction.executable({ 66 | channel_id: msg.channelId, 67 | content: "Chat ended" 68 | }, console.log); 69 | } 70 | }); 71 | })(); -------------------------------------------------------------------------------- /examples/chat-agent-example/telegram-with-chatAgent-example.ts: -------------------------------------------------------------------------------- 1 | import TelegramPlugin from "../../plugins/telegramPlugin/src/telegramPlugin"; 2 | import { ChatAgent } from "../../src/chatAgent"; 3 | 4 | const telegramBot = new TelegramPlugin({ 5 | credentials: { 6 | botToken: process.env.TELEGRAM_BOT_TOKEN || "" 7 | } 8 | }) 9 | 10 | const chatAgent = new ChatAgent(process.env.GAME_API_KEY || "", "You are a helpful assistant") 11 | 12 | const main = async () => { 13 | // Track active chats using a Map 14 | const activeChats = new Map(); 15 | 16 | // Set up Telegram message handler 17 | telegramBot.onMessage(async (message) => { 18 | // Get or create chat for this user 19 | let chat = activeChats.get(message.from.id); 20 | if (!chat) { 21 | chat = await chatAgent.createChat({ 22 | partnerId: message.from.id.toString(), 23 | partnerName: message.from.first_name, 24 | actionSpace: [ 25 | telegramBot.sendMessageFunction, 26 | telegramBot.sendMediaFunction, 27 | telegramBot.createPollFunction, 28 | telegramBot.pinnedMessageFunction, 29 | telegramBot.unPinnedMessageFunction, 30 | telegramBot.deleteMessageFunction 31 | ], 32 | }); 33 | activeChats.set(message.from.id, chat); 34 | } 35 | 36 | const userMessage = message.text; 37 | const response = await chat.next(userMessage); 38 | 39 | if (response.functionCall) { 40 | console.log(`Function call: ${response.functionCall.fn_name}`); 41 | // The function will be automatically executed by the agent 42 | } 43 | 44 | if (response.message) { 45 | await telegramBot.sendMessageFunction.executable({ 46 | chat_id: message.chat.id, 47 | text: response.message 48 | }, console.log); 49 | } 50 | 51 | if (response.isFinished) { 52 | await telegramBot.sendMessageFunction.executable({ 53 | chat_id: message.chat.id, 54 | text: "Chat ended" 55 | }, console.log); 56 | } 57 | }); 58 | 59 | // Start the bot 60 | }; 61 | 62 | main().catch(console.error); -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "examples", 3 | "private": true, 4 | "dependencies": { 5 | "@virtuals-protocol/game": "^0.1.9", 6 | "dotenv": "^16.4.7", 7 | "openai": "^4.81.0", 8 | "twitter-api-v2": "^1.15.0" 9 | }, 10 | "scripts": { 11 | "start": "ts-node -P ./tsconfig.json", 12 | "build": "tsc -p ./tsconfig.json", 13 | "twitter-example": "ts-node twitter-example/twitter.ts", 14 | "telegram-example": "ts-node telegram-example/tg.ts", 15 | "state-management": "ts-node state-management/index.ts" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/state-management/README.md: -------------------------------------------------------------------------------- 1 | # Kitchen Manager Agent (to demonstrate state management) 2 | 3 | A virtual kitchen management system powered by AI agents that simulate running a restaurant kitchen, managing inventory, and preparing dishes. 4 | 5 | ## Overview 6 | 7 | This project implements a kitchen management system with two main workers supervised by a Kitchen Manager: 8 | 9 | 1. **Head Chef**: Responsible for preparing dishes using available ingredients from the inventory 10 | 2. **Ingredient Manager**: Manages the kitchen's budget and purchases ingredients 11 | 12 | ## System Components 13 | 14 | ### Kitchen Manager (Agent) 15 | - Oversees the entire kitchen operation 16 | - Coordinates between the Head Chef and Ingredient Manager 17 | - Makes decisions based on available moves and kitchen state 18 | - Aims to maximize food production quality within given constraints 19 | 20 | ### State Management 21 | - **Move Counter**: Limits the number of actions that can be performed (Tracked by the agent) 22 | - **Restaurant Budget**: Tracks available funds for purchasing ingredients (Tracked by worker) 23 | - **Inventory System**: Maintains count of all available ingredients (Tracked by worker) 24 | - Each worker action consumes one move from the total available moves 25 | 26 | ## Setup and Running 27 | 28 | 1. **Environment Setup** 29 | ```bash 30 | # Clone the repository 31 | git clone [repository-url] 32 | cd [repository-name] 33 | 34 | # Install dependencies 35 | npm install 36 | ``` 37 | 38 | 2. **Configuration** 39 | Create a `.env` file in the project root: 40 | ``` 41 | API_KEY=your_api_key_here 42 | ``` 43 | 44 | 3. **Running the Agent** 45 | In the example directory, run the following command: 46 | ```bash 47 | npm run state-management 48 | # or 49 | ts-node examples/state-management/index.ts 50 | ``` 51 | 52 | ## Available Functions 53 | 54 | ### Head Chef Functions 55 | - `getIngredients()`: Check current inventory 56 | - `makeFood()`: Prepare dishes using available ingredients 57 | 58 | ### Ingredient Manager Functions 59 | - `buyIngredient()`: Purchase new ingredients 60 | - `getBudget()`: Check current kitchen budget 61 | 62 | ## State Tracking 63 | 64 | The system maintains two types of state: 65 | 1. **Agent State**: Used by the Task Generator(Agent) to determine what tasks to generate 66 | 2. **Worker State**: Represents what workers see when making decisions 67 | 68 | Both states are typically synchronized but can be managed separately if needed. 69 | 70 | ## additional info 71 | - Each action (function call) consumes one move 72 | - Purchases are limited by available budget 73 | - Food can only be prepared with available ingredients in inventory 74 | 75 | The kitchen manages the following ingredients with their respective prices: 76 | - Tomatoes ($2.99) 77 | - Chicken ($5.99) 78 | - Rice ($1.99) 79 | - Onions ($1.49) 80 | - Garlic ($0.99) 81 | - Beef ($8.99) 82 | - Pasta ($2.49) 83 | - Cheese ($4.99) 84 | - Bell Peppers ($1.79) 85 | - Olive Oil ($6.99) -------------------------------------------------------------------------------- /examples/state-management/agent.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from "@virtuals-protocol/game" 2 | import dotenv from "dotenv"; 3 | dotenv.config({ path: __dirname + '/.env' }); 4 | 5 | import { HeadChef, IngredientManager } from "./worker" 6 | 7 | let moves = 3; 8 | const getAgentState = async () => { 9 | return { 10 | moves_left: moves 11 | } 12 | } 13 | 14 | export const setAgentState = (state: any) => { 15 | moves = state.moves_left; 16 | } 17 | 18 | export const updateMoves = (amount: number) => { 19 | moves = amount; 20 | } 21 | 22 | export const getMoves = () => { 23 | return moves; 24 | } 25 | 26 | if (!process.env.API_KEY) { 27 | throw new Error('API_KEY is required in environment variables'); 28 | } 29 | 30 | export const agent = new GameAgent(process.env.API_KEY, { 31 | name: "kitchen_manager", 32 | description: `You are a skilled restaurant manager overseeing a busy kitchen. Your main responsibilities are: 33 | 34 | 1. Working with the Ingredient Manager to: 35 | - Plan and maintain ingredient inventory 36 | - Stay within budget when ordering supplies 37 | - Ensure all necessary ingredients are available for upcoming dishes 38 | 39 | 2. Coordinating with the Head Chef to: 40 | - Prepare high-quality dishes using available ingredients 41 | - Maintain food quality standards 42 | - Maximize kitchen efficiency 43 | 44 | You have a limited number of actions you can take (shown as moves_left). Each time you delegate a task 45 | to either the Ingredient Manager or Head Chef, it uses one move. You must stop all operations when you 46 | have no moves remaining. 47 | 48 | Important: Never continue operations when moves_left reaches 0. If this happens, immediately stop and 49 | report the current status. 50 | NO MATTER WHAT, you must make sure that you STOP OPERATING when the moves_left <= 0. NO NEGATIVE MOVES_LEFT ALLOWED. 51 | If negative moves_left is detected, STOP PROCEEDING and STOP OPERATING.`, 52 | 53 | goal: "Run an efficient kitchen by coordinating ingredient purchases within budget and food preparation to produce the highest quality dishes possible with your available resources and time.", 54 | workers: [ 55 | IngredientManager, 56 | HeadChef 57 | ], 58 | getAgentState: getAgentState 59 | }) 60 | -------------------------------------------------------------------------------- /examples/state-management/index.ts: -------------------------------------------------------------------------------- 1 | import { agent } from './agent'; 2 | import dotenv from 'dotenv'; 3 | dotenv.config(); 4 | 5 | async function main() { 6 | try { 7 | // Initialize the agent 8 | await agent.init(); 9 | 10 | // Run the agent 11 | while (true) { 12 | await agent.step({ verbose: true }); 13 | } 14 | } catch (error) { 15 | console.error("Error running kitchen manager:", error); 16 | } 17 | } 18 | 19 | main(); -------------------------------------------------------------------------------- /examples/state-management/worker.ts: -------------------------------------------------------------------------------- 1 | import { GameWorker } from "@virtuals-protocol/game" 2 | import { getIngredients, makeFood, buyIngredient, getBudget, getIngredientPrices, getMovesLeft, doNothing } from "./functions" 3 | 4 | export let restaurantBudget: number = 100.00; 5 | export const updateRestaurantBudget = (newBudget: number) => { 6 | restaurantBudget = newBudget 7 | } 8 | export const ingredientPrices: Record = { 9 | 'tomatoes': 2.99, 10 | 'chicken': 5.99, 11 | 'rice': 1.99, 12 | 'onions': 1.49, 13 | 'garlic': 0.99, 14 | 'beef': 8.99, 15 | 'pasta': 2.49, 16 | 'cheese': 4.99, 17 | 'bell_peppers': 1.79, 18 | 'olive_oil': 6.99 19 | }; 20 | 21 | export const restaurantInventory: Record = { 22 | 'tomatoes': 0, 23 | 'chicken': 0, 24 | 'rice': 0, 25 | 'onions': 0, 26 | 'garlic': 0, 27 | 'beef': 0, 28 | 'pasta': 0, 29 | 'cheese': 0, 30 | 'bell_peppers': 0, 31 | 'olive_oil': 0 32 | }; 33 | 34 | export const HeadChef = new GameWorker({ 35 | id: "head_chef", 36 | name: "HeadChef", 37 | description: `The head chef of the kitchen, your goal is to utilize the available inventory to make the best food. Available inventory is based on the amount behind the inventory object. 38 | For example, if the inventory object has 2 tomatoes, it will show like 'tomatoes': 2, and you can make 10 dishes with tomatoes.`, 39 | functions: [getIngredients , makeFood, getMovesLeft, doNothing], 40 | getEnvironment: async () => { 41 | return { 42 | inventory: restaurantInventory, 43 | ingredientPrices: ingredientPrices 44 | } 45 | } 46 | }) 47 | 48 | export const IngredientManager = new GameWorker({ 49 | id: "ingredient_manager", 50 | name: "IngredientManager", 51 | description: `The ingredient manager of the kitchen, your goal is to maximize the use of budget to buy ingredients that can be used to make the best food based on the current inventory. 52 | only buy ingredients that are listed in the inventory. When making a purchase of the ingredient, you MUST at all costs refer to the prices in the ingredientPrices object , DO NOT create your own prices, 53 | For example, if the ingredientPrices object has 'tomatoes': 2.99, it will show like 'tomatoes': 2.99, and you can buy 10 tomatoes for 29.90, and the budget will then be 70.10`, 54 | functions: [buyIngredient, getBudget, getIngredientPrices, getMovesLeft, doNothing], 55 | getEnvironment: async () => { 56 | return { 57 | budget: restaurantBudget, 58 | inventory: restaurantInventory 59 | } 60 | } 61 | }) 62 | -------------------------------------------------------------------------------- /examples/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "../", // Look up one directory to include everything 5 | "outDir": "./dist" 6 | }, 7 | "include": [ 8 | "./**/*", // Include all example files 9 | "../plugins/**/example.ts" // Include plugin examples 10 | ] 11 | } -------------------------------------------------------------------------------- /game-starter/.dockerignore: -------------------------------------------------------------------------------- 1 | # .dockerignore 2 | 3 | # Ignore node_modules from the build context 4 | node_modules 5 | 6 | # Ignore logs and temporary files 7 | *.log 8 | *.tmp 9 | .DS_Store 10 | 11 | # Ignore Git files and metadata 12 | .git 13 | .gitignore 14 | 15 | # Ignore IDE and editor config files 16 | .vscode 17 | .idea 18 | *.swp 19 | 20 | # Ignore build artifacts from the host 21 | dist 22 | build 23 | -------------------------------------------------------------------------------- /game-starter/.env.example: -------------------------------------------------------------------------------- 1 | API_KEY=YOUR_GAME_SDK_API_KEY 2 | WEATHER_API_KEY=YOUR_WEATHER_API_KEY 3 | OPENAI_API_KEY=YOUR_OPENAI_API_KEY 4 | botToken=YOUR_TELEGRAM_BOT_TOKEN -------------------------------------------------------------------------------- /game-starter/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules 3 | dist/ -------------------------------------------------------------------------------- /game-starter/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use a specific Node.js version for better reproducibility 2 | FROM node:23.3.0-slim AS builder 3 | 4 | # Install necessary build tools 5 | RUN apt-get update && \ 6 | apt-get upgrade -y && \ 7 | apt-get install -y \ 8 | git \ 9 | python3 \ 10 | python3-pip \ 11 | curl \ 12 | node-gyp \ 13 | ffmpeg \ 14 | libtool-bin \ 15 | autoconf \ 16 | automake \ 17 | libopus-dev \ 18 | make \ 19 | g++ \ 20 | build-essential \ 21 | libcairo2-dev \ 22 | libjpeg-dev \ 23 | libpango1.0-dev \ 24 | libgif-dev \ 25 | openssl \ 26 | libssl-dev libsecret-1-dev && \ 27 | apt-get clean && \ 28 | rm -rf /var/lib/apt/lists/* 29 | 30 | # Set Python 3 as the default python 31 | RUN ln -sf /usr/bin/python3 /usr/bin/python 32 | 33 | # Set the working directory 34 | WORKDIR /app 35 | 36 | # Copy application code 37 | COPY . . 38 | 39 | # Install dependencies 40 | RUN npm install --no-frozen-lockfile 41 | 42 | # Install TypeScript globally 43 | RUN npm install -g typescript 44 | 45 | # Build the project 46 | RUN npm run build && npm prune --production 47 | 48 | # Final runtime image 49 | FROM node:23.3.0-slim 50 | 51 | # Install runtime dependencies 52 | RUN apt-get update && \ 53 | apt-get install -y \ 54 | git \ 55 | python3 \ 56 | ffmpeg && \ 57 | apt-get clean && \ 58 | rm -rf /var/lib/apt/lists/* 59 | 60 | # Set the working directory 61 | WORKDIR /app 62 | 63 | # Copy built artifacts and production dependencies from the builder stage 64 | COPY --from=builder /app/package.json ./ 65 | COPY --from=builder /app/package-lock.json ./ 66 | COPY --from=builder /app/node_modules ./node_modules 67 | COPY --from=builder /app/dist ./dist 68 | 69 | # Expose necessary ports 70 | # EXPOSE 3000 71 | 72 | # Command to start the application 73 | CMD ["npm", "start"] 74 | -------------------------------------------------------------------------------- /game-starter/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | game-starter: 3 | image: virtuals-game-starter 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | platform: linux/amd64 8 | environment: 9 | - API_KEY= 10 | - WEATHER_API_KEY= 11 | - OPENAI_API_KEY= 12 | - OPENAI_BASE_URL= 13 | - botToken= 14 | volumes: 15 | - /var/run/tappd.sock:/var/run/tappd.sock 16 | - virtuals:/app 17 | restart: always 18 | 19 | volumes: 20 | virtuals: 21 | -------------------------------------------------------------------------------- /game-starter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "game-starter", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "start": "node dist/index.js", 9 | "plugin": "node dist/plugins/example.js", 10 | "dev": "ts-node src/index.ts", 11 | "watch": "tsc --watch" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "@types/node": "^22.12.0", 18 | "ts-node": "^10.9.2", 19 | "typescript": "^5.7.3" 20 | }, 21 | "dependencies": { 22 | "@types/dotenv": "^6.1.1", 23 | "@virtuals-protocol/game": "^0.1.9", 24 | "dotenv": "^16.4.7", 25 | "openai": "^4.81.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /game-starter/rofl-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | game-starter: 3 | image: docker.io//virtuals-game-starter 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | platform: linux/amd64 8 | environment: 9 | - API_KEY=${API_KEY} 10 | - WEATHER_API_KEY=${WEATHER_API_KEY} 11 | - OPENAI_API_KEY=${OPENAI_API_KEY} 12 | volumes: 13 | - virtuals:/app 14 | restart: always 15 | 16 | volumes: 17 | virtuals: 18 | -------------------------------------------------------------------------------- /game-starter/rofl.yaml: -------------------------------------------------------------------------------- 1 | name: game-starter 2 | version: 0.1.0 3 | tee: tdx 4 | kind: container 5 | resources: 6 | memory: 512 7 | cpus: 1 8 | storage: 9 | kind: disk-persistent 10 | size: 10000 11 | artifacts: 12 | firmware: https://github.com/oasisprotocol/oasis-boot/releases/download/v0.4.1/ovmf.tdx.fd#db47100a7d6a0c1f6983be224137c3f8d7cb09b63bb1c7a5ee7829d8e994a42f 13 | kernel: https://github.com/oasisprotocol/oasis-boot/releases/download/v0.4.1/stage1.bin#06e12cba9b2423b4dd5916f4d84bf9c043f30041ab03aa74006f46ef9c129d22 14 | stage2: https://github.com/oasisprotocol/oasis-boot/releases/download/v0.4.1/stage2-podman.tar.bz2#6f2487aa064460384309a58c858ffea9316e739331b5c36789bb2f61117869d6 15 | container: 16 | runtime: https://github.com/oasisprotocol/oasis-sdk/releases/download/rofl-containers%2Fv0.4.2/rofl-containers#0cbaa4c0c1b35c5ed41156868bee9f3726f52eeedc01b3060d3b2eb67d76f546 17 | compose: rofl-compose.yml 18 | -------------------------------------------------------------------------------- /game-starter/src/agent.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent, LLMModel } from "@virtuals-protocol/game"; 2 | import { activityRecommenderWorker } from "./worker"; 3 | import dotenv from "dotenv"; 4 | dotenv.config(); 5 | 6 | if (!process.env.API_KEY) { 7 | throw new Error('API_KEY is required in environment variables'); 8 | } 9 | 10 | export const activity_agent = new GameAgent(process.env.API_KEY, { 11 | name: "Activity Recommender", 12 | goal: "Help users find the perfect activities based on their location and current weather conditions", 13 | description: "You are an agent that gets location of the user and then uses that to get weather information and then uses that to recommend activities", 14 | workers: [activityRecommenderWorker], 15 | llmModel: LLMModel.DeepSeek_R1 // this is an optional paramenter to set the llm model for the agent. Default is Llama_3_1_405B_Instruct 16 | }); 17 | 18 | activity_agent.setLogger((agent: GameAgent, msg: string) => { 19 | console.log(`🎯 [${agent.name}]`); 20 | console.log(msg); 21 | console.log("------------------------\n"); 22 | }); -------------------------------------------------------------------------------- /game-starter/src/index.ts: -------------------------------------------------------------------------------- 1 | import { activity_agent } from './agent'; 2 | 3 | async function main() { 4 | try { 5 | // Initialize the agent 6 | await activity_agent.init(); 7 | 8 | // Run the agent 9 | while (true) { 10 | await activity_agent.step({ verbose: true }); 11 | } 12 | } catch (error) { 13 | console.error("Error running activity recommender:", error); 14 | } 15 | } 16 | 17 | main(); -------------------------------------------------------------------------------- /game-starter/src/worker.ts: -------------------------------------------------------------------------------- 1 | import { GameWorker } from "@virtuals-protocol/game"; 2 | import { getWeatherFunction, getLocationFunction, recommendActivitiesFunction } from "./functions"; 3 | 4 | // Create a demo worker with our functions 5 | export const activityRecommenderWorker = new GameWorker({ 6 | id: "activity_recommender", 7 | name: "Activity Recommender", 8 | description: "Gets location and weather information and recommends activities", 9 | functions: [ 10 | getLocationFunction, 11 | getWeatherFunction, 12 | recommendActivitiesFunction 13 | ] 14 | }); -------------------------------------------------------------------------------- /game-starter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "rootDir": "./src", 6 | "outDir": "./dist", 7 | "strict": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "declaration": true, 11 | "forceConsistentCasingInFileNames": true, 12 | }, 13 | "include": [ 14 | "src/**/*" 15 | ], 16 | "exclude": [ 17 | "node_modules" 18 | ] 19 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game", 3 | "version": "0.1.14", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "build": "tsc", 11 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 12 | }, 13 | "author": "", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "@types/jsonwebtoken": "^9.0.7", 17 | "@types/node": "^22.10.3", 18 | "ts-node-dev": "^2.0.0", 19 | "tsup": "^8.3.5", 20 | "typescript": "^5.7.2" 21 | }, 22 | "dependencies": { 23 | "axios": "^1.7.9", 24 | "dotenv": "^16.4.7" 25 | }, 26 | "files": [ 27 | "dist" 28 | ], 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/game-by-virtuals/game-node" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /plugins/adNetworkPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ -------------------------------------------------------------------------------- /plugins/adNetworkPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/adNetworkPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/ad-network-plugin", 3 | "version": "0.1.1", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/index.ts src/example.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "ts-node-dev": "^2.0.0", 16 | "typescript": "^5.7.2" 17 | }, 18 | "dependencies": { 19 | "@virtuals-protocol/game": "^0.1.9", 20 | "@virtuals-protocol/game-twitter-plugin": "^0.1.1", 21 | "tsup": "^8.3.5" 22 | }, 23 | "files": [ 24 | "dist" 25 | ], 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/game-by-virtuals/game-node" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /plugins/adNetworkPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import AdNetworkPlugin from "./adNetworkPlugin"; 2 | 3 | export default AdNetworkPlugin; 4 | -------------------------------------------------------------------------------- /plugins/alchemyPlugin/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY=your_alchemy_api_key 2 | VIRTUALS_API_TOKEN=your_virtuals_api_token -------------------------------------------------------------------------------- /plugins/alchemyPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | coverage/ -------------------------------------------------------------------------------- /plugins/alchemyPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/alchemyPlugin/README.md: -------------------------------------------------------------------------------- 1 | # Alchemy Plugin for Virtuals Protocol 2 | 3 | The **Alchemy Plugin** provides a set of functions to retrieve on-chain data from the Alchemy API giving your agent the power to work with web3 data. With this plugin, you can fetch portfolio data—including transaction history, token details, NFT information, and NFT contracts—by querying wallet addresses across various supported networks. 4 | 5 | ## Features 6 | 7 | - **Transaction History:** Retrieve historical transactions for a given EVM wallet. 8 | - **Tokens by Wallet:** Get the tokens held by a wallet along with associated metadata and prices. 9 | - **Token Balances by Wallet:** Fetch current token balances for a wallet. 10 | - **NFTs by Wallet:** Retrieve NFTs currently owned by a wallet, with optional paging and metadata. 11 | - **NFT Contracts by Wallet:** Retrieve distinct NFT contracts (collections) owned by a wallet, including metadata. 12 | 13 | ## Installation 14 | 15 | The plugin comes in the `plugins` directory at the root of `game-node` official repo. You'll need your `ALCHEMY_API_KEY` to use it which you can get by [creating your free alchemy account](https://bit.ly/42Emg95). You'll also need your `VIRTUALS_API_TOKEN` which you can get from the [G.A.M.E console](https://console.game.virtuals.io/projects). Add these variables to your `.env` file. 16 | 17 | ## Usage 18 | 19 | An example of how to instantiate the plugin and create an agent is given in `src/example.ts` file. 20 | 21 | All you need to do is run these commands at the root of `alchemyPlugin`: 22 | 23 | - `npm install` 24 | - `npm run build` 25 | - `node dist/example.js` 26 | 27 | ## Development 28 | 29 | Feel free to modify or extend the plugin as needed. Contributions, bug reports, and feature requests are welcome! 30 | 31 | 1. Fork the repository. 32 | 2. Create a new branch with your feature or bug fix. 33 | 3. Submit a pull request with detailed descriptions of your changes. 34 | -------------------------------------------------------------------------------- /plugins/alchemyPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-alchemy-plugin", 3 | "version": "0.1.0", 4 | "description": "A plugin for Virtuals Protocol G.A.M.E. to fetch on-chain data using the Alchemy API.", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "jest --coverage", 10 | "tsup": "tsup src/example.ts --dts --format cjs,esm --out-dir dist", 11 | "build": "npm run tsup" 12 | }, 13 | "author": "Alchemy", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "@types/jest": "^29.5.14", 17 | "@types/node": "^22.10.3", 18 | "@typescript-eslint/eslint-plugin": "^8.19.1", 19 | "@typescript-eslint/parser": "^8.19.1", 20 | "eslint": "^9.17.0", 21 | "jest": "^29.7.0", 22 | "ts-jest": "^29.2.5", 23 | "ts-node": "^10.9.2", 24 | "ts-node-dev": "^2.0.0", 25 | "tsup": "^8.3.5", 26 | "typescript": "^5.7.3" 27 | }, 28 | "dependencies": { 29 | "@virtuals-protocol/game": "^0.1.7", 30 | "axios": "^1.7.7" 31 | }, 32 | "files": [ 33 | "dist" 34 | ], 35 | "repository": { 36 | "type": "git" 37 | } 38 | } -------------------------------------------------------------------------------- /plugins/alchemyPlugin/plugin_metadata.yml: -------------------------------------------------------------------------------- 1 | # General Information 2 | plugin_name: "Alchemy Plugin" 3 | author: "Alchemy" 4 | logo_url: "https://bit.ly/alchemy-logo" 5 | release_date: "2025-04" 6 | 7 | # Description 8 | short_description: "The Alchemy Plugin provides a set of functions to retrieve on-chain data from the Alchemy API giving your agent the power to work with web3 data." # One-liner description for listings 9 | detailed_description: "The Alchemy Plugin provides a set of functions to retrieve on-chain data from the Alchemy API giving your agent the power to work with web3 data. With this plugin, you can fetch portfolio data—including transaction history, token details, NFT information, and NFT contracts—by querying wallet addresses across various supported networks." # Full description with features and benefits 10 | 11 | # Media & Assets 12 | plugin_logo_url: "https://bit.ly/alchemy-logo" 13 | screenshots: 14 | - "" 15 | - "" 16 | demo_video_url: "" 17 | documentation_url: "" 18 | changelog_url: "" 19 | 20 | # Contact & Support 21 | x_account_handle: "@Alchemy" 22 | support_contact: "https://www.alchemy.com/support" 23 | community_url: "https://alchemy.com/discord" -------------------------------------------------------------------------------- /plugins/alchemyPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from "@virtuals-protocol/game"; 2 | import AlchemyPlugin from "./alchemyPlugin"; 3 | import dotenv from "dotenv"; 4 | dotenv.config(); 5 | 6 | // Add your Alchemy API key to the .env file 7 | const alchemyPlugin = new AlchemyPlugin({ 8 | credentials: { 9 | apiKey: process.env.ALCHEMY_API_KEY || "", 10 | }, 11 | }); 12 | 13 | /** 14 | * Create an agent to fetch on-chain data using the Alchemy API 15 | * In this example, the agent fetches the nfts owned by 0xe5cB067E90D5Cd1F8052B83562Ae670bA4A211a8 on eth mainnet 16 | * Add your Virtuals Protocol API token to the .env file 17 | */ 18 | const alchemyAgent = new GameAgent(process.env.VIRTUALS_API_TOKEN || "", { 19 | name: "Alchemy Agent", 20 | goal: "Fetch the nfts owned by 0xe5cB067E90D5Cd1F8052B83562Ae670bA4A211a8 on eth mainnet", 21 | description: "An agent that can fetch on-chain data using the Alchemy API including transaction history, tokens held (with metadata/prices), token balances, NFTs by wallet, and NFT contracts by wallet.", 22 | workers: [ 23 | alchemyPlugin.getWorker(), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | // Initialize the agent 29 | await alchemyAgent.init(); 30 | await alchemyAgent.run(10, {verbose: true}); 31 | })(); -------------------------------------------------------------------------------- /plugins/alchemyPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import AlchemyPlugin from "./alchemyPlugin"; 2 | 3 | export default AlchemyPlugin; -------------------------------------------------------------------------------- /plugins/alchemyPlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugins/alloraPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ -------------------------------------------------------------------------------- /plugins/alloraPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/alloraPlugin/README.md: -------------------------------------------------------------------------------- 1 | # Allora Plugin for Virtuals Game 2 | 3 | The [Allora Network](https://allora.network) plugin seamlessly empowers G.A.M.E agents with real-time, advanced, self-improving AI inferences, delivering high-performance insights without introducing any additional complexity. 4 | 5 | ### Features 6 | - Get price inferences for various assets and timeframes 7 | - Get all available topics on Allora Network 8 | - Fetch inferences by topic ID 9 | 10 | ### Available Functions 11 | 1. `getPriceInference`: Fetches the price inference for the specified asset and a timeframe 12 | 2. `getAllTopics`: Retrieves all available topics on Allora Network 13 | 3. `getInferenceByTopicId`: Fetches the latest inference for a specific topic 14 | 15 | 16 | ## Installation 17 | 18 | To install the plugin, use npm or yarn: 19 | 20 | ```bash 21 | npm install @virtuals-protocol/game-allora-plugin 22 | ``` 23 | 24 | or 25 | 26 | ```bash 27 | yarn add @virtuals-protocol/game-allora-plugin 28 | ``` 29 | 30 | ## Usage 31 | 32 | ### Importing the Plugin 33 | 34 | First, import the `AlloraPlugin` class from the plugin: 35 | 36 | ```typescript 37 | import AlloraPlugin from "@virtuals-protocol/game-allora-plugin"; 38 | ``` 39 | 40 | ### Setup environment variables 41 | 42 | Set the following environment variables: 43 | - `ALLORA_API_KEY`: Create an API key by [creating an account](https://developer.upshot.xyz/signup). 44 | - `ALLORA_CHAIN_SLUG` (Optional): Must be one of: `mainnet`, `testnet`. Default value: `testnet` 45 | 46 | ### Creating a Worker 47 | 48 | Create a worker with the necessary Allora API client config: 49 | 50 | ```typescript 51 | const alloraPlugin = new AlloraPlugin({ 52 | apiClientConfig: { 53 | chainSlug: process.env.ALLORA_CHAIN_SLUG as ChainSlug, // Should be one of "testnet" or "mainnet". Default: "testnet" 54 | apiKey: process.env.ALLORA_API_KEY, // Default key: UP-17f415babba7482cb4b446a1 55 | }, 56 | }); 57 | ``` 58 | 59 | ### Creating an Agent 60 | 61 | Create an agent and add the worker to it: 62 | 63 | ```typescript 64 | import { GameAgent } from "@virtuals-protocol/game"; 65 | 66 | const agent = new GameAgent("GAME_API_KEY", { 67 | name: "Allora Worker", 68 | goal: "Retrieve the price of ETH in 5 minutes.", 69 | description: "You are an AI agent able to fetch price inferences and topic inferences from Allora Network.", 70 | workers: [alloraPlugin.getWorker({})], 71 | }); 72 | ``` 73 | 74 | ### Running the Agent 75 | 76 | Initialize and run the agent: 77 | 78 | ```typescript 79 | (async () => { 80 | await agent.init(); 81 | 82 | while (true) { 83 | await agent.step({ 84 | verbose: true, 85 | }); 86 | } 87 | })(); 88 | ``` 89 | -------------------------------------------------------------------------------- /plugins/alloraPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-allora-plugin", 3 | "version": "0.1.1", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "ts-node-dev": "^2.0.0", 16 | "typescript": "^5.7.2" 17 | }, 18 | "dependencies": { 19 | "@virtuals-protocol/game": "^0.1.4", 20 | "tsup": "^8.3.5", 21 | "@alloralabs/allora-sdk": "^0.1.0" 22 | }, 23 | "files": [ 24 | "dist" 25 | ], 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/game-by-virtuals/game-node" 29 | } 30 | } -------------------------------------------------------------------------------- /plugins/alloraPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug, PriceInferenceTimeframe, PriceInferenceToken } from "@alloralabs/allora-sdk"; 2 | import { GameAgent } from "@virtuals-protocol/game"; 3 | import AlloraPlugin from "."; 4 | 5 | 6 | const alloraPlugin = new AlloraPlugin({ 7 | apiClientConfig: { 8 | chainSlug: process.env.ALLORA_CHAIN_SLUG as ChainSlug, 9 | apiKey: process.env.ALLORA_API_KEY, // Default key: UP-17f415babba7482cb4b446a1 10 | }, 11 | }); 12 | 13 | // Create an agent with the worker 14 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 15 | name: "Allora Worker", 16 | goal: "Get the 5m price inference for BTC and Luna from Allora Network.", 17 | description: `You are an AI agent specialized in Allora Network. 18 | You are able to get price inferences from Allora Network and provide users insights into future price of different crypto assets. 19 | You are able to get details about the topics deployed on Allora Network and provide users insights into the topics. 20 | For all the active topics, you are able to get the latest inference using the topic id. 21 | The available assets for price inferences worker are ${Object.values(PriceInferenceToken).join(", ")}; 22 | for the following timeframes: ${Object.values(PriceInferenceTimeframe).join(", ")}. 23 | If a price inference is not available for a specific asset and timeframe, 24 | you should determine the topic id for the asset and timeframe and use the topics inferences worker to get the latest inference 25 | for the specified asset and timeframe. This will return the equivalent of a price inference for the asset and timeframe. 26 | `, 27 | workers: [ 28 | alloraPlugin.getWorker({}), 29 | ], 30 | }); 31 | 32 | (async () => { 33 | agent.setLogger((agent, message) => { 34 | console.log(`-----[${agent.name}]-----`); 35 | console.log(message); 36 | console.log("\n"); 37 | }); 38 | 39 | await agent.init(); 40 | 41 | while (true) { 42 | await agent.step({ 43 | verbose: true, 44 | }); 45 | } 46 | })(); 47 | -------------------------------------------------------------------------------- /plugins/alloraPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import AlloraPlugin from "./alloraPlugin"; 2 | 3 | export default AlloraPlugin; 4 | -------------------------------------------------------------------------------- /plugins/alloraPlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 4 | "module": "commonjs", /* Specify what module code is generated. */ 5 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 6 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 7 | "strict": true, /* Enable all strict type-checking options. */ 8 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugins/attpsPlugin/.env.example: -------------------------------------------------------------------------------- 1 | PROXY_ADDRESS= 2 | PRIVATE_KEY= 3 | RPC_URL= 4 | AGENT_API_KEY= -------------------------------------------------------------------------------- /plugins/attpsPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ -------------------------------------------------------------------------------- /plugins/attpsPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/attpsPlugin/README.md: -------------------------------------------------------------------------------- 1 | # ATTPs Plugin for Virtuals Game 2 | 3 | The ATTPs Plugin enables G.A.M.E agents to interact with the ATTPs Platform, providing capabilities for agent creation, data verification, and price querying functionalities. 4 | 5 | ### Features 6 | - Create and register new agents on the ATTPs Platform 7 | - Verify data with agent signatures 8 | - Query price data from various feeds 9 | 10 | ### Available Functions 11 | 1. `createAndRegisterAgent`: Creates and registers a new agent with specified signers and settings 12 | 2. `verifyData`: Verifies data with provided signatures and metadata 13 | 3. `priceQuery`: Fetches price data for specific feeds and agents 14 | 15 | ## Installation 16 | 17 | To install the plugin, use npm or yarn: 18 | 19 | ```bash 20 | npm install @virtuals-protocol/game-attps-plugin 21 | ``` 22 | 23 | or 24 | 25 | ```bash 26 | yarn add @virtuals-protocol/game-attps-plugin 27 | ``` 28 | 29 | ## Usage 30 | 31 | ### Importing the Plugin 32 | 33 | First, import the `AttpsPlugin` class from the plugin: 34 | 35 | ```typescript 36 | import AttpsPlugin from "@virtuals-protocol/game-attps-plugin"; 37 | ``` 38 | 39 | ### Setup environment variables 40 | 41 | Set the following environment variables: 42 | - `RPC_URL`: The RPC URL for the blockchain network 43 | - `PRIVATE_KEY`: Your private key for transaction signing 44 | - `PROXY_ADDRESS`: The proxy address for the ATTPs Platform 45 | 46 | ### Creating a Worker 47 | 48 | Create a worker with the necessary credentials: 49 | 50 | ```typescript 51 | const attpsPlugin = new AttpsPlugin({ 52 | credentials: { 53 | proxyAddress: process.env.PROXY_ADDRESS, 54 | privateKey: process.env.PRIVATE_KEY, 55 | rpcUrl: process.env.RPC_URL, 56 | } 57 | }); 58 | ``` 59 | 60 | ### Creating an Agent 61 | 62 | Create an agent and add the worker to it: 63 | 64 | ```typescript 65 | import { GameAgent } from "@virtuals-protocol/game"; 66 | 67 | const agent = new GameAgent("GAME_API_KEY", { 68 | name: "ATTPs Bot", 69 | goal: "Create agents, verify data, and query price data.", 70 | description: "A bot that can interact with the ATTPs Platform", 71 | workers: [attpsPlugin.getWorker({})], 72 | }); 73 | ``` 74 | 75 | ### Running the Agent 76 | 77 | Initialize and run the agent: 78 | 79 | ```typescript 80 | (async () => { 81 | await agent.init(); 82 | 83 | while (true) { 84 | await agent.step({ 85 | verbose: true, 86 | }); 87 | } 88 | })(); 89 | ``` 90 | -------------------------------------------------------------------------------- /plugins/attpsPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-attps-plugin", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "vitest run", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "dotenv": "^16.4.7", 16 | "ts-node-dev": "^2.0.0", 17 | "typescript": "^5.7.2", 18 | "vite": "^6.0.11", 19 | "vitest": "^3.0.4" 20 | }, 21 | "dependencies": { 22 | "@virtuals-protocol/game": "^0.1.7", 23 | "attps-sdk-js": "^0.1.0", 24 | "tsup": "^8.3.5" 25 | }, 26 | "files": [ 27 | "dist" 28 | ], 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/game-by-virtuals/game-node" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /plugins/attpsPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import AttpsPlugin from "./attpsPlugin"; 2 | 3 | export default AttpsPlugin; -------------------------------------------------------------------------------- /plugins/attpsPlugin/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface AttpsPriceQueryResponse { 2 | feedId: string 3 | validTimeStamp: number 4 | observeTimeStamp: number 5 | nativeFee: number 6 | tokenFee: number 7 | expireTimeStamp: number 8 | midPrice: string 9 | askPrice: string 10 | bidPrice: string 11 | } -------------------------------------------------------------------------------- /plugins/attpsPlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 4 | "module": "commonjs", /* Specify what module code is generated. */ 5 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 6 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 7 | "strict": true, /* Enable all strict type-checking options. */ 8 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugins/attpsPlugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | import { defineConfig } from 'vitest/config' 3 | import dotenv from 'dotenv' 4 | 5 | export default defineConfig({ 6 | test: { 7 | testTimeout: 300000, 8 | env: dotenv.config().parsed, 9 | }, 10 | resolve: { 11 | alias: { 12 | '@': path.resolve(__dirname, './src'), 13 | '@test': path.resolve(__dirname, './test'), 14 | }, 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-coingecko-maop-plugin", 3 | "version": "0.1.0", 4 | "description": "coingecko plugin for GAME SDK under questflow MAOP", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist", 11 | "example": "ts-node src/example.ts", 12 | "coinDataByID": "ts-node src/example.coinDataByID.ts", 13 | "coinPricesByAddress": "ts-node src/example.coinPricesByAddress.ts", 14 | "coinPricesByIDs": "ts-node src/example.coinPricesByIDs.ts", 15 | "coinsCategoriesList": "ts-node src/example.coinsCategoriesList.ts", 16 | "coinsListWithMarketData": "ts-node src/example.coinsListWithMarketData.ts", 17 | "newPoolsByNetwork": "ts-node src/example.newPoolsByNetwork.ts", 18 | "specificPoolData": "ts-node src/example.specificPoolData.ts", 19 | "tokenInfoByAddress": "ts-node src/example.tokenInfoByAddress.ts", 20 | "tokenPriceByAddresses": "ts-node src/example.tokenPriceByAddresses.ts", 21 | "topGainersLosersConfig": "ts-node src/example.topGainersLosersConfig.ts", 22 | "trendingPoolsByNetwork": "ts-node src/example.trendingPoolsByNetwork.ts", 23 | "trendingPoolsList": "ts-node src/example.trendingPoolsList.ts", 24 | "trendingSearchList": "ts-node src/example.trendingSearchList.ts" 25 | }, 26 | "author": "Questflow", 27 | "license": "MIT", 28 | "devDependencies": { 29 | "@types/node": "^22.13.1", 30 | "dotenv": "^16.4.7", 31 | "ts-node-dev": "^2.0.0", 32 | "typescript": "^5.7.3" 33 | }, 34 | "dependencies": { 35 | "@virtuals-protocol/game": "^0.1.4", 36 | "tsup": "^8.3.5" 37 | }, 38 | "files": [ 39 | "dist" 40 | ], 41 | "repository": { 42 | "type": "git", 43 | "url": "https://github.com/game-by-virtuals/game-node" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.coinDataByID.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "Fetch the coin data of Bitcoin.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.coinDataByID], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.coinPricesByAddress.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "Fetch the coin price by address: 0x2260fac5e5542a773aa44fbcfedf7c193bc2c599 on ethereum platform.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.coinPricesByAddress], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.coinPricesByIDs.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "Fetch the coin price of Bitcoin.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.coinPricesByIDs], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.coinsCategoriesList.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "list coin categories.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.coinsCategoriesList], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.coinsListWithMarketData.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "find bitcoin info with market data, use usd as standard currency.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.coinsListWithMarketData], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.newPoolsByNetwork.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "find new pools on network 'eth', include base_token.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.newPoolsByNetwork], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.specificPoolData.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "find pool address '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640' on network 'eth', include 'base_token,quote_token'.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.specificPoolData], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.tokenInfoByAddress.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "find token info on address '0xdac17f958d2ee523a2206206994597c13d831ec7' on network 'eth'.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.tokenInfoByAddress], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.tokenPriceByAddresses.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "find token price on address '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' on network 'eth'.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.tokenPriceByAddresses], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.topGainersLosersConfig.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "find top gainers and losers of last 24h, use 'usd' as currency, limit 1000 top coins .", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.topGainersLosersConfig], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.trendingPoolsByNetwork.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "find a page of last 24h trending pools on network 'eth', include 'base_token'.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.trendingPoolsByNetwork], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.trendingPoolsList.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "find trending pools list, include 'base_token'.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.trendingPoolsList], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.trendingSearchList.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "find trending search list.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [ 21 | coingeckoMAOPPlugin.getWorker({ 22 | functions: [coingeckoMAOPPlugin.trendingSearchList], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: "./.env" }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import CoingeckoMAOPPlugin from "."; 6 | 7 | const coingeckoMAOPPlugin = new CoingeckoMAOPPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.MAOP_GAME_PLUGIN_API_KEY, 10 | baseApiUrl: process.env.MAOP_ENDPOINT, 11 | }, 12 | }); 13 | 14 | // Create an agent with the worker 15 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 16 | name: "Cryptocurrency Data Worker", 17 | goal: "Fetch the coin data of Bitcoin.", 18 | description: 19 | "You are an AI agent specialized in fetching cryptocurrency data. You can retrieve current market data using the Coingecko API.", 20 | workers: [coingeckoMAOPPlugin.getWorker({})], 21 | }); 22 | 23 | (async () => { 24 | agent.setLogger((agent, message) => { 25 | console.log(`-----[${agent.name}]-----`); 26 | console.log(message); 27 | console.log("\n"); 28 | }); 29 | 30 | await agent.init(); 31 | 32 | while (true) { 33 | await agent.step({ 34 | verbose: true, 35 | }); 36 | } 37 | })(); 38 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import CoingeckoMAOPPlugin from "./coingeckoMaopPlugin"; 2 | 3 | export default CoingeckoMAOPPlugin; 4 | -------------------------------------------------------------------------------- /plugins/coingeckoMaopPlugin/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExecutableGameFunctionResponse, 3 | ExecutableGameFunctionStatus, 4 | } from "@virtuals-protocol/game"; 5 | 6 | export async function maopVisitor( 7 | apiKey: string, 8 | baseApiUrl: string, 9 | toolName: string, 10 | args: any, 11 | logger: any 12 | ) { 13 | // Prepare headers for the request 14 | const headers = { 15 | "content-type": "application/json", 16 | accept: "application/json", 17 | "x-game-plugin": "0.1", 18 | Authorization: apiKey, 19 | }; 20 | 21 | // Prepare request URL 22 | const url = new URL(`${baseApiUrl}/api/v3/game-plugin/run-tool`); 23 | 24 | logger(`Querying coin data with ID: ${args.id}`); 25 | 26 | // Make the API request 27 | const response = await fetch(url.href, { 28 | method: "post", 29 | headers, 30 | body: JSON.stringify({ toolName, args }), 31 | }); 32 | 33 | if (!response.ok) { 34 | throw new Error(`HTTP error! status: ${response.status}`); 35 | } 36 | 37 | const jsonResponse = await response.json(); 38 | // return jsonResponse; 39 | const message = `Successfully queried data. Response: ${JSON.stringify( 40 | jsonResponse 41 | )}`; 42 | logger(message); 43 | 44 | return new ExecutableGameFunctionResponse( 45 | ExecutableGameFunctionStatus.Done, 46 | message 47 | ); 48 | } 49 | 50 | export function exceptionHandler(e: any, logger: any) { 51 | const errorMessage = `An error occurred while querying coin data: ${ 52 | e.message || "Unknown error" 53 | }`; 54 | logger(errorMessage); 55 | 56 | return new ExecutableGameFunctionResponse( 57 | ExecutableGameFunctionStatus.Failed, 58 | errorMessage 59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /plugins/d.a.t.aPlugin/.env.example: -------------------------------------------------------------------------------- 1 | # GAME 2 | GAME_API_KEY=your-game-api-key 3 | 4 | # CARV D.A.T.A. API Configuration 5 | CARV_DATA_API_KEY=your-api-key 6 | CARV_DATA_AUTH_TOKEN=your-auth-token -------------------------------------------------------------------------------- /plugins/d.a.t.aPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | .env 4 | *.log -------------------------------------------------------------------------------- /plugins/d.a.t.aPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | tsconfig.json 3 | .gitignore -------------------------------------------------------------------------------- /plugins/d.a.t.aPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@game-node/d.a.t.a-plugin", 3 | "version": "1.0.0", 4 | "description": "D.A.T.A Plugin for SQL query execution and data analysis", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "build": "tsc", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [ 12 | "data", 13 | "sql", 14 | "query", 15 | "analysis" 16 | ], 17 | "author": "", 18 | "license": "ISC", 19 | "dependencies": { 20 | "@virtuals-protocol/game": "^0.1.7", 21 | "dotenv": "^16.4.7" 22 | }, 23 | "devDependencies": { 24 | "ts-node": "^10.9.2", 25 | "typescript": "^5.0.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /plugins/d.a.t.aPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { config } from 'dotenv'; 2 | import { GameAgent } from "@virtuals-protocol/game"; 3 | import { createDataPlugin } from "./d.a.t.aPlugin"; 4 | 5 | // Load environment variables 6 | config(); 7 | 8 | // Example usage 9 | async function example() { 10 | try { 11 | // Create data plugin with environment variables 12 | const plugin = createDataPlugin(); 13 | const worker = plugin.getWorker(); 14 | 15 | // Create an agent with the worker 16 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 17 | name: "D.A.T.A Query Agent", 18 | goal: "Query and analyze Ethereum transaction data", 19 | description: "An agent that executes SQL queries against the CARV D.A.T.A API", 20 | workers: [worker], 21 | }); 22 | 23 | // Set up logging 24 | agent.setLogger((agent, message) => { 25 | console.log(`-----[${agent.name}]-----`); 26 | console.log(message); 27 | console.log("\n"); 28 | }); 29 | 30 | // Initialize agent 31 | await agent.init(); 32 | 33 | // Execute SQL query 34 | const sql = "SELECT * FROM eth.transactions LIMIT 2"; 35 | console.log(`\nExecuting query: ${sql}`); 36 | const result = await worker.functions[0].executable({ sql }, console.log); 37 | console.log("Query Result:", JSON.stringify(result, null, 2)); 38 | 39 | // Let the agent process the result 40 | await agent.step({ 41 | verbose: true, 42 | }); 43 | } catch (error) { 44 | console.error("Error in example:", error); 45 | } 46 | } 47 | 48 | // Run example 49 | example(); -------------------------------------------------------------------------------- /plugins/d.a.t.aPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | export { createDataPlugin, DataPlugin } from "./d.a.t.aPlugin"; -------------------------------------------------------------------------------- /plugins/d.a.t.aPlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "./dist", 7 | "strict": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "forceConsistentCasingInFileNames": true 11 | }, 12 | "include": ["src/**/*"], 13 | "exclude": ["node_modules", "dist"] 14 | } -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/.env.example: -------------------------------------------------------------------------------- 1 | # DESK Exchange Plugin Configuration 2 | 3 | DESK_EXCHANGE_PRIVATE_KEY= 4 | 5 | DESK_EXCHANGE_NETWORK= -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/.gitignore: -------------------------------------------------------------------------------- 1 | #dependencies 2 | node_modules/ 3 | 4 | #env 5 | .env 6 | 7 | #build 8 | dist/ 9 | 10 | #IDE 11 | .vscode/ 12 | .idea/ 13 | 14 | #test 15 | coverage/ 16 | -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/README.md: -------------------------------------------------------------------------------- 1 | # Desk Plugin 2 | 3 | A plugin for interacting with a trading desk/exchange, providing functionality for perpetual trading, account management, and order handling. 4 | 5 | ## Features 6 | 7 | - Account summary retrieval 8 | - Perpetual trading execution 9 | - Order management (placing and canceling orders) 10 | 11 | ## Installation 12 | 13 | ```bash 14 | pnpm install @virtuals-protocol/game-desk-exchange-plugin 15 | ``` 16 | 17 | ## Configuration 18 | 19 | The plugin requires the following environment variables: 20 | 21 | - `DESK_EXCHANGE_PRIVATE_KEY`: Your private key for authentication 22 | - `DESK_EXCHANGE_NETWORK`: Network to connect to (`mainnet` or `testnet`) 23 | 24 | ## Usage 25 | 26 | ### Initializing the Plugin 27 | 28 | ```typescript 29 | import DeskExchangePlugin from '@virtuals-protocol/game-desk-exchange-plugin' 30 | 31 | const deskExchangePlugin = new DeskExchangePlugin({ 32 | credentials: { 33 | network: 'testnet', // or 'mainnet' 34 | privateKey: 'YOUR_PRIVATE_KEY' 35 | } 36 | }) 37 | ``` 38 | 39 | ### Available Functions 40 | 41 | #### Get Account Summary 42 | 43 | Retrieves a comprehensive summary of your account, including positions, orders, and collaterals. 44 | 45 | ```typescript 46 | const summary = await deskExchangePlugin.getAccountSummary.executable({}, logger) 47 | ``` 48 | 49 | #### Place Perpetual Trade 50 | 51 | Execute a perpetual trade with specified parameters. 52 | 53 | ```typescript 54 | const tradeRequest = { 55 | amount: '1', // Desired amount 56 | price: '10000', // Market price 57 | side: 'Long', // 'Long' or 'Short' 58 | symbol: 'BTC' // Trading pair symbol (without 'USD') 59 | } 60 | 61 | const trade = await deskExchangePlugin.perpTrade.executable(tradeRequest, logger) 62 | ``` 63 | 64 | #### Cancel Orders 65 | 66 | Cancel all open orders for the account. 67 | 68 | ```typescript 69 | const cancelResult = await deskExchangePlugin.cancelOrders.executable({}, logger) 70 | ``` 71 | 72 | ## Response Format 73 | 74 | All functions return an `ExecutableGameFunctionResponse` with the following structure: 75 | 76 | ```typescript 77 | { 78 | status: ExecutableGameFunctionStatus; 79 | feedback: string; 80 | } 81 | ``` 82 | 83 | ## Testing 84 | 85 | To run the tests: 86 | 87 | ```bash 88 | pnpm test 89 | ``` 90 | 91 | Make sure to set up the required environment variables before running tests. 92 | 93 | ## License 94 | 95 | [License Type] - See LICENSE file for details -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/__test__/log.ts: -------------------------------------------------------------------------------- 1 | import { log } from 'console' 2 | 3 | export const logger = (msg: string): void => { 4 | log(msg) 5 | } 6 | -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import configPrettier from 'eslint-config-prettier' 3 | import importPlugin from 'eslint-plugin-import' 4 | import prettierPlugin from 'eslint-plugin-prettier' 5 | import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort' 6 | import tseslint from 'typescript-eslint' 7 | 8 | export default tseslint.config( 9 | { ignores: ['dist', 'node_modules', 'coverage'] }, 10 | { 11 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 12 | files: ['**/*.ts'], 13 | languageOptions: { 14 | ecmaVersion: 2020, 15 | }, 16 | plugins: { 17 | import: importPlugin, 18 | configPrettier: configPrettier, 19 | prettier: prettierPlugin, 20 | 'simple-import-sort': simpleImportSortPlugin, 21 | }, 22 | rules: { 23 | 'no-console': 1, 24 | 'prettier/prettier': [ 25 | 'error', 26 | { 27 | printWidth: 120, 28 | semi: false, 29 | singleQuote: true, 30 | tabWidth: 2, 31 | trailingComma: 'all', 32 | }, 33 | ], 34 | '@typescript-eslint/no-explicit-any': 'off', 35 | '@typescript-eslint/no-inferrable-types': 'off', 36 | '@typescript-eslint/array-type': ['error', { default: 'generic' }], 37 | '@typescript-eslint/typedef': [ 38 | 1, 39 | { 40 | arrayDestructuring: true, 41 | arrowParameter: true, 42 | memberVariableDeclaration: true, 43 | objectDestructuring: true, 44 | parameter: true, 45 | propertyDeclaration: true, 46 | variableDeclaration: true, 47 | variableDeclarationIgnoreFunction: true, 48 | }, 49 | ], 50 | 'simple-import-sort/imports': 'error', 51 | 'simple-import-sort/exports': 'error', 52 | 'import/first': 'error', 53 | 'import/newline-after-import': 'error', 54 | 'import/no-duplicates': 'error', 55 | }, 56 | }, 57 | ) 58 | -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | setupFiles: ['/jest.setup.js'], 5 | } -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/jest.setup.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config({ path: '.env' }); -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-desk-exchange-plugin", 3 | "version": "1.0.0", 4 | "description": "DESK Exchange Plugin for ...", 5 | "main": "dist/index.js", 6 | "dependencies": { 7 | "@virtuals-protocol/game": "^0.1.7" 8 | }, 9 | "devDependencies": { 10 | "@desk-exchange/typescript-sdk": "1.0.3", 11 | "@eslint/js": "9.15.0", 12 | "@jest/globals": "29.7.0", 13 | "@types/jest": "29.5.14", 14 | "@types/node": "20.0.0", 15 | "eslint": "9.15.0", 16 | "eslint-config-prettier": "9.1.0", 17 | "eslint-plugin-import": "2.31.0", 18 | "eslint-plugin-prettier": "5.2.1", 19 | "eslint-plugin-simple-import-sort": "12.1.1", 20 | "jest": "29.7.0", 21 | "ts-jest": "29.2.5", 22 | "tsup": "8.3.5", 23 | "typescript-eslint": "8.16.0" 24 | }, 25 | "scripts": { 26 | "build": "tsup --format esm --dts", 27 | "dev": "tsup --watch --format esm --dts", 28 | "lint": "eslint . --config eslint.config.mjs", 29 | "test": "jest --coverage" 30 | } 31 | } -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/src/constants.ts: -------------------------------------------------------------------------------- 1 | export enum GAME_WORKER_FUNCTION_NAME { 2 | GET_ACCOUNT_SUMMARY = 'get_account_summary', 3 | CANCEL_ORDERS = 'cancel_orders', 4 | PERP_TRADE = 'perp_trade', 5 | } 6 | 7 | export const GAME_WORKER_FUNCTIONS: Array = Object.values(GAME_WORKER_FUNCTION_NAME) 8 | 9 | export enum FMT_ERRORS { 10 | SOMETHING_WENT_WRONG = 'Something went wrong: {{error}}', 11 | FAILED_TO_GET_ACCOUNT_SUMMARY = 'Failed to get account summary: {{error}}', 12 | FAILED_TO_CANCEL_ORDERS = 'Failed to cancel orders: {{error}}', 13 | FAILED_TO_PERP_TRADE = 'Failed to perp trade: {{error}}', 14 | } 15 | 16 | // NOTE: these messages are used in the feedback of the executable game function 17 | // also use to compare in tests 18 | export enum SUCCESS_MESSAGES { 19 | // get account summary 20 | ACCOUNT_SUMMARY = 'Here is the summary of your account:', 21 | YOUR_POSITIONS = 'Your positions:', 22 | YOUR_ORDERS = 'Your orders:', 23 | YOUR_COLLATERALS = 'Your collaterals:', 24 | // cancel orders 25 | ORDER_CANCELLED = 'Successfully cancelled:', 26 | // perp trade 27 | PERP_TRADE = 'Successfully placed', 28 | } 29 | -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import DeskExchangePlugin from './deskExchangePlugin' 2 | 3 | export default DeskExchangePlugin 4 | -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { ExecutableGameFunctionResponse, ExecutableGameFunctionStatus } from '@virtuals-protocol/game' 2 | 3 | import { FMT_ERRORS } from './constants' 4 | 5 | export function errorHandler(f: FMT_ERRORS, e: unknown, logger: (msg: string) => void) { 6 | let errorMessage: string 7 | // build message 8 | if (e instanceof Error) { 9 | errorMessage = f.replace('{{error}}', e.message) 10 | } else { 11 | errorMessage = FMT_ERRORS.SOMETHING_WENT_WRONG.replace('{{error}}', JSON.stringify(e, null, 2)) 12 | } 13 | // log 14 | logger(errorMessage) 15 | // return error response 16 | return new ExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Failed, errorMessage) 17 | } 18 | 19 | export const formatNumber = (num: string | number, decimalPlaces?: number): string => { 20 | return Number(num).toLocaleString(undefined, { 21 | style: 'decimal', 22 | minimumFractionDigits: 0, 23 | maximumFractionDigits: decimalPlaces || 8, 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "rootDir": ".", 6 | "types": [ 7 | "node" 8 | ], 9 | "moduleResolution": "bundler", 10 | "module": "ESNext", 11 | }, 12 | "include": [ 13 | "./src/**/*.ts", 14 | "./__test__/**/*.ts", 15 | "./__test__/**/*.test.ts" 16 | ] 17 | } -------------------------------------------------------------------------------- /plugins/deskExchangePlugin/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig({ 4 | entry: ['./src/index.ts'], 5 | outDir: 'dist', 6 | sourcemap: true, 7 | clean: true, 8 | format: ['esm'], 9 | }) 10 | -------------------------------------------------------------------------------- /plugins/discordPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | coverage/ -------------------------------------------------------------------------------- /plugins/discordPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/discordPlugin/README.md: -------------------------------------------------------------------------------- 1 | # Discord Plugin for Virtuals Game 2 | 3 | This plugin allows you to integrate Discord functionalities into your Virtuals Game. With this plugin, you can send message, pin message, add reaction and delete message in Discord. 4 | 5 | ## Installation 6 | 7 | To install the plugin, use npm or yarn: 8 | 9 | ```bash 10 | npm install @virtuals-protocol/game-discord-plugin 11 | ``` 12 | 13 | or 14 | 15 | ```bash 16 | yarn add @virtuals-protocol/game-discord-plugin 17 | ``` 18 | 19 | ## Usage 20 | 21 | ### Importing the Plugin 22 | 23 | First, import the `DiscordPlugin` class from the plugin: 24 | 25 | ```typescript 26 | import DiscordPlugin from "@virtuals-protocol/game-discord-plugin"; 27 | ``` 28 | 29 | ### Creating a Worker 30 | 31 | Create a worker with the necessary DiscordPlugin credentials: 32 | 33 | ```typescript 34 | const discordPlugin = new DiscordPlugin({ 35 | credentials: { 36 | botToken: "" 37 | }, 38 | }); 39 | ``` 40 | 41 | ### Creating an Agent 42 | 43 | Create an agent and add the worker to it: 44 | 45 | ```typescript 46 | import { GameAgent } from "@virtuals-protocol/game"; 47 | 48 | const agent = new GameAgent("", { 49 | name: "Discord Bot", 50 | goal: "increase engagement and grow follower count", 51 | description: "A bot that can reply message, add reaction, pin message and delete message in Discord.", 52 | workers: [ 53 | discordPlugin.getWorker({ 54 | // Define the functions that the worker can perform, by default it will use the all functions defined in the plugin 55 | functions: [ 56 | discordPlugin.sendMessageFunction, 57 | discordPlugin.addReactionFunction, 58 | discordPlugin.pinMessageFunction, 59 | discordPlugin.deleteMessageFunction, 60 | ], 61 | }), 62 | ], 63 | }); 64 | ``` 65 | 66 | ### Running the Agent 67 | 68 | Initialize and run the agent: 69 | 70 | ```typescript 71 | (async () => { 72 | await agent.init(); 73 | 74 | while (true) { 75 | await agent.step({ 76 | verbose: true, 77 | }); 78 | } 79 | })(); 80 | ``` 81 | 82 | ## Available Functions 83 | 84 | The `DiscordPlugin` provides several functions that can be used by the agent: 85 | 86 | - `sendMessageFunction`: Send a message in discord 87 | - `addReactionFunction`: Add a reaction in discord message. 88 | - `pinMessageFunction`: Pin a message in discord message. 89 | - `deleteMessageFunction`: Delete a message in discord. 90 | 91 | ## Event Handlers 92 | The plugin also supports custom handlers for the following Discord events: 93 | ### Handling Incoming Messages 94 | To handle incoming messages, use the `onMessage` method to listen on: 95 | ```typescript 96 | discordPlugin.onMessage((msg) => { 97 | console.log("Received message:", msg); 98 | }); 99 | ``` 100 | 101 | ## License 102 | 103 | This project is licensed under the MIT License. 104 | -------------------------------------------------------------------------------- /plugins/discordPlugin/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | }; -------------------------------------------------------------------------------- /plugins/discordPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-discord-plugin", 3 | "version": "0.1.4", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "jest --coverage", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "@types/jest": "^29.5.14", 16 | "@types/node": "^22.10.3", 17 | "@typescript-eslint/eslint-plugin": "^8.19.1", 18 | "@typescript-eslint/parser": "^8.19.1", 19 | "eslint": "^9.17.0", 20 | "typescript": "^5.7.2", 21 | "jest": "^29.7.0", 22 | "ts-jest": "^29.2.5", 23 | "ts-node": "^10.9.2", 24 | "ts-node-dev": "^2.0.0" 25 | }, 26 | "dependencies": { 27 | "@virtuals-protocol/game": "^0.1.7", 28 | "discord.js": "^14.17.3", 29 | "tsup": "^8.3.5" 30 | }, 31 | "files": [ 32 | "dist" 33 | ], 34 | "repository": { 35 | "type": "git", 36 | "url": "https://github.com/game-by-virtuals/game-node" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /plugins/discordPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from "@virtuals-protocol/game"; 2 | import DiscordPlugin from "./discordPlugin"; 3 | 4 | // Create a worker with the functions 5 | const discordPlugin = new DiscordPlugin({ 6 | credentials: { 7 | botToken: "" 8 | }, 9 | }); 10 | 11 | const agent = new GameAgent("", { 12 | name: "Discord Bot", 13 | goal: "A bot that will auto reply messages", 14 | description: "This agent will auto reply to messages, add reactions, pin messages, and delete messages", 15 | workers: [ 16 | discordPlugin.getWorker({ 17 | // Define the functions that the worker can perform, by default it will use the all functions defined in the plugin 18 | functions: [ 19 | discordPlugin.sendMessageFunction, 20 | discordPlugin.addReactionFunction, 21 | discordPlugin.pinMessageFunction, 22 | discordPlugin.deleteMessageFunction, 23 | ], 24 | }), 25 | ], 26 | }); 27 | 28 | (async () => { 29 | agent.setLogger((agent, message) => { 30 | console.log(`-----[${agent.name}]-----`); 31 | console.log(message); 32 | console.log("\n"); 33 | }); 34 | 35 | await agent.init(); 36 | discordPlugin.onMessage(async (msg) => { 37 | if (msg.guild) { 38 | console.log(msg); 39 | console.log(`Guild Name: ${msg.guild.name}, Guild ID: ${msg.guild.id}`); 40 | } else { 41 | console.log('This message is not from a guild (e.g., DM).'); 42 | } 43 | if (msg.author.bot) { 44 | console.log('This message is from a bot.'); 45 | return; 46 | } 47 | const agentTgWorker = agent.getWorkerById(discordPlugin.getWorker().id); 48 | const task = "Reply to chat id: " + msg.channelId + " and the incoming is message: " + msg.content + " and the message id is: " + msg.id; 49 | 50 | await agentTgWorker.runTask(task, { 51 | verbose: true, // Optional: Set to true to log each step 52 | }); 53 | }); 54 | })(); 55 | 56 | -------------------------------------------------------------------------------- /plugins/discordPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import DiscordPlugin from "./discordPlugin"; 2 | 3 | export default DiscordPlugin; 4 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | ./coverage 2 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/.npmignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game-by-virtuals/game-node/0d991ce28db65a5a0e2d4046bc05d8d3bfcab3df/plugins/dpsnPlugin/.npmignore -------------------------------------------------------------------------------- /plugins/dpsnPlugin/__test__/__mocks__/dpsn-client.ts: -------------------------------------------------------------------------------- 1 | import mockDpsnClient from '../mocks/dpsnClient.mock'; 2 | 3 | // Export the mock client as the default export 4 | const MockDpsnClient = jest.fn().mockImplementation(() => { 5 | return mockDpsnClient; 6 | }); 7 | 8 | export default MockDpsnClient; 9 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/__test__/mocks/dpsnClient.mock.ts: -------------------------------------------------------------------------------- 1 | // Mock for DpsnClient 2 | const mockDpsnClient = { 3 | init: jest.fn().mockResolvedValue(undefined), 4 | subscribe: jest.fn().mockImplementation((topic, handler) => { 5 | // Store the handler for later use in tests 6 | mockDpsnClient.subscriptionHandlers[topic] = handler; 7 | return Promise.resolve(); 8 | }), 9 | unsubscribe: jest.fn().mockImplementation((topic) => { 10 | // Remove the handler for the topic 11 | delete mockDpsnClient.subscriptionHandlers[topic]; 12 | return Promise.resolve(); 13 | }), 14 | disconnect: jest.fn().mockResolvedValue(undefined), 15 | setBlockchainConfig: jest.fn(), 16 | 17 | // Helper properties for testing 18 | subscriptionHandlers: {} as Record< 19 | string, 20 | (topic: string, message: any) => void 21 | >, 22 | 23 | // Helper method to simulate receiving a message 24 | simulateMessage: (topic: string, message: any) => { 25 | const handler = mockDpsnClient.subscriptionHandlers[topic]; 26 | if (handler) { 27 | // Call the handler with topic and message as separate parameters 28 | // The handler will emit an event with the combined object 29 | handler(topic, message); 30 | } 31 | }, 32 | 33 | resetMocks: () => { 34 | mockDpsnClient.init.mockClear(); 35 | mockDpsnClient.subscribe.mockClear(); 36 | mockDpsnClient.unsubscribe.mockClear(); 37 | mockDpsnClient.disconnect.mockClear(); 38 | mockDpsnClient.subscriptionHandlers = {}; 39 | }, 40 | }; 41 | 42 | export default mockDpsnClient; 43 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/__test__/mocks/gameAgent.mock.ts: -------------------------------------------------------------------------------- 1 | // Mock for GameAgent and related classes 2 | import { GameWorker, GameFunction } from '@virtuals-protocol/game'; 3 | 4 | // Mock for GameAgent 5 | export const mockGameAgent = { 6 | init: jest.fn().mockResolvedValue(undefined), 7 | step: jest.fn().mockResolvedValue(undefined), 8 | setLogger: jest.fn(), 9 | name: 'Mock Agent', 10 | }; 11 | 12 | // Helper to create a mock GameWorker 13 | export const createMockGameWorker = (id: string, functions: GameFunction[]) => { 14 | const mockWorker = new GameWorker({ 15 | id, 16 | name: `Mock Worker ${id}`, 17 | description: 'Mock worker for testing', 18 | functions, 19 | }); 20 | 21 | // Spy on methods 22 | jest.spyOn(mockWorker, 'getEnvironment'); 23 | 24 | return mockWorker; 25 | }; 26 | 27 | // Reset all mocks 28 | export const resetGameAgentMocks = () => { 29 | mockGameAgent.init.mockClear(); 30 | mockGameAgent.step.mockClear(); 31 | mockGameAgent.setLogger.mockClear(); 32 | }; 33 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/__test__/setup.ts: -------------------------------------------------------------------------------- 1 | // Jest setup file 2 | import dotenv from 'dotenv'; 3 | import path from 'path'; 4 | 5 | // Load environment variables from .env file 6 | dotenv.config({ path: path.resolve(__dirname, "../../../.env") }); 7 | 8 | // Set default timeout for tests 9 | jest.setTimeout(60000); // Increased to 60 seconds 10 | 11 | // Global mocks and setup 12 | global.console = { 13 | ...console, 14 | // You can customize console behavior for tests if needed 15 | log: jest.fn(), 16 | error: jest.fn(), 17 | warn: jest.fn(), 18 | info: jest.fn(), 19 | }; 20 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/coverage/lcov-report/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game-by-virtuals/game-node/0d991ce28db65a5a0e2d4046bc05d8d3bfcab3df/plugins/dpsnPlugin/coverage/lcov-report/favicon.png -------------------------------------------------------------------------------- /plugins/dpsnPlugin/coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game-by-virtuals/game-node/0d991ce28db65a5a0e2d4046bc05d8d3bfcab3df/plugins/dpsnPlugin/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /plugins/dpsnPlugin/coverage/lcov.info: -------------------------------------------------------------------------------- 1 | TN: 2 | SF:src/dpsnPlugin.ts 3 | FN:35,(anonymous_8) 4 | FN:64,(anonymous_9) 5 | FN:81,(anonymous_11) 6 | FN:92,(anonymous_13) 7 | FN:101,(anonymous_14) 8 | FN:110,(anonymous_16) 9 | FN:131,(anonymous_17) 10 | FN:143,(anonymous_18) 11 | FN:143,(anonymous_19) 12 | FN:156,(anonymous_20) 13 | FN:160,(anonymous_21) 14 | FN:178,(anonymous_22) 15 | FN:181,(anonymous_23) 16 | FN:201,(anonymous_24) 17 | FN:212,(anonymous_25) 18 | FN:212,(anonymous_26) 19 | FN:225,(anonymous_27) 20 | FN:230,(anonymous_28) 21 | FN:239,(anonymous_29) 22 | FN:259,(anonymous_30) 23 | FNF:20 24 | FNH:19 25 | FNDA:26,(anonymous_8) 26 | FNDA:18,(anonymous_9) 27 | FNDA:8,(anonymous_11) 28 | FNDA:0,(anonymous_13) 29 | FNDA:14,(anonymous_14) 30 | FNDA:6,(anonymous_16) 31 | FNDA:9,(anonymous_17) 32 | FNDA:3,(anonymous_18) 33 | FNDA:3,(anonymous_19) 34 | FNDA:2,(anonymous_20) 35 | FNDA:1,(anonymous_21) 36 | FNDA:1,(anonymous_22) 37 | FNDA:1,(anonymous_23) 38 | FNDA:5,(anonymous_24) 39 | FNDA:3,(anonymous_25) 40 | FNDA:3,(anonymous_26) 41 | FNDA:2,(anonymous_27) 42 | FNDA:1,(anonymous_28) 43 | FNDA:1,(anonymous_29) 44 | FNDA:3,(anonymous_30) 45 | DA:1,2 46 | DA:7,2 47 | DA:12,2 48 | DA:33,26 49 | DA:36,26 50 | DA:38,26 51 | DA:39,26 52 | DA:40,26 53 | DA:45,26 54 | DA:53,26 55 | DA:54,0 56 | DA:65,18 57 | DA:66,17 58 | DA:67,17 59 | DA:68,16 60 | DA:70,1 61 | DA:71,1 62 | DA:84,8 63 | DA:85,8 64 | DA:95,0 65 | DA:102,14 66 | DA:103,4 67 | DA:115,6 68 | DA:132,9 69 | DA:143,3 70 | DA:144,3 71 | DA:145,3 72 | DA:147,3 73 | DA:148,1 74 | DA:154,2 75 | DA:156,2 76 | DA:157,2 77 | DA:159,2 78 | DA:162,1 79 | DA:168,1 80 | DA:171,1 81 | DA:179,1 82 | DA:182,1 83 | DA:191,0 84 | DA:192,0 85 | DA:202,5 86 | DA:212,3 87 | DA:213,3 88 | DA:214,3 89 | DA:216,3 90 | DA:217,1 91 | DA:223,2 92 | DA:225,2 93 | DA:226,2 94 | DA:228,2 95 | DA:231,1 96 | DA:232,1 97 | DA:240,1 98 | DA:249,0 99 | DA:250,0 100 | DA:260,3 101 | DA:261,2 102 | DA:262,2 103 | DA:267,2 104 | LF:59 105 | LH:53 106 | BRDA:38,0,0,26 107 | BRDA:38,0,1,25 108 | BRDA:39,1,0,26 109 | BRDA:39,1,1,25 110 | BRDA:41,2,0,26 111 | BRDA:41,2,1,25 112 | BRDA:53,3,0,0 113 | BRDA:65,4,0,17 114 | BRDA:102,5,0,4 115 | BRDA:119,6,0,6 116 | BRDA:119,6,1,1 117 | BRDA:119,7,0,1 118 | BRDA:119,7,1,5 119 | BRDA:119,8,0,6 120 | BRDA:119,8,1,6 121 | BRDA:123,9,0,1 122 | BRDA:123,9,1,5 123 | BRDA:123,10,0,6 124 | BRDA:123,10,1,6 125 | BRDA:147,11,0,1 126 | BRDA:216,12,0,1 127 | BRDA:260,13,0,2 128 | BRDA:260,14,0,3 129 | BRDA:260,14,1,2 130 | BRF:24 131 | BRH:23 132 | end_of_record 133 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | testMatch: ['**/__test__/**/*.test.ts'], 5 | collectCoverage: true, 6 | collectCoverageFrom: [ 7 | 'src/**/*.ts', 8 | '!src/example.ts', 9 | '!src/index.ts' 10 | ], 11 | coverageDirectory: 'coverage', 12 | coverageReporters: ['text', 'lcov'], 13 | transform: { 14 | '^.+\\.tsx?$': ['ts-jest', { 15 | tsconfig: 'tsconfig.json', 16 | }], 17 | }, 18 | moduleNameMapper: { 19 | '^@/(.*)$': '/src/$1', 20 | }, 21 | setupFilesAfterEnv: ['/__test__/setup.ts'], 22 | }; 23 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-dpsn-plugin", 3 | "version": "1.0.0", 4 | "description": "DPSN plugin for Virtuals Protocol Game Node", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "jest --coverage", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "@types/jest": "^29.5.14", 16 | "@types/node": "^22.10.3", 17 | "@typescript-eslint/eslint-plugin": "^8.19.1", 18 | "@typescript-eslint/parser": "^8.19.1", 19 | "eslint": "^9.17.0", 20 | "jest": "^29.7.0", 21 | "ts-jest": "^29.2.5", 22 | "ts-node": "^10.9.2", 23 | "ts-node-dev": "^2.0.0", 24 | "tsup": "^8.3.5", 25 | "typescript": "^5.7.3" 26 | }, 27 | "dependencies": { 28 | "@virtuals-protocol/game": "^0.1.7", 29 | "dpsn-client": "^1.0.9" 30 | }, 31 | "files": [ 32 | "dist" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/plugin_metadata.yml: -------------------------------------------------------------------------------- 1 | # General Information 2 | plugin_name: 'game-dpsn-plugin' # Name of the plugin 3 | author: 'DPSN-Tech-Team' # Author and team name 4 | logo_url: 'https://pbs.twimg.com/profile_images/1832068773064355840/tUbNKURh_400x400.jpg' # URL to the author photo or team logo (512x512 recommended) (if any) 5 | release_date: 2025-04 # Release date (YYYY-MM) 6 | 7 | # Description 8 | short_description: 'DPSN plugin to subscribe to dpsn data streams for Virtuals Protocol agents' # One-liner description for listings 9 | detailed_description: 'This plugin allows Virtuals Protocol agents to connect to and interact with real-time data streams from the DPSN Data Streams Store. Agents can use it for decision-making and event handling. Developers can also publish custom streams using the dpsn-client-nodejs library on npmjs.' 10 | 11 | # Media & Assets 12 | plugin_logo_url: 'https://pbs.twimg.com/profile_images/1832068773064355840/tUbNKURh_400x400.jpg' # URL to the plugin logo (512x512 recommended) (if any or fallback to logo_url) 13 | 14 | # Contact & Support 15 | x_account_handle: '@DPSN_org' # X (formerly known as Twitter) account handle (ie: @GAME_Virtuals) 16 | support_contact: 'sanil@dpsn.org' # Email or Slack/Discord link for user support 17 | community_url: 'https://t.me/dpsn_dev' # Forum or community link (if any) 18 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from '@virtuals-protocol/game'; 2 | import DpsnPlugin from './dpsnPlugin'; 3 | import dotenv from 'dotenv'; 4 | import path from 'path'; 5 | dotenv.config({ path: path.resolve(__dirname, '../.env') }); 6 | 7 | // Define the topic you want to subscribe to 8 | const TOPIC = 9 | '0xe14768a6d8798e4390ec4cb8a4c991202c2115a5cd7a6c0a7ababcaf93b4d2d4/BTCUSDT/ticker'; 10 | 11 | const dpsnPlugin = new DpsnPlugin({ 12 | credentials: { 13 | privateKey: process.env.EVM_WALLET_PRIVATE_KEY || '', 14 | dpsnUrl: process.env.DPSN_URL || '', 15 | chainOptions: { 16 | network: 'testnet', 17 | wallet_chain_type: 'ethereum', 18 | }, 19 | }, 20 | }); 21 | 22 | const agent = new GameAgent(process.env.VIRTUALS_API_KEY || '', { 23 | name: 'DPSN Bot', 24 | goal: 'A bot that consumes realtime data from dpsn', 25 | description: 'A bot that consumes realtime data from dpsn', 26 | workers: [ 27 | dpsnPlugin.getWorker({ 28 | functions: [ 29 | dpsnPlugin.subscribeToTopicFunction, 30 | dpsnPlugin.unsubscribeToTopicFunction, 31 | ], 32 | }), 33 | ], 34 | }); 35 | 36 | (async () => { 37 | agent.setLogger((agent, message) => { 38 | console.log(`---------[${agent.name}]--------`); 39 | console.log(message); 40 | console.log('\n'); 41 | }); 42 | 43 | await agent.init(); 44 | const agentDpsnWorker = agent.getWorkerById(agent.workers[0].id); 45 | 46 | dpsnPlugin.onMessage(({ topic, message }) => { 47 | console.log('Topic: ', topic); 48 | console.log('Message', message); 49 | }); 50 | 51 | try { 52 | await agentDpsnWorker.runTask(`subscribe to topic ${TOPIC}`, { 53 | verbose: true, 54 | }); 55 | await agentDpsnWorker.runTask(`unsubscribe to topic ${TOPIC}`, { 56 | verbose: true, 57 | }); 58 | await agentDpsnWorker.runTask(`disconnect`, { verbose: true }); 59 | 60 | // Keep the process running 61 | process.on('SIGINT', async () => { 62 | console.log('Disconnecting from DPSN...'); 63 | await dpsnPlugin.disconnect(); 64 | process.exit(0); 65 | }); 66 | } catch (error) { 67 | console.error('Error:', error); 68 | await dpsnPlugin.disconnect(); 69 | process.exit(1); 70 | } 71 | })(); 72 | -------------------------------------------------------------------------------- /plugins/dpsnPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import DpsnPlugin from './dpsnPlugin'; 2 | 3 | export default DpsnPlugin; 4 | -------------------------------------------------------------------------------- /plugins/echochambersPlugin/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Savage | x.com/savageapi | t.me/savagejay 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /plugins/echochambersPlugin/README.md: -------------------------------------------------------------------------------- 1 | # Echochambers Plugin for GAME Protocol 2 | 3 | ## Overview 4 | This plugin enables GAME Protocol agents to interact with Echochambers, providing functionality for message sending, history retrieval, and metrics analysis. 5 | 6 | ## Features Added 7 | 8 | ### Core Functions 9 | 1. Message Sending 10 | - `sendMessageFunction`: Send messages to Echochambers rooms with reasoning context 11 | 12 | 2. History Retrieval 13 | - `getRoomHistoryFunction`: Get message history from specific rooms with customizable limits 14 | 15 | 3. Metrics Analysis 16 | - `getRoomMetricsFunction`: Get metrics for specific rooms 17 | - `getAgentMetricsFunction`: Get metrics for all agents in a room 18 | - `getMetricsHistoryFunction`: Get historical metrics data for rooms 19 | 20 | ### Infrastructure 21 | - New [EchochambersPlugin]() class for managing Echochambers interactions 22 | - REST API integration 23 | - Type-safe function definitions 24 | 25 | ## Implementation Details 26 | ### Core Components 27 | - [echochambersPlugin.ts]() Main plugin implementation with: 28 | - Message sending functionality 29 | - Room history retrieval 30 | - Room and agent metrics analysis 31 | - Metrics history tracking 32 | - `types.ts`: TypeScript interfaces for all Echochambers data structures 33 | - `example.ts`: Basic usage example 34 | - `example_mock.ts`: mock example 35 | 36 | ### Plugin Architecture 37 | - Follows GAME Protocol's worker/function pattern 38 | - Uses getter methods for function definitions (matching other plugins) 39 | - Implements proper TypeScript types for configuration and responses 40 | 41 | ## Testing 42 | - Verified all function implementations: 43 | - Message sending 44 | - History retrieval 45 | - Room metrics 46 | - Agent metrics 47 | - Metrics history 48 | - Validated TypeScript types and compilation 49 | 50 | ## Dependencies 51 | - No new dependencies beyond core GAME Protocol requirements 52 | - Uses standard `axios` for API calls 53 | 54 | ## Future Updates 55 | - WebSocket support 56 | - Advanced context tracking 57 | - Enhanced room management features 58 | -------------------------------------------------------------------------------- /plugins/echochambersPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-echochambers-plugin", 3 | "version": "0.1.0", 4 | "main": "./dist/index.js", 5 | "module": "./dist/index.mjs", 6 | "types": "./dist/index.d.ts", 7 | "license": "MIT", 8 | "author": { 9 | "name": "SavageOps", 10 | "url": "https://x.com/savageapi" 11 | }, 12 | "scripts": { 13 | "build": "tsup src/index.ts --format cjs,esm --dts", 14 | "dev": "tsup src/index.ts --format cjs,esm --dts --watch", 15 | "example": "ts-node src/example.ts", 16 | "example:mock": "ts-node src/example_mock.ts", 17 | "example:2": "ts-node src/example_2.ts", 18 | "example:dev": "nodemon --exec ts-node src/example.ts", 19 | "example:2:dev": "nodemon --exec ts-node src/example_2.ts", 20 | "prepublish": "npm run build" 21 | }, 22 | "dependencies": { 23 | "@virtuals-protocol/game": "^0.1.4", 24 | "axios": "^1.6.5" 25 | }, 26 | "devDependencies": { 27 | "typescript": "^5.3.3", 28 | "tsup": "^8.0.1", 29 | "ts-node": "^10.9.2", 30 | "nodemon": "^3.0.2" 31 | }, 32 | "peerDependencies": { 33 | "@virtuals-protocol/game": "^0.1.4" 34 | }, 35 | "keywords": [ 36 | "virtuals", 37 | "game", 38 | "protocol", 39 | "echochambers", 40 | "plugin" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /plugins/echochambersPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from "@virtuals-protocol/game"; 2 | import EchochambersPlugin from "./echochambersPlugin"; 3 | 4 | // Create plugin instance with credentials 5 | const echochambersPlugin = new EchochambersPlugin({ 6 | credentials: { 7 | apiKey: "your-api-key-here", // Replace with your API key 8 | }, 9 | sender: { 10 | username: "Virtuals_Agent", 11 | model: "VirtualsLLM" 12 | } 13 | }); 14 | 15 | // Create an agent with the worker 16 | const agent = new GameAgent("API_KEY", { 17 | name: "Echochambers Bot", 18 | goal: "monitor room metrics and engage in conversations", 19 | description: "A bot that can monitor room metrics, retrieve history, and send messages", 20 | workers: [ 21 | echochambersPlugin.getWorker({ 22 | // Define the functions that the worker can perform, by default it will use all functions defined in the plugin 23 | // functions: [ 24 | // echochambersPlugin.sendMessageFunction, 25 | // echochambersPlugin.getRoomHistoryFunction, 26 | // echochambersPlugin.getRoomMetricsFunction, 27 | // echochambersPlugin.getAgentMetricsFunction, 28 | // echochambersPlugin.getMetricsHistoryFunction, 29 | // ], 30 | // Define the environment variables that the worker can access 31 | // getEnvironment: async () => ({ 32 | // activeRoom: "general", 33 | // messagesSent: 0, 34 | // lastActivity: new Date().toISOString(), 35 | // metrics: { 36 | // totalMessagesSent: 0, 37 | // activeConversations: 0, 38 | // responseRate: 0, 39 | // averageResponseTime: 0 40 | // } 41 | // }), 42 | }), 43 | ], 44 | }); 45 | 46 | (async () => { 47 | // Set up logging 48 | agent.setLogger((agent, message) => { 49 | const timestamp = new Date().toISOString(); 50 | console.log(`\n-----[${timestamp}][${agent.name}]-----`); 51 | console.log(`Goal: ${agent.goal}`); 52 | console.log(`Message: ${message}\n`); 53 | }); 54 | 55 | // Initialize the agent 56 | await agent.init(); 57 | 58 | // Run the agent continuously 59 | while (true) { 60 | await agent.step({ 61 | verbose: true, 62 | }); 63 | 64 | // Optional: Add a delay between steps 65 | await new Promise(resolve => setTimeout(resolve, 60000)); // 1 minute delay 66 | } 67 | })(); 68 | -------------------------------------------------------------------------------- /plugins/echochambersPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import EchochambersPlugin from './echochambersPlugin'; 2 | export default EchochambersPlugin; 3 | -------------------------------------------------------------------------------- /plugins/echochambersPlugin/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface Message { 2 | id: string; 3 | content: string; 4 | sender: { 5 | username: string; 6 | model: string; 7 | }; 8 | timestamp: string; 9 | roomId: string; 10 | } 11 | 12 | export interface RoomHistory { 13 | messages: Message[]; 14 | roomId: string; 15 | } 16 | 17 | export interface Metric { 18 | category: string; 19 | value: number; 20 | maxValue: number; 21 | description: string; 22 | } 23 | 24 | export interface AgentMetrics { 25 | agent: string; 26 | metrics: Metric[]; 27 | } 28 | 29 | export interface RoomMetrics { 30 | metrics: Metric[]; 31 | agentMetrics: AgentMetrics[]; 32 | lastUpdated: number; 33 | } 34 | 35 | export interface MetricsHistory { 36 | roomMetrics: Array<{ 37 | metrics: Metric[]; 38 | }>; 39 | } 40 | -------------------------------------------------------------------------------- /plugins/echochambersPlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "./dist", 7 | "strict": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "forceConsistentCasingInFileNames": true 11 | }, 12 | "include": ["src"], 13 | "exclude": ["node_modules", "dist"] 14 | } 15 | -------------------------------------------------------------------------------- /plugins/elfaAiPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | coverage/ -------------------------------------------------------------------------------- /plugins/elfaAiPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/elfaAiPlugin/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | }; -------------------------------------------------------------------------------- /plugins/elfaAiPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-elfa-ai-plugin", 3 | "version": "0.1.0", 4 | "description": "Elfa AI Plugin for Virtuals GAME", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "build": "tsup src/index.ts --dts --format cjs,esm --out-dir dist", 10 | "test": "jest --coverage" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "ts-node-dev": "^2.0.0", 16 | "typescript": "^5.7.2", 17 | "@types/jest": "^29.5.14", 18 | "jest": "^29.7.0", 19 | "ts-jest": "^29.2.5" 20 | }, 21 | "dependencies": { 22 | "tsup": "^8.3.5", 23 | "axios": "^0.27.2", 24 | "@virtuals-protocol/game": "^0.1.7" 25 | }, 26 | "files": [ 27 | "dist" 28 | ], 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/game-by-virtuals/game-node" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /plugins/elfaAiPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from "@virtuals-protocol/game"; 2 | import ElfaAiPlugin from "./elfaAiPlugin"; 3 | 4 | // Replace "" with your actual Elfa API key or load it from process.env. 5 | const elfaAiPlugin = new ElfaAiPlugin({ 6 | credentials: { 7 | apiKey: "", 8 | }, 9 | }); 10 | 11 | // Create a worker from the plugin that includes all available functions. 12 | const elfaWorker = elfaAiPlugin.getWorker({ 13 | functions: [ 14 | elfaAiPlugin.pingFunction, 15 | elfaAiPlugin.keyStatusFunction, 16 | elfaAiPlugin.mentionsFunction, 17 | elfaAiPlugin.topMentionsFunction, 18 | elfaAiPlugin.searchMentionsFunction, 19 | elfaAiPlugin.trendingTokensFunction, 20 | elfaAiPlugin.accountSmartStatsFunction, 21 | ], 22 | }); 23 | 24 | // Create a GameAgent that uses the above worker. 25 | // Replace "" with your actual agent API token. 26 | const elfaAgent = new GameAgent("", { 27 | name: "Elfa AI Agent", 28 | goal: "Demonstrate integration with the Elfa AI API", 29 | description: 30 | "An agent that interacts with the Elfa AI API to discover alpha from industry insiders, influencers & traders.", 31 | workers: [elfaWorker], 32 | }); 33 | 34 | (async () => { 35 | elfaAgent.setLogger((agent, message) => { 36 | console.log(`-----[${agent.name}]-----`); 37 | console.log(message); 38 | console.log("\n"); 39 | }); 40 | await elfaAgent.init(); 41 | const worker = elfaAgent.getWorkerById(elfaWorker.id); 42 | if (!worker) { 43 | throw new Error("Worker not found in the agent"); 44 | } 45 | const taskDescription = "get my api key status from the Elfa AI API"; 46 | console.log("Executing task:", taskDescription); 47 | await worker.runTask(taskDescription, { verbose: true }); 48 | })(); 49 | -------------------------------------------------------------------------------- /plugins/elfaAiPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import ElfaAiPlugin from "./elfaAiPlugin"; 2 | 3 | export default ElfaAiPlugin; 4 | -------------------------------------------------------------------------------- /plugins/ensoPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | 4 | .env 5 | src/.env 6 | -------------------------------------------------------------------------------- /plugins/ensoPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/ensoPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-enso-plugin", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "@types/node": "^22.13.9", 16 | "dotenv": "^16.4.7", 17 | "ts-node-dev": "^2.0.0", 18 | "typescript": "^5.7.2" 19 | }, 20 | "dependencies": { 21 | "@ensofinance/sdk": "^1.0.10", 22 | "@virtuals-protocol/game": "^0.1.4", 23 | "tsup": "^8.3.5", 24 | "viem": "^2.22.16" 25 | }, 26 | "files": [ 27 | "dist" 28 | ], 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/game-by-virtuals/game-node" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /plugins/ensoPlugin/src/.env.example: -------------------------------------------------------------------------------- 1 | WALLET_PRIVATE_KEY= 2 | RPC_PROVIDER_URL= 3 | ENSO_API_KEY=1e02632d-6feb-4a75-a157-documentation 4 | -------------------------------------------------------------------------------- /plugins/ensoPlugin/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const ENSO_SUPPORTED_CHAINS = new Map([ 2 | [1, "ethereum"], 3 | [10, "optimism"], 4 | [56, "bnb chain"], 5 | [100, "gnosis"], 6 | [137, "polygon"], 7 | [324, "zksync"], 8 | [8453, "base"], 9 | [42161, "arbitrum"], 10 | [43114, "avalanche"], 11 | [59144, "linea"], 12 | [80094, "berachain"], 13 | ]); 14 | 15 | export const ENSO_ETH = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" as const; 16 | 17 | export const ERC20_ABI_MIN = [ 18 | { 19 | constant: false, 20 | inputs: [ 21 | { 22 | name: "_spender", 23 | type: "address", 24 | }, 25 | { 26 | name: "_value", 27 | type: "uint256", 28 | }, 29 | ], 30 | name: "approve", 31 | outputs: [ 32 | { 33 | name: "", 34 | type: "bool", 35 | }, 36 | ], 37 | payable: false, 38 | stateMutability: "nonpayable", 39 | type: "function", 40 | }, 41 | ] as const; 42 | -------------------------------------------------------------------------------- /plugins/ensoPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from "@virtuals-protocol/game"; 2 | import { getEnsoWorker } from "."; 3 | import { base } from "viem/chains"; 4 | import { 5 | Address, 6 | createPublicClient, 7 | createWalletClient, 8 | http, 9 | PublicClient, 10 | } from "viem"; 11 | import { privateKeyToAccount } from "viem/accounts"; 12 | import * as dotenv from "dotenv"; 13 | 14 | dotenv.config(); 15 | 16 | const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as Address); 17 | 18 | const publicClient = createPublicClient({ 19 | transport: http(process.env.RPC_PROVIDER_URL), 20 | chain: base, 21 | }) as PublicClient; 22 | 23 | const walletClient = createWalletClient({ 24 | account: account, 25 | transport: http(process.env.RPC_PROVIDER_URL), 26 | chain: base, 27 | }); 28 | 29 | (async () => { 30 | const ensoActionsWorker = await getEnsoWorker({ 31 | wallet: walletClient, 32 | publicClient, 33 | apiKey: process.env.ENSO_API_KEY || "1e02632d-6feb-4a75-a157-documentation", 34 | }); 35 | 36 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 37 | name: "Enso Actions Agent", 38 | goal: "Find the best route between two tokens and execute it", 39 | description: 40 | "An agent that finds the best route between tokens and executes it", 41 | workers: [ensoActionsWorker], 42 | }); 43 | 44 | agent.setLogger((agent, message) => { 45 | console.log(`-----[${agent.name}]-----`); 46 | console.log(`${message}\n`); 47 | }); 48 | 49 | await agent.init(); 50 | const agentWorker = agent.getWorkerById(ensoActionsWorker.id); 51 | const task = `Swap 0.0002 WETH (address 0x4200000000000000000000000000000000000006) for USDC (address 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913)`; 52 | 53 | await agentWorker.runTask(task, { verbose: true }); 54 | })(); 55 | -------------------------------------------------------------------------------- /plugins/ensoPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ensoPlugin"; 2 | -------------------------------------------------------------------------------- /plugins/ensoPlugin/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { EnsoClient } from "@ensofinance/sdk"; 2 | 3 | type Route = Awaited>["route"]; 4 | 5 | // The buildRoutePath will return string as follows: 6 | // 7 | //"Split via enso 8 | // Internal Routes: 9 | // Route 1: 10 | // Swap via enso 11 | // Route 2: 12 | // Swap via enso 13 | // Deposit via stakestone-stone 14 | // Deposit via uniswap-v2" 15 | 16 | /** 17 | * Build a route path string from Enso route 18 | * @returns string 19 | */ 20 | export function buildRoutePath(route: Route): string { 21 | let str = ""; 22 | 23 | function buildStep(step: Route[number], indent: string = ""): string { 24 | const action = capitalizeWord(step.action); 25 | let stepStr = `${indent}${action} via ${step.protocol}\n`; 26 | 27 | if (step.internalRoutes) { 28 | stepStr += `${indent} Internal Routes:\n`; 29 | step.internalRoutes.forEach((internalRoute, index) => { 30 | stepStr += `${indent} Route ${index + 1}:\n`; 31 | internalRoute.forEach((internalStep) => { 32 | stepStr += buildStep(internalStep, `${indent} `); 33 | }); 34 | }); 35 | } 36 | 37 | return stepStr; 38 | } 39 | 40 | route.forEach((step) => { 41 | str += buildStep(step); 42 | }); 43 | 44 | return str.trim(); // Trim to remove the last newline 45 | } 46 | 47 | function capitalizeWord(word: string) { 48 | return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); 49 | } 50 | -------------------------------------------------------------------------------- /plugins/ensoPlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 4 | "module": "commonjs", /* Specify what module code is generated. */ 5 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 6 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 7 | "strict": true, /* Enable all strict type-checking options. */ 8 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugins/evalEnginePlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | .env 4 | *.lock -------------------------------------------------------------------------------- /plugins/evalEnginePlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/evalEnginePlugin/README.md: -------------------------------------------------------------------------------- 1 | # Eval Engine Twitter Plugin for Virtuals Game 2 | 3 | This plugin allows you to integrate Twitter functionalities into your Virtuals Game with [Eval Engine](https://evalengine.ai). With this plugin, you can post tweets, reply to tweets, like tweets, and more. 4 | 5 | > This plugin is built on top of twitterPlugin. It logs the performance of your AI Agent and prevents spammy replies 6 | 7 | ## Installation 8 | 9 | Setup Chromia Private Key: [Guide](https://github.com/evalengine/eval-docs/blob/main/setup-chromia-account.md) 10 | 11 | To install the plugin, use npm or yarn: 12 | 13 | ```bash 14 | npm install @virtuals-protocol/game-eval-engine-plugin 15 | ``` 16 | 17 | or 18 | 19 | ```bash 20 | yarn add @virtuals-protocol/game-eval-engine-plugin 21 | ``` 22 | 23 | ## Usage 24 | 25 | ### Importing the Plugin 26 | 27 | First, import the `TwitterPlugin` class from the plugin: 28 | 29 | ```typescript 30 | import TwitterEvalEnginePlugin from "@virtuals-protocol/game-eval-engine-plugin"; 31 | ``` 32 | 33 | ### Creating a Worker 34 | 35 | Create a worker with the necessary Twitter credentials: 36 | 37 | ```typescript 38 | const evalClient = await initEvalClient(PRIVATE_KEY); 39 | 40 | const twitterPlugin = new TwitterEvalEnginePlugin({ 41 | credentials: { 42 | apiKey: X_API_KEY, 43 | apiSecretKey: X_API_KEY_SECRET, 44 | accessToken: X_ACCESS_TOKEN, 45 | accessTokenSecret: X_ACCESS_TOKEN_SECRET, 46 | }, 47 | thresholdScore: 0.5, 48 | evalClient, 49 | }); 50 | 51 | ``` 52 | 53 | ### Creating an Agent 54 | 55 | Create an agent and add the worker to it: 56 | 57 | ```typescript 58 | import { GameAgent } from "@virtuals-protocol/game"; 59 | 60 | const agent = new GameAgent("API_KEY", { 61 | name: "Twitter Bot", 62 | goal: "Increase engagement and grow follower count", 63 | description: "A bot that can post tweets, reply to tweets, and like tweets", 64 | workers: [twitterPlugin.getWorker()], 65 | }); 66 | ``` 67 | 68 | ### Running the Agent 69 | 70 | Initialize and run the agent: 71 | 72 | ```typescript 73 | (async () => { 74 | await agent.init(); 75 | 76 | while (true) { 77 | await agent.step({ 78 | verbose: true, 79 | }); 80 | } 81 | })(); 82 | ``` 83 | 84 | ## Available Functions 85 | 86 | The `TwitterPlugin` provides several functions that can be used by the agent: 87 | 88 | - `searchTweetsFunction`: Search for tweets based on a query. 89 | - `replyTweetFunction`: Reply to a tweet. 90 | - `postTweetFunction`: Post a new tweet. 91 | - `likeTweetFunction`: Like a tweet. 92 | - `quoteTweetFunction`: Quote a tweet with your own commentary. 93 | 94 | ## License 95 | 96 | This project is licensed under the MIT License. 97 | -------------------------------------------------------------------------------- /plugins/evalEnginePlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-eval-engine-plugin", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "ts-node-dev": "^2.0.0", 16 | "typescript": "^5.7.2" 17 | }, 18 | "dependencies": { 19 | "@virtuals-protocol/game": "^0.1.4", 20 | "eval-engine-sdk": "^0.0.6", 21 | "tsup": "^8.3.5", 22 | "twitter-api-v2": "^1.19.0" 23 | }, 24 | "files": [ 25 | "dist" 26 | ], 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/game-by-virtuals/game-node" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /plugins/evalEnginePlugin/src/evalEngine.ts: -------------------------------------------------------------------------------- 1 | import { CHROMIA_CHAIN, EvalClient } from "eval-engine-sdk"; 2 | 3 | export const initEvalClient = async (privateKey: string) => { 4 | const evalClient = await EvalClient.init(privateKey, CHROMIA_CHAIN.MAINNET, { 5 | url: "https://api.evalengine.ai/api", 6 | prefix: "EVA", 7 | pub: "026822066B64608E0A6E071D8AE76BDE509011FF823DBBF9FD6AC2E1F202904A0A", 8 | }); 9 | 10 | return evalClient; 11 | }; 12 | -------------------------------------------------------------------------------- /plugins/evalEnginePlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from "@virtuals-protocol/game"; 2 | 3 | import dotenv from "dotenv"; 4 | dotenv.config(); 5 | 6 | // import TwitterEvalEnginePlugin from "@virtuals-protocol/game-evalengine-twitter-plugin"; 7 | import TwitterEvalEnginePlugin from "./index"; 8 | import { initEvalClient } from "./evalEngine"; 9 | 10 | const { 11 | X_API_KEY, 12 | X_API_KEY_SECRET, 13 | X_ACCESS_TOKEN, 14 | X_ACCESS_TOKEN_SECRET, 15 | VIRTUALS_API_KEY, 16 | PRIVATE_KEY, 17 | } = process.env; 18 | 19 | // Validate required environment variables 20 | if ( 21 | !X_API_KEY || 22 | !X_API_KEY_SECRET || 23 | !X_ACCESS_TOKEN || 24 | !X_ACCESS_TOKEN_SECRET || 25 | !VIRTUALS_API_KEY 26 | ) { 27 | throw new Error( 28 | "Missing required environment variables. Please check your .env file." 29 | ); 30 | } 31 | 32 | (async () => { 33 | // Uncomment and validate PRIVATE_KEY if initEvalClient is needed 34 | if (!PRIVATE_KEY) { 35 | throw new Error("Missing PRIVATE_KEY environment variable"); 36 | } 37 | const evalClient = await initEvalClient(PRIVATE_KEY); 38 | 39 | // Create a worker with the functions 40 | const twitterPlugin = new TwitterEvalEnginePlugin({ 41 | credentials: { 42 | apiKey: X_API_KEY, 43 | apiSecretKey: X_API_KEY_SECRET, 44 | accessToken: X_ACCESS_TOKEN, 45 | accessTokenSecret: X_ACCESS_TOKEN_SECRET, 46 | }, 47 | thresholdScore: 50, 48 | evalClient, 49 | }); 50 | 51 | // Create an agent with the worker 52 | const agent = new GameAgent(VIRTUALS_API_KEY, { 53 | name: "Twitter Reply Bot", 54 | goal: "increase engagement and grow follower count, and always reply to tweets", 55 | description: "A bot that can post tweets, reply to tweets, and like tweets", 56 | workers: [ 57 | twitterPlugin.getWorker({ 58 | // Define the functions that the worker can perform, by default it will use the all functions defined in the plugin 59 | functions: [ 60 | twitterPlugin.searchTweetsFunction, 61 | twitterPlugin.replyTweetFunction, 62 | // twitterPlugin.postTweetFunction, 63 | ], 64 | // Define the environment variables that the worker can access, by default it will use the metrics defined in the plugin 65 | // getEnvironment: async () => ({ 66 | // ...(await twitterPlugin.getMetrics()), 67 | // username: "virtualsprotocol", 68 | // token_price: "$100.00", 69 | // }), 70 | }), 71 | ], 72 | }); 73 | 74 | agent.setLogger((agent, message) => { 75 | console.log(`-----[${agent.name}]-----`); 76 | console.log(message); 77 | console.log("\n"); 78 | }); 79 | 80 | await agent.init(); 81 | 82 | while (true) { 83 | await agent.step({ 84 | verbose: true, 85 | }); 86 | await setInterval(() => {}, 10000); 87 | } 88 | })(); 89 | -------------------------------------------------------------------------------- /plugins/evalEnginePlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import TwitterPlugin from "./twitterPlugin"; 2 | 3 | export default TwitterPlugin; 4 | -------------------------------------------------------------------------------- /plugins/evalEnginePlugin/src/tweet/fetch-tweet.ts: -------------------------------------------------------------------------------- 1 | // Modified code of https://github.com/vercel/react-tweet 2 | 3 | import type { Tweet } from "./tweet"; 4 | import axios, { AxiosRequestConfig } from 'axios'; 5 | 6 | const SYNDICATION_URL = "https://cdn.syndication.twimg.com"; 7 | 8 | export class TwitterApiError extends Error { 9 | status: number; 10 | data: any; 11 | 12 | constructor({ 13 | message, 14 | status, 15 | data, 16 | }: { 17 | message: string; 18 | status: number; 19 | data: any; 20 | }) { 21 | super(message); 22 | this.name = "TwitterApiError"; 23 | this.status = status; 24 | this.data = data; 25 | } 26 | } 27 | 28 | const TWEET_ID = /^[0-9]+$/; 29 | 30 | function getToken(id: string) { 31 | return ((Number(id) / 1e15) * Math.PI) 32 | .toString(6 ** 2) 33 | .replace(/(0+|\.)/g, ""); 34 | } 35 | 36 | /** 37 | * Fetches a tweet from the Twitter syndication API. 38 | */ 39 | export async function fetchTweet( 40 | id: string, 41 | fetchOptions?: AxiosRequestConfig 42 | ): Promise<{ data?: Tweet; tombstone?: true; notFound?: true }> { 43 | if (id.length > 40 || !TWEET_ID.test(id)) { 44 | throw new Error(`Invalid tweet id: ${id}`); 45 | } 46 | 47 | const url = new URL(`${SYNDICATION_URL}/tweet-result`); 48 | 49 | url.searchParams.set("id", id); 50 | url.searchParams.set("lang", "en"); 51 | url.searchParams.set( 52 | "features", 53 | [ 54 | "tfw_timeline_list:", 55 | "tfw_follower_count_sunset:true", 56 | "tfw_tweet_edit_backend:on", 57 | "tfw_refsrc_session:on", 58 | "tfw_fosnr_soft_interventions_enabled:on", 59 | "tfw_show_birdwatch_pivots_enabled:on", 60 | "tfw_show_business_verified_badge:on", 61 | "tfw_duplicate_scribes_to_settings:on", 62 | "tfw_use_profile_image_shape_enabled:on", 63 | "tfw_show_blue_verified_badge:on", 64 | "tfw_legacy_timeline_sunset:true", 65 | "tfw_show_gov_verified_badge:on", 66 | "tfw_show_business_affiliate_badge:on", 67 | "tfw_tweet_edit_frontend:on", 68 | ].join(";") 69 | ); 70 | url.searchParams.set("token", getToken(id)); 71 | 72 | try { 73 | const res = await axios.get(url.toString(), fetchOptions); 74 | 75 | if (res.data?.__typename === "TweetTombstone") { 76 | return { tombstone: true }; 77 | } 78 | return { data: res.data }; 79 | } catch (error) { 80 | if (axios.isAxiosError(error)) { 81 | if (error.response?.status === 404) { 82 | return { notFound: true }; 83 | } 84 | 85 | throw new TwitterApiError({ 86 | message: error.response?.data?.error || `Failed to fetch tweet at "${url}" with "${error.response?.status}".`, 87 | status: error.response?.status || 500, 88 | data: error.response?.data, 89 | }); 90 | } 91 | throw error; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /plugins/evalEnginePlugin/src/tweet/get-tweet.ts: -------------------------------------------------------------------------------- 1 | // Modified code of https://github.com/vercel/react-tweet 2 | 3 | import { AxiosRequestConfig } from "axios"; 4 | import { fetchTweet } from "./fetch-tweet"; 5 | import type { Tweet } from "./tweet"; 6 | 7 | /** 8 | * Returns a tweet from the Twitter syndication API. 9 | */ 10 | export async function getTweet( 11 | id: string, 12 | fetchOptions?: AxiosRequestConfig 13 | ): Promise { 14 | const { data, tombstone, notFound } = await fetchTweet(id, fetchOptions); 15 | 16 | if (notFound) { 17 | console.error( 18 | `The tweet ${id} does not exist or has been deleted by the account owner. Update your code to remove this tweet when possible.` 19 | ); 20 | } else if (tombstone) { 21 | console.error( 22 | `The tweet ${id} has been made private by the account owner. Update your code to remove this tweet when possible.` 23 | ); 24 | } 25 | 26 | return data; 27 | } 28 | -------------------------------------------------------------------------------- /plugins/farcasterPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ -------------------------------------------------------------------------------- /plugins/farcasterPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/farcasterPlugin/README.md: -------------------------------------------------------------------------------- 1 | # Farcaster Plugin for Virtuals Game 2 | 3 | This plugin allows you to integrate Farcaster functionalities into your Virtuals Game. With this plugin, you can post casts on the Farcaster network. 4 | 5 | ## Installation 6 | 7 | To install the plugin, use npm or yarn: 8 | 9 | ```bash 10 | npm install @virtuals-protocol/game-farcaster-plugin 11 | ``` 12 | 13 | or 14 | 15 | ```bash 16 | yarn add @virtuals-protocol/game-farcaster-plugin 17 | ``` 18 | 19 | ## Usage 20 | 21 | ### Importing the Plugin 22 | 23 | First, import the `FarcasterPlugin` class from the plugin: 24 | 25 | ```typescript 26 | import FarcasterPlugin from "@virtuals-protocol/game-farcaster-plugin"; 27 | ``` 28 | 29 | ### Creating a Worker 30 | 31 | Create a worker with the necessary Farcaster credentials: 32 | 33 | ```typescript 34 | const farcasterPlugin = new FarcasterPlugin({ 35 | credentials: { 36 | neynarApiKey: "your_neynar_api_key" 37 | }, 38 | }); 39 | ``` 40 | 41 | ### Creating an Agent 42 | 43 | Create an agent and add the worker to it: 44 | 45 | ```typescript 46 | import { GameAgent } from "@virtuals-protocol/game"; 47 | 48 | const agent = new GameAgent("API_KEY", { 49 | name: "Farcaster Bot", 50 | goal: "Engage with the Farcaster community", 51 | description: "A bot that can post casts on Farcaster", 52 | workers: [farcasterPlugin.getWorker()], 53 | }); 54 | ``` 55 | 56 | ### Running the Agent 57 | 58 | Initialize and run the agent: 59 | 60 | ```typescript 61 | (async () => { 62 | await agent.init(); 63 | 64 | while (true) { 65 | await agent.step({ 66 | verbose: true, 67 | }); 68 | } 69 | })(); 70 | ``` 71 | 72 | ## Available Functions 73 | 74 | The `FarcasterPlugin` currently provides the following function: 75 | 76 | - `postCastFunction`: Post a new cast to Farcaster. Takes two arguments: 77 | - `text`: The content of the cast 78 | - `cast_reasoning`: The reasoning behind the cast 79 | 80 | ## License 81 | 82 | This project is licensed under the MIT License. 83 | -------------------------------------------------------------------------------- /plugins/farcasterPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-farcaster-plugin", 3 | "version": "0.1.3", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "ts-node-dev": "^2.0.0", 16 | "typescript": "^5.7.2" 17 | }, 18 | "dependencies": { 19 | "@coinbase/agentkit": "^0.1.1", 20 | "@coinbase/agentkit-langchain": "^0.1.0", 21 | "@virtuals-protocol/game": "^0.1.7", 22 | "tsup": "^8.3.5" 23 | }, 24 | "files": [ 25 | "dist" 26 | ], 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/game-by-virtuals/game-node" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /plugins/farcasterPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import FarcasterPlugin from "./farcasterPlugin"; 2 | 3 | export default FarcasterPlugin; 4 | -------------------------------------------------------------------------------- /plugins/imageGenPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-imagegen-plugin", 3 | "version": "0.1.0", 4 | "description": "Image generation plugin for GAME SDK using Together AI", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "Chinese Powered Labs", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "@types/node": "^22.13.1", 16 | "dotenv": "^16.4.7", 17 | "ts-node-dev": "^2.0.0", 18 | "typescript": "^5.7.3" 19 | }, 20 | "dependencies": { 21 | "@virtuals-protocol/game": "^0.1.4", 22 | "tsup": "^8.3.5" 23 | }, 24 | "files": [ 25 | "dist" 26 | ], 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/game-by-virtuals/game-node" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /plugins/imageGenPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { config } from 'dotenv'; 2 | config({ path: './.env' }); 3 | 4 | import { GameAgent } from "@virtuals-protocol/game"; 5 | import ImageGenPlugin from "."; 6 | 7 | const imageGenPlugin = new ImageGenPlugin({ 8 | apiClientConfig: { 9 | apiKey: process.env.TOGETHER_API_KEY, // Default key: UP-17f415babba7482cb4b446a1 10 | }, 11 | }); 12 | 13 | // Create an agent with the worker 14 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 15 | name: "Image Generation Worker", 16 | goal: "Generate an anime-style character image with Twitter logo.", 17 | description: "You are an AI agent specialized in generating images. You can create images based on text prompts using Together AI's FLUX schnell model.", 18 | workers: [ 19 | imageGenPlugin.getWorker({}), 20 | ], 21 | }); 22 | 23 | (async () => { 24 | agent.setLogger((agent, message) => { 25 | console.log(`-----[${agent.name}]-----`); 26 | console.log(message); 27 | console.log("\n"); 28 | }); 29 | 30 | await agent.init(); 31 | 32 | while (true) { 33 | await agent.step({ 34 | verbose: true, 35 | }); 36 | } 37 | })(); -------------------------------------------------------------------------------- /plugins/imageGenPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import ImageGenPlugin from "./imageGenPlugin"; 2 | 3 | export default ImageGenPlugin; -------------------------------------------------------------------------------- /plugins/mindNetworkPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ -------------------------------------------------------------------------------- /plugins/mindNetworkPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/mindNetworkPlugin/README.md: -------------------------------------------------------------------------------- 1 | # Mind Network Plugin for Virtuals GAME Framework 2 | 3 | A plugin for interacting with [Mind Network Hubs](https://dapp.mindnetwork.xyz/votetoearn/voteonhubs/) within the [Virtuals ecosystem](https://www.virtuals.io/). [CitizenZ](https://www.mindnetwork.xyz/citizenz) and broader communities can secure trust their agents operation and decisioning. 4 | 5 | ## Overview 6 | 7 | The [Mind Network](https://www.mindnetwork.xyz/) plugin empowers users to participate in secure, privacy-preserving voting on the Mind Network. Leveraging [Fully Homomorphic Encryption (FHE)](https://docs.mindnetwork.xyz/minddocs/developer-guide/fhe-validation), it ensures encrypted votes while allowing users to track rewards earned for their participation. Designed for seamless integration with the [Virtuals GAME Framework](https://whitepaper.virtuals.io/developer-documents/game-framework), this plugin enables interactive and guided actions for an enhanced user experience. 8 | 9 | ## Features 10 | - **Voter Registration:** Join the Mind Network's Randgen Hub and other hubs to participate in secure voting, validation and consensus. 11 | - **FHE Encryption:** Safeguard vote content using Fully Homomorphic Encryption. The key difference is encryption key is never shared but still be able to run computation over encrypted data. 12 | - **Submit Encrypted Votes:** Cast votes in Mind Network Hubs elections without compromising data privacy. So AI Agents can get consensus over collective predictions, inference and serving. 13 | - **Reward Tracking:** Monitor your vFHE rewards earned through voting contributions. 14 | 15 | ## Installation 16 | 17 | Depedency for the plugin: 18 | - [mind-randgen-sdk](https://github.com/mind-network/mind-sdk-randgen-ts) 19 | - [mind-sdk-hubs](https://github.com/mind-network/mind-sdk-hubs-ts) 20 | 21 | To install the plugin, use the following command: 22 | 23 | ```bash 24 | npm install @virtuals-protocol/game-mind-network-plugin 25 | ``` 26 | 27 | ## Configuration 28 | 29 | Before using the plugin, configure the necessary environment variables: 30 | 31 | ```bash 32 | MIND_HOT_WALLET_PRIVATE_KEY= 33 | MIND_COLD_WALLET_ADDRESS= 34 | ``` 35 | 36 | ## Support 37 | 38 | If you have any queries, please feel free to contact Mind Team via [Discord](https://discord.com/invite/UYj94MJdGJ) or [Twitter](https://x.com/mindnetwork_xyz). -------------------------------------------------------------------------------- /plugins/mindNetworkPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-mind-network-plugin", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "ts-node": "^10.9.2", 16 | "ts-node-dev": "^2.0.0", 17 | "typescript": "^5.7.2" 18 | }, 19 | "dependencies": { 20 | "@virtuals-protocol/game": "^0.1.4", 21 | "ethers": "^6.13.5", 22 | "mind-randgen-sdk": "^1.0.2", 23 | "tsup": "^8.3.5" 24 | }, 25 | "files": [ 26 | "dist" 27 | ], 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/game-by-virtuals/game-node" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugins/mindNetworkPlugin/src/cache.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | latestEncryptedNumber: "", 3 | lastVoteTs: 0, 4 | } -------------------------------------------------------------------------------- /plugins/mindNetworkPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from "@virtuals-protocol/game"; 2 | import MindNetworkPlugin from "."; 3 | 4 | const mindNetworkPlugin = new MindNetworkPlugin({}); 5 | 6 | // Create an agent with the worker 7 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 8 | name: "Mind Network Voter", 9 | goal: "Get the reward amount earned for voting with FHE.", 10 | description: `You are an AI agent specialized in Mind Network. Check the voting reward I have earned so far.`, 11 | workers: [ 12 | mindNetworkPlugin.getWorker({}), 13 | ], 14 | }); 15 | 16 | (async () => { 17 | agent.setLogger((agent, message) => { 18 | console.log(`-----[${agent.name}]-----`); 19 | console.log(message); 20 | console.log("\n"); 21 | }); 22 | 23 | await agent.init(); 24 | 25 | while (true) { 26 | await agent.step({ 27 | verbose: true, 28 | }); 29 | } 30 | })(); 31 | -------------------------------------------------------------------------------- /plugins/mindNetworkPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import MindNetworkPlugin from "./mindNetworkPlugin"; 2 | 3 | export default MindNetworkPlugin; 4 | -------------------------------------------------------------------------------- /plugins/mindNetworkPlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 4 | "module": "commonjs", /* Specify what module code is generated. */ 5 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 6 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 7 | "strict": true, /* Enable all strict type-checking options. */ 8 | "skipLibCheck": true , /* Skip type checking all .d.ts files. */ 9 | "outDir": "./dist", /* Specify an output folder for all emitted files. */ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /plugins/onChainActionsPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ -------------------------------------------------------------------------------- /plugins/onChainActionsPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/onChainActionsPlugin/README.md: -------------------------------------------------------------------------------- 1 | # Onchain Actions Plugin for Virtuals Game 2 | 3 | The onchain actions plugin allows your GAME agents to execute onchain actions such as swaps, transfers, staking, etc. all by leveraging the [GOAT SDK](https://github.com/goat-sdk/goat). 4 | 5 | Supports: 6 | - Any chain, from EVM, to Solana, to Sui, etc. 7 | - Any wallet type, from key pairs to smart wallets from Crossmint, etc. 8 | - More than +200 onchain tools from the GOAT SDK, [see all available tools here](https://ohmygoat.dev/chains-wallets-plugins#plugins) 9 | 10 | Are you part of a startup agent team building with Virtuals? 11 | You may be eligible for free credits through Crossmint's Startup Program! [Apply now](https://www.crossmint.com/startup-program) to unlock exclusive startup benefits — and don’t forget to mention you’re part of a startup building with Virtuals when you get in touch. 12 | 13 | ## Installation 14 | 15 | To install the plugin, use npm or yarn: 16 | 17 | ```bash 18 | npm install @virtuals-protocol/game-on-chain-actions-plugin 19 | ``` 20 | 21 | or 22 | 23 | ```bash 24 | yarn add @virtuals-protocol/game-on-chain-actions-plugin 25 | ``` 26 | 27 | ## Usage 28 | 29 | 1. Import the `getOnChainActionsWorker` function from the plugin: 30 | 31 | ```typescript 32 | import { getOnChainActionsWorker } from "@virtuals-protocol/game-on-chain-actions-plugin"; 33 | ``` 34 | 35 | 2. Setup up a wallet 36 | 37 | Set up a wallet for the chain you want to use 38 | 39 | Example for EVM 40 | 41 | ```typescript 42 | import { createWalletClient, http } from "viem"; 43 | import { privateKeyToAccount } from "viem/accounts"; 44 | 45 | const account = privateKeyToAccount( 46 | process.env.WALLET_PRIVATE_KEY as `0x${string}` 47 | ); 48 | 49 | const walletClient = createWalletClient({ 50 | account: account, 51 | transport: http(process.env.RPC_PROVIDER_URL), 52 | chain: base, 53 | }); 54 | ``` 55 | 56 | 3. Create the worker adding the wallet and the plugins you want to use 57 | 58 | ```typescript 59 | const onChainActionsWorker = await getOnChainActionsWorker({ 60 | wallet: viem(walletClient), 61 | plugins: [ 62 | sendETH(), 63 | erc20({ tokens: [USDC, PEPE] }), 64 | uniswap({ 65 | baseUrl: process.env.UNISWAP_BASE_URL as string, 66 | apiKey: process.env.UNISWAP_API_KEY as string, 67 | }), 68 | ], 69 | }); 70 | ``` 71 | 72 | 4. Create an agent and add the worker to it: 73 | 74 | ```typescript 75 | import { GameAgent } from "@virtuals-protocol/game"; 76 | 77 | const agent = new GameAgent("GAME_API_KEY", { 78 | name: "Onchain Actions Agent", 79 | goal: "Swap 0.01 USDC to PEPE", 80 | description: "An agent that executes onchain actions", 81 | workers: [onChainActionsWorker], 82 | }); 83 | ``` 84 | 85 | 5. Initialize and run the agent: 86 | 87 | ```typescript 88 | (async () => { 89 | await agent.init(); 90 | 91 | while (true) { 92 | await agent.step({ 93 | verbose: true, 94 | }); 95 | } 96 | })(); 97 | ``` 98 | -------------------------------------------------------------------------------- /plugins/onChainActionsPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-on-chain-actions-plugin", 3 | "version": "0.1.1", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "ts-node-dev": "^2.0.0", 16 | "typescript": "^5.7.2" 17 | }, 18 | "dependencies": { 19 | "@goat-sdk/core": "0.4.6", 20 | "@goat-sdk/plugin-erc20": "0.2.8", 21 | "@goat-sdk/plugin-uniswap": "0.2.9", 22 | "@goat-sdk/wallet-evm": "0.2.6", 23 | "@goat-sdk/wallet-viem": "0.2.6", 24 | "@virtuals-protocol/game": "^0.1.4", 25 | "ajv": "8.17.1", 26 | "tsup": "^8.3.5", 27 | "zod": "3.23.8", 28 | "zod-to-json-schema": "^3.24.1" 29 | }, 30 | "files": [ 31 | "dist" 32 | ], 33 | "repository": { 34 | "type": "git", 35 | "url": "https://github.com/game-by-virtuals/game-node" 36 | } 37 | } -------------------------------------------------------------------------------- /plugins/onChainActionsPlugin/src/.env.example: -------------------------------------------------------------------------------- 1 | WALLET_PRIVATE_KEY= 2 | RPC_PROVIDER_URL= 3 | UNISWAP_API_KEY=kHEhfIPvCE3PO5PeT0rNb1CA3JJcnQ8r7kJDXN5X # Public key to test with 4 | UNISWAP_BASE_URL=https://trade-api.gateway.uniswap.org/v1 5 | -------------------------------------------------------------------------------- /plugins/onChainActionsPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from "@virtuals-protocol/game"; 2 | import { getOnChainActionsWorker } from "."; 3 | import { base } from "viem/chains"; 4 | import { createWalletClient, http } from "viem"; 5 | import { PEPE, USDC, erc20 } from "@goat-sdk/plugin-erc20"; 6 | import { sendETH } from "@goat-sdk/wallet-evm"; 7 | import { viem } from "@goat-sdk/wallet-viem"; 8 | import { uniswap } from "@goat-sdk/plugin-uniswap"; 9 | import { privateKeyToAccount } from "viem/accounts"; 10 | 11 | const account = privateKeyToAccount( 12 | process.env.WALLET_PRIVATE_KEY as `0x${string}` 13 | ); 14 | 15 | const walletClient = createWalletClient({ 16 | account: account, 17 | transport: http(process.env.RPC_PROVIDER_URL), 18 | chain: base, 19 | }); 20 | 21 | (async () => { 22 | const onChainActionsWorker = await getOnChainActionsWorker({ 23 | wallet: viem(walletClient), 24 | plugins: [ 25 | sendETH(), 26 | erc20({ tokens: [USDC, PEPE] }), 27 | uniswap({ 28 | baseUrl: process.env.UNISWAP_BASE_URL as string, 29 | apiKey: process.env.UNISWAP_API_KEY as string, 30 | }), 31 | ], 32 | }); 33 | 34 | // Create an agent with the worker 35 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 36 | name: "On chain actions agent", 37 | goal: "Swap 0.01 USDC to PEPE", 38 | description: "An agent that executes onchain actions", 39 | workers: [onChainActionsWorker], 40 | }); 41 | 42 | agent.setLogger((agent, message) => { 43 | console.log(`-----[${agent.name}]-----`); 44 | console.log(message); 45 | console.log("\n"); 46 | }); 47 | 48 | await agent.init(); 49 | 50 | while (true) { 51 | await agent.step({ 52 | verbose: true, 53 | }); 54 | } 55 | })(); 56 | -------------------------------------------------------------------------------- /plugins/onChainActionsPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./onChainActionsPlugin"; 2 | -------------------------------------------------------------------------------- /plugins/onChainActionsPlugin/src/onChainActionsPlugin.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExecutableGameFunctionResponse, 3 | ExecutableGameFunctionStatus, 4 | GameFunction, 5 | GameWorker, 6 | } from "@virtuals-protocol/game"; 7 | 8 | import { 9 | PluginBase, 10 | ToolBase, 11 | WalletClientBase, 12 | getTools, 13 | } from "@goat-sdk/core"; 14 | 15 | import type { JSONSchemaType } from "ajv"; 16 | import { zodToJsonSchema } from "zod-to-json-schema"; 17 | 18 | export type GetToolsParams = { 19 | wallet: TWalletClient; 20 | plugins?: (PluginBase | PluginBase)[]; 21 | }; 22 | 23 | export async function getOnChainActionsWorker< 24 | TWalletClient extends WalletClientBase 25 | >(params: GetToolsParams) { 26 | const tools: ToolBase[] = await getTools({ 27 | wallet: params.wallet, 28 | plugins: params.plugins, 29 | }); 30 | 31 | const workerFunctions = tools.map((tool) => { 32 | // biome-ignore lint/suspicious/noExplicitAny: Fix types later 33 | const schema = zodToJsonSchema(tool.parameters as any, { 34 | target: "jsonSchema7", 35 | }) as JSONSchemaType; 36 | 37 | const properties = Object.keys(schema.properties); 38 | 39 | const args = properties.map((property) => ({ 40 | name: property, 41 | description: schema.properties[property].description ?? "", 42 | })); 43 | 44 | return new GameFunction({ 45 | name: tool.name, 46 | description: tool.description, 47 | args: args, 48 | executable: async (args: any) => { 49 | try { 50 | const result = await tool.execute(args); 51 | return new ExecutableGameFunctionResponse( 52 | ExecutableGameFunctionStatus.Done, 53 | JSON.stringify(result) 54 | ); 55 | } catch (e) { 56 | return new ExecutableGameFunctionResponse( 57 | ExecutableGameFunctionStatus.Failed, 58 | `Failed to execute tool: ${e}` 59 | ); 60 | } 61 | }, 62 | }); 63 | }); 64 | 65 | return new GameWorker({ 66 | id: "onchain_actions_worker", 67 | name: "Onchain Actions Worker", 68 | description: 69 | "Worker that executes onchain actions such as swaps, transfers, etc.", 70 | functions: [...workerFunctions], 71 | }); 72 | } 73 | -------------------------------------------------------------------------------- /plugins/onChainActionsPlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 4 | "module": "commonjs", /* Specify what module code is generated. */ 5 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 6 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 7 | "strict": true, /* Enable all strict type-checking options. */ 8 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugins/plugin_metadata_template.yml: -------------------------------------------------------------------------------- 1 | # General Information 2 | plugin_name: "" # Name of the plugin 3 | author: "" # Author and team name 4 | logo_url: "" # URL to the author photo or team logo (512x512 recommended) (if any) 5 | release_date: "" # Release date (YYYY-MM) 6 | 7 | # Description 8 | short_description: "" # One-liner description for listings 9 | detailed_description: "" # Full description with features and benefits 10 | 11 | # Media & Assets 12 | plugin_logo_url: "" # URL to the plugin logo (512x512 recommended) (if any or fallback to logo_url) 13 | screenshots: # List of screenshots showcasing the plugin (if any) 14 | - "" # e.g., "https://example.com/screenshot1.png" 15 | - "" 16 | demo_video_url: "" # Link to a demo or walkthrough video (if any) 17 | documentation_url: "" # Link to the plugin's official documentation (if any) 18 | changelog_url: "" # Link to the changelog (if maintained) 19 | 20 | # Contact & Support 21 | x_account_handle: "" # X (formerly known as Twitter) account handle (ie: @GAME_Virtuals) 22 | support_contact: "" # Email or Slack/Discord link for user support 23 | community_url: "" # Forum or community link (if any) 24 | -------------------------------------------------------------------------------- /plugins/recallStoragePlugin/.env.example: -------------------------------------------------------------------------------- 1 | GAME_API_KEY=xxxxxxxxxxxxxxxxxxxx 2 | RECALL_PRIVATE_KEY=0xyour_private_key 3 | RECALL_BUCKET_ALIAS=game-agent 4 | RECALL_PREFIX=cot/ 5 | RECALL_NETWORK=testnet -------------------------------------------------------------------------------- /plugins/recallStoragePlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | .env -------------------------------------------------------------------------------- /plugins/recallStoragePlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/recallStoragePlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-recall-storage-plugin", 3 | "version": "0.1.0", 4 | "description": "", 5 | "type": "module", 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.mjs", 8 | "types": "./dist/index.d.ts", 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 12 | }, 13 | "author": "", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "dotenv": "^16.4.7", 17 | "tempy": "^3.1.0", 18 | "ts-node-dev": "^2.0.0", 19 | "tsup": "^8.3.5", 20 | "typescript": "^5.7.2" 21 | }, 22 | "dependencies": { 23 | "@recallnet/chains": "^0.0.6", 24 | "@recallnet/sdk": "^0.0.7", 25 | "@virtuals-protocol/game": "^0.1.9", 26 | "viem": "^2.23.10" 27 | }, 28 | "files": [ 29 | "dist" 30 | ], 31 | "repository": { 32 | "type": "git", 33 | "url": "https://github.com/game-by-virtuals/game-node" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /plugins/recallStoragePlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import RecallStoragePlugin from "./recallStoragePlugin.js"; 2 | 3 | export default RecallStoragePlugin; 4 | -------------------------------------------------------------------------------- /plugins/recallStoragePlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 4 | "module": "NodeNext" /* Specify what module code is generated. */, 5 | "moduleResolution": "NodeNext" /* Specify how modules are resolved. */, 6 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 7 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 8 | "strict": true /* Enable all strict type-checking options. */, 9 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /plugins/rss3Plugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ -------------------------------------------------------------------------------- /plugins/rss3Plugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/rss3Plugin/README.md: -------------------------------------------------------------------------------- 1 | # RSS3 Plugin for Virtuals Game 2 | 3 | This plugin allows you to integrate decentralized activities into your Virtuals Game. With this plugin, you can easily retrieve activities of anyone, in a format that is structured to be easily interpreted by AI Agents. 4 | 5 | ## Installation 6 | 7 | To install the plugin, use npm or yarn: 8 | 9 | ```bash 10 | npm install @virtuals-protocol/game-rss3-plugin 11 | ``` 12 | 13 | or 14 | 15 | ```bash 16 | yarn add @virtuals-protocol/game-rss3-plugin 17 | ``` 18 | 19 | ## Usage 20 | 21 | ### Importing the Plugin 22 | 23 | First, import the `RSS3Plugin` class from the plugin: 24 | 25 | ```typescript 26 | import RSS3Plugin from "@virtuals-protocol/game-rss3-plugin"; 27 | ``` 28 | 29 | ### Creating a Worker 30 | 31 | Create a worker with the necessary RSS3 credentials: 32 | 33 | ```typescript 34 | const rss3Plugin = new RSS3Plugin({ 35 | credentials: { 36 | apiKey: "your_api_key", // this is currently optional, you may leave it empty 37 | }, 38 | }); 39 | ``` 40 | 41 | ### Creating an Agent 42 | 43 | Create an agent and add the worker to it: 44 | 45 | ```typescript 46 | import { GameAgent } from "@virtuals-protocol/game"; 47 | 48 | const agent = new GameAgent("API_KEY", { 49 | name: "RSS3 Bot", 50 | goal: "Monitor decentralized activities for sentiment analysis", 51 | description: "A bot that can monitor anyone's decentralized activities", 52 | workers: [rss3Plugin.getWorker()], 53 | }); 54 | ``` 55 | 56 | ### Running the Agent 57 | 58 | Initialize and run the agent: 59 | 60 | ```typescript 61 | (async () => { 62 | await agent.init(); 63 | 64 | while (true) { 65 | await agent.step({ 66 | verbose: true, 67 | }); 68 | } 69 | })(); 70 | ``` 71 | 72 | ## Available Functions 73 | 74 | The `RSS3Plugin` provides 2 functions that can be used by the agent: 75 | 76 | - `getCryptoNewsFunction`: Retrieve the latest crypto news structured for AI agents to be used as a source of information for analysis and decision-making. 77 | - `getActivitiesFunction`: Retrieve activities of anyone based on a query. 78 | - This function accepts a list of parameters: 79 | - `account`: Required, the address of the user whose activities you want to retrieve. 80 | - `tag`: Optional, the tag of activities to retrieve. 81 | - `type`: Optional, the type of the activities to retrieve. 82 | - `netwrk`: Optional, the network to retrieve activities from. 83 | - `platform`: Optional, the platform to retrieve activities from. 84 | - `limit`: Optional, the number of activities to retrieve. 85 | - For more information on the parameters, refer to the [RSS3 documentation](https://docs.rss3.io/) or [OpenAPI](https://petstore.swagger.io/?url=https://gi.rss3.io/docs/openapi.json#/DSL/getAccountActivities). 86 | 87 | ## License 88 | 89 | This project is licensed under the MIT License. 90 | -------------------------------------------------------------------------------- /plugins/rss3Plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-rss3-plugin", 3 | "version": "0.1", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "ts-node-dev": "^2.0.0", 16 | "typescript": "^5.7.2" 17 | }, 18 | "dependencies": { 19 | "@rss3/sdk": "^0.0.23", 20 | "@virtuals-protocol/game": "^0.1.4", 21 | "tsup": "^8.3.5" 22 | }, 23 | "files": [ 24 | "dist" 25 | ], 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/game-by-virtuals/game-node" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /plugins/rss3Plugin/src/example.ts: -------------------------------------------------------------------------------- 1 | 2 | import { GameAgent } from "@virtuals-protocol/game"; 3 | import RSS3Plugin from "."; 4 | 5 | 6 | const rss3Plugin = new RSS3Plugin({ 7 | credentials: { 8 | apiKey: process.env.RSS3_API_KEY ?? "", // RSS3 API Key is currently optional 9 | }, 10 | }); 11 | 12 | 13 | const agent = new GameAgent(process.env.GAME_API_KEY ?? "", { 14 | name: "RSS3 Worker", 15 | goal: "Retrieve account activities via the RSS3 Network.", 16 | description: `You are an AI agent with the ability to access real-time activities via the RSS3 Network. You take in a blockchain wallet address (beginning with 0x) or an ENS domain (ending with .eth) and retrieve the activities associated with the account. 17 | `, 18 | workers: [ 19 | rss3Plugin.getWorker({ 20 | functions: [ 21 | rss3Plugin.getActivitiesFunction, 22 | ], 23 | }), 24 | ], 25 | }); 26 | 27 | (async () => { 28 | agent.setLogger((agent, message) => { 29 | console.log(`-----[${agent.name}]-----`); 30 | console.log(message); 31 | console.log("\n"); 32 | }); 33 | 34 | await agent.init(); 35 | 36 | while (true) { 37 | await agent.step({ 38 | verbose: true, 39 | }); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /plugins/rss3Plugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import RSS3Plugin from "./rss3Plugin"; 2 | 3 | export default RSS3Plugin; 4 | -------------------------------------------------------------------------------- /plugins/s3Plugin/.env.example: -------------------------------------------------------------------------------- 1 | S3_ACCESS_KEY_ID=xxxxxxx 2 | S3_SECRET_ACCESS_KEY=xxxxxxx 3 | S3_REGION=xxxxxxx 4 | S3_BUCKET=xxxxxxx 5 | S3_ENDPOINT=xxxxxxx 6 | S3_SSL_ENABLED=true 7 | S3_FORCE_PATH_STYLE=false 8 | GAME_API_KEY=xxxxxxx -------------------------------------------------------------------------------- /plugins/s3Plugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | .env -------------------------------------------------------------------------------- /plugins/s3Plugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/s3Plugin/README.md: -------------------------------------------------------------------------------- 1 | # S3 Plugin for Virtuals Game 2 | 3 | This plugin allows you to integrate S3 functionalities into your Virtuals Game. With this plugin, 4 | you can upload files to S3, download files from S3, and more. 5 | 6 | ## Installation 7 | 8 | To install the plugin, use npm or yarn: 9 | 10 | ```bash 11 | npm install @virtuals-protocol/game-s3-plugin 12 | ``` 13 | 14 | or 15 | 16 | ```bash 17 | yarn add @virtuals-protocol/game-s3-plugin 18 | ``` 19 | 20 | ## Usage 21 | 22 | ### Importing the Plugin 23 | 24 | First, import the `S3Plugin` class from the plugin: 25 | 26 | ```typescript 27 | import S3Plugin from "@virtuals-protocol/game-s3-plugin"; 28 | ``` 29 | 30 | ### Creating a Worker 31 | 32 | Create a worker with the necessary Twitter credentials: 33 | 34 | ```typescript 35 | const s3Plugin = new S3Plugin({ 36 | credentials: { 37 | accessKeyId: "AKEXAMPLES3S", 38 | secretAccessKey: "SKEXAMPLES3S, 39 | }, 40 | region: "us-east-1", 41 | bucket: "virtuals-game-bucket", 42 | endpoint: "http://localhost:8014", 43 | sslEnabled: false, 44 | forcePathStyle: true, 45 | }); 46 | ``` 47 | 48 | ### Creating an Agent 49 | 50 | Create an agent and add the worker to it: 51 | 52 | ```typescript 53 | import { GameAgent } from "@virtuals-protocol/game"; 54 | 55 | const agent = new GameAgent("GAME_API_KEY", { 56 | name: "S3 Agent", 57 | goal: "Upload and download files to S3", 58 | description: "An agent that can upload and download files to S3", 59 | workers: [s3Plugin.getWorker()], 60 | }); 61 | ``` 62 | 63 | ### Running the Agent 64 | 65 | Initialize and run the agent: 66 | 67 | ```typescript 68 | (async () => { 69 | await agent.init(); 70 | 71 | const task1 = 72 | "Upload a file to the S3 bucket at the path `./package.json` and key `hello/world`, and use a signed URL with a TTL of 900 seconds"; 73 | const task2 = 74 | "Download a file from the S3 bucket at key `hello/world` to the a file at `./test.txt`"; 75 | 76 | while (true) { 77 | await agent.step({ 78 | verbose: true, 79 | }); 80 | 81 | await agentS3Worker.runTask(task1, { 82 | verbose: true, 83 | }); 84 | await agentS3Worker.runTask(task2, { 85 | verbose: true, 86 | }); 87 | } 88 | })(); 89 | ``` 90 | 91 | ## Available Functions 92 | 93 | The `S3Plugin` provides several functions that can be used by the agent: 94 | 95 | - `uploadFileFunction`: Upload a file to S3. Possible arguments: `file_path`, `object_key`, 96 | `use_signed_url`, `ttl`. 97 | - `downloadFileFunction`: Download a file from S3. Possible arguments: `file_path`, `object_key`. 98 | 99 | ## License 100 | 101 | This project is licensed under the MIT License. 102 | -------------------------------------------------------------------------------- /plugins/s3Plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-s3-plugin", 3 | "version": "0.1.3", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "dotenv": "^16.4.7", 16 | "ts-node-dev": "^2.0.0", 17 | "tsup": "^8.3.5", 18 | "typescript": "^5.7.2" 19 | }, 20 | "dependencies": { 21 | "@aws-sdk/client-s3": "^3.735.0", 22 | "@aws-sdk/s3-request-presigner": "^3.735.0", 23 | "@virtuals-protocol/game": "^0.1.7" 24 | }, 25 | "files": [ 26 | "dist" 27 | ], 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/game-by-virtuals/game-node" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugins/s3Plugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import S3Plugin from "./s3Plugin"; 2 | 3 | export default S3Plugin; 4 | -------------------------------------------------------------------------------- /plugins/s3Plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 4 | "module": "commonjs" /* Specify what module code is generated. */, 5 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 6 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 7 | "strict": true /* Enable all strict type-checking options. */, 8 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /plugins/stateofmikaPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | 4 | # Build 5 | dist/ 6 | 7 | # Coverage 8 | coverage/ 9 | 10 | # IDE 11 | .vscode/ 12 | .idea/ 13 | 14 | # Logs 15 | *.log 16 | 17 | # Environment 18 | .env 19 | .env.local 20 | .env.*.local 21 | 22 | # OS 23 | .DS_Store 24 | Thumbs.db 25 | -------------------------------------------------------------------------------- /plugins/stateofmikaPlugin/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | testMatch: ['**/__tests__/**/*.test.ts'], 5 | }; 6 | -------------------------------------------------------------------------------- /plugins/stateofmikaPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-state-mika-plugin", 3 | "version": "0.1.0", 4 | "description": "State of Mika Plugin for Virtuals GAME", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "build": "tsup src/index.ts --dts --format cjs,esm --out-dir dist", 10 | "test": "jest --coverage" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "ts-node-dev": "^2.0.0", 16 | "typescript": "^5.7.2", 17 | "@types/jest": "^29.5.14", 18 | "jest": "^29.7.0", 19 | "ts-jest": "^29.2.5" 20 | }, 21 | "dependencies": { 22 | "tsup": "^8.3.5", 23 | "axios": "^0.27.2", 24 | "@virtuals-protocol/game": "^0.1.7" 25 | }, 26 | "files": [ 27 | "dist" 28 | ], 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/game-by-virtuals/game-node" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /plugins/stateofmikaPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './stateMikaPlugin'; 2 | -------------------------------------------------------------------------------- /plugins/stateofmikaPlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "outDir": "./dist", 10 | "declaration": true, 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true 13 | }, 14 | "include": ["src/**/*", "__tests__/**/*"], 15 | "exclude": ["node_modules", "dist"] 16 | } 17 | -------------------------------------------------------------------------------- /plugins/telegramPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | coverage/ -------------------------------------------------------------------------------- /plugins/telegramPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/telegramPlugin/README.md: -------------------------------------------------------------------------------- 1 | # Telegram Plugin for Virtuals Game 2 | 3 | This plugin allows you to integrate Telegram functionalities into your Virtuals Game. 4 | 5 | ## Installation 6 | 7 | To install the plugin, use npm or yarn: 8 | 9 | ```bash 10 | npm install @virtuals-protocol/game-telegram-plugin 11 | ``` 12 | 13 | or 14 | 15 | ```bash 16 | yarn add @virtuals-protocol/game-telegram-plugin 17 | ``` 18 | 19 | ## Usage 20 | 21 | ### Importing the Plugin 22 | 23 | First, import the `TelegramPlugin` class from the plugin: 24 | 25 | ```typescript 26 | import TelegramPlugin from "@virtuals-protocol/game-telegram-plugin"; 27 | ``` 28 | 29 | ### Creating a Worker 30 | 31 | Create a worker with the necessary Telegram credentials: 32 | 33 | ```typescript 34 | const telegramPlugin = new TelegramPlugin({ 35 | credentials: { 36 | botToken: "", 37 | }, 38 | }); 39 | ``` 40 | 41 | ### Creating an Agent 42 | 43 | Create an agent and add the worker to it: 44 | 45 | ```typescript 46 | import { GameAgent } from "@virtuals-protocol/game"; 47 | 48 | const agent = new GameAgent("", { 49 | name: "Telegram Bot", 50 | goal: "Auto reply message", 51 | description: "A bot that can post send message and pinned message", 52 | workers: [ 53 | telegramPlugin.getWorker(), 54 | ], 55 | }); 56 | ``` 57 | 58 | ### Running the Agent 59 | 60 | Initialize and run the agent: 61 | 62 | ```typescript 63 | (async () => { 64 | await agent.init(); 65 | 66 | const agentTgWorker = agent.getWorkerById(telegramPlugin.getWorker().id); 67 | const task = "PROMPT"; 68 | 69 | await agentTgWorker.runTask(task, { 70 | verbose: true, // Optional: Set to true to log each step 71 | }); 72 | })(); 73 | ``` 74 | 75 | ## Available Functions 76 | 77 | The `TelegramPlugin` provides several functions that can be used by the agent: 78 | 79 | - `sendMessageFunction`: Send message. 80 | - `sendMediaFunction`: Send media. 81 | - `createPollFunction`: Create poll. 82 | - `pinnedMessageFunction`: Pinned message. 83 | - `unPinnedMessageFunction`: Unpinned message. 84 | - `deleteMessageFunction`: Delete message. 85 | 86 | ## Event Handlers 87 | The plugin also supports custom handlers for the following Telegram events: 88 | ### Handling Incoming Messages 89 | To handle incoming messages, use the `onMessage` method to listen on: 90 | ```typescript 91 | telegramPlugin.onMessage((msg) => { 92 | console.log("Received message:", msg); 93 | }); 94 | ``` 95 | ### Handling Poll Answers 96 | To handle poll answers, use the `onPollAnswer` method: 97 | ```typescript 98 | telegramPlugin.onPollAnswer((pollAnswer) => { 99 | console.log("Received poll answer:", pollAnswer); 100 | }); 101 | ``` 102 | 103 | ## License 104 | 105 | This project is licensed under the MIT License. 106 | -------------------------------------------------------------------------------- /plugins/telegramPlugin/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | }; -------------------------------------------------------------------------------- /plugins/telegramPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-telegram-plugin", 3 | "version": "0.1.4", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "jest --coverage", 10 | "tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "@types/jest": "^29.5.14", 16 | "@types/jsonwebtoken": "^9.0.7", 17 | "@types/node": "^22.10.3", 18 | "@types/node-telegram-bot-api": "^0.64.7", 19 | "@typescript-eslint/eslint-plugin": "^8.19.1", 20 | "@typescript-eslint/parser": "^8.19.1", 21 | "eslint": "^9.17.0", 22 | "jest": "^29.7.0", 23 | "ts-jest": "^29.2.5", 24 | "ts-node": "^10.9.2", 25 | "ts-node-dev": "^2.0.0", 26 | "tsup": "^8.3.5", 27 | "typescript": "^5.7.3" 28 | }, 29 | "dependencies": { 30 | "@virtuals-protocol/game": "^0.1.7", 31 | "node-telegram-bot-api": "^0.66.0", 32 | "tsup": "^8.3.5" 33 | }, 34 | "files": [ 35 | "dist" 36 | ], 37 | "repository": { 38 | "type": "git", 39 | "url": "https://github.com/game-by-virtuals/game-node" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /plugins/telegramPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import TelegramPlugin from "./telegramPlugin"; 2 | 3 | export default TelegramPlugin; 4 | -------------------------------------------------------------------------------- /plugins/twitterPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ -------------------------------------------------------------------------------- /plugins/twitterPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/twitterPlugin/example/.env.example: -------------------------------------------------------------------------------- 1 | GAME_TWITTER_ACCESS_TOKEN=apx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 2 | -------------------------------------------------------------------------------- /plugins/twitterPlugin/example/index.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent, GameWorker } from "@virtuals-protocol/game"; 2 | import TwitterPlugin from "@virtuals-protocol/game-twitter-plugin"; 3 | import { TwitterApi } from "@virtuals-protocol/game-twitter-node"; 4 | 5 | const gameTwitterClient = new TwitterApi({ 6 | gameTwitterAccessToken: "xxxx", 7 | }); 8 | 9 | // const nativeTwitterClient = new TwitterApi({ 10 | // appKey: "xxxxxxx", 11 | // appSecret: "xxxxxxx", 12 | // accessToken: "xxxxxxx", 13 | // accessSecret: "xxxxxxxxx", 14 | // }); 15 | 16 | // Create a worker with the functions 17 | const twitterPlugin = new TwitterPlugin({ 18 | id: "twitter_worker", 19 | name: "Twitter Worker", 20 | description: 21 | "A worker that will execute tasks within the Twitter Social Platforms. It is capable of posting, reply, quote and like tweets.", 22 | twitterClient: gameTwitterClient, 23 | }); 24 | 25 | // Create an agent with the worker 26 | const agent = new GameAgent("xxxx", { 27 | name: "Twitter Bot", 28 | goal: "increase engagement and grow follower count", 29 | description: "A bot that can post tweets, reply to tweets, and like tweets", 30 | workers: [ 31 | // Use local GameWorker that's compatible with local GameAgent 32 | new GameWorker({ 33 | id: "twitter_worker", 34 | name: "Twitter Worker", 35 | description: "Twitter integration worker", 36 | functions: [ 37 | twitterPlugin.searchTweetsFunction, 38 | //twitterPlugin.replyTweetFunction, 39 | twitterPlugin.postTweetFunction, 40 | ], 41 | getEnvironment: async () => { 42 | return { 43 | ...(await twitterPlugin.getMetrics()), 44 | username: "virtualsprotocol", 45 | token_price: "$100.00", 46 | }; 47 | }, 48 | }), 49 | ], 50 | }); 51 | 52 | (async () => { 53 | agent.setLogger((agent, message) => { 54 | console.log(`-----[${agent.name}]-----`); 55 | console.log(message); 56 | console.log("\n"); 57 | }); 58 | 59 | await agent.init(); 60 | 61 | while (true) { 62 | await agent.step({ 63 | verbose: true, 64 | }); 65 | } 66 | })(); 67 | -------------------------------------------------------------------------------- /plugins/twitterPlugin/example/media_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game-by-virtuals/game-node/0d991ce28db65a5a0e2d4046bc05d8d3bfcab3df/plugins/twitterPlugin/example/media_file.png -------------------------------------------------------------------------------- /plugins/twitterPlugin/example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twitter-plugin-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@virtuals-protocol/game": "^0.1.7", 13 | "@virtuals-protocol/game-twitter-plugin": "^0.1.4", 14 | "@virtuals-protocol/game-twitter-node": "^0.1.0", 15 | "axios": "^1.7.7", 16 | "dotenv": "^16.4.5" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /plugins/twitterPlugin/example/virtuals-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game-by-virtuals/game-node/0d991ce28db65a5a0e2d4046bc05d8d3bfcab3df/plugins/twitterPlugin/example/virtuals-logo.png -------------------------------------------------------------------------------- /plugins/twitterPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-twitter-plugin", 3 | "version": "0.1.11", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "tsup": "tsup src/*.ts --dts --format cjs --out-dir dist" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "ts-node-dev": "^2.0.0", 16 | "typescript": "^5.7.2" 17 | }, 18 | "dependencies": { 19 | "@virtuals-protocol/game": "^0.1.7", 20 | "@virtuals-protocol/game-twitter-node": "^0.1.0", 21 | "@virtuals-protocol/game-twitter-plugin": "^0.1.9" 22 | }, 23 | "files": [ 24 | "dist" 25 | ], 26 | "bin": { 27 | "game-twitter-plugin": "./dist/bin.js" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/game-by-virtuals/game-node" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /plugins/twitterPlugin/src/bin.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import axios from "axios"; 4 | import { Command } from "commander"; 5 | import http from "http"; 6 | import open from "open"; 7 | 8 | const client = axios.create({ 9 | baseURL: "https://twitter.game.virtuals.io/accounts", 10 | }); 11 | 12 | const getLoginUrl = async (apiKey: string) => { 13 | const response = await client.get<{ 14 | url: string; 15 | }>("/auth", { 16 | headers: { 17 | "x-api-key": apiKey, 18 | }, 19 | }); 20 | 21 | return response.data.url; 22 | }; 23 | 24 | const verify = async (code: string, state: string) => { 25 | const response = await client.get<{ 26 | token: string; 27 | }>("/verify", { 28 | params: { 29 | code, 30 | state, 31 | }, 32 | }); 33 | 34 | return response.data.token; 35 | }; 36 | 37 | const program = new Command(); 38 | 39 | program 40 | .name("game-twitter-plugin") 41 | .description("CLI to authenticate and interact with GAME's Twitter API") 42 | .version("0.1.0"); 43 | 44 | program 45 | .command("auth") 46 | .description("Authenticate with Twitter API") 47 | .option("-k, --key ", "project's API key") 48 | .action((options) => { 49 | const apiKey = options.key; 50 | 51 | if (!apiKey) { 52 | console.error("API key is required!"); 53 | return; 54 | } 55 | 56 | const server = http.createServer(async (req, res) => { 57 | if (req.method === "GET" && req.url?.startsWith("/callback")) { 58 | const query = new URLSearchParams(req.url.split("?")[1]); 59 | const code = query.get("code"); 60 | const state = query.get("state"); 61 | 62 | const token = await verify(code!, state!); 63 | 64 | res.writeHead(200, { "Content-Type": "text/plain" }); 65 | res.end( 66 | "Authentication successful! You may close this window and return to the terminal." 67 | ); 68 | 69 | console.log("Authenticated! Here's your access token:"); 70 | console.log(token); 71 | console.log("\n"); 72 | 73 | server.close(); 74 | } else { 75 | res.writeHead(404, { "Content-Type": "text/plain" }); 76 | res.end("Not Found"); 77 | } 78 | }); 79 | 80 | server.listen(8714, async () => { 81 | const url = await getLoginUrl(apiKey); 82 | 83 | console.log("\nWaiting for authentication...\n"); 84 | 85 | console.log("Visit the following URL to authenticate:"); 86 | console.log(url, "\n"); 87 | 88 | await open(url); 89 | }); 90 | }); 91 | 92 | program.parse(); 93 | -------------------------------------------------------------------------------- /plugins/twitterPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import TwitterPlugin from "./twitterPlugin"; 2 | 3 | export default TwitterPlugin; 4 | -------------------------------------------------------------------------------- /plugins/zytronPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | 4 | .env 5 | src/.env 6 | -------------------------------------------------------------------------------- /plugins/zytronPlugin/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | tsconfig.json 3 | -------------------------------------------------------------------------------- /plugins/zytronPlugin/README.md: -------------------------------------------------------------------------------- 1 | # Zytron Plugin for Virtuals Game 2 | 3 | This plugin enables interaction with the Zytron Mainnet, providing functionality to query wallet balances and send tokens. 4 | 5 | ## Installation 6 | 7 | To install the plugin, use npm or yarn: 8 | 9 | ```bash 10 | npm install @virtuals-protocol/game-zytron-plugin 11 | ``` 12 | 13 | or 14 | 15 | ```bash 16 | yarn add @virtuals-protocol/game-zytron-plugin 17 | ``` 18 | 19 | ## Usage 20 | 21 | ### Wallet Setup 22 | 23 | Before using the plugin, you need to have a Zytron wallet with some native tokens(ETH). Make sure you have: 24 | - A Zytron wallet address 25 | - Private key for transactions 26 | - Sufficient native tokens for transactions 27 | 28 | ### Importing the Plugin 29 | 30 | First, import the `ZytronPlugin` and `ZytronWallet` classes from the plugin: 31 | 32 | ```typescript 33 | import { ZytronPlugin, ZytronWallet } from "@virtuals-protocol/game-zytron-plugin"; 34 | ``` 35 | 36 | ### Creating a Worker 37 | 38 | Create a worker with your Zytron credentials: 39 | 40 | ```typescript 41 | const zytronWallet = new ZytronWallet(ZYTRON_PRIVATE_KEY); 42 | const zytronPlugin = new ZytronPlugin({ 43 | id: "zytron_worker", 44 | name: "Zytron Worker", 45 | description: "This Worker enables users to execute interactions on the Zytron mainnet.", 46 | wallet: zytronWallet, 47 | }); 48 | ``` 49 | 50 | ### Creating an Agent 51 | 52 | Create an agent and add the worker to it: 53 | 54 | ```typescript 55 | import { GameAgent } from "@virtuals-protocol/game"; 56 | 57 | const agent = new GameAgent(GAME_API_KEY, { 58 | name: "Zytron Bot", 59 | goal: "Interact with Zytron Mainnet", 60 | description: "A bot that can check balances and send tokens on Zytron Mainnet", 61 | workers: [ 62 | zytronPlugin.getWorker([ 63 | zytronPlugin.checkWalletFunction, 64 | zytronPlugin.sendTokenFunction, 65 | ]), 66 | ], 67 | }); 68 | ``` 69 | 70 | ### Running the Agent 71 | 72 | Initialize and run the agent: 73 | 74 | ```typescript 75 | (async () => { 76 | await agent.init(); 77 | 78 | const task1 = "Check my wallet"; 79 | const task2 = "Send 0.0001 ETH to 0x456..."; 80 | 81 | while (true) { 82 | await agent.step({ 83 | verbose: true, 84 | }); 85 | await agent.runTask(task1, { 86 | verbose: true, 87 | }); 88 | await agent.runTask(task2, { 89 | verbose: true, 90 | }); 91 | } 92 | })(); 93 | ``` 94 | 95 | ## Available Functions 96 | 97 | The `ZytronPlugin` provides several functions that can be used by the agent: 98 | 99 | - `checkWalletFunction`: Query a wallet's balance. Arguments: `wallet_address` 100 | - `sendTokenFunction`: Send tokens to another wallet. Arguments: `recipient`, `amount`, `symbol` 101 | 102 | -------------------------------------------------------------------------------- /plugins/zytronPlugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-zytron-plugin", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "build": "tsup src/index.ts --dts --format cjs,esm --out-dir dist" 10 | }, 11 | "author": "", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@types/node": "^22.13.10", 15 | "ts-node-dev": "^2.0.0", 16 | "typescript": "^5.8.2", 17 | "vitest": "^3.0.9" 18 | }, 19 | "dependencies": { 20 | "@virtuals-protocol/game": "^0.1.10", 21 | "tsup": "^8.4.0", 22 | "viem": "^2.23.13" 23 | }, 24 | "files": [ 25 | "dist" 26 | ], 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/game-by-virtuals/game-node" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /plugins/zytronPlugin/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { Chain } from "viem"; 2 | 3 | export const zytron = { 4 | id: 9901, 5 | name: "Zytron Mainnet", 6 | nativeCurrency: { name: 'ETHEREUM', symbol: 'ETH', decimals: 18 }, 7 | rpcUrls: { 8 | default: { 9 | http: ['https://rpc.zypher.network'] 10 | }, 11 | }, 12 | blockExplorers: { 13 | default: { name: "Zytron Mainnet Explorer", url: 'https://explorer.zypher.network/' } 14 | }, 15 | contracts: { 16 | multicall3: { 17 | address: '0xa8fAD960aCf062715e1fd3DBD0ee319B2d753b23', 18 | }, 19 | }, 20 | testnet: false, 21 | } as const satisfies Chain; 22 | 23 | 24 | export const SupportedToken = { 25 | ETH: '0x0000000000000000000000000000000000000000', 26 | } as Record; 27 | 28 | -------------------------------------------------------------------------------- /plugins/zytronPlugin/src/example.ts: -------------------------------------------------------------------------------- 1 | import { GameAgent } from "@virtuals-protocol/game"; 2 | import ZytronPlugin from "./zytronPlugin"; 3 | import ZytronWallet from "./zytronWallet"; 4 | 5 | const zytronWallet = new ZytronWallet(""); 6 | 7 | const zytronPlugin = new ZytronPlugin({ 8 | id: "zytron_worker", 9 | name: "Zytron Worker", 10 | description: "This Worker enables users to execute interactions on the Zytron mainnet.", 11 | wallet: zytronWallet, 12 | }); 13 | 14 | const worker = zytronPlugin.getWorker([ 15 | zytronPlugin.checkWalletFunction, 16 | zytronPlugin.sendTokenFunction, 17 | ]); 18 | 19 | const agent = new GameAgent("", { 20 | name: "Zytron Bot", 21 | goal: "Interact with Zytron Mainnet", 22 | description: "A bot that can check balances and send tokens on Zytron Mainnet", 23 | workers: [ 24 | worker, 25 | ], 26 | }); 27 | 28 | (async () => { 29 | agent.setLogger((zytronAgent, message) => { 30 | console.log(`-----[${zytronAgent.name}]-----`); 31 | console.log(message); 32 | console.log("\n"); 33 | }); 34 | 35 | await agent.init(); 36 | const agentWorker = agent.getWorkerById(worker.id); 37 | 38 | const task = 'Check my wallet'; 39 | await agentWorker.runTask(task, { verbose: true }); 40 | 41 | // const task = 'Check 0x421E75Fe9Ad40baa99Ec1170957238A0Eba8d51C'; 42 | // await agentWorker.runTask(task, { verbose: true }); 43 | 44 | // const task = 'Send 0.0001 ETH to 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'; 45 | // await agentWorker.runTask(task, { verbose: true }); 46 | })(); 47 | -------------------------------------------------------------------------------- /plugins/zytronPlugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import ZytronPlugin from './zytronPlugin'; 2 | import ZytronWallet from './zytronWallet'; 3 | 4 | export default ZytronPlugin; 5 | export { ZytronPlugin, ZytronWallet }; 6 | -------------------------------------------------------------------------------- /plugins/zytronPlugin/src/utils.ts: -------------------------------------------------------------------------------- 1 | export const isValidNumber = (input?: string): boolean => { 2 | if (typeof input !== "string") return false; 3 | return /^[0-9]+(\.[0-9]+)?$/.test(input); 4 | } 5 | -------------------------------------------------------------------------------- /plugins/zytronPlugin/src/zytronWallet.ts: -------------------------------------------------------------------------------- 1 | import { Address, createPublicClient, createWalletClient, formatEther, Hex, http, parseUnits, PrivateKeyAccount, PublicClient, WalletClient } from "viem"; 2 | import { privateKeyToAccount } from "viem/accounts"; 3 | import { zytron } from "./constants"; 4 | 5 | interface ISendNativeTokenOptions { 6 | recipient: Address; 7 | value: bigint; 8 | } 9 | 10 | class ZytronWallet { 11 | private account: PrivateKeyAccount; 12 | private client: WalletClient; 13 | private publicClient: PublicClient; 14 | 15 | constructor(pk: string) { 16 | if (!pk) throw new Error('private key is missing'); 17 | const account = privateKeyToAccount((pk.startsWith("0x") ? pk : `0x${pk}`) as Hex); 18 | this.account = account; 19 | this.client = createWalletClient({ 20 | account, 21 | chain: zytron, 22 | transport: http(), 23 | }); 24 | this.publicClient = createPublicClient({ 25 | chain: zytron, 26 | transport: http(), 27 | }) 28 | } 29 | 30 | public async getBalance(address?: Address) { 31 | if (!address) { 32 | address = this.account.address; 33 | } 34 | const balance = await this.publicClient.getBalance({ address }); 35 | return { value: balance, format: formatEther(balance), symbol: zytron.nativeCurrency.symbol }; 36 | } 37 | 38 | public getAddress() { 39 | return this.account.address; 40 | } 41 | 42 | public async sendNativeToken(options: ISendNativeTokenOptions): Promise { 43 | const { recipient, value } = options; 44 | const hash = await this.client.sendTransaction({ 45 | value, 46 | account: this.account, 47 | to: recipient, 48 | chain: zytron, 49 | }); 50 | return hash; 51 | } 52 | } 53 | 54 | export default ZytronWallet; 55 | -------------------------------------------------------------------------------- /plugins/zytronPlugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "outDir": "./dist", 10 | "declaration": true, 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true 13 | }, 14 | "include": ["src/**/*", "__tests__/**/*"], 15 | "exclude": ["node_modules", "dist"] 16 | } 17 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import GameAgent from "./agent"; 2 | import GameWorker from "./worker"; 3 | import GameFunction, { 4 | ExecutableGameFunctionResponse, 5 | ExecutableGameFunctionStatus, 6 | } from "./function"; 7 | import { LLMModel } from "./interface/GameClient"; 8 | import { ChatAgent, Chat } from "./chatAgent"; 9 | 10 | export { 11 | GameAgent, 12 | GameFunction, 13 | GameWorker, 14 | ExecutableGameFunctionResponse, 15 | ExecutableGameFunctionStatus, 16 | LLMModel, 17 | ChatAgent, 18 | Chat, 19 | }; 20 | -------------------------------------------------------------------------------- /src/interface/GameClient.ts: -------------------------------------------------------------------------------- 1 | import { Axios } from "axios"; 2 | import GameWorker from "../worker"; 3 | import { ExecutableGameFunctionResponseJSON } from "../function"; 4 | 5 | export interface Map { 6 | id: string; 7 | } 8 | 9 | export interface GameAgent { 10 | id: string; 11 | name: string; 12 | goal: string; 13 | description: string; 14 | } 15 | 16 | export enum ActionType { 17 | CallFunction = "call_function", 18 | ContinueFunction = "continue_function", 19 | Wait = "wait", 20 | TryToTalk = "try_to_talk", 21 | Conversation = "conversation", 22 | GoTo = "go_to", 23 | Unknown = "unknown", 24 | } 25 | 26 | export interface ActionArgs { 27 | location_id: string; 28 | task_id: string; 29 | fn_id: string; 30 | args: Record; 31 | fn_name: string; 32 | thought: string; 33 | } 34 | 35 | export interface GameAction { 36 | action_type: ActionType; 37 | action_args: ActionArgs; 38 | agent_state?: Record; 39 | } 40 | 41 | export enum LLMModel { 42 | Llama_3_1_405B_Instruct = "Llama-3.1-405B-Instruct", 43 | Llama_3_3_70B_Instruct = "Llama-3.3-70B-Instruct", 44 | DeepSeek_R1 = "DeepSeek-R1", 45 | DeepSeek_V3 = "DeepSeek-V3", 46 | Qwen_2_5_72B_Instruct = "Qwen-2.5-72B-Instruct", 47 | } 48 | 49 | export interface IGameClient { 50 | client: Axios | null; 51 | createMap(workers: GameWorker[]): Promise; 52 | createAgent( 53 | name: string, 54 | goal: string, 55 | description: string 56 | ): Promise; 57 | getAction( 58 | agentId: string, 59 | mapId: string, 60 | worker: GameWorker, 61 | gameActionResult: ExecutableGameFunctionResponseJSON | null, 62 | environment: Record, 63 | agentState: Record 64 | ): Promise; 65 | setTask(agentId: string, task: string): Promise; 66 | getTaskAction( 67 | agentId: string, 68 | submissionId: string, 69 | worker: GameWorker, 70 | gameActionResult: ExecutableGameFunctionResponseJSON | null, 71 | environment: Record 72 | ): Promise; 73 | } 74 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | # Tools 2 | 3 | This directory contains tools that help with the development of the SDK. 4 | 5 | ## Available Tools 6 | 7 | ### cloud-to-sdk 8 | Converts GAME cloud configuration JSON files into SDK-compatible TypeScript files. 9 | Please refer to the [cloud-to-sdk/README.md](cloud-to-sdk/README.md) for more information on how to use this tool. -------------------------------------------------------------------------------- /tools/cloud-to-sdk/README.md: -------------------------------------------------------------------------------- 1 | # Cloud-to-SDK Converter Tool 2 | 3 | This tool helps you convert GAME cloud configuration JSON files into SDK-compatible TypeScript files. 4 | 5 | ## Important Notes 6 | 7 | *Note: This tool provides a starting point for code generation but has some limitations:* 8 | 9 | * Always verify generated code before production use 10 | * Some edge cases might not automatically handled: 11 | * Complex function implementations 12 | * Special character handling in descriptions/hints 13 | * Some functions might have been abstracted by GAME Cloud and is not generated in the json file, in which case you will need to implement them manually 14 | * Manual review and modification may be needed 15 | 16 | ## Overview 17 | 18 | If you have an existing GAME configuration JSON file from the cloud platform, you can use this tool to automatically generate the necessary TypeScript files for SDK integration. 19 | 20 | ## Usage 21 | 22 | 1. Go to your GAME Cloud page, and click on the "Export Agent" button to download the JSON file 23 | 24 | Export JSON 25 | 26 | 2. Place your GAME cloud JSON file in the tools/cloud-to-sdk directory 27 | 3. Run the conversion tool with the following command: 28 | npm run cloud-to-sdk -- 29 | 30 | This will create an `output` directory containing: 31 | - agent.ts - Contains the GameAgent configuration 32 | - worker.ts - Contains worker definitions 33 | - functions.ts - Contains function implementations 34 | 35 | *note: the functions generated are currently incomplete, they just contain function name, description and a boilerplate implementation, you will need to implement them. 36 | 37 | -------------------------------------------------------------------------------- /tools/cloud-to-sdk/generateAgent.ts: -------------------------------------------------------------------------------- 1 | // generateAgent.ts 2 | import fs from 'fs'; 3 | import path from 'path'; 4 | import { PluginJson } from './types'; 5 | import { GameAgent, LLMModel } from "@virtuals-protocol/game"; 6 | 7 | export function generateAgent(json: PluginJson, outputPath: string): void { 8 | try { 9 | // Ensure directory exists 10 | const dir = path.dirname(outputPath); 11 | if (!fs.existsSync(dir)) { 12 | fs.mkdirSync(dir, { recursive: true }); 13 | } 14 | 15 | const modelMapping: { [key: string]: string } = { 16 | 'llama_3_1_405b': 'Llama_3_1_405B_Instruct', 17 | 'llama_3_3_70b': 'Llama_3_3_70B_Instruct', 18 | 'deepseek_r1': 'DeepSeek_R1', 19 | 'deepseek_v3': 'DeepSeek_V3', 20 | 'qwen_2_5_72b': 'Qwen_2_5_72B_Instruct' 21 | }; 22 | 23 | const modelName = modelMapping[json.gameEngineModel.toLowerCase()] || 'Llama_3_3_70B_Instruct'; 24 | 25 | const content = ` 26 | import { GameAgent, LLMModel } from "@virtuals-protocol/game"; 27 | import { workers } from "./worker"; 28 | 29 | export const agent = new GameAgent("YOUR_API_KEY", { 30 | name: "${json.name || 'name'}", 31 | goal: \`${json.goal}\`, 32 | description: \`${json.description}\`, 33 | workers: workers, 34 | llmModel: LLMModel.${modelName} 35 | });`; 36 | 37 | fs.writeFileSync(outputPath, content); 38 | console.log(`✅ Generated agent.ts at ${outputPath}`); 39 | } catch (error) { 40 | console.error(`❌ Error generating agent.ts:`, error); 41 | throw error; 42 | } 43 | } -------------------------------------------------------------------------------- /tools/cloud-to-sdk/generateWorker.ts: -------------------------------------------------------------------------------- 1 | // generateWorker.ts 2 | import fs from 'fs'; 3 | import path from 'path'; 4 | import { PluginJson } from './types'; 5 | 6 | export function generateWorker(json: PluginJson, outputPath: string): void { 7 | try { 8 | const dir = path.dirname(outputPath); 9 | if (!fs.existsSync(dir)) { 10 | fs.mkdirSync(dir, { recursive: true }); 11 | } 12 | 13 | if (!json.workers?.length) { 14 | throw new Error('No worker configuration found in JSON'); 15 | } 16 | 17 | const workersContent = json.workers.map(worker => ` 18 | new GameWorker({ 19 | id: "${worker.id}", 20 | name: "${worker.name}", 21 | description: \`${worker.description}\`, 22 | functions: functions["${worker.workerId}"] || [] 23 | })`).join(',\n'); 24 | 25 | const content = ` 26 | import { GameWorker } from "@virtuals-protocol/game"; 27 | import { functions } from "./functions"; 28 | 29 | export const workers = [${workersContent} 30 | ];`; 31 | 32 | fs.writeFileSync(outputPath, content); 33 | console.log(`✅ Generated worker.ts at ${outputPath}`); 34 | } catch (error) { 35 | console.error(`❌ Error generating worker.ts:`, error); 36 | throw error; 37 | } 38 | } -------------------------------------------------------------------------------- /tools/cloud-to-sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@virtuals-protocol/game-cloud-to-sdk", 3 | "version": "0.1.0", 4 | "description": "Tool to convert GAME cloud configuration JSON files into SDK-compatible TypeScript files", 5 | "main": "index.ts", 6 | "scripts": { 7 | "start": "ts-node index.ts", 8 | "build": "tsc", 9 | "cloud-to-sdk": "ts-node index.ts" 10 | }, 11 | "dependencies": { 12 | "@virtuals-protocol/game": "^1.0.0", 13 | "ts-node": "^10.9.1", 14 | "typescript": "^5.0.0" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "^18.0.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tools/cloud-to-sdk/types.ts: -------------------------------------------------------------------------------- 1 | // types.ts 2 | export interface PluginJson { 3 | name: string; 4 | goal: string; 5 | description: string; 6 | gameEngineModel: string; 7 | workers: Worker[]; 8 | customFunctions: CustomFunction[]; 9 | } 10 | 11 | interface Worker { 12 | id: string; 13 | name: string; 14 | description: string; 15 | workerId: string; 16 | environment?: Record; 17 | isDefault?: boolean; 18 | deleted?: boolean; 19 | environmentString?: string; 20 | } 21 | 22 | interface CustomFunction { 23 | id: string; 24 | fn_name: string; 25 | fn_description: string; 26 | args: FunctionArg[]; 27 | hint?: string; 28 | config: { 29 | workerId: string; 30 | [key: string]: any; // For other config properties 31 | }; 32 | workerId?: string; 33 | } 34 | 35 | interface FunctionArg { 36 | id: string; 37 | name: string; 38 | description: string; 39 | type: string; 40 | } --------------------------------------------------------------------------------