Skip to content

Tool-Using ReAct¤

react is for tasks where the model should choose and chain tools. It still lives inside the behavior tree as one leaf.

from jdsl import react, root, tool

@tool
def distance_km(origin: str, destination: str) -> int:
    """Road distance between two cities."""
    ...

@tool
def drive_hours(km: int) -> float:
    """Driving time in hours."""
    ...

@tool
def fuel_cost(km: int) -> float:
    """Fuel cost for the trip."""
    ...

skill = (
    root("Trip", system="Use tools for every number.")
    .model("deepseek-chat")
    .do(react("request -> answer", tools=[distance_km, drive_hours, fuel_cost], max_steps=8))
)

Run the example:

uv run jdsl run examples/trip.py \
  -i request="Driving Nairobi to Mombasa - how long and how much fuel?"

Tool Schemas¤

@tool keeps the callable usable from Python and attaches metadata for the model. react derives a JSON schema from the function signature:

Python hint Tool schema
str string
int integer
float number
bool boolean
list[T], tuple, set array

Arguments without defaults are required. Unannotated arguments fall back to strings.

Failure and Recovery¤

If the model calls an unknown tool, jdsl sends an error observation back into the loop. If a tool raises, jdsl also sends an error observation rather than crashing the whole react leaf. The leaf fails only when no final answer arrives within max_steps or the final answer is empty.

Use a selector outside react when you want a deterministic fallback:

sel(
    react("request -> answer", tools=[search, fetch], max_steps=6),
    act(fallback_answer),
)