diff --git a/README.md b/README.md index 5ef61898d..86be5c3ee 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,50 @@ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) -This directory is home to the [LIGHT](https//parl.ai/projects/light/) project. At the moment it is very much a migration in progress, but it will be home to all of the LIGHT experiments, reproducible code, and more! +This directory is home to the [LIGHT](https://parl.ai/projects/light/) project. At the moment it is very much a migration in progress, but it will be home to all of the LIGHT experiments, reproducible code, and more! For now, much of the code is split between the two locations, so missing segments and data can likely be found from the projects game. + +## What is LIGHT? + +LIGHT is part Text-Adventure game, part Dialogue + Natural Language research platform. We host a game at [light-rpg.ai](https://light-rpg.ai) built upon the research work contained in this repo. Here we're also happy to consider developments from the LIGHT community of researchers, creators, and players. Our long-term goal is to create something that is all of: +1. A strong multiplayer game environment that is easy and fun to interact with for players. +2. An AI-Powered storytelling tool for creators to build interactive experiences for others to enjoy. +3. A platform for exploring advancements in Dialogue and Natural Language research through developing better models to power the game. + +## The LIGHT Repo + +This repo contains a few directories related to the LIGHT project. More details can be found in each directory: +- [**`crowdsourcing`**](https://github.com/facebookresearch/LIGHT/tree/main/crowdsourcing): Contains the full setup and deploy code for (nearly) all of the crowdsourced data used in LIGHT. Useful examples of how to collect similar types of data. +- [**`deploy`**](https://github.com/facebookresearch/LIGHT/tree/main/deploy): Contains code relevant for various deploys of LIGHT for public consumption. +- [**`light`**](https://github.com/facebookresearch/LIGHT/tree/main/light): Contains the core LIGHT game engine. Includes the `OOGraph` data model, descriptions of all of the node types, actions and manipulations on the graph (`GraphEvent`s), and the abstract API (`Soul`s) for creating agents that can act in LIGHT. +- [**`modeling`**](): A (currently-nonexistant) directory of code for agents and teachers that can be trained to work in LIGHT. +- [**`projects`**](https://github.com/facebookresearch/LIGHT/tree/main/projects): Contains code that's still in-development, either for research endeavors that haven't yet been incorporated into the game, or works that derive from work but ultimately don't feed back in. Also contains code relevant preserved to reproduce specific paper results. +- [**`scripts`**](https://github.com/facebookresearch/LIGHT/tree/main/scripts): Contains execution code for running LIGHT, exploring our dataset, filtering through examples, and more. + +## Getting started + +First off, to get started you'll need to install LIGHT into your python environment. For this, you can navigate to this repo and run +``` +pip install -e . +``` +The rest of the core interactions with LIGHT may require additional environment and other downloads, explained below. + +### Interacting with the LIGHT engine (no models) +To jump right into a LIGHT world on the command line, you can use some of our example code. The following will put you in the simplest world: +``` +python scripts/examples/play_map.py +``` + +You can also try a more complex LIGHT world using the following: +``` +python scripts/examples/play_map.py --load-map scripts/examples/complex_world.json +``` + +Deeper explanations on how the engine itself functions can be found in the [LIGHT graph](https://github.com/facebookresearch/LIGHT/tree/main/light/graph) directory. + +### Exploring the environment with models + +TODO - Fill out once all of the required minimal models are hosted for access outside of the cluster. + +### Launching the full game server locally + +TODO - more details are in the [web deploy](https://github.com/facebookresearch/LIGHT/tree/main/deploy/web/) directory. diff --git a/crowdsourcing/README.md b/crowdsourcing/README.md index 5e626d79c..6273f1053 100644 --- a/crowdsourcing/README.md +++ b/crowdsourcing/README.md @@ -1,3 +1,10 @@ -# crowdsourcing +# Crowdsourcing -All LIGHT crowdsourcing tasks launched through regular crowd providers (like MTurk) belong in here. +All LIGHT crowdsourcing tasks launched through regular crowd providers (like MTurk) belong in here. Overall this collection should be the full setup and deploy code for (nearly) all of the crowdsourced data used in LIGHT. Some are useful examples of how to collect similar types of data. + +**Subdirectories:** +- **`custom_world_interactions`**: Tasks that together allow us to collect custom `GraphEvent` operations outside of the basic game engine. These allow LIGHT to have "common sense" interactions. +- **`dialogues`**: Tasks to improve the dialogue capabilities of models in specific situations. +- **`environment`**: Tasks to expand on or clean up the LIGHT environment. +- **`filtering`**: Tasks that allow us to filter out data collected in LIGHT for safety or other reasons. +- **`quests`**: Tasks for collecting quests and motivations for characters, as well as some plans or paths to accomplish those goals. diff --git a/deploy/README.md b/deploy/README.md index 1c3aea217..2216a5b39 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1,3 +1,8 @@ -# deploy +# Deploy Folder containing all of the backend and frontend code for deploying an aspect of LIGHT on one of the surfaces we support. + + +**Subdirectories:** +- **`web`**: Code for the current [light-rpg.ai](https://light-rpg.ai) deploy. Minus some deploy + safety secrets, of course! You'll need to supply your own for a local deployment. +- **`messenger`**: Code for the messenger deploy used in our [LIGHT-WILD](https://arxiv.org/abs/2008.08076) data collection. Not in a deploy-ready state, though the underlying ParlAI worlds contain the same logic we used in those experiments. diff --git a/light/hobbot/onboarding_worlds.py b/deploy/messenger/hobbot/onboarding_worlds.py similarity index 100% rename from light/hobbot/onboarding_worlds.py rename to deploy/messenger/hobbot/onboarding_worlds.py diff --git a/light/hobbot/single_player_world.py b/deploy/messenger/hobbot/single_player_world.py similarity index 100% rename from light/hobbot/single_player_world.py rename to deploy/messenger/hobbot/single_player_world.py diff --git a/light/hobbot/strategies/fb_messenger_strategy.py b/deploy/messenger/hobbot/strategies/fb_messenger_strategy.py similarity index 100% rename from light/hobbot/strategies/fb_messenger_strategy.py rename to deploy/messenger/hobbot/strategies/fb_messenger_strategy.py diff --git a/light/hobbot/strategies/light_chat_strategy.py b/deploy/messenger/hobbot/strategies/light_chat_strategy.py similarity index 100% rename from light/hobbot/strategies/light_chat_strategy.py rename to deploy/messenger/hobbot/strategies/light_chat_strategy.py diff --git a/light/hobbot/strategies/sockets_strategy.py b/deploy/messenger/hobbot/strategies/sockets_strategy.py similarity index 100% rename from light/hobbot/strategies/sockets_strategy.py rename to deploy/messenger/hobbot/strategies/sockets_strategy.py diff --git a/light/hobbot/utils.py b/deploy/messenger/hobbot/utils.py similarity index 100% rename from light/hobbot/utils.py rename to deploy/messenger/hobbot/utils.py diff --git a/light/hobbot/worlds.py b/deploy/messenger/hobbot/worlds.py similarity index 100% rename from light/hobbot/worlds.py rename to deploy/messenger/hobbot/worlds.py diff --git a/light/README.md b/light/README.md index 853f6b63b..bc80a4138 100644 --- a/light/README.md +++ b/light/README.md @@ -1,3 +1,9 @@ -# LIGHT Core +# light -Folder for all of the generally shared content within the LIGHT project. +Contains the core LIGHT game engine and data model. Includes the `OOGraph` data model, descriptions of all of the node types, actions and manipulations on the graph (`GraphEvent`s), and the abstract API (`Soul`s) for creating agents that can act in LIGHT. + +**Subdirectories:** +- **`data_model`**: Classes that represent LIGHT data in _cold storage_, absent of a specific LIGHT world. At the moment this is mostly centralized in the `LIGHTDatabase`, which uses SQLite storage, but given new data types and systems this is definitely subject to change. +- **`graph`**: Classes that represent a LIGHT Graph (the state of a LIGHT world), the elements inside, builders to create a new Graph, events that modify Graphs, and related tooling. +- **`registry`**: Classes that allow registering LIGHT models to an active LIGHT world, allowing them to interact and fill certain decisions in the LIGHT setup. Currently in development as we transition models out from being initialized at their usage locations. +- **`world`**: Contains all the higher-level code that is required to run an _active_ LIGHT graph, including processing agent actions into events, executing them on the graph, and handling logging. diff --git a/light/colors.py b/light/colors.py index 8d8ac5647..39aa039c6 100644 --- a/light/colors.py +++ b/light/colors.py @@ -4,6 +4,11 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +""" +Simple shared class of colors we can use for displaying terminal content in +visually appealing ways. +""" + class Colors: CYAN = "\u001b[36m" @@ -18,4 +23,4 @@ class Colors: BOLD_BLUE = "\u001b[34;1m" PURPLE = "\u001b[35m" BOLD_PURPLE = "\u001b[35;1m" - RESET = "\u001b[0m" \ No newline at end of file + RESET = "\u001b[0m" diff --git a/light/graph/README.md b/light/graph/README.md index 03f4a0a5a..6fa395009 100644 --- a/light/graph/README.md +++ b/light/graph/README.md @@ -1,3 +1,41 @@ # LIGHT Graph The LIGHT graph is the core state of the environment over which LIGHT takes place. This folder contains the components for managing, building, and operating on Graphs. + +## The LIGHT `OOGraph` + +Generally, the LIGHT `OOGraph` is constructed of `GraphNode`s and `GraphEdge`s. Nodes contained in or containing other nodes use the `GraphEdge` class. We use a special `NeighborEdge` class to note the connections between rooms, as these may have additional attributes. All of the contents of a graph should be json-serializable, so you can see a JSON representation of a simple graph [here](https://github.com/facebookresearch/LIGHT/tree/main/scripts/examples/simple_world.json). + +### Special Conditions +Beyond the basic structure of nodes and edges, the `OOGraph` keeps track of a few special considerations. + +#### The Void +As all nodes must have a container, we create a special `GraphVoidNode` which is the default continer for all nodes. When creating a node, all nodes are initially created in the void, and can later be moved to their correct containers with `move_to` functions. Room nodes generally will remain in the void. + +#### Deletion Lifecycles +Node deletion is somewhat tricky in LIGHT, as it's possible that an action leads to the deletion of a node that, in the same timestep, needs to be used for a description, log, or otherwise. For this, we can instead mark a node for deletion with `mark_node_for_deletion` and later use `delete_nodes` to clear these. Further, even when a node is deleted, we still maintain a reference to it in `_deleted_nodes` for logging purposes. (This may eventually be removed for memory usage reasons) + +#### Agent Death +Death in the LIGHT world, in a base sense, is the transition from a node being a `GraphAgent` that can be inhabited by a `Soul` to a `GraphNode`. As of now this transition is managed by the _to be deprecated_ `agent_die` function, which makes an object copy of the agent, transfers over the contents to the copy, and then delete the agent node. These special post-death nodes are tracked in the `dead_nodes` array. + +#### Node searching +It is important in many cases (especially parsing) to try and find nodes that match a specific description in the graph. Accessors of this type are bundled in the `desc_to_nodes` function, which can either search the whole graph or can use a `nearby_node` and `nearbytype` to search with a specific strategy. + +`nearbytype` is a string of `+` separated options, having the following effects: +- `'all'`: include the contents of `nearby_node`, its parent, and its parent's neighbors. +- `'sameloc'`: searches over all nodes sharing the same parent container as `nearby_node`. +- `'carrying'`: searches over all nodes contained by `nearby_node`. +- `'path'`: searches over rooms attached to the container of `nearby_node`. +- `'contains'`: includes the container of `nearby_node`. +- `'other_agents'`: includes nodes carried by agents in the same **room** as `nearby_node`. +- `'others'`: extend search to recursively include anything contained in the search list already. + +#### Nodes vs IDs +Some functions in the `OOGraph` still refer to using a node's `node_id` rather than using the reference to the `node` directly. In general, this access pattern is deprecated, but remaining usage tends to very clearly note whether an access is getting a `GraphNode` or is `node_id`. To convert `node_id` to `GraphNode`, you can use `OOGraph.get_node(node_id)`. To get a node's id, you can just use `GraphNode.node_id`. + +## Subdirectories +- **`builders`**: `GraphBuilder`s are utility classes used to create and extend `OOGraph`s with content. +- **`elements`**: `GraphNode`s are the the contents of a graph, and comprise the information stored within. +- **`events`**: `GraphEvent`s define the types of operations and manipulations that can be performed on an `OOGraph`. +- **`tests`**: Some testing to ensure that the graph is acting as expected. +- **`viz`**: Visualization tooling that allows inspection of an `OOGraph`. diff --git a/light/graph/build_map.py b/light/graph/build_map.py deleted file mode 100644 index 1f3bc379b..000000000 --- a/light/graph/build_map.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python3 -# Builds a LIGHT map using a StarSpace model to connect locations. -# Is not currently connected to the LIGHT text adventure game API -# (but should be straight-forward). - - -from light.graph.builders.starspace_neighbor import StarspaceNeighborBuilder - -from light.world.world import World -import random -import copy -import numpy as np - -random.seed(6) -np.random.seed(6) - - -# TODO deprecate in favor of graph builders -class BuildLightMap: - def __init__(self, debug=True): - self.world = StarspaceNeighborBuilder() - self.world.build_world() - - def get_graph(self): - return World.from_graph(self.world.get_graph()) - - def add_agent(self, g, agent_id): - g._node_npcs.add(agent_id) - - -if __name__ == "__main__": - random.seed(6) - m = BuildLightMap() diff --git a/light/graph/builders/README.md b/light/graph/builders/README.md new file mode 100644 index 000000000..caf6375db --- /dev/null +++ b/light/graph/builders/README.md @@ -0,0 +1,12 @@ +# Builders + +Core folder containing the LIGHT `GraphBuilder` classes. A `GraphBuilder` is used to directly construct or modify a LIGHT `OOGraph` in a controllable way. The core types are the `GraphBuilder` and the `SingleSuggestionGraphBuilder`. The former exposes an API where you can simply create a graph or add agents to it (to fill for dying agents). The latter provides an abstract API for a graph builder that can later be used to make suggestions for modifications to the graph. + +**Contents:** +- **`base.py`**: Underlying base `GraphBuilder` class definitions. +- **`base_elements.py`**: Utility classes representing the contents retrieved from the `LIGHTDatabase` as would be useful for a `GraphBuilder`. +- **`db_utils.py`**: Utility classes to access graph-construction-related content from a `LIGHTDatabase`. +- **`external_map_json_builder.py`**: Graph builder using a _deprecated_ format (from an early world builder tool) to load a graph directly from that json format. +- **`one_room_builder.py`**: Graph builder that creates a single room and populates it with the desired number of characters. Often used to create dialogue tasks. +- **`starspace_all.py`**, **`starspace_assisted.py`**, and **`starspace_neighbor.py`**: Various starspace-based graph builders that use a `starspace` model to make large graphs from knowledge on local connections. Nearly deprecated by Commonsense-based agents, and will likely be deprecated once a `GraphBuilder` is created from them. +- **`user_world_builder.py`**: Creates a LIGHT Graph based on contents saved in the `LIGHTDatabase` for a given user. Likely to be deprecated when we start saving the new world format. diff --git a/light/graph/elements/README.md b/light/graph/elements/README.md new file mode 100644 index 000000000..157bf9827 --- /dev/null +++ b/light/graph/elements/README.md @@ -0,0 +1,5 @@ +# elements + +Contains the main `GraphNode` and `GraphEdge` types that comprise a LIGHT `OOGraph`. + +At the moment, `GraphNode`s can have two different edge types. The first is a `GraphEdge`, which represents a relation between two nodes that are in the graph. The second is the more implicit attribute edge, which allows for `GraphNode`s to be identified as containers or having certain properties. diff --git a/light/graph/events/README.md b/light/graph/events/README.md index 74e68fd29..225d8472f 100644 --- a/light/graph/events/README.md +++ b/light/graph/events/README.md @@ -1,375 +1,211 @@ - - - - - # LIGHT Events - - - +LIGHT `GraphEvent`s comprise all types of manipulations that can occur on a LIGHT `OOGraph`. These, on their own, include checks for parsing, valid construction and executability, etc, however construction of a `GraphEvent` alone doesn't actually manipulate the graph. Calling `GraphEvent.execute` on a LIGHT `World` is required to actually attempt the transition. -An event is any interaction triggered or not by player action between two entities in the LIGHT environment. +We use `GraphEvent`s to parse text commands into valid actions, find all possible valid events for a given model agent, replay previous logs, and more. - - - - -## LIGHT Use Events - +## Base Graph Events +The base events are `GraphEvent`, representing any action on the graph, `ErrorEvent`, which represents a failure to parse or execute an event, and `TriggeredEvent`, which represents an event that can only be created directly by another event, rather than being parsed out from a determined action. - +The `GraphEvent` itself sets a baseline API for interacting with an `OOGraph` and making controllable transitions over it. This interface covers the direct and parsed creation of an event, as well as execution and failure conditions. Details are further expanded on in the `base.py` file and class definition, but the following gives a brief overview: +- `__init__`: Generally, `GraphEvent`s are boiled down to an interaction between nodes, but can also include arbitrary text (for directly messaging, or updating graph text state). As such, graphs require an `actor`, and then optionally have `target_nodes` which may be involved in the interaction, as well as `text_content` which can be any string used in the event. +- `execute`: Actually make direct changes to the `OOGraph`, or broadcast observable messages to agents in the `OOGraph`. At the moment, assumes that the event _can_ be successfully executed if it is properly constructed. +- `split_text_args`: Given a string, split into a list of possibly valid text lists to parse into arguments to form an event. Return an `ErrorEvent` if no such parsing is possible. +- `find_nodes_for_args`: Given a list of text args, find appropriate elements in the graph that both match the name and event requirements. Return an `ErrorEvent` if no such find is possible. +- `construct_from_args`: Use the given args returned from `find_nodes_for_args` to construct a `GraphEvent` of this type. +- `to_canonical_form`: Produces a standard text representation for the event, such that a `split_text_args -> find_nodes_for_args -> construct_from_args` pass would produce the same event. +- `get_valid_actions`: Return a list of `GraphEvent`s of this type that a given agent would be able to perform on the given graph, if any. +- `view_as`: Provides a string representation for the event from the perpsective of a given agent. -These events describe any interaction of the type `use x with y`. Every use interaction (Described in the world as an `on_use` function) is made of two parts: +A complete list of instances of events is defined in `graph_events.py`. - +## LIGHT Use Events -`Constraints` and `Events`. `Constraints` are the conditions that must be fullfilled in order for an event to happen. For example, if try to dig for a pirate treasure +These event types cover the contents of `use_events.py`, `use_triggered_events.py`, and `constraint.py`. Overall these events describe any interaction of the type `use x with y`. Every use interaction (Described in the world as an `on_use` function) is made of two parts: `Constraints` and `Events`. - +Note, the contents currently handled by the `magic.py` class should eventually be rolled into these types of events. -it will only trigger the `Find Treasure Chest` event if you use the shovel item in the spot with an X on it - if you try to use in another spot the event will not happen. +### `Constraint`s +`Constraints` are the conditions that must be fullfilled in order for an event to happen. - +For example, if try to dig for a pirate treasure it will only trigger the `Find Treasure Chest` event if you use the shovel item in the spot with an X on it - if you try to use in another spot the event will not happen. Being in the X spot is a `Constraint` of the `Find Treasure Chest` event. -Being in the X spot is a `Constraint` of the `Find Treasure Chest` event. +### `Event`s - +`Events` describe the effects triggered from the ocurrence of an `Use Event`. For example, the aforementioned `Find Treasure Chest` use event would trigger a `Create Entity Event`, creating a `Treasure Chest` item inside the `X-spot landmark` object. These events are all of that `UseTriggeredEvent` type. -`Events` describe the effects triggered from the ocurrence of an `Use Event`. For example, the aforementioned `Find Treasure Chest` use event would trigger a `Create Entity Event`, creating a `Treasure Chest` item inside the `X-spot landmark` object. +### `remaining_uses` -There's also a third element in the `Use Event` called `remaining_uses`, which represent how many times this event can still be played out. For example, the event above should have `remaning_uses: 1` as it can only happen one time. If you try it another time, no treasure will be found. If the event can happen infinite times, you should use `remaining_uses: inf`. +There's also a third element in the `UseEvent` called `remaining_uses`, which represent how many times this event can still be played out. For example, the event above should have `remaning_uses: 1` as it can only happen one time. If you try it another time, no treasure will be found. If the event can happen infinite times, you should use `remaining_uses: inf`. - +### Formatting Every constraint and event is a dictionary of the format: - -``` - +```json { - -"type": "...", - -"params": { - -... - + "type": "...", + "params": { + ... + } } - -} - ``` - - -Every `on_use` functions is an array of Use events, which are arrays of `Constraints` and `Events` as described above. In general, when describing an object, the format of their custom interactions will be: - -``` +Every `on_use` function is an array of Use events, which are arrays of `Constraints` and `Events` as described above. In general, when describing an object, the format of their custom interactions will be: +```json "object_id": { - -"name": "object_name", - -"contain_size": 0, - -... - -"on_use": [ - -//Interaction 1 - -{ - -"events": { - -... - -}, - -"constraints": { - -... - -}, - -"remaining_uses": "..." - -}, - -//Interaction 2 - -{ - -"events": { - -... - -}, - -"constraints": { - -... - -}, - -"remaining_uses": "..." - -}, - -... - -] - + "name": "object_name", + "contain_size": 0, + ... + "on_use": [ + //Interaction 1 + { + "events": { + ... + }, + "constraints": { + ... + }, + "remaining_uses": "..." + }, + //Interaction 2 + { + "events": { + ... + }, + "constraints": { + ... + }, + "remaining_uses": "..." + }, + ... + ] } - - - ``` - - ## Constraint Types - - ### Is Holding - - Checks whether the actor of the event is holding one of the objects involved in the event. The `complement` argument represent if the constraint is being applied on the item being used or the target of the `on_use` event. If you try to use a shovel in a muddy area, for example, to be holding the shovel. Is has the format: - -``` - +```json { - -"type": "is_holding", - -"params": { - -"complement": "used_item" - + "type": "is_holding", + "params": { + "complement": "used_item" + } } - -} - ``` - - ### Used with Item - - - Checks whether the actor of the event is doing the event with a specific object. Certain events can only happen by using certain combinations of objects, so this is a must. It has the format: - -``` - +```json { - -"type": "used_with_item_name", - -"params": { - -"item": "muddy area" - + "type": "used_with_item_name", + "params": { + "item": "muddy area" + } } - -} - ``` ### Used with Agent - - - Checks if the target of the event is an agent. This is useful as some events modify attributes which only exist in agents, like for example, an `on_use` event which modifies the target's health. It uses no params. It has the format: - -``` - +```json { - -"type": "used_with_agent" - + "type": "used_with_agent" } - ``` ### In Room - - Checks if the event is happening inside a specific room. Some events only happen in certain places, like a magic orb that only works when placed inside the sanctuary of its creator. It has the format: - -``` - +```json { - -"type": "in_room", - -"params": { - -"room_name": "Orc cave" - + "type": "in_room", + "params": { + "room_name": "Orc cave" + } } - -} - ``` ### Attribute Compare Value - - - It compares the attribute of the Use event target with a list of possible values. The attribute to be compared is passed through `key` and the list of possible values is passed through the `list` argument. The comparison method is passed through `cmp_type`, which can be: - - - - `eq` for equal or `==` - - `neq`for not equal or `!=` - - `greater` for greater or `>` - - `geq` for greater than or equal, `>=` - - `less`for less or `<` - - `leq`for less than or equal, `<=` - - It's important to remind that the attribute value needs to satisfy its comparison to only one of the list values, meaning this constraint's list works as an _OR_. In case of an _AND_ conjoint being necessary, use multiple `attribute_compare_value` constraints in the same Use event. It has the format: - -``` - +```json { - -"type": "attribute_compare_value", - -"params": { - -"type": "in_used_target_item", - -"key": "health", - -"list": "[0]", - -"cmp_type": "greater" - -} - + "type": "attribute_compare_value", + "params": { + "type": "in_used_target_item", + "key": "health", + "list": "[0]", + "cmp_type": "greater" + } } - ``` - - ## Event Types - - ### Create Entity - - - Creates an entity after the event happens. The entity created may belong to the room (In this case, `type = in_room`), the actor of the event (`type=in_actor`), the item being used on the Use event (`type=in_used_item`) or the target of the Use event itself (`type=in_use_target_item`). To use this event, it's necessary to specify where the entity is being created and the object itself. It has the format: -``` - -"type": "create_entity", - -"params": { - -"type": "in_used_target_item", - -"object": { - -"name_prefix": "an", - -"is_wearable": true, - -"name": "emerald ring", - -"desc": "A beautiful and mysterious ring.. could it have magical powers?" - -} - +```json +{ + "type": "create_entity", + "params": { + "type": "in_used_target_item", + "object": { + "name_prefix": "an", + "is_wearable": true, + "name": "emerald ring", + "desc": "A beautiful and mysterious ring.. could it have magical powers?" + } + } } - ``` - - -### Broadcast Message - +### Broadcast Message Broadcasts a message related to the Use event to the room the agent is currently in. To use it, it is necessary to specify the views of the message (Which message will be sent to the agent doing the use event, to agents in the same room, etc.). The format is as following: -``` - -"type": "broadcast_message", - -"params": { - -"self_view": "You say the words aloud, and runes on the scroll glow with gold.", - -"self_as_target_view": "You are struck with searing pain!", - -"self_not_target_view": "{recipient_text} is struck with searing pain!", - -"room_view": "{actor_text} says the words of a scroll aloud, and it glows with gold. {recipient_text} is struck with searing pain!" - +```json +{ + "type": "broadcast_message", + "params": { + "self_view": "You say the words aloud, and runes on the scroll glow with gold.", + "self_as_target_view": "You are struck with searing pain!", + "self_not_target_view": "{recipient_text} is struck with searing pain!", + "room_view": "{actor_text} says the words of a scroll aloud, and it glows with gold. {recipient_text} is struck with searing pain!" + } } - ``` - - #### Recipient Text and Actor Text templates - - - The templates used in the example (`{recipient_text}`and `{actor_text}`) refer to the target and actor of the Use event respectively - which are specified in the code by the name of the objects related to the event itself. For an use event of the format `use x with y`, `actor_text` refer to `x` and `recipient_text` refer to `y`. If necessary, you can use these two templates in strings for _any_ event, not only Broadcast Message events. - - ### Modify Attribute - - - This event modifies the value of a certain attribute involved in the Use event. The target (Which should have the attribute) and the attribute being modified are specified through the `type` and `key` fields. The `value` field specifies the numeric change in the attribute, its syntax is as follows: - - - - `+num` means that `new_value = curr_value + num` - - `-num` means that `new_value = curr_value - num` - - `=num` means that `new_value = num` - - And the general syntax for this event is: - -``` - +```json { - -"type": "modify_attribute", - -"params": { - -"type": "in_used_target_item", - -"key": "health", - -"value": "-20" - -} - + "type": "modify_attribute", + "params": { + "type": "in_used_target_item", + "key": "health", + "value": "-20" + } } - -``` \ No newline at end of file +``` diff --git a/light/graph/viz/README.md b/light/graph/viz/README.md new file mode 100644 index 000000000..789b38237 --- /dev/null +++ b/light/graph/viz/README.md @@ -0,0 +1,3 @@ +# viz + +Helper functions that allow for direct visualization of the light `OOGraph`. diff --git a/light/world/README.md b/light/world/README.md index 86767a92b..d8af2f57b 100644 --- a/light/world/README.md +++ b/light/world/README.md @@ -1,10 +1,21 @@ # LIGHT World -The LIGHT World operates on a level above the LIGHT Graph, and it is responsible for maintaining track of agents within the world, listening to their actions, parsing them, and executing them on the underlying graph. +The LIGHT World operates on a level above the LIGHT Graph, and it is responsible for maintaining track of agents within the world, listening to their actions, parsing them, and executing them on the underlying graph. While this directory contains other classes, the core unifying principle is that they operate on top of a live `OOGraph`. -## Purgatory +## World -`Purgatory` is responsible for managing `Soul`'s. It should be created as a member of a `World` when the world is created. Whatever created that world can then register souls to fill up the `World`'s agents by using `register_filler_soul_provider` and `fill_soul`. +The world class itself is a wrapper around an `OOGraph` that keeps track of session-dependent attributes and provides helpful functions for interacting on a graph live. It delegates some of this responsiblity to the `Purgatory`, `WorldViewer` classes described below. This section covers an overview on other core functionality. Additional functionality of the `World` has been deprecated and marked as such. + +### Parsing Text to `GraphEvent`s +The `World`'s parsing methods are responsible for executing the construction methods for a `GraphEvent` in the correct order, and handling errors properly along the way. This is handled by the `parse_exec` function, which extracts the target `GraphEvent` type and uses `attempt_parse_event` to try and create the event if it's valid. + +The `World` is also able to determine all possible `GraphEvent`s for an agent with `get_possible_events`. + +### Broadcasting executed events +Once an event is executed on a LIGHT graph, it's the `World`'s responsiblity to ensure that expected listeners (including loggers) are able to observe what just occurred. These responsibilities are handled with the `broadcast_to_room`, `broadcast_to_agents`, and `broadcast_to_all_agents` methods. These ultimately rely on `send_action` and `send_msg` to direct the observations to the correct `Soul`s. + +### Removing corpses +One issue with a text world, especially one where characters can die in, is that eventually it becomes filled with corpses if they aren't removed. The LIGHT `World` takes up this responsibility with `clean_corpses_and_respawn`, ensuring that nodes can be removed and replaced with new characters as death inevitably occurs. ## Content Loggers @@ -21,3 +32,14 @@ Files ending in `event.log` record a meta episode from the POV of the room or ag event_to_json All event logs are in the `log_path/light_event_dumps` directory. The graph_uuid references a graph in the `log_path/light_graph_dumps` directory + +## Subdirectories +- **`souls`**: Directory containing `Soul`s, which are used as the layer allowing models or players to assume the role of a `GraphAgent` and observe and interact within a LIGHT `World`. +- **`tests`**: Testing to ensure that the `World` is functional. +- **`utils`**: Utility classes for `World`-related code. + +## Other Classes: +- [**`PlayerProvider`**](https://github.com/facebookresearch/LIGHT/tree/main/light/world/player_provider.py): Abstraction defining required functions for a human agent to be able to interact within LIGHT. +- [**`Purgatory`**](https://github.com/facebookresearch/LIGHT/tree/main/light/world/purgatory.py): `Purgatory` is responsible for managing `Soul`'s. It should be created as a member of a `World` when the world is created. Whatever created that world can then register souls to fill up the `World`'s agents by using `register_filler_soul_provider` and `fill_soul`. +- [**`WorldViewer`**](https://github.com/facebookresearch/LIGHT/tree/main/light/world/quest_loader.py): Class used to load in saved 'motivations' and quests for characters, as well as to generate new ones after one has been completed. +- [**`QuestLoader`**](https://github.com/facebookresearch/LIGHT/tree/main/light/world/views.py): Baseline implementation of a class defining how contents of the world should _look_ to an observer. May be overwritten for special cases. diff --git a/light/world/souls/README.md b/light/world/souls/README.md index 4d7857819..a0e049e73 100644 --- a/light/world/souls/README.md +++ b/light/world/souls/README.md @@ -15,3 +15,12 @@ Some `Soul`'s set flags on `GraphAgent`'s to be able to be interpreted by other Current flags: - `is_player`: Set by `PlayerSoul` to designate `GraphAgent`'s that are inhabited by a real player. Used by the world to ensure we don't doubly assign a `GraphAgent` to two different players, and by `ModelSoul`'s to differentiate between inter-model chat and chat with a human. + +## Current Souls: +- [**`Soul`**](https://github.com/facebookresearch/LIGHT/tree/main/light/world/souls/soul.py): Abstract class defining the minimum API for an agent-attached interaction layer into a LIGHT world. +- [**`BaseSoul`**](https://github.com/facebookresearch/LIGHT/tree/main/light/world/souls/base_soul.py): Extension on the basic `Soul` class including various helpers and state that are useful for both player and model-based interactions. +- [**`ModelSoul`**](https://github.com/facebookresearch/LIGHT/tree/main/light/world/souls/model_soul.py): Basic `Soul` that is defines an interface where models can be loaded in and used as agents. +- [**`OnEventSoul`**](https://github.com/facebookresearch/LIGHT/tree/main/light/world/souls/on_event_soul.py): Extended `ModelSoul` class that is able to handle some basic scripted heuristic events as well as the more general `on_event` types that can be linked to a `GraphNode`. +- [**`PlayerSoul`**](https://github.com/facebookresearch/LIGHT/tree/main/light/world/souls/player_soul.py): Simple `Soul` class that allows for a human player to take control of the `GraphAgent`. Requires use of a `PlayerProvider` containing the abstractions for sending observations and receiving actions. +- [**`RepeatSoul`**](https://github.com/facebookresearch/LIGHT/tree/main/light/world/souls/repeat_soul.py): Bare-bones `Soul` class for use in demonstrations. Simply speaks back the observations it sees with a `SayEvent`. +- [**`TestSoul`**](https://github.com/facebookresearch/LIGHT/tree/main/light/world/souls/test_soul.py): Core soul for being able to run tests on the LIGHT `World` classes. Has a directly accessible `observations` field and a `do_act` function allowing scripted execution of actions. diff --git a/light/world/utils/README.md b/light/world/utils/README.md new file mode 100644 index 000000000..232b2ea7c --- /dev/null +++ b/light/world/utils/README.md @@ -0,0 +1,7 @@ +# utils + +Contains some world-related utils. + +**Contents:** +- **`json_utils.py`**: Helper classes for converting Graphs to JSON for saving and loading. Also can read event log JSON files. +- **`terminal_player_provider.py`**: `PlayerProvider` class that allows use of `Soul`s controlled by terminal input. diff --git a/light/world/world.py b/light/world/world.py index ea6ed44b2..e4f214a3d 100644 --- a/light/world/world.py +++ b/light/world/world.py @@ -9,7 +9,6 @@ import os import random -# TODO don't use * imports from light.graph.utils import rm, deprecated from light.graph.events.base import GraphEvent, ErrorEvent from light.graph.events.graph_events import ( diff --git a/projects/README.md b/projects/README.md new file mode 100644 index 000000000..d3c8deed0 --- /dev/null +++ b/projects/README.md @@ -0,0 +1,13 @@ +# Projects + +The projects directory contains code that's still in-development, either for research endeavors that haven't yet been incorporated into the game, or works that derive from work but ultimately don't feed back in. Also contains code relevant preserved to reproduce specific paper results. + +Much of the code underneath isn't necessarily public-ready or well documented, but _should_ be for a clean paper release. + +**Subdirectories:** +- **`aaai_world_building`**: Eclectic code related to our first [world building paper](https://arxiv.org/abs/1911.09194) around examining the impact AI-assisted tooling has on building interesting text worlds. +- **`dialog_and_act_trainer`**: Early experimental work around having a single model that is able to switch modes between dialogue and action, using model-based decisions on when to do each rather than heuristics. +- **`lightqa`**: Project code related to [knowledge-infused](https://arxiv.org/pdf/2111.05204.pdf) LIGHT agents. +- **`long_context`**: Some code relevant to creating LIGHT longcontext examples. +- **`quest_generator`**: Some code relevant to generating a relevant quest for a given agent node. +- **`quest_scorer`**: Some code relevant to selecting a relevant quest for a given agent node. diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 000000000..41e25b591 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,15 @@ +# Scripts + +This directory contains execution code for running LIGHT, exploring our dataset, filtering through examples, and more. + +At the moment, subdirectories contain a mixture of complete and ready examples as well as deprecated older code that isn't relevant to LIGHT in its current form. Outside of `examples/play_map.py`, consider the rest present for usage examples or historical purposes. + +Not everything here will remain here, and may be more appropriately stored elsewhere in the future. + +**Subdirectories:** +- **`browse_game`**: Scripts we use to explore contents of the LIGHT main web deploy database. +- **`examples`**: Scripts that allow local live interaction with specific parts of the LIGHT platform. +- **`filtering`**: Scripts used to process and filter incoming data, primarily from the messenger project. +- **`labelling`**: Scripts to manually label and edit data from the LIGHT dataset or database. +- **`misc`**: Scripts for various other things that don't cleanly fit into other categories. +- **`training`**: Scripts for training various LIGHT models.