AgentWorld is a unique game/simulation environment, underpinned by a language model acting as the game engine. This project was born from our curiosity about what it would take to create such a system.
We sought to make it extremely simple for anyone to set up their own language-based games. This repository is the result of that effort.
AgentWorld is unique in that the game engine itself is a language model. This model maintains the state of the virtual environment, embedding, retrieving, and modifying the state as per the actions of the players.
Agents (or humans) can interact inside the virtual world via text, prompted by the game engine.
Note: The terms players
, agents
, and characters
are used interchangeably throughout this documentation, as are game
, simulation
, and server
.
Before the game begins, the "World State" is written in json format (see: server/src/prompts.ts
). This includes initial 'places & things' that exist in the world.
At the start of a game, the server embeds the entire world state in a vector database (a ChromaDB collection called world
). The game starts once two agents have joined the server.
To join the game, agents make a post request to the game server with their Character's Name, and a postback URL to their server. The game server will make a post request to the provided URL on each turn.
The server then requests actions from each agent in a turn-based, round-robin fashion.
For each agent, the server generates a 'narration' of the current state of the world, and sends it to the agent.
The narration is dynamically generated on each turn. To create the narration, the game engine considers three things:
- The previous action taken by the agent (if applicable)
- All actions that have occurred since the last time this agent took an action (if applicable)
- Relevant information about the current state of the world, fetched from Chroma via semantic search
The narration is sent to the agent's server as a post request. The agent then has 30 seconds to respond with their next action.
When the response is received, the server will:
- Store the action in the
actions
collection in Chroma and theactions
array in the server - Query Chroma (
world
collection) for relevant items, locations, etc that may have been affected by the action - Update or add to the state of the world in Chroma using OpenAI Functions (implementation can be found in
server/lib/stateManager
)
The server will then repeat the process for the next agent.
There are three ways to set up this repository:
- Run an entire local environment, with agents and a server
- Run a local server, and allow others to connect to it
- Run an agent, and connect to a remote server
- Node.js installed locally
- docker installed
- Node.js installed locally
- docker installed
- Clone this repository
cd
into the repository- type
cp .env.example .env
and add your OpenAI API key to the newly created.env
file - type
docker-compose up --build
to start the server and sample agents (having issues? upgrade docker-compose to v2.12.1) - Navigate to
http://localhost:3000
to follow along
If you want to create a custom world with custom characters, you can edit server/src/prompts.ts
and restart the server.
- Node.js installed
- ngrok installed
- Docker installed
- Clone this repository
- in a terminal, type
git clone https://github.com/petersolimine/AgentWorld.git
- in a terminal, type
cd
into the directory- type
cd AgentWorld
- type
- Add your OpenAI API Key
- type
cp .env.example .env
and add your OpenAI API key to the newly created.env
file
- type
- Edit the
WorldState
JSON object inside ofserver/src/prompts.ts
to your liking- This is optional, but it's how you can customize the virtual world
- Start a ChromaDB instance in Docker
- Run
docker-compose -f docker-compose.chroma.yaml up --build -d
- Run
- Run
npm install
and thennpm start
- This will start the server on port 3123. You can change this value in
server/lib/constants.ts
if necessary.
- This will start the server on port 3123. You can change this value in
- Open a new terminal, run
ngrok http 3123
, and copy the ngrok URL- It will look something like this:
https://9d06-104-7-12-69.ngrok-free.app
- It will look something like this:
- Share the URL with your friends, and have them follow the steps in the next section!
If you want to follow along with the game, you can open a new terminal and navigate to the frontend
directory,
then run npm install
and npm run dev
. This will start a local nextjs app on http://localhost:3000
that will show you the actions of the game engine and the actions of each agent.
If you are not running the server but want to view the frontend, edit server/.env
with the server url :8080, run npm i
, and then npm run dev
.
There are three ways to do this. You can either
- Run the sample agent written in node.js, which requires nodejs and Docker to be installed
- Run the sample agent written in python, which only requires python to be installed
- Write your own agent in any language, following the spec, and connect to the server
These sections will be outlined below as 3.1, 3.2, and 3.3, respectively.
- Node.js installed
- Docker installed
- Clone this repository
cd
into the repository- type
cd AgentWorld
- type
- Add your OpenAI API Key
- type
cp .env.example .env
and add your OpenAI API key to the newly created.env
file
- type
- Describe your agent by editing the content inside of this file:
agent/config.json
- Server URL: The URL of the server you want to connect to
- Character Name: The name of your character
- Character Description: A short description of your character (this will be used as the agent's System Prompt)
- Start a ChromaDB instance in Docker (this is where your agent's memory 🧠 is stored)
- type
docker-compose -f docker-compose.chroma.yaml up --build -d
- type
- Install necessary packages and start the agent
- type
npm install
and thennpm run agent
- type
- (optional) Follow along with the gameplay (the stuff that your agent can't see)
- open a new terminal, navigate to the directory (type
cd AgentWorld
) and then typenpm run view
- open a new terminal, navigate to the directory (type
TODO
TODO
TODO
You can write your agent in any language, as long as it follows the spec outlined below. You could also build a client that prompts you for text input, so that you can play the game yourself.
N/A, make your own rules. But use Chroma for your agent's memory if you are based and AGI pilled.
-
Set up an agent and establish a connection with the server.
-
To connect, make a POST request to the server's
/join/
endpoint, including a JSON object with: - name: Your agent's name - url: Your agent's server URL -
Your agent's server should accept POST requests at the
/chat/
endpoint. -
When the game server makes a POST request to
/chat/
withactionRequest
in the body, your server should respond with a JSON object containing: -action
: The response of your agent, which will be treated as the agent's action.
For an example of this, see the implementation in agent/index.ts
Interested in contributing? We've got a few ideas that would be cool to add. We outlined the steps you could potentially take. Feel free to follow them, or take your own approach.
Also, feel free to just contribute other ideas!
-
Build a "map" into the game
- Add x,y coordinates as metadata on each world state item within Chroma.
- Display those items on the frontend using the coordinates.
- When fetching world state items, filter by distance from the character.
- Or, do it some other way!
-
Build a win-state
- Change the game loop from while (True) to while (!game_over)
- Create a "WinCriteria" variable, described as text,
inside of prompts.ts
- Add an additional OpenAI call in
app.ts
after each agent action, which injects both the WinCriteria and the user's action into context for a T/F classifier that decides whether the action meets the criteria. - If so, exit the game loop and crown the winner!
-
Build a filter to check if content is relevant before summarizing it
- This will make the game engine more effective, but will come at a higher compute cost.
- Before passing World State elements into the GenerateRequestNextActionPrompt function, filter the list using another call to OpenAI. In that way, you could be more confident that only relevant items would be inserted.
- Note: Adding coordinates (above) could be a more efficient means of filtering.
-
Implement other sample agents
- First of all, it would be great to have an agent implementation written in python
- It would be so cool to see how AutoGPT matches up against BabyAGI, etc...