Hallucinate Tree
This script uses a Large Language Model (LLM) to generate a hierarchical breakdown of tasks (a "tree") for a given topic. It can save the resulting tree structure either as a nested directory structure on the filesystem or as a single flat JSON file.
This script uses a Large Language Model (LLM) to generate a hierarchical breakdown of tasks (a “tree”) for a given topic. It can save the resulting tree structure either as a nested directory structure on the filesystem or as a single flat JSON file.
Purpose¶
The primary goal of hallucinate-tree.py is to take a high-level task or topic and recursively break it down into smaller, manageable sub-steps using an LLM. This process, often referred to as “hallucination” in the context of AI, creates a structured plan or workflow.
Usage¶
The script is executed from the command line:
python hallucinate-tree.py <input_json> [output_path] [-flat] [-saveInputs] [-uuid="UUID"] [-flow_uuid="FLOW-UUID"]
Arguments:
<input_json>: (Required) Path to the input JSON file containing the task details.[output_path]: (Optional) Specifies the output location.- If
-flatis not used: This is the base directory where the tree structure andmetadata.jsonwill be saved. If not provided, defaults tooutput/hallucinate-tree/<tree_uuid>/. - If
-flatis used: This is the full path (including filename) for the output JSON file. If the path points to a directory, a file named<tree_uuid>.jsonwill be created inside it. If not provided, defaults tooutput/hallucinate-tree/<tree_uuid>/<tree_uuid>.json.
- If
-flat: (Optional) If present, saves the output as a single flat JSON file instead of a directory structure.-saveInputs: (Optional) If present, saves the system and user prompts sent to the LLM during generation into theflow/<flowUUID>/inputs/directory. Requires-flow_uuidto be set.-uuid="UUID": (Optional) Specify a custom UUID for the root node of the generated tree. If omitted, a new UUID is generated.-flow_uuid="FLOW-UUID": (Optional) Specify a UUID for the overall flow, used primarily for organizing saved inputs when-saveInputsis active.
Input Files¶
The script expects an input JSON file (<input_json>) with the following structure:
{
"topic": "The main task or topic to break down",
"depth": 2, // Optional: How many levels deep to generate steps (default: 2)
"model": "gemma3", // Optional: The LLM model to use (default: "gemma3")
"parameters": {} // Optional: Additional parameters for the LLM API call
}
Key Functions¶
sanitize_filename(name): Converts a step name into a valid, lowercase directory name using underscores, removing invalid characters and truncating length.save_tree_to_filesystem(tree, base_path, parent_uuid=None): Recursively saves the generated tree structure to the filesystem. Each node becomes a directory containing anode.jsonfile. Directory names are generated usingtranslate_to_basic_english,sanitize_filename, and the node’s UUID.save_tree_as_flat_json(tree, metadata, output_path): Saves the complete tree structure and associated metadata into a single JSON file.generate_task_tree(input_data, save_inputs=False): The main function orchestrating the tree generation. It initializes the process and calls the recursiveexpand_stepfunction.expand_step(step, current_depth): (Nested withingenerate_task_tree) This recursive function interacts with the LLM. For a givenstep, it prompts the LLM to generate sub-steps. It continues recursively until the specifieddepthis reached. It usesutils.chat_with_llmfor the API call andutils.parse_llm_json_responseto interpret the hierarchical JSON response. Ifsave_inputsis true, it usesutils.saveToFileto store prompts.
main(): Parses command-line arguments (usingutils.handle_command_args), loads the input JSON (utils.load_json), callsgenerate_task_tree, creates metadata (utils.create_output_metadata), and then calls eithersave_tree_to_filesystemorsave_tree_as_flat_jsonbased on the presence of the-flatflag.
LLM Interaction¶
The core of the task breakdown happens in the generate_task_tree function, specifically within its nested expand_step function.
expand_stepis called initially with the maintopicandcurrent_depth = 0.- If
current_depthis less than the targetdepth, it constructs a prompt asking the LLM to break down the currentstepinto 3-7 sub-steps. - It calls the LLM using the
utils.chat_with_llmfunction, providing the system message (instructing the LLM to return hierarchical JSON) and the user message (the specific task breakdown request). - The LLM’s response is expected to be a JSON array of step objects, potentially containing nested
childrenarrays for sub-sub-steps. utils.parse_llm_json_response(response_text, include_children=True)is used to parse this potentially complex JSON structure. Theinclude_children=Trueargument is crucial for handling the hierarchical nature of the expected response.- For each sub-step returned by the LLM (if it doesn’t already have children),
expand_stepcalls itself recursively with the sub-step text and an incrementedcurrent_depth. - This process continues until the maximum
depthis reached for all branches of the tree.
Output Formats¶
The script supports two distinct output formats, controlled by the -flat command-line flag.
Default (Directory Structure)¶
- Triggered by: Running the script without the
-flatflag. - Function:
save_tree_to_filesystemis used. - Structure:
- A base directory is created (either at
[output_path]oroutput/hallucinate-tree/<tree_uuid>/). - Inside the base directory, a
metadata.jsonfile is saved containing information about the generation process (script name, timestamp, tree UUID). - The root node’s details (
step,uuid) are saved innode.jsonwithin the base directory. - For each child node, a subdirectory is created within its parent’s directory.
- The subdirectory name is generated by:
- Translating the child step text to Basic English (
utils.translate_to_basic_english). - Sanitizing the Basic English text (
sanitize_filename). - Appending
_and the child node’s full UUID (e.g.,sanitized_name_<child_uuid>).
- Translating the child step text to Basic English (
- Inside the child subdirectory, a
node.jsonfile is created containing the child’sstep,uuid, and aparent_uuidreferencing its parent node.
- The subdirectory name is generated by:
- This process repeats recursively for all nodes in the tree.
- A base directory is created (either at
Flat JSON (-flat flag)¶
- Triggered by: Running the script with the
-flatflag. - Function:
save_tree_as_flat_jsonis used. - Structure:
- A single JSON file is created (either at
[output_path]oroutput/hallucinate-tree/<tree_uuid>/<tree_uuid>.json). - The JSON file contains a top-level object with two keys:
"metadata": An object containing the same metadata as in the directory structure format."tree": An object representing the entire hierarchical tree structure, including nestedchildrenarrays anduuidfields for each node.
- A single JSON file is created (either at