context.planner() – NodePlanner for Typed DAG Planning¶
context.planner() returns a NodePlanner: a node-bound façade over PlannerService that generates and executes typed DAG plans with an LLM.
Today, planning is static: the planner proposes a DAG from the available graphs/skills, validates it against typed inputs/outputs, then you execute it. In the future, this will evolve toward dynamic planning (re-planning based on intermediate execution signals, tool feedback, and typed state).
Core ideas¶
Typed DAG planning¶
- Each plan is a directed acyclic graph (DAG) of steps.
- Each step references an action (
action_ref) plusinputs. - The planner uses typed input/output constraints to ensure the plan is executable.
Flow constraints (flow_ids)¶
flow_ids is a list of flow identifiers used to constrain the search space. This can be specified when defining the graph/graph function in the decorator @graph(flow_id=...) or @graph_fn(flow_id=...). Any graphs/actions registered under the same flow list can be combined into a single valid DAG (subject to type compatibility).
Node-bound execution context¶
NodePlanner auto-fills execution metadata from the active NodeContext (identity/session/app/agent), while still allowing overrides via keyword arguments.
1. Planning Types and Dataclasses¶
These dataclasses define the planning protocol and validation surface.
PlanStep
Represents a single step in a plan, referencing an action and its inputs.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
Unique identifier for the plan step. |
action |
str
|
short, human/LLM-readable name for the action |
action_ref |
str
|
Reference to the associated action specification. This is a canonicial identifier used in AetherGraph. |
inputs |
Dict[str, Any]
|
Input parameters for the action. |
Methods:
| Name | Description |
|---|---|
from_dict |
Creates a PlanStep instance from a dictionary. |
to_dict |
Serializes the PlanStep instance to a dictionary. |
Notes
- this class is usually not accessed unless you are building or inspecting plans directly.
CandidatePlan
CandidatePlan represents a plan consisting of multiple steps and additional metadata.
Attributes:
| Name | Type | Description |
|---|---|---|
steps |
list[PlanStep]
|
A list of steps that make up the plan. |
extras |
dict[str, Any]
|
Additional metadata or information associated with the plan. |
Methods:
| Name | Description |
|---|---|
from_dict |
dict[str, Any]) -> CandidatePlan: Creates an instance of CandidatePlan from a dictionary representation. |
to_dict |
Converts the CandidatePlan instance into a dictionary representation. |
ValidationIssue
Represents a validation issue encountered in a planning process.
Attributes:
| Name | Type | Description |
|---|---|---|
kind |
str
|
The type of validation issue. Possible values include 'missing_input', 'unknown_action', 'type_mismatch', 'cycle', etc. |
step_id |
str
|
The identifier of the plan step where the issue occurred. |
field |
str
|
The name of the input, output, or other field related to the issue. |
message |
str
|
A human-readable message describing the issue. |
details |
dict[str, Any]
|
Additional details about the issue, provided as a dictionary. Defaults to an empty dictionary. |
ValidationResult
ValidationResult represents the result of validating a plan, including its validity, any structural errors, and missing user-provided values.
Attributes:
| Name | Type | Description |
|---|---|---|
ok |
bool
|
Indicates whether the plan is valid (True) or invalid (False). |
issues |
list[ValidationIssue]
|
A list of validation issues found in the plan. |
has_structural_errors |
bool
|
Indicates if the plan has structural errors. |
missing_user_bindings |
dict[str, list[str]]
|
A dictionary mapping keys to lists of locations where user-provided values are missing. |
Methods: is_partial_ok() -> bool: Checks if the plan is structurally valid but requires user-provided values before execution. summary() -> str: Generates a summary string describing the validity of the plan and any issues found. If the plan is valid, the summary states "Plan is valid." If invalid, the summary lists the issues with their details.
PlanningEvent
Represents a lightweight event emitted during the planning process. This class is intended for use in logging, debugging, and updating UI progress (e.g., updating a spinner or status text). It provides optional structured payloads for additional context.
Attributes:
| Name | Type | Description |
|---|---|---|
phase |
PlanningPhase
|
The current phase of the planning process. |
iteration |
int
|
The iteration number within the planning phase. |
message |
str | None
|
An optional message describing the event. |
raw_llm_output |
dict[str, Any] | None
|
An optional dictionary containing raw output from the language model. |
plan_dict |
dict[str, Any] | None
|
An optional dictionary representing the plan structure. |
validation |
ValidationResult | None
|
An optional validation result associated with the event. |
PlanningContext
Represents the context for planning, including user inputs, external slots, memory snippets, and other parameters that guide the planning process.
Attributes:
| Name | Type | Description |
|---|---|---|
goal |
str
|
The goal or objective of the planning process. |
user_inputs |
dict[str, Any]
|
A dictionary of user-provided inputs. |
external_slots |
dict[str, Any]
|
A dictionary of external slots or parameters. |
memory_snippets |
list[str]
|
A list of memory snippets for narrow, LLM-facing context. |
artifact_snippets |
list[str]
|
A list of artifact snippets for narrow, LLM-facing context. |
flow_ids |
list[str] | None
|
A list of flow IDs representing the tools/graphs that are allowed to be used. Defaults to None. |
instruction |
str | None
|
A richer agent context, used by planner code but not directly dumped. Can be parsed from skills. Defaults to None. |
allow_partial_plans |
bool
|
Indicates whether the planner should accept structurally valid but missing user input plans. Defaults to True. |
preferred_external_keys |
list[str] | None
|
A list of keys that are allowed or
preferred as |
PlanResult
PlanResult is a data class that encapsulates the result of a planning operation.
Attributes:
| Name | Type | Description |
|---|---|---|
plan |
CandidatePlan | None
|
The candidate plan resulting from the planning operation. It can be None if no valid plan was generated. |
validation |
ValidationResult | None
|
The validation result associated with the plan. It can be None if validation was not performed or not applicable. |
events |
list[PlanningEvent]
|
A list of planning events that occurred during the planning process. Defaults to an empty list. |
2. Execution Types and Dataclasses¶
Execution returns structured events and results, and can be run synchronously or in the background.
ExecutionEvent
Represents an event emitted during the execution of a plan. This class is used to encapsulate information about the current state of execution, which can be useful for logging purposes or updating the UI with progress information.
Attributes:
| Name | Type | Description |
|---|---|---|
phase |
ExecutionPhase
|
The current phase of execution. |
step_id |
str | None
|
The identifier of the current step, if applicable. |
message |
str | None
|
An optional message providing additional context about the event. |
step_outputs |
dict[str, Any] | None
|
Outputs produced by the step, applicable for success phases. |
error |
Exception | None
|
The exception raised during execution, applicable for failure phases. |
ExecutionResult
Represents the result of an execution process.
Attributes:
| Name | Type | Description |
|---|---|---|
ok |
bool
|
Indicates whether the execution was successful. |
outputs |
dict[str, Any]
|
A dictionary containing the outputs of the execution. |
errors |
list[ExecutionEvent]
|
A list of errors that occurred during execution. Defaults to an empty list. |
BackgroundExecutionHandle
BackgroundExecutionHandle is a data class that represents a handle for managing the execution of a background task.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
A unique identifier for the execution handle. |
plan_id |
str | None
|
The identifier of the associated plan, if any. |
task |
Task[ExecutionResult]
|
The asyncio task representing the background execution. |
Methods:
| Name | Description |
|---|---|
done |
Checks if the background task has completed. |
cancelled |
Checks if the background task has been cancelled. |
cancel |
Cancels the background task. |
wait |
Awaits the completion of the background task and returns its result. |
3. Core APIs¶
Below are the primary entry points. Paths are stable (do not change imports/targets for these API docs).
Plan¶
plan()is the standard entry point for planning with high-level inputs.plan_with_context()is a lower-level entry point when you already have aPlanningContext.parse_inputs()extracts missing structured inputs from free-form user text.
plan(*, goal, user_inputs, external_slots, flow_id, ...)
Generate a plan based on the provided goal and context.
This method delegates the planning process to the underlying PlannerService, using the provided inputs and optional callbacks for event handling.
Examples:
Basic usage to generate a plan:
result = await node_planner.plan(goal="Optimize workflow")
Providing additional inputs and handling events:
result = await node_planner.plan(
goal="Generate report",
user_inputs={"date": "2023-10-01"},
on_event=lambda event: print(f"Event: {event}")
)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
goal
|
str
|
The primary objective or goal for the planning process. |
required |
user_inputs
|
dict[str, Any] | None
|
Optional dictionary of user-provided inputs for the plan. |
None
|
external_slots
|
dict[str, Any] | None
|
Optional dictionary of external slot values to consider. |
None
|
flow_ids
|
list[str] | None
|
Optional list of flow identifiers to constrain the planning scope. |
None
|
instruction
|
str | None
|
Optional instruction or guidance for the planner. |
None
|
allow_partial
|
bool
|
Whether to allow partial plans if the goal cannot be fully satisfied (default: True). |
True
|
preferred_external_keys
|
list[str] | None
|
Optional list of preferred external keys to prioritize. |
None
|
memory_snippets
|
list[str] | None
|
Optional list of memory snippets to include in the planning context. |
None
|
artifact_snippets
|
list[str] | None
|
Optional list of artifact snippets to include in the planning context. |
None
|
on_event
|
PlanEventsCallback | None
|
Optional callback function to handle planning events.
The callback should be of type |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
PlanResult |
PlanResult
|
The result of the planning process, including the generated plan and metadata. |
Notes:
You can use on_event to monitor the planning process and react to intermediate events.
plan_with_context(ctx, *, on_event)
Plan a task using the provided planning context.
This method delegates the planning process to the underlying service, allowing for the generation of a plan based on the given context and optional event callback.
Examples:
Basic usage to generate a plan:
result = await planner.plan_with_context(context)
Using an event callback to monitor planning progress:
async def on_event(event):
print(f"Received event: {event}")
result = await planner.plan_with_context(context, on_event=on_event)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ctx
|
PlanningContext
|
The |
required |
on_event
|
PlanEventsCallback | None
|
Optional callback function to handle planning events. Defaults to None. |
None
|
Returns:
| Type | Description |
|---|---|
PlanResult
|
A |
Notes
- The
on_eventcallback can be used to receive updates or intermediate results during the planning process.
parse_inputs(*, message, missing_keys, instruction)
Parse input data and handle missing keys.
This method processes the provided input message, identifies any missing keys,
and optionally uses an instruction to guide the parsing process. It delegates
the actual parsing logic to the service.parse_inputs method.
Examples:
Basic usage to parse inputs:
result = await node_planner.parse_inputs(
message="Input data with key1 = 0.1 and key2 = dummy string inputs",
missing_keys=["key1", "key2"]
)
Parsing with an additional instruction:
result = await node_planner.parse_inputs(
message="Input data with key1 equals 0.1 and key2 is some dummy string inputs",
missing_keys=["key1", "key2"],
instruction="key1 is a float and key2 is a string. Make sure all values are included in a dictionary."
)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
The input message to be parsed. |
required |
missing_keys
|
list[str]
|
Field names whose values we want to extract. |
required |
instruction
|
str | None
|
Optional instruction to guide the parsing process. |
None
|
Returns:
| Type | Description |
|---|---|
|
The result of the parsing operation as returned by the |
Notes:
This method is asynchronous and relies on the service.parse_inputs implementation
for the actual parsing logic.
Execute¶
execute()runs a validatedCandidatePlanimmediately.execute_background()runs the plan asynchronously and returns a handle.
execute(plan, *, user_inputs, on_event, ...)
Execute a plan with the provided context and parameters.
This method uses the NodeContext to auto-fill execution metadata such as identity, session, agent, and application IDs. Callers can override these defaults by providing explicit keyword arguments.
Examples:
Basic usage to execute a plan:
result = await node_planner.execute(plan)
Executing with additional user inputs and event handling:
result = await node_planner.execute(
plan,
user_inputs={"key1": "value1"},
on_event=lambda event: print(f"Execution event: {event}")
)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
plan
|
CandidatePlan
|
The |
required |
user_inputs
|
dict[str, Any] | None
|
Optional dictionary of user-provided inputs for the execution. Values referenced as "${user. |
None
|
on_event
|
ExecEventsCallback | None
|
Optional callback function to handle execution events. |
None
|
identity
|
RequestIdentity | None
|
Optional |
None
|
visibility
|
RunVisibility
|
Visibility level for the execution (default: |
normal
|
importance
|
RunImportance
|
Importance level for the execution (default: |
normal
|
session_id
|
str | None
|
Optional session ID to override the default session. |
None
|
agent_id
|
str | None
|
Optional agent ID to override the default agent. |
None
|
app_id
|
str | None
|
Optional application ID to override the default application. |
None
|
tags
|
list[str] | None
|
Optional list of tags to associate with the execution. |
None
|
origin
|
RunOrigin | None
|
Optional |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
ExecutionResult |
ExecutionResult
|
The result of the execution process, including status and metadata. |
Notes:
Use the on_event callback to monitor execution progress and handle intermediate events.
execute_background(plan, *, user_inputs, on_event, ...)
Execute a candidate plan in the background, bound to this node.
This method initiates a fire-and-forget execution of the provided plan,
leveraging the node's context and metadata. Progress updates can be
reported via the on_event callback, and completion is signaled through
the on_complete callback.
Examples:
Basic usage to execute a plan in the background:
handle = await node_planner.execute_background(plan)
Executing with additional metadata and callbacks:
handle = await node_planner.execute_background(
user_inputs={"param1": "value1"},
on_event=event_callback,
on_complete=completion_callback,
tags=["custom:tag"],
)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
plan
|
CandidatePlan
|
The candidate plan to execute. |
required |
user_inputs
|
dict[str, Any] | None
|
Optional dictionary of user-provided inputs for the execution. |
None
|
on_event
|
ExecEventsCallback | None
|
Optional callback to handle execution progress events. |
None
|
identity
|
RequestIdentity | None
|
Optional identity to associate with the execution; defaults to the node's context identity. |
None
|
visibility
|
RunVisibility
|
The visibility level of the execution (default: RunVisibility.normal). |
normal
|
importance
|
RunImportance
|
The importance level of the execution (default: RunImportance.normal). |
normal
|
session_id
|
str | None
|
Optional session ID to associate with the execution; defaults to the node's context session ID. |
None
|
agent_id
|
str | None
|
Optional agent ID to associate with the execution; defaults to the node's context agent ID. |
None
|
app_id
|
str | None
|
Optional application ID to associate with the execution; defaults to the node's context app ID. |
None
|
tags
|
list[str] | None
|
Optional list of tags to associate with the execution; additional tags are derived from the node's context. |
None
|
origin
|
RunOrigin | None
|
Optional origin of the execution; defaults to |
None
|
on_complete
|
Callable[[ExecutionResult], Any] | None
|
Optional callback to handle execution completion. |
None
|
exec_id
|
str | None
|
Optional explicit execution ID to associate with the execution. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
BackgroundExecutionHandle |
BackgroundExecutionHandle
|
A handle to monitor or interact with the background execution. |
Notes
- Tags automatically include identifiers for the graph, node, and run (if available) from the node's context.
- The
on_eventcallback is invoked with progress updates, while theon_completecallback is invoked upon completion.