Skip to content

[Feature]: Support direct return from tool execution to bypass ReAct loop #857

@QianzhenSun

Description

@QianzhenSun

Issue Body

Problem

In the current ReActAgent implementation, all tool execution results go through the full ReAct loop:

Tool executes → Result added to memory → Model processes → Decides next action → Loop continues

This is inefficient for "final-answer" tools where the tool output is the final answer and no further model reasoning is needed.

Example scenarios:

  • A search tool that returns search results as the final answer
  • A Q&A tool that directly answers user questions
  • A query tool that returns data without needing interpretation

Currently, even for these tools, the agent will:

  1. Add the result to memory
  2. Call the LLM to process the result
  3. Wait for the LLM to decide to stop

This adds unnecessary latency and cost.


Proposed Feature

Add a mechanism that allows tools to signal "this result should be returned directly to the user" without continuing the ReAct loop.

When a tool returns with a return_directly flag set to true:

  1. The agent should immediately return the tool result to the caller
  2. Skip the next model call
  3. End the current ReAct iteration

Expected Behavior

Before (Current)

User: "Search for weather in Beijing"
Agent calls: weather_search("Beijing")
Tool returns: "Beijing weather: Sunny, 25°C"
Agent calls LLM: "What should I do with this result?"
LLM responds: "The answer is ready, I should stop"
Agent returns: "Beijing weather: Sunny, 25°C"

After (With direct return)

User: "Search for weather in Beijing"
Agent calls: weather_search("Beijing") with return_directly=true
Tool returns: "Beijing weather: Sunny, 25°C" with return_directly=true
Agent detects flag and returns immediately
Agent returns: "Beijing weather: Sunny, 25°C"


Demo

Tool Result with Direct Return Flag

// Tool returns result with return_directly flag
ToolResultBlock result = ToolResultBlock.text("Beijing weather: Sunny, 25°C", true);

// Check if should return directly
if (result.isReturnDirectly()) {
    // Agent should return this result immediately
    // without further model processing
}

Message with Direct Return Reason

Msg response = Msg.builder()
    .role(MsgRole.ASSISTANT)
    .content(result.getOutput())
    .generateReason(GenerateReason.TOOL_DIRECT_RETURN)
    .build();

---
Key Requirements

1. ToolResultBlock should support a return_directly metadata flag
2. ReActAgent should check this flag after tool execution
3. When flag is true, agent should:
  - Build a response message with the tool result
  - Return immediately without calling the model again
  - Set GenerateReason.TOOL_DIRECT_RETURN on the response

---
Priority Handling

When multiple conditions exist, the priority should be:

1. HITL stop (highest) - User explicitly stopped the agent
2. Suspended results - Tools waiting for external execution
3. Direct return - Tools with return_directly=true
4. Continue iteration - Normal ReAct loop (lowest)

---
Questions

1. Should direct return results be added to agent memory before returning?
2. When multiple tools execute in parallel with return_directly=true, should we return all results or just the first one?
3. Should this flag be configurable per tool in the tool config?

---

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions