Data Types ================ L2P serves as an intermediary between Large Language Models (LLMs) and the construction of reliable planning components in PDDL. All data structures are modeled as **Pydantic** ``BaseModel`` subclasses with strict validation. These are the core data structures that flow through every L2P pipeline - generation, validation, formatting, and planning. Each model class carries a ``tag`` class variable (XML tag tuple) used by the LLM output parser to identify which XML block maps to which model. .. tip:: See :doc:`l2p` for the full autogenerated API reference of every model field, validator, and method. Below we provide a high-level overview with concrete JSON ↔ Python examples. You can find more information on PDDL `here `_. LogicalCondition ---------------- ``LogicalCondition`` is a **type alias** - ``Union[str, Dict[str, Any]]`` - that represents a single node in a PDDL formula. Nearly every condition/effect model uses it. **1. Simple Predicates & Numeric Checks (str):**:: "(at ?r ?l)" "(>= (battery-level ?r) 20)" **2. Logical Operators (Dict):**:: # NOT {"operator": "not", "condition": "(busy ?r)"} # AND / OR { "operator": "and", # or "or" "conditions": ["(has-power ?r)", {"operator": "not", "condition": "(busy ?r)"}] } # IMPLY { "operator": "imply", "antecedent": ["(at ?r ?l)"], "consequent": ["(can-transmit ?r)"] } **3. Quantifiers (Dict):**:: # FORALL / EXISTS { "quantifier": "forall", # or "exists" "parameters": [{"variable": "?p", "type": "packet"}], "conditions": ["(transmitted ?p)"] } **4. PDDL 3.0 Trajectory Constraints (Dict):**:: # ALWAYS / SOMETIME / AT-MOST-ONCE {"operator": "always", "condition": "(has-power ?r)"} # WITHIN / HOLD-AFTER (time-bounded) {"operator": "within", "time": 10.5, "condition": "(transmitted ?p)"} # HOLD-DURING (interval) {"operator": "hold-during", "time_start": 5.0, "time_end": 15.0, "condition": "(transmitting ?r)"} # SOMETIME-AFTER / SOMETIME-BEFORE (relational) {"operator": "sometime-after", "antecedent": "(transmitted ?p)", "consequent": "(acknowledged ?p)"} # ALWAYS-WITHIN (time-bounded relational) {"operator": "always-within", "time": 5.0, "antecedent": "(error-detected ?r)", "consequent": "(safe-mode ?r)"} **5. PDDL 3.0 Preferences (Dict):**:: { "preference": "pref_transmit_early", "condition": {"operator": "sometime", "condition": "(transmitted ?p)"} } Domain Models ------------- Requirement ~~~~~~~~~~~ A single PDDL requirement flag. .. code-block:: json {"name": ":typing", "desc": "Enables typed variables"} **Fields**: ``name`` (*str*, must start with ``:``), ``desc`` (*Optional[str]*) PDDLType ~~~~~~~~ A PDDL type, optionally with a parent type for inheritance. .. code-block:: json {"name": "rover", "parent": "object", "desc": "A planetary rover"} {"name": "waypoint", "parent": "object", "desc": "A navigable location"} **Fields**: ``name`` (*str*), ``parent`` (*str*), ``desc`` (*Optional[str]*) A flat dict ``{name: desc}`` is still accepted as input to the LLM prompt, but the canonical form is the structured JSON above. **Nested (hierarchical) types** can be represented as a list of inheritance chains:: [ { "parent_type_1": "description for parent type 1", "children": [ { "child_type_1": "description for child type 1", "children": [ {"child_child_type_1": "description", "children": []} ] } ] } ] Converted via ``format_types(types)`` into PDDL:: parent_type_1 ; description for parent type 1 child_type_1 - parent_type_1 ; description for child type 1 child_child_type_1 - child_type_1 ; description for child child type 1 Constant ~~~~~~~~ A named object that is available in every problem instance of a domain. .. code-block:: json {"name": "base_station", "type": "location", "desc": "The main hub"} **Fields**: ``name`` (*str*), ``type`` (*str*), ``desc`` (*Optional[str]*) Parameter ~~~~~~~~~ A typed parameter variable used in actions, predicates, and functions. .. code-block:: json {"variable": "?r", "type": "rover", "desc": "A rover"} **Fields**: ``variable`` (*str*, must start with ``?``), ``type`` (*str*), ``desc`` (*Optional[str]*) Predicate ~~~~~~~~~ A predicate symbol with typed parameters. .. code-block:: json { "name": "at", "params": [ {"variable": "?r", "type": "rover"}, {"variable": "?l", "type": "location"} ], "desc": "True if rover is at location" } **Fields**: ``name`` (*str*), ``params`` (*List[Parameter]*), ``desc`` (*Optional[str]*) Function ~~~~~~~~ A numeric fluent (PDDL 2.1+) with typed parameters. .. code-block:: json { "name": "battery-level", "params": [{"variable": "?r", "type": "rover"}], "desc": "Current battery level of the rover" } **Fields**: ``name`` (*str*), ``params`` (*List[Parameter]*), ``desc`` (*Optional[str]*) DerivedPredicate ~~~~~~~~~~~~~~~~ A derived predicate / axiom (PDDL 2.1+) - defined in terms of a condition rather than an action effect. .. code-block:: json { "name": "can-move", "params": [{"variable": "?r", "type": "rover"}], "condition": "(> (battery-level ?r) 0.0)", "desc": "Derived from having positive battery" } **Fields**: ``name`` (*str*), ``params`` (*List[Parameter]*), ``condition`` (*LogicalCondition*), ``desc`` (*Optional[str]*) ActionPrecondition ~~~~~~~~~~~~~~~~~~ The precondition of an action, consisting of a list of logical conditions. .. code-block:: json { "conditions": [ "(at ?r ?from)", {"operator": "not", "condition": "(busy ?r)"} ], "desc": "Rover must be at start and not busy" } **Fields**: ``conditions`` (*List[LogicalCondition]*), ``desc`` (*Optional[str]*) ActionEffect ~~~~~~~~~~~~ The effect of an action, split into additive, deletive, numeric, and conditional blocks. .. code-block:: json { "add": ["(at ?r ?to)"], "delete": ["(at ?r ?from)"], "numeric": ["(decrease (battery-level ?r) 5.0)"], "conditional": [ { "condition": ["(has-payload ?r)"], "effect": { "add": ["(payload-delivered ?r)"], "delete": [], "numeric": [] } } ], "desc": "Drives rover from one location to another" } **Fields**: - ``add`` (*List[LogicalCondition]*) - facts added by the action - ``delete`` (*List[LogicalCondition]*) - facts deleted - ``numeric`` (*List[LogicalCondition]*) - numeric changes (increase, decrease, assign) - ``conditional`` (*List[ConditionalEffect]*) - conditional effects (PDDL 2.2+) - ``desc`` (*Optional[str]*) ConditionalEffect ~~~~~~~~~~~~~~~~~ A ``when`` clause: when the *condition* holds, apply the *effect*. .. code-block:: json { "condition": ["(has-payload ?r)"], "effect": { "add": ["(payload-delivered)"], "delete": [], "numeric": [] }, "desc": "If it has a payload, deliver it" } **Fields**: ``condition`` (*List[LogicalCondition]*), ``effect`` (``Dict[str, List[LogicalCondition]]``), ``desc`` (*Optional[str]*) Action ~~~~~~ A classical PDDL action (instantaneous). .. code-block:: json { "name": "drive", "params": [ {"variable": "?r", "type": "rover"}, {"variable": "?from", "type": "location"}, {"variable": "?to", "type": "location"} ], "preconditions": { "conditions": ["(at ?r ?from)"] }, "effects": { "add": ["(at ?r ?to)"], "delete": ["(at ?r ?from)"], "numeric": ["(decrease (battery-level ?r) 10.0)"], "conditional": [] }, "desc": "Drive rover between locations" } **Fields**: ``name`` (*str*), ``params`` (*List[Parameter]*), ``preconditions`` (*ActionPrecondition*), ``effects`` (*ActionEffect*), ``desc`` (*Optional[str]*) DurativeActionConditions ~~~~~~~~~~~~~~~~~~~~~~~~ Temporal conditions split across ``at_start``, ``over_all``, and ``at_end``. .. code-block:: json { "at_start": ["(at ?r ?from)"], "over_all": [{"operator": "not", "condition": "(busy ?r)"}], "at_end": [], "desc": null } **Fields**: ``at_start`` (*List[LogicalCondition]*), ``over_all`` (*List[LogicalCondition]*), ``at_end`` (*List[LogicalCondition]*), ``desc`` (*Optional[str]*) DurativeActionEffect ~~~~~~~~~~~~~~~~~~~~ Temporal effects split across ``at_start``, ``at_end``, and ``continuous`` (PDDL 2.1+). .. code-block:: json { "at_start": { "add": ["(busy ?r)"], "delete": [], "numeric": [], "conditional": [] }, "at_end": { "add": ["(at ?r ?to)"], "delete": ["(at ?r ?from)", "(busy ?r)"], "numeric": [], "conditional": [] }, "continuous": ["(decrease (battery ?r) (* #t 1.0))"], "desc": null } **Fields**: ``at_start`` (*ActionEffect*), ``at_end`` (*ActionEffect*), ``continuous`` (*List[LogicalCondition]*), ``desc`` (*Optional[str]*) DurativeAction ~~~~~~~~~~~~~~ A durative action (PDDL 2.1+) with duration, temporal conditions, and temporal effects. .. code-block:: json { "name": "navigate", "params": [ {"variable": "?r", "type": "rover"}, {"variable": "?from", "type": "waypoint"}, {"variable": "?to", "type": "waypoint"} ], "duration": ["(= ?duration 10.0)"], "conditions": { "at_start": ["(at ?r ?from)"], "over_all": ["(has-power ?r)"], "at_end": [] }, "effects": { "at_start": {"add": ["(busy ?r)"], "delete": [], "numeric": [], "conditional": []}, "at_end": {"add": ["(at ?r ?to)"], "delete": ["(at ?r ?from)", "(busy ?r)"], "numeric": [], "conditional": []}, "continuous": [] }, "desc": "Navigate between waypoints over a fixed duration" } **Fields**: ``name`` (*str*), ``params`` (*List[Parameter]*), ``duration`` (*List[str]*), ``conditions`` (*DurativeActionConditions*), ``effects`` (*DurativeActionEffect*), ``desc`` (*Optional[str]*) Event ~~~~~ An instantaneous event in a PDDL+ process model - triggered automatically when its precondition becomes true. .. code-block:: json { "name": "battery-depleted", "params": [{"variable": "?r", "type": "rover"}], "preconditions": { "conditions": ["(<= (battery-level ?r) 0)"] }, "effects": { "add": ["(dead ?r)"], "delete": ["(has-power ?r)"], "numeric": [], "conditional": [] }, "desc": "Triggers when battery dies" } **Fields**: ``name`` (*str*), ``params`` (*List[Parameter]*), ``preconditions`` (*ActionPrecondition*), ``effects`` (*ActionEffect*), ``desc`` (*Optional[str]*) Process ~~~~~~~ A continuous process in a PDDL+ model - applies continuous effects over time while its precondition holds. .. code-block:: json { "name": "solar-charging", "params": [{"variable": "?r", "type": "rover"}], "preconditions": { "conditions": ["(in-sun ?r)"] }, "effects": { "add": [], "delete": [], "numeric": ["(increase (battery-level ?r) (* #t 2.0))"], "conditional": [] }, "desc": "Charges continuously in sun" } **Fields**: ``name`` (*str*), ``params`` (*List[Parameter]*), ``preconditions`` (*ActionPrecondition*), ``effects`` (*ActionEffect*), ``desc`` (*Optional[str]*) Constraint ~~~~~~~~~~ A PDDL 3.0 trajectory constraint - a modal logical condition that must hold over the plan. .. code-block:: json { "condition": { "operator": "always", "condition": "(> (battery-level ?r) 0.0)" }, "desc": "Battery must always be positive" } **Fields**: ``condition`` (*LogicalCondition*), ``desc`` (*Optional[str]*) DomainDetails ~~~~~~~~~~~~~ The root container for a complete PDDL domain. This is the top-level model returned when parsing an entire domain specification. .. code-block:: text { "name": "rover-domain", "desc": "Planetary rover exploration domain", "requirements": [{"name": ":strips"}, {"name": ":typing"}], "types": [{"name": "rover", "parent": "object"}], "constants": [], "predicates": [{"name": "at", "params": [...]}], "functions": [{"name": "battery-level", "params": [...]}], "derived_predicates": [], "actions": [{"name": "drive", "params": [...], ...}], "durative_actions": [], "events": [], "processes": [], "constraint": [] } **Fields**: ``name`` (*str*), ``desc`` (*Optional[str]*), ``domain_pddl`` (*Optional[str]*), ``requirements`` (*List[Requirement]*), ``types`` (*List[PDDLType]*), ``constants`` (*List[Constant]*), ``predicates`` (*List[Predicate]*), ``functions`` (*List[Function]*), ``derived_predicates`` (*List[DerivedPredicate]*), ``actions`` (*List[Action]*), ``durative_actions`` (*List[DurativeAction]*), ``events`` (*List[Event]*), ``processes`` (*List[Process]*), ``constraint`` (*List[Constraint]*) Problem Models -------------- PDDLObject ~~~~~~~~~~ A typed object instance in a PDDL problem. .. code-block:: json {"name": "rover1", "type": "rover", "desc": "Instance of a rover"} **Fields**: ``name`` (*str*), ``type`` (*str*), ``desc`` (*Optional[str]*) TimedFact ~~~~~~~~~ A timed initial literal (TIL) that triggers a fact at a specific time during plan execution. .. code-block:: json {"time": 15.5, "fact": "(communications-blackout)", "desc": "Event triggers at t=15.5"} **Fields**: ``time`` (*float*), ``fact`` (*LogicalCondition*), ``desc`` (*Optional[str]*) InitialState ~~~~~~~~~~~~ The initial state of a problem, with optional timed facts. .. code-block:: json { "facts": [ "(at rover1 loc1)", "(= (battery-level rover1) 100)" ], "timed_facts": [{"time": 50.0, "fact": "(= (solar-flare-level) 80.0)"}], "desc": "Starting state of the rover" } **Fields**: ``facts`` (*List[LogicalCondition]*), ``timed_facts`` (*List[TimedFact]*), ``desc`` (*Optional[str]*) GoalState ~~~~~~~~~ The goal conditions of a problem. .. code-block:: json { "conditions": [ "(at rover1 loc2)", "(data-transmitted)" ], "desc": "Target state" } **Fields**: ``conditions`` (*List[LogicalCondition]*), ``desc`` (*Optional[str]*) Metric ~~~~~~ A plan optimization metric (PDDL 2.1+ / PDDL 3.0). .. code-block:: json { "optimization": "minimize", "expression": "total-time", "desc": "Minimize makespan" } **Fields**: ``optimization`` (*str*, one of ``minimize`` / ``maximize``), ``expression`` (*str*), ``desc`` (*Optional[str]*) ProblemDetails ~~~~~~~~~~~~~~ The root container for a complete PDDL problem. .. code-block:: text { "name": "prob1", "domain_name": "rover_domain", "objects": [{"name": "rover1", "type": "rover"}], "initial_state": {"facts": [...], "timed_facts": [...]}, "goal_state": {"conditions": [...]}, "constraint": [], "metric": {"optimization": "minimize", "expression": "total-time"} } **Fields**: ``name`` (*str*), ``domain_name`` (*str*), ``desc`` (*Optional[str]*), ``problem_pddl`` (*Optional[str]*), ``objects`` (*List[PDDLObject]*), ``initial_state`` (*InitialState*), ``goal_state`` (*GoalState*), ``constraint`` (*List[Constraint]*), ``metric`` (*Optional[Metric]*)