FoundationAgents/OpenManus · error · ValueError

Tool calls required but none provided

Error message

Tool calls required but none provided

What it means

Raised in ToolCallAgent.act() when the agent produced no tool calls while tool_choices is ToolChoice.REQUIRED. In REQUIRED mode the LLM must invoke at least one tool; an empty tool_calls list means the model answered in plain text instead. This is a hard contract violation for pipelines that depend on structured tool output.

Source

Thrown at app/agent/toolcall.py:135

            # For 'auto' mode, continue with content if no commands but content exists
            if self.tool_choices == ToolChoice.AUTO and not self.tool_calls:
                return bool(content)

            return bool(self.tool_calls)
        except Exception as e:
            logger.error(f"🚨 Oops! The {self.name}'s thinking process hit a snag: {e}")
            self.memory.add_message(
                Message.assistant_message(
                    f"Error encountered while processing: {str(e)}"
                )
            )
            return False

    async def act(self) -> str:
        """Execute tool calls and handle their results"""
        if not self.tool_calls:
            if self.tool_choices == ToolChoice.REQUIRED:
                raise ValueError(TOOL_CALL_REQUIRED)

            # Return last message content if no tool calls
            return self.messages[-1].content or "No content or commands to execute"

        results = []
        for command in self.tool_calls:
            # Reset base64_image for each tool call
            self._current_base64_image = None

            result = await self.execute_tool(command)

            if self.max_observe:
                result = result[: self.max_observe]

            logger.info(
                f"🎯 Tool '{command.function.name}' completed its mission! Result: {result}"
            )

View on GitHub (pinned to 52a13f2a57)

Solutions

  1. Re-run think() before act() so the model gets another chance (loop think/act as the framework intends) instead of calling act() directly
  2. Use a model that honors tool_choice="required" (gpt-4o class models)
  3. If plain-text answers are acceptable, set tool_choices=ToolChoice.AUTO so act() falls back to the last message content

Example fix

# before
result = await agent.act()  # raises if think() produced no tool calls

# after
await agent.think()
result = await agent.act()
Defensive patterns

Strategy: validation

Validate before calling

from app.agent.toolcall import ToolChoice

def can_act(agent) -> bool:
    if agent.tool_choices == ToolChoice.REQUIRED:
        return bool(agent.tool_calls)
    return True

Try / catch

try:
    out = await agent.act()
except ValueError as e:
    if "Tool calls required" in str(e):
        # give the model another chance to produce tool calls
        await agent.think()
        out = await agent.act()
    else:
        raise

Prevention

When it happens

Trigger: Agent configured with tool_choices=ToolChoice.REQUIRED ("required") but the model replies with text only; weaker models ignoring the tool_choice constraint; tool schemas not registered so the model has nothing valid to call.

Common situations: Using a model that does not support tool_choice="required" (some open-weight/local models); tools list empty at request time; temperature too high causing the model to skip tools.

Related errors


AI-assisted analysis of FoundationAgents/OpenManus@52a13f2a57 (2026-08-15). Data as JSON: /api/errors/efd18ddae1dd462c. Report an issue: GitHub.