|
|
from pydantic import Field |
|
|
from typing import Optional, List |
|
|
|
|
|
from ..core.logging import logger |
|
|
from ..models.base_model import BaseLLM |
|
|
from .action import Action, ActionInput, ActionOutput |
|
|
from ..prompts.task_planner import TASK_PLANNING_ACTION |
|
|
from ..workflow.workflow_graph import WorkFlowNode |
|
|
|
|
|
|
|
|
class TaskPlanningInput(ActionInput): |
|
|
""" |
|
|
Input specification for the task planning action. |
|
|
""" |
|
|
goal: str = Field(description="A clear and detailed description of the user's goal, specifying what needs to be achieved.") |
|
|
history: Optional[str] = Field(default=None, description="Optional field containing previously generated task plan.") |
|
|
suggestion: Optional[str] = Field(default=None, description="Optional suggestions or ideas to guide the planning process.") |
|
|
|
|
|
|
|
|
class TaskPlanningOutput(ActionOutput): |
|
|
""" |
|
|
Output structure for the task planning action. |
|
|
""" |
|
|
sub_tasks: List[WorkFlowNode] = Field(description="A list of sub-tasks that collectively achieve user's goal.") |
|
|
|
|
|
|
|
|
class TaskPlanning(Action): |
|
|
""" |
|
|
Action for planning a series of tasks to achieve a goal. |
|
|
""" |
|
|
|
|
|
def __init__(self, **kwargs): |
|
|
|
|
|
name = kwargs.pop("name") if "name" in kwargs else TASK_PLANNING_ACTION["name"] |
|
|
description = kwargs.pop("description") if "description" in kwargs else TASK_PLANNING_ACTION["description"] |
|
|
prompt = kwargs.pop("prompt") if "prompt" in kwargs else TASK_PLANNING_ACTION["prompt"] |
|
|
|
|
|
|
|
|
inputs_format = kwargs.pop("inputs_format", None) or TaskPlanningInput |
|
|
outputs_format = kwargs.pop("outputs_format", None) or TaskPlanningOutput |
|
|
super().__init__(name=name, description=description, prompt=prompt, inputs_format=inputs_format, outputs_format=outputs_format, **kwargs) |
|
|
|
|
|
def execute(self, llm: Optional[BaseLLM] = None, inputs: Optional[dict] = None, sys_msg: Optional[str]=None, return_prompt: bool = False, **kwargs) -> TaskPlanningOutput: |
|
|
"""Execute the task planning process. |
|
|
|
|
|
This method uses the provided language model to generate a structured |
|
|
plan of sub-tasks based on the user's goal and any additional context. |
|
|
|
|
|
Args: |
|
|
llm: The language model to use for planning. |
|
|
inputs: Input data containing the goal and optional context. |
|
|
sys_msg: Optional system message for the language model. |
|
|
return_prompt: Whether to return both the task plan and the prompt used. |
|
|
**kwargs: Additional keyword arguments. |
|
|
|
|
|
Returns: |
|
|
If return_prompt is False (default): The generated task plan. |
|
|
If return_prompt is True: A tuple of (task plan, prompt used). |
|
|
|
|
|
Raises: |
|
|
ValueError: If the inputs are None or empty. |
|
|
""" |
|
|
if not inputs: |
|
|
logger.error("TaskPlanning action received invalid `inputs`: None or empty.") |
|
|
raise ValueError('The `inputs` to TaskPlanning action is None or empty.') |
|
|
|
|
|
prompt_params_names = ["goal", "history", "suggestion"] |
|
|
prompt_params_values = {param: inputs.get(param, "") for param in prompt_params_names} |
|
|
prompt = self.prompt.format(**prompt_params_values) |
|
|
task_plan = llm.generate( |
|
|
prompt = prompt, |
|
|
system_message = sys_msg, |
|
|
parser=self.outputs_format, |
|
|
parse_mode="json" |
|
|
) |
|
|
|
|
|
if return_prompt: |
|
|
return task_plan, prompt |
|
|
|
|
|
return task_plan |