Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.27.0-rc0
2.27.0
38 changes: 38 additions & 0 deletions haystack/components/agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,44 @@ def from_dict(cls, data: dict[str, Any]) -> "Agent":

return default_from_dict(cls, data)

def can_run(self, inputs: dict[str, Any]) -> bool:
"""
Check if the agent can run with the given inputs.

If there's a snapshot input, the agent can always run because it can resume from the snapshot state without
needing any of the other inputs. Otherwise, if any of the main inputs (messages, user_prompt, system_prompt)
are connected as input, they must be provided at runtime.

For the special case where none of the main inputs are connected, nor provided, and no prompts are set via
initialization, we return True, to raise an exception later in the run method.

:param inputs: Inputs for the agent.
:returns: True if the agent can run, False otherwise.
"""
# If there's a snapshot, we can always run (we can resume from the snapshot state without needing any of the
# other inputs)
if inputs.get("snapshot") is not None:
return True

# messages, user_prompt, or system_prompt are the main inputs that can trigger the agent to run.
# If any of them is connected as input it must be provided at runtime, otherwise the agent won't be triggered.
main_inputs = ["messages", "user_prompt", "system_prompt"]
for main_input in main_inputs:
if self.is_socket_connected(main_input) and inputs.get(main_input) is None:
return False

# Either none of the main inputs are connected, or all connected inputs have a value at runtime
return True

def is_socket_connected(self, socket_name: str) -> bool:
"""
Check if a socket is connected to any sender.

:param socket_name: The name of the socket to check.
:returns: True if the socket is connected to at least one sender, False otherwise.
"""
return bool(self.__haystack_input__[socket_name].senders)

def _create_agent_span(self) -> Any:
"""
Create a span for the agent run.
Expand Down
4 changes: 4 additions & 0 deletions haystack/core/pipeline/component_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ def can_component_run(component: dict, inputs: dict) -> bool:
:param component: Component metadata and the component instance.
:param inputs: Inputs for the component.
"""
instance = component["instance"]
if hasattr(instance, "can_run") and callable(instance.can_run):
return instance.can_run(inputs)

received_all_mandatory_inputs = are_all_sockets_ready(component, inputs, only_check_mandatory=True)
received_trigger = has_any_trigger(component, inputs)

Expand Down