mirror of
https://github.com/deepset-ai/haystack.git
synced 2026-01-10 14:16:59 +00:00
* wip: fixing tests * wip: fixing tests * wip: fixing tests * wip: fixing tests * fixing circular imports * decoupling resume and initial run() for agent * adding release notes * re-raising BreakPointException from pipeline.run() * fixing imports * refactor: Refactor suggestions for Pipeline breakpoints (#9614) * Refactoring * Start adding debug_path into Breakpoint class * Fully move debug_path into Breakpoint dataclass * Simplifications in pipeline run logic * More simplification * lint * More simplification * Updates * Rename resume_state to pipeline_snapshot * PR comments * Missed renaming of state in a few more places * feat: Add dataclasses to represent a `PipelineSnapshot` and refactored to use it (#9619) * Refactor to use dataclasses for PipelineSnapshot and AgentSnapshot * Fix integration tests * Mypy * Fix mypy * Fix lint * Refactor AgentSnapshot to only contain needed info * Fix mypy * More refactoring * removing unused import --------- Co-authored-by: David S. Batista <dsbatista@gmail.com> * feat: saving include_outputs_from intermediate results to `PipelineState` object (#9629) * saving intermediate components results in include_outputs_from into the PipelineSnaptshot * cleaning up * fixing tests * fixing tests * extending tests * Update haystack/dataclasses/breakpoints.py Co-authored-by: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com> * Update haystack/dataclasses/breakpoints.py Co-authored-by: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com> * linting * moving intermediate results to pipeline state and adding pipeline outputs to state * moving ordered_component_names and include_outputs_from to PipelineSnapshot * moving original_input_data to PipelineSnapshot * simplifying saving the intermediate results * Update haystack/dataclasses/breakpoints.py Co-authored-by: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com> * Update haystack/dataclasses/breakpoints.py Co-authored-by: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com> * Update haystack/dataclasses/breakpoints.py Co-authored-by: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com> * Update haystack/dataclasses/breakpoints.py Co-authored-by: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com> --------- Co-authored-by: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com> * linting * cleaning up * avoiding creating PipelineSnapshot for every component run * removing unecessary code * Update checks in Agent to not unecessarily create AgentSnapshot when not needed. * Update haystack/components/agents/agent.py Co-authored-by: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com> * Update haystack/components/agents/agent.py Co-authored-by: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com> * cleaning up tests * linting --------- Co-authored-by: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com> Co-authored-by: Sebastian Husch Lee <sjrl423@gmail.com>
111 lines
3.5 KiB
Python
111 lines
3.5 KiB
Python
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from haystack.components.agents import Agent
|
|
from haystack.components.generators.chat import OpenAIChatGenerator
|
|
from haystack.dataclasses import ChatMessage, ToolCall
|
|
from haystack.tools import Tool
|
|
from test.components.agents.test_agent import (
|
|
MockChatGeneratorWithoutRunAsync,
|
|
MockChatGeneratorWithRunAsync,
|
|
weather_function,
|
|
)
|
|
|
|
|
|
# Common fixtures
|
|
@pytest.fixture
|
|
def weather_tool():
|
|
return Tool(
|
|
name="weather_tool",
|
|
description="Provides weather information for a given location.",
|
|
parameters={"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]},
|
|
function=weather_function,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def debug_path(tmp_path):
|
|
return str(tmp_path / "debug_snapshots")
|
|
|
|
|
|
@pytest.fixture
|
|
def agent_sync(weather_tool):
|
|
generator = MockChatGeneratorWithoutRunAsync()
|
|
mock_run = MagicMock()
|
|
mock_run.return_value = {
|
|
"replies": [
|
|
ChatMessage.from_assistant(
|
|
"I'll help you check the weather.",
|
|
tool_calls=[{"tool_name": "weather_tool", "tool_args": {"location": "Berlin"}}],
|
|
)
|
|
]
|
|
}
|
|
|
|
def mock_run_with_tools(messages, tools=None, **kwargs):
|
|
return mock_run.return_value
|
|
|
|
generator.run = mock_run_with_tools
|
|
|
|
return Agent(
|
|
chat_generator=generator,
|
|
tools=[weather_tool],
|
|
system_prompt="You are a helpful assistant that can use tools to help users.",
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_agent_with_tool_calls_sync(monkeypatch, weather_tool):
|
|
monkeypatch.setenv("OPENAI_API_KEY", "fake-key")
|
|
generator = OpenAIChatGenerator()
|
|
mock_messages = [
|
|
ChatMessage.from_assistant("First response"),
|
|
ChatMessage.from_assistant(tool_calls=[ToolCall(tool_name="weather_tool", arguments={"location": "Berlin"})]),
|
|
]
|
|
agent = Agent(chat_generator=generator, tools=[weather_tool], max_agent_steps=1)
|
|
agent.warm_up()
|
|
agent.chat_generator.run = MagicMock(return_value={"replies": mock_messages})
|
|
return agent
|
|
|
|
|
|
@pytest.fixture
|
|
def agent_async(weather_tool):
|
|
generator = MockChatGeneratorWithRunAsync()
|
|
mock_run_async = AsyncMock()
|
|
mock_run_async.return_value = {
|
|
"replies": [
|
|
ChatMessage.from_assistant(
|
|
"I'll help you check the weather.",
|
|
tool_calls=[{"tool_name": "weather_tool", "tool_args": {"location": "Berlin"}}],
|
|
)
|
|
]
|
|
}
|
|
|
|
async def mock_run_async_with_tools(messages, tools=None, **kwargs):
|
|
return mock_run_async.return_value
|
|
|
|
generator.run_async = mock_run_async_with_tools
|
|
return Agent(
|
|
chat_generator=generator,
|
|
tools=[weather_tool],
|
|
system_prompt="You are a helpful assistant that can use tools to help users.",
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_agent_with_tool_calls_async(monkeypatch, weather_tool):
|
|
monkeypatch.setenv("OPENAI_API_KEY", "fake-key")
|
|
generator = MockChatGeneratorWithRunAsync()
|
|
mock_messages = [
|
|
ChatMessage.from_assistant("First response"),
|
|
ChatMessage.from_assistant(tool_calls=[ToolCall(tool_name="weather_tool", arguments={"location": "Berlin"})]),
|
|
]
|
|
agent = Agent(chat_generator=generator, tools=[weather_tool], max_agent_steps=1)
|
|
agent.warm_up()
|
|
agent.chat_generator.run_async = AsyncMock(return_value={"replies": mock_messages})
|
|
return agent
|