jeevesagent.architecture.rewoo

ReWOO: Reasoning WithOut Observation — plan-then-tool-execute.

Xu et al. 2023 — ReWOO: Decoupling Reasoning from Observations for Efficient Augmented Language Models. The cost-saving sibling of PlanAndExecute: each step in the plan is a real tool call, with {{En}} placeholder substitution to reference prior step outputs. Independent steps (no dependency on each other) run in parallel.

Total cost: 2 LLM calls + N tool calls. ReAct on the same task needs roughly N+1 LLM calls (one per turn). For tool-heavy workloads where the planner can predict the call sequence upfront, ReWOO is 30-50% cheaper.

Pattern

  1. Planner. ONE LLM call. Output is a JSON list of steps. Each step has shape:

    {"id": "E1", "tool": "<tool_name>", "args": {...}}
    

    Args may reference prior steps via {{En}} placeholders — {"args": {"url": "{{E1}}"}} will use E1’s output as the url arg when E2 runs.

  2. Worker. Compute topological levels from the plan’s placeholder dependencies. For each level, dispatch all steps in parallel via deps.tools.call(...). Substitute {{En}} placeholders in args from prior step outputs first.

  3. Solver. ONE LLM call. Given the original task and the step→output map, produce the final answer.

Strengths

  • Cheaper than ReAct on tool-heavy multi-step tasks. Two LLM calls cap the LLM cost regardless of plan length.

  • Parallelism for free. Independent steps run concurrently via anyio.create_task_group (same primitive Supervisor + ReAct use for parallel tool dispatch).

  • Observable plan. The plan is a structured Pydantic object — log it, audit it, override it before execution.

Weaknesses

  • Planner must predict accurately upfront. No replanning on failure in v1. If a step fails, the worker logs the error and the solver sees it as the step’s “output.”

  • Limited to known tool names. A planner that hallucinates a tool name produces a step that errors at dispatch time.

  • Placeholder substitution is string-typed. Tool outputs get stringified. For structured-output tools, the planner has to treat outputs as opaque text.

Attributes

Classes

ReWOO

Plan-then-tool-execute with placeholder substitution.

ReWOOPlan

A list of ReWOO steps (no required ordering — dependencies

ReWOOStep

One step of a ReWOO plan: id + tool + args.

ReWOOStepResult

!!! abstract "Usage Documentation"

Module Contents

class jeevesagent.architecture.rewoo.ReWOO(*, max_steps: int = 8, planner_prompt: str | None = None, solver_prompt: str | None = None, parallel_levels: bool = True)[source]

Plan-then-tool-execute with placeholder substitution.

declared_workers() dict[str, jeevesagent.agent.api.Agent][source]
async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]
name = 'rewoo'
class jeevesagent.architecture.rewoo.ReWOOPlan(/, **data: Any)[source]

Bases: pydantic.BaseModel

A list of ReWOO steps (no required ordering — dependencies are inferred from {{En}} placeholders).

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

steps: list[ReWOOStep] = None
class jeevesagent.architecture.rewoo.ReWOOStep(/, **data: Any)[source]

Bases: pydantic.BaseModel

One step of a ReWOO plan: id + tool + args.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

args: dict[str, Any] = None
property depends_on: list[str]

Extract {{En}} step ids referenced in args.

id: str
tool: str
class jeevesagent.architecture.rewoo.ReWOOStepResult(/, **data: Any)[source]

Bases: pydantic.BaseModel

!!! abstract “Usage Documentation”

[Models](../concepts/models.md)

A base class for creating Pydantic models.

__class_vars__

The names of the class variables defined on the model.

__private_attributes__

Metadata about the private attributes of the model.

__signature__

The synthesized __init__ [Signature][inspect.Signature] of the model.

__pydantic_complete__

Whether model building is completed, or if there are still undefined fields.

__pydantic_core_schema__

The core schema of the model.

__pydantic_custom_init__

Whether the model has a custom __init__ function.

__pydantic_decorators__

Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.

__pydantic_generic_metadata__

Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.

__pydantic_parent_namespace__

Parent namespace of the model, used for automatic rebuilding of models.

__pydantic_post_init__

The name of the post-init method for the model, if defined.

__pydantic_root_model__

Whether the model is a [RootModel][pydantic.root_model.RootModel].

__pydantic_serializer__

The pydantic-core SchemaSerializer used to dump instances of the model.

__pydantic_validator__

The pydantic-core SchemaValidator used to validate instances of the model.

__pydantic_fields__

A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.

__pydantic_computed_fields__

A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.

__pydantic_extra__

A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to ‘allow’.

__pydantic_fields_set__

The names of fields explicitly set during instantiation.

__pydantic_private__

Values of private attributes set on the model instance.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

error: str | None = None
output: str
step_id: str
tool: str
jeevesagent.architecture.rewoo.DEFAULT_PLANNER_PROMPT = Multiline-String
Show Value
"""You produce a step-by-step plan to solve the user's task using the
available tools. Each step is a tool call.

Output ONLY a JSON array of step objects. Each step has:
- "id": a short identifier like "E1", "E2", ... unique within the plan
- "tool": the name of one of the available tools
- "args": a dict of arguments to pass to the tool

You may reference a prior step's output in args using `{{En}}`. The
worker will substitute `{{En}}` with the actual output of step En
before invoking the tool.

Available tools:
{tool_descriptions}

Output format example:
[
  {{"id": "E1", "tool": "web_search", "args": {{"query": "Tokyo weather"}}}},
  {{"id": "E2", "tool": "summarize", "args": {{"text": "{{{{E1}}}}"}}}}
]

Output ONLY the JSON array. No prose, no markdown fences.
"""
jeevesagent.architecture.rewoo.DEFAULT_SOLVER_PROMPT = Multiline-String
Show Value
"""You synthesize the final answer from a sequence of tool-call
results. Use the original task and the step outputs to produce the
final answer. Be concise."""