github deepset-ai/haystack v2.26.0-rc1

pre-release5 hours ago

🚀 New Features

  • Added LLMRanker, a new ranker component that uses a ChatGenerator and PromptBuilder to rerank documents based on JSON-formatted LLM output. LLMRanker supports configurable prompts, optional custom chat generators, runtime top_k overrides, and serialization.

  • AzureOpenAIResponsesChatGenerator exposes a SUPPORTED_MODELS class variable listing supported model IDs, for example gpt-5-mini and gpt-4o. To view all supported models go to the [API reference](https://docs.haystack.deepset.ai/reference/generators-api#azureopenairesponseschatgenerator) or run:

    from haystack.components.generators.chat import AzureOpenAIResponsesChatGenerator
    print(AzureOpenAIResponsesChatGenerator.SUPPORTED_MODELS)
  • We now allow a component's whose input type is typed as a union of lists (e.g. list[str] | list[ChatMessage]) to allow multiple input connections. Previously we only supported bare lists (e.g. list[str]) or optional lists (e.g. list[str] | None) to allow multiple input connections. A common use case for this is using the AnswerBuilder component which has it's replies input typed as list[str] | list[ChatMessage].

  • The system_prompt initialization parameter of the Agent component now supports Jinja2 message template syntax. This allows you to define the template at initialization time and pass runtime variables when calling the run method. This can be useful to inject dynamic values (such as the current time) or to add conditional instructions.

    Example usage:

    from haystack.components.agents import Agent
    from haystack.components.generators.chat import OpenAIChatGenerator
    from haystack.dataclasses import ChatMessage
    from haystack.tools import tool
    
    @tool
    def weather(location: str) -> str:
        return f"The weather in {location} is sunny."
    
    agent = Agent(
        chat_generator=OpenAIChatGenerator(),
        tools=[weather],
        system_prompt="""{% message role='system' %}
        You always respond in {{language}}.
        {% endmessage %}""",
        required_variables=["language"],
    )
    
    messages = [ChatMessage.from_user("What is the weather in London?")]
    
    result = agent.run(messages=messages, language="Italian")
    print(result["last_message"].text)
    # >> Il tempo a Londra è soleggiato.
  • OpenAIChatGenerator exposes a SUPPORTED_MODELS class variable listing supported model IDs, for example gpt-5-mini and gpt-4o. To view all supported models go to the [API reference](https://docs.haystack.deepset.ai/reference/generators-api#openaichatgenerator) or run:

    from haystack.components.generators.chat import OpenAIChatGenerator
    print(OpenAIChatGenerator.SUPPORTED_MODELS)

    We will add this for other model providers in their respective ChatGenerator components step by step.

⚡️Enhancement Notes

  • SearchableToolset now supports customizing the bootstrap search tool's name, description, and parameter descriptions via three new optional __init__ parameters: search_tool_name, search_tool_description, and search_tool_parameters_description. This allows users to tune the LLM-facing metadata to work better with different models.

    Example usage:

    from haystack.tools import SearchableToolset
    
    toolset = SearchableToolset(
        catalog=my_tools,
        search_tool_name="find_tools",
        search_tool_description="Find tools by keyword. Pass 1-3 words, not sentences.",
        search_tool_parameters_description={
            "tool_keywords": "Single words only, e.g. 'hotel booking'.",
        },
    )
  • Add support for python 3.14 to Haystack. Haystack already mostly supported python 3.14. Only minor changes were needed in regards to our type serialization and type checking when handling bare Union types.

  • Make the runtime parameter messages to Agent messages optional since it is possible to execute the agent with only providing a user_prompt.

  • Improve performance of HuggingFaceAPIDocumentEmbedder.run_async by requesting embedding inference concurrently. This can be controlled using the new concurrency_limit parameter.

  • Removed redundant deepcopy operations from Pipeline and AsyncPipeline execution. Component outputs are no longer deepcopied when collecting pipeline results, as inputs are already deepcopied before each component executes, preventing unintended mutations. Component inputs and outputs are also no longer deepcopied before being stored in tracing spans. These changes improve pipeline execution performance, especially when large objects (e.g., lists of Documents) flow between components and when include_outputs_from is used.

  • Reduced unnecessary deepcopies in Agent for improved performance. Replaced deepcopy of state_schema with a shallow dict copy since only top-level keys are modified, and removed deepcopy of agent_inputs for span tags since the dict is freshly created and only used for tracing.

  • Enable async embedding-based splitting with a new run_async method on EmbeddingBasedDocumentSplitter.

  • Added gpt-5.4 to OpenAIChatGenerator's list of supported models.

  • Added runtime validation of component output keys in Pipeline and AsyncPipeline. When a component returns keys that were not declared in its @component.output_types, the pipeline now logs a warning identifying the misconfigured component. This helps diagnose issues where a component returns unexpected keys, which previously caused a confusing "Pipeline Blocked" error pointing to an unexpected (downstream) component.

🐛 Bug Fixes

  • Fixed Agent.run_async to mirror Agent.run crash handling for internal chat_generator and tool_invoker failures. Async runs now wrap internal PipelineRuntimeError exceptions with Agent context and attach pipeline snapshots so standalone async failures can be debugged and resumed consistently.

  • Fixed ToolBreakpoint validation in Agent.run and Agent.run_async to validate against tools selected for the current run. This allows breakpoints for runtime tool overrides to work correctly.

  • Replaced in-place dataclass attribute mutation with dataclasses.replace() across multiple components to prevent unintended side-effects when the same dataclass instance is shared across pipeline branches.

    Affected components and dataclasses:

    • ChatPromptBuilder and DynamicChatPromptBuilder: ChatMessage._content
    • HuggingFaceLocalChatGenerator: ChatMessage._content
    • HuggingFaceTEIRanker: Document.score
    • MetaFieldRanker: Document.score
    • SentenceTransformersSimilarityRanker: Document.score
    • TransformersSimilarityRanker: Document.score
    • ExtractiveReader: ExtractedAnswer.query
    • InMemoryDocumentStore: Document.embedding
  • Update Pipeline.inputs() to return any variadic inputs as not mandatory if they already have a connection. Removed the utility functions describe_pipeline_inputs and describe_pipeline_inputs_as_string from haystack/core/pipeline/descriptions.py since they were not used and not referenced in the documentation. Use the Pipeline.inputs() method to inspect the inputs of a pipeline.

  • Fixed a bug in the pipeline scheduling logic where a component with all-optional inputs (e.g. Agent after making messages optional) could be scheduled ahead of a variadic joiner (e.g. ListJoiner) that was still waiting on inputs. The fix updates the tiebreaking logic in _tiebreak_waiting_components so that variadic joiners and components with all-optional inputs are treated at the same priority level, with topological order determining which waiting component runs first.

  • Fix ConditionalRouter incorrectly validating a plain str as list[str]. Since str is a Sequence, it previously passed the Sequence type check. Now str and bytes values are explicitly rejected when the expected type is a generic Sequence like list[str].

  • Use TypeVar instead of type as the type hint for cls in _warn_on_inplace_mutation. Using type would type the function as (type) -> type, losing information about which class was passed in. With (cls: T) -> T, the type checker understands that the specific class passed in is returned unchanged, rather than an anonymous type.

  • Improved the warning message emitted when the pipeline appears to be blocked. The message now lists all potentially affected components along with their types, and clarifies that some components may be intentionally inactive due to conditional branching. Previously the error message only listed one of the potentially blocking components and sometimes erroneously identified the wrong component as the blocker.

💙 Big thank you to everyone who contributed to this release!

@Aftabbs, @agnieszka-m, @anakin87, @B-Step62, @bogdankostic, @Br1an67, @davidsbatista, @it-education-md, @jnMetaCode, @julian-risch, @kacperlukawski, @marc-mrt, @maxdswain, @rob-9, @sjrl, @travellingsoldier85, @Waqar53

Don't miss a new haystack release

NewReleases is sending notifications on new releases.