portia.builder.step_v2
Implementation of the various step types used in :class:PlanV2
.
StepV2 Objects
class StepV2(BaseModel, ABC)
Abstract base class for all steps executed within a plan.
Each step represents an action that can be performed during plan execution, such as calling an LLM / agent, invoking a tool, or requesting user input.
run
@abstractmethod
async def run(run_data: RunContext) -> Any | LocalDataValue
Execute the step and return its output.
Returns:
The step's output value, which may be used by subsequent steps.
to_legacy_step
@abstractmethod
def to_legacy_step(plan: PlanV2) -> Step
Convert this step to the legacy Step format.
This is primarily used to determine how the steps should be presented in the Portia Dashboard.
LLMStep Objects
class LLMStep(StepV2)
A step that executes a task using an LLM without any tool access.
This step is used for pure language model tasks like text generation, analysis, or transformation that don't require external tool calls.
__str__
def __str__() -> str
Return a description of this step for logging purposes.
run
@override
@traceable(name="LLM Step - Run")
async def run(run_data: RunContext) -> str | BaseModel
Execute the LLM task and return its response.
to_legacy_step
@override
def to_legacy_step(plan: PlanV2) -> Step
Convert this LLMStep to a legacy Step.
InvokeToolStep Objects
class InvokeToolStep(StepV2)
A step that directly invokes a tool with specific arguments.
This performs a direct tool call without LLM involvement, making it suitable for deterministic operations where you know exactly which tool to call and what arguments to pass.
__str__
def __str__() -> str
Return a description of this step for logging purposes.
run
@override
@traceable(name="Invoke Tool Step - Run")
async def run(run_data: RunContext) -> Any
Execute the tool and return its result.
to_legacy_step
@override
def to_legacy_step(plan: PlanV2) -> Step
Convert this InvokeToolStep to a legacy Step.
SingleToolAgentStep Objects
class SingleToolAgentStep(StepV2)
A step where an LLM agent intelligently uses a specific tool to complete a task.
Unlike InvokeToolStep which requires you to specify exact tool arguments, this step allows an LLM agent to determine how to use the tool based on the task description and available context. The agent will call the tool at most once during execution.
__str__
def __str__() -> str
Return a description of this step for logging purposes.
run
@override
@traceable(name="Single Tool Agent Step - Run")
async def run(run_data: RunContext) -> Any
Run the agent and return its output.
to_legacy_step
@override
def to_legacy_step(plan: PlanV2) -> Step
Convert this SingleToolAgentStep to a Step.
ReActAgentStep Objects
class ReActAgentStep(StepV2)
A step where an LLM agent uses ReAct reasoning to complete a task with multiple tools.
Unlike SingleToolAgentStep which is limited to one specific tool and one tool call, this step allows an LLM agent to reason about which tools to use and when to use them. The agent follows the ReAct (Reasoning and Acting) pattern, iteratively thinking about the problem and taking actions until the task is complete.
__str__
def __str__() -> str
Return a description of this step for logging purposes.
run
@override
@traceable(name="ReAct Agent Step - Run")
async def run(run_data: RunContext) -> Any
Run the agent step.
to_legacy_step
@override
def to_legacy_step(plan: PlanV2) -> Step
Convert this SingleToolAgentStep to a Step.
UserVerifyStep Objects
class UserVerifyStep(StepV2)
A step that requests user confirmation before proceeding with plan execution.
This step pauses execution to ask the user to verify or approve a message. If the user rejects the verification, the plan execution will stop with an error.
This pauses plan execution and asks the user to confirm or reject the provided message. The plan will only continue if the user confirms. If the user rejects, the plan execution will stop with an error. This is useful for getting user approval before taking important actions like sending emails, making purchases, or modifying data.
A UserVerificationClarification is used to get the verification from the user, so ensure you have set up handling for this type of clarification in order to use this step. For more details, see https://docs.portialabs.ai/understand-clarifications.
This step outputs True if the user confirms.
__str__
def __str__() -> str
Return a description of this step for logging purposes.
run
@override
@traceable(name="User Verify Step - Run")
async def run(run_data: RunContext) -> bool | UserVerificationClarification
Prompt the user for confirmation.
Returns a UserVerificationClarification to get input from the user (if not already provided).
If the user has already confirmed, returns True. Otherwise, if the user has rejected the verification, raises a PlanRunExitError.
to_legacy_step
@override
def to_legacy_step(plan: PlanV2) -> Step
Convert this UserVerifyStep to a legacy Step.
UserInputStep Objects
class UserInputStep(StepV2)
A step that requests input from the user and returns their response.
This pauses plan execution and prompts the user to provide input. If options are provided, the user must choose from the given choices (multiple choice). If no options are provided, the user can enter free-form text.
A Clarification (either InputClarification or MultipleChoiceClarification) is used to get the input from the user, so ensure you have set up handling for the required type of clarification in order to use this step. For more details, see https://docs.portialabs.ai/understand-clarifications.
The user's response becomes the output of this step and can be referenced by subsequent steps in the plan.
__str__
def __str__() -> str
Return a description of this step for logging purposes.
run
@override
@traceable(name="User Input Step - Run")
async def run(run_data: RunContext) -> Any
Request input from the user and return the response.
to_legacy_step
@override
def to_legacy_step(plan: PlanV2) -> Step
Convert this UserInputStep to a legacy Step.
ConditionalStep Objects
class ConditionalStep(StepV2)
A step that represents a conditional clause within a conditional execution block.
This step handles conditional logic such as if, else-if, else, and end-if statements that control which subsequent steps should be executed based on runtime conditions.
validate_conditional_block
@field_validator("conditional_block", mode="after")
@classmethod
def validate_conditional_block(cls,
v: ConditionalBlock | None) -> ConditionalBlock
Validate the conditional block.
block
@property
def block() -> ConditionalBlock
Get the conditional block for this step.
__str__
def __str__() -> str
Return a description of this step for logging purposes.
run
@override
@traceable(name="Conditional Step - Run")
async def run(run_data: RunContext) -> Any
Evaluate the condition and return a ConditionalStepResult.
to_legacy_step
@override
def to_legacy_step(plan: PlanV2) -> Step
Convert this ConditionalStep to a legacy Step.
LoopStep Objects
class LoopStep(StepV2)
A step that represents a loop in a loop block.
This step handles loop logic such as while, do-while, and for-each loops that control which subsequent steps should be executed based on runtime conditions.
validate_model
@model_validator(mode="after")
def validate_model() -> Self
Validate the loop.
run
@override
@traceable(name="Loop Step - Run")
async def run(run_data: RunContext) -> Any
Run the loop step.
to_legacy_step
@override
def to_legacy_step(plan: PlanV2) -> Step
Convert this LoopStep to a PlanStep.