huggingface/smolagents · critical · NotImplementedError

This method should be implemented in child classes

Error message

This method should be implemented in child classes

What it means

MultiStepAgent is an abstract base class: its _step_stream method just raises NotImplementedError('This method should be implemented in child classes'). Each concrete agent (ToolCallingAgent, CodeAgent) overrides it to define its ReAct step behavior.

Source

Thrown at src/smolagents/agents.py:780

        """
        Reads past llm_outputs, actions, and observations or errors from the memory into a series of messages
        that can be used as input to the LLM. Adds a number of keywords (such as PLAN, error, etc) to help
        the LLM.
        """
        messages = self.memory.system_prompt.to_messages(summary_mode=summary_mode)
        for memory_step in self.memory.steps:
            messages.extend(memory_step.to_messages(summary_mode=summary_mode))
        return messages

    def _step_stream(
        self, memory_step: ActionStep
    ) -> Generator[ChatMessageStreamDelta | ToolCall | ToolOutput | ActionOutput]:
        """
        Perform one step in the ReAct framework: the agent thinks, acts, and observes the result.
        Yields ChatMessageStreamDelta during the run if streaming is enabled.
        At the end, yields either None if the step is not final, or the final answer.
        """
        raise NotImplementedError("This method should be implemented in child classes")

    def step(self, memory_step: ActionStep) -> Any:
        """
        Perform one step in the ReAct framework: the agent thinks, acts, and observes the result.
        Returns either None if the step is not final, or the final answer.
        """
        return list(self._step_stream(memory_step))[-1]

    def extract_action(self, model_output: str, split_token: str) -> tuple[str, str]:
        """
        Parse action from the LLM output

        Args:
            model_output (`str`): Output of the LLM
            split_token (`str`): Separator for the action. Should match the example in the system prompt.
        """
        try:
            split = model_output.split(split_token)

View on GitHub (pinned to 30bb116109)

Solutions

  1. Don't instantiate MultiStepAgent directly; use CodeAgent or ToolCallingAgent
  2. In your subclass, implement _step_stream as a generator yielding ChatMessageStreamDelta/ToolCall/ToolOutput and finally an ActionOutput
  3. Model your subclass on ToolCallingAgent's implementation or delegate by composition instead of inheritance

Example fix

# before
class MyAgent(MultiStepAgent):
    def _do_step(self): ...  # wrong name; _step_stream left abstract

# after
class MyAgent(MultiStepAgent):
    def _step_stream(self):
        # think / act / observe logic
        yield ActionOutput(output=result, is_final_answer=done)
Defensive patterns

Strategy: validation

Validate before calling

import inspect

def assert_concrete(agent_cls):
    if inspect.isabstract(agent_cls) or agent_cls._step_stream is MultiStepAgent._step_stream:
        raise TypeError(f"{agent_cls.__name__} must implement _step_stream")

Type guard

def implements_step_stream(cls) -> bool:
    return '_step_stream' in cls.__dict__ or any('_step_stream' in c.__dict__ for c in cls.__mro__[1:-1]) and cls.__dict__.get('_step_stream') is not None

Prevention

When it happens

Trigger: Instantiating MultiStepAgent directly and calling run()/step(), or subclassing MultiStepAgent without overriding _step_stream; also calling super()._step_stream(...) from a subclass override.

Common situations: Creating a custom agent type by extending MultiStepAgent and forgetting to implement the step logic; refactorings that rename the override or accidentally call the parent implementation.

Related errors


AI-assisted analysis of huggingface/smolagents@30bb116109 (2026-08-28). Data as JSON: /api/errors/9bf52f63db6d5ae1. Report an issue: GitHub.