Paper Recreations

This library is a collection of tools for PDDL model generation extracted from natural language driven by large language models. This library is an expansion from the survey paper “LLMs as Planning Formalizers: A Survey for Leveraging Large Language Models to Construct Automated Planning Models”.

The following are papers that have been reconstructed so far. This list will be updated in the future.

Papers that have been reconstructed so far and can be found in the Github repo. To see full list of current up-to-date papers in literature, please visit (see Paper Feed). This list will be continuously updated.


Below is L2P code reconstruction of “action-by-action algorithm” from “Leveraging Pre-trained Large Language Models to Construct and Utilize World Models for Model-based Task Planning”:

  1DOMAINS = [
  2"household",
  3"logistics",
  4"tyreworld",
  5]
  6
  7def construct_action(
  8    model: BaseLLM,
  9    act_pred_prompt: str,
 10    action_name: str,
 11    predicates: list[Predicate],
 12    types: dict[str,str],
 13    max_iter: int = 8,
 14    syntax_validator: bool = True
 15    ):
 16    """
 17    This is the inner function of the overall `Action-by-action` algorithm. Specifically,
 18    this function generates a single action from the list of actions and new predicates created.
 19    Process looping until it abides the custom syntax validation check.
 20
 21    Args:
 22        - model (BaseLLM): the large language model to be inferenced
 23        - act_pred_prompt (str): contains information of action and format creation passed to LLM
 24        - action_name (str): current action to be generated
 25        - predicates (list[Predicate]): current list of predicates generated
 26        - types (dict[str,str]): domain types - used for validation checks
 27        - max_iter (int): max attempts of generating action (defaults at 8)
 28        - syntax_validator (bool): flag if syntax checker is on (defaults to True)
 29
 30    Returns:
 31        - action (Action): action data type containing parameters, preconditions, and effects
 32        - predicates (list[Predicate]): list of updated predicates
 33        - llm_response (str): original LLM output
 34    """
 35
 36    # better format for LLM to interpret
 37    predicate_str = "\n".join([f"- {pred['clean']}" for pred in predicates])
 38
 39    # syntax validator check
 40    if syntax_validator:
 41        validator = SyntaxValidator()
 42        validator.unsupported_keywords = []
 43
 44        validator.error_types = [
 45            'validate_header', 'validate_duplicate_headers', 'validate_unsupported_keywords',
 46            'validate_params', 'validate_duplicate_predicates', 'validate_types_predicates',
 47            'validate_format_predicates', 'validate_usage_action'
 48            ]
 49
 50    else: validator = None
 51
 52    no_syntax_error = False
 53    i_iter = 0
 54
 55    # generate single action in loop, loops until no syntax error or max iters reach
 56    while not no_syntax_error and i_iter < max_iter:
 57        i_iter += 1
 58        print(f'[INFO] generating PDDL of action: `{action_name}`')
 59        try:
 60                # L2P usage for extracting actions and predicates
 61                action, new_predicates, llm_response, validation_info = (
 62                    domain_builder.formalize_pddl_action(
 63                        model=model,
 64                        domain_desc="",
 65                        prompt_template=act_pred_prompt,
 66                        action_name=action_name,
 67                        predicates=predicates,
 68                        types=types,
 69                        extract_new_preds=True,
 70                        syntax_validator=validator,
 71                    )
 72                )
 73
 74                # retrieve validation check and error message
 75                no_error, error_msg = validation_info
 76
 77        except Exception as e:
 78            no_error = False
 79            error_msg = str(e)
 80
 81        # if error exists, swap templates and return feedback message
 82        if not no_error:
 83            with open("paper_reconstructions/llm+dm/domains/error_prompt.txt") as f:
 84                error_template = f.read().strip()
 85            error_prompt = error_template.replace("{action_name}", action_name)
 86            error_prompt = error_prompt.replace("{predicates}", predicate_str)
 87            error_prompt = error_prompt.replace("{error_msg}", error_msg)
 88            error_prompt = error_prompt.replace("{llm_response}", llm_response)
 89
 90            act_pred_prompt = error_prompt
 91
 92        # break the loop if no syntax error was made
 93        else:
 94            no_syntax_error = True
 95
 96    # if max attempts reached and there are still errors, print out error on action.
 97    if not no_syntax_error:
 98        print(f'[WARNING] syntax error remaining in the action model: {action_name}')
 99
