To install the package, run:
npm install @virtuals-protocol/gameCurrently, this SDK allows you to develop your agents powered by the GAME architecture in its most fullest and most flexible form.
The SDK is made up of 3 main components (Agent, Worker, function), each with configurable arguments.
Agent (a.k.a. high level planner)
- Takes in a Goal
- Drives the agent's behavior through the high-level plan which influences the thinking and creation of tasks that would contribute towards this goal
- Takes in a Description
- Combination of what was previously known as World Info + Agent Description
- This includes a description of the "world" the agent lives in, and the personality and background of the agent
Worker (a.k.a. low-level planner)
- Takes in a Description
- Used to control which workers are called by the agent, based on the high-level plan and tasks created to contribute to the goal
Function
- Takes in a Description
- Used to control which functions are called by the workers, based on each worker's low-level plan
- This can be any executable
Request for a GAME API key in the Game Console. https://console.game.virtuals.io/ If you have any trouble, contact Virtuals support or DevRel team members via Discord or Telegram.
Functions define available actions for the agent:
import{GameFunction,ExecutableGameFunctionResponse,ExecutableGameFunctionStatus,}from"@virtuals-protocol/game";constmyFunction=newGameFunction({name: "action_name",description: "Description of action",args: [{name: "param",type: "type",description: "param description"},]asconst,executable: async(args)=>{try{// Implement your function logic herereturnnewExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Done,"Action completed successfully");}catch(e){returnnewExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Failed,"Action failed");}},});Executable functions must return an instance of ExecutableGameFunctionResponse with:
ExecutableGameFunctionStatus- Feedback message
Easy and flexible way to define the state management, what the agent sees and how that changes.
asyncfunctiongetAgentState(): Promise<Record<string,any>>{return{health: 100,inventory: ["sword","shield","potion"],};}Workers are simple interactable agents that execute the tasks defined by the user. They can be specialized agents with defined capabilities:
import{GameWorker}from"@virtuals-protocol/game";constworker=newGameWorker({id: "worker_id",name: "Worker Name",description: "Worker description",functions: [list_of_functions],getEnvironment: async()=>{return{// environment details};},});Key features:
- Can be shared or unique per worker
- Processes function execution results to update state
Agents are used to autonomously function in an open-ended manner by just providing a general goal. Tasks are generated by the agent itself continuously, and the agent will attempt to complete them. You can provide many workers to the agent, and they will be used to execute the tasks.
import{GameAgent}from"@virtuals-protocol/game";constagent=newGameAgent("your_api_key",{name: "Agent Name",goal: "Primary goal",description: "Description",getAgentState: agent_state_function,workers: [worker1,worker2],});// Compile and runawaitagent.init();awaitagent.run();To run a worker individually, you can initialize and run the worker without the main loop. Here's an example:
constagentWorker=agent.getWorkerById(worker1.id);consttask="Gotten a message from user. Message content: hey! I will need help with my project, I need an image of a cat-hugging AI. Can you help me with that? Give me something that cool and cute!";awaitagentWorker.runTask(task);This allows you to run specific workers of an agent.
For more detailed information, please refer to the Virtuals Game Framework Whitepaper.
Create the Twitter Functions
Define the functions for posting tweets, searching tweets, and replying to tweets:
import{ExecutableGameFunctionResponse,ExecutableGameFunctionStatus,GameFunction,}from"@virtuals-protocol/game";constpostTweetFunction=newGameFunction({name: "post_tweet",description: "Post a tweet",args: [{name: "tweet",description: "The tweet content"},{name: "tweet_reasoning",description: "The reasoning behind the tweet",},]asconst,executable: async(args,logger)=>{try{// TODO: Implement posting tweetlogger(`Posting tweet: ${args.tweet}`);logger(`Reasoning: ${args.tweet_reasoning}`);returnnewExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Done,"Tweet posted");}catch(e){returnnewExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Failed,"Failed to post tweet");}},});constsearchTweetsFunction=newGameFunction({name: "search_tweets",description: "Search tweets and return results",args: [{name: "query",description: "The query to search for"},{name: "reasoning",description: "The reasoning behind the search"},]asconst,executable: async(args,logger)=>{try{constquery=args.query;// TODO: Implement searching of tweets based on query stringlogger(`Searching tweets for query: ${query}`);returnnewExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Done,"Tweets searched here are the results: [{tweetId: 1, content: 'Hello World'}, {tweetId: 2, content: 'Goodbye World'}]");}catch(e){returnnewExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Failed,"Failed to search tweets");}},});constreplyToTweetFunction=newGameFunction({name: "reply_to_tweet",description: "Reply to a tweet",args: [{name: "tweet_id",description: "The tweet id to reply to"},{name: "reply",description: "The reply content"},]asconst,executable: async(args,logger)=>{try{consttweetId=args.tweet_id;constreply=args.reply;// TODO: Implement reply tweetlogger(`Replying to tweet ${tweetId}`);logger(`Replying with ${reply}`);returnnewExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Done,`Replied to tweet ${tweetId} with ${reply}`);}catch(e){returnnewExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Failed,"Failed to reply to tweet");}},});
Create the Worker
Define a worker that uses the functions in
twitter.ts:import{GameWorker}from"@virtuals-protocol/game";constpostTweetWorker=newGameWorker({id: "twitter_main_worker",name: "Twitter main worker",description: "Worker that posts tweets",functions: [searchTweetsFunction,replyToTweetFunction,postTweetFunction],// Optional: Provide environment to LLPgetEnvironment: async()=>{return{tweet_limit: 15,};},});
Create the Agent
Define an agent that uses the worker in
agent.ts:import{GameAgent}from"@virtuals-protocol/game";constagent=newGameAgent("YOUR_API_KEY",{name: "Twitter Bot",goal: "Search and reply to tweets",description: "A bot that searches for tweets and replies to them",workers: [postTweetWorker],// Optional: Provide state to HLPgetAgentState: async()=>{return{username: "twitter_bot",follower_count: 1000,tweet_count: 10,};},});
To define a custom logger for the agent, you can use the setLogger method. This method allows you to specify how the agent's log messages should be handled. Here's an example of how to set up a custom logger:
agent.setLogger(agent,(msg)=>{console.log(`-----[${agent.name}]-----`);console.log(msg);console.log("\n");});In this example, the custom logger will print the agent's name followed by the log message to the console. You can customize the logger function to handle log messages in any way you prefer, such as writing them to a file or sending them to a logging service.
You can use the logger within your custom functions to log messages. The logger is passed as an argument to the executable function. Here's an example of how to use the logger in a custom function:
constcustomFunction=newGameFunction({name: "custom_action",description: "A custom action with logging",args: [{name: "param",description: "Parameter for the action"}]asconst,executable: async(args,logger)=>{try{logger(`Executing custom action with param: ${args.param}`);// Implement your function logic herereturnnewExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Done,"Custom action completed successfully");}catch(e){logger(`Failed to execute custom action: ${e.message}`);returnnewExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Failed,"Custom action failed");}},});In this example, the logger is used to log messages before and after the execution of the custom action. This helps in tracking the function's execution flow and any errors that occur.
The agent will initialize and start running, performing actions such as posting tweets, searching for tweets, and replying to tweets at regular intervals.
awaitagent.init();// running at a fix interval of 60 secondsawaitagent.run(60,{/** * @property {boolean} verbose - A flag to enable or disable verbose logging. * * @description * The `verbose` property is used to control the verbosity of the logging output. * When set to `true`, detailed logs will be generated, which can be useful for * debugging and development purposes. When set to `false`, only essential logs * will be produced, reducing the amount of log output. */verbose: true|false,});With the step function app has more control over in interval
awaitagent.step();This example provides a use case where agents are reacting to a task.
The agent will initialize and start running, performing actions such as generating images and replying to messages.
Define a worker that uses the functions in tg.ts:
import{GameWorker}from"@virtuals-protocol/game";consttelegramWorker=newGameWorker({id: "telegram",name: "telegram",description: "Telegram worker",functions: [.........],});awaitagent.init();constagentTgWorker=agent.getWorkerById(telegramWorker.id);consttask="Gotten a message from user. Message content: hey! I will need help with my project, I need an image of a cat-hugging AI. Can you help me with that? Give me something that cool and cute!";awaitagentTgWorker.runTask(task,{/** * @property {boolean} verbose - A flag to enable or disable verbose logging. * * @description * The `verbose` property is used to control the verbosity of the logging output. * When set to `true`, detailed logs will be generated, which can be useful for * debugging and development purposes. When set to `false`, only essential logs * will be produced, reducing the amount of log output. */verbose: true|false,});This project is licensed under the MIT License.