100    predicates.extend(new_predicates) # extend the predicate list
101
102    return action, predicates, llm_response
103
104
105
106def run_llm_dm(
107    model: BaseLLM,
108    domain: str = "household",
109    max_iter: int = 2,
110    max_attempts: int = 8
111    ):
112    """
113    This is the main function for `construct_action_models.py` component of LLM+DM paper. Specifically, it generates
114    actions (params, preconditions, effects) and predicates to create an overall PDDL domain file.
115
116    Args:
117        - model (BaseLLM): the large language model to be inferenced
118        - domain (str): choice of domain to task (defaults to `household`)
119        - max_iter: outer loop iteration; # of overall action list resets (defaults to 2)
120        - max_attempts: # of attempts to generate a single actions properly (defaults to 8)
121    """
122
123    # load in assumptions
124    prompt_template = load_file("paper_reconstructions/llm+dm/domains/pddl_prompt.txt")
125    domain_desc_str = load_file(f"paper_reconstructions/llm+dm/domains/{domain}/domain_desc.txt")
126
127    if '{domain_desc}' in prompt_template:
128        prompt_template = prompt_template.replace('{domain_desc}', domain_desc_str)
129
130    action_model = load_file(f"paper_reconstructions/llm+dm/domains/{domain}/action_model.json")
131    hierarchy_reqs = load_file(f"paper_reconstructions/llm+dm/domains/{domain}/hierarchy_requirements.json")
132
133    reqs = [":" + r for r in hierarchy_reqs['requirements']]
134    types = format_types(get_types(hierarchy_reqs))
135
136    actions = list(action_model.keys())
137    action_list = list()
138    predicates = list()
139
140    """
141    Action-by-action algorithm: iteratively generates an action model (parameters, precondition, effects) one at a time. At the same time,
142        it is generating new predicates if needed and is added to a dynamic list. At the end of the iterations, it is ran again once more to
143        create the action models agains, but with using the new predicate list. This algorithm can iterative as many times as needed until no
144        new predicates are added to the list. This is an action model refinement algorithm, that refines itself by a growing predicate list.
145    """
146
147    # outer loop that resets all action creation to be conditioned on updated predicate list
148    for i_iter in range(max_iter):
149        prev_predicate_list = deepcopy(predicates) # copy previous predicate list
150        action_list = []
151
152        # inner loop that generates a single action along with its predicates
153        for _, action in enumerate(actions):
154
155            # retrieve prompt for specific action
156            action_prompt, _ = get_action_prompt(prompt_template, action_model[action])
157
158            # retrieve prompt for current predicate list
159            predicate_prompt = get_predicate_prompt(predicates)
160
161            # assemble template
162            action_predicate_prompt = f'{action_prompt}\n\n{predicate_prompt}'
163            action_predicate_prompt += '\n\nParameters:'
164
165            # create single action + corresponding predicates
166            action, predicates, llm_response = construct_action(
167                model, action_predicate_prompt, action, predicates, types, max_attempts, True)
168
169            # add action to current list + remove any redundant predicates
170            action_list.append(action)
171            predicates = prune_predicates(predicates, action_list)
172
173        gen_done = False
174        if len(prev_predicate_list) == len(predicates):
175            print(f'[INFO] iter {i_iter} | no new predicate has been defined, will terminate the process')
176            gen_done = True
177
178        if gen_done:
179            break
180
181    # generate PDDL format
182    pddl_domain = domain_builder.generate_domain(
183            domain_name=domain,
184            requirements=reqs,
185            types=types,
186            predicates=predicates,
187            actions=action_list,
188        )
189
190
191# helper functions
192def get_action_prompt(prompt_template: str, action_desc: str):
193    """Creates prompt for specific action."""
194
195    action_desc_prompt = action_desc['desc']
196    for i in action_desc['extra_info']:
197        action_desc_prompt += ' ' + i
198
199    full_prompt = str(prompt_template) + ' ' + action_desc_prompt
200
201    return full_prompt, action_desc_prompt
202
203
204def get_predicate_prompt(predicates):
205    """Creates prompt for list of available predicates generated so far."""
206
207    predicate_prompt = 'You can create and define new predicates, but you may also reuse the following predicates:\n'
208    if len(predicates) == 0:
209        predicate_prompt += 'No predicate has been defined yet'
210    else:
211        predicate_prompt += "\n".join([f"- {pred['clean']}" for pred in predicates])
212    return predicate_prompt
213
214
215def get_types(hierarchy_requirements):
216    """Creates proper dictionary types (for L2P) from JSON format."""
217
218    types = {
219        name: description
220        for name, description in hierarchy_requirements["hierarchy"].items()
221        if name
222    }
223    return types