diff --git a/docs-website/reference/haystack-api/hooks_api.md b/docs-website/reference/haystack-api/hooks_api.md index f281f7c969d..3d02aabaa45 100644 --- a/docs-website/reference/haystack-api/hooks_api.md +++ b/docs-website/reference/haystack-api/hooks_api.md @@ -1,7 +1,7 @@ --- title: "Hooks" id: hooks-api -description: "Hooks that run at points in the Agent's run loop and influence it by mutating State, including built-in tool result offloading." +description: "Hooks that run at points in the Agent's run loop and influence it by mutating State, including built-in tool result offloading and Human-in-the-Loop tool confirmation." slug: "/hooks-api" --- @@ -131,6 +131,470 @@ agent = Agent(chat_generator=..., tools=[...], hooks={"on_exit": [require_save]} - FunctionHook – A `FunctionHook` wrapping the function. +## human_in_the_loop/dataclasses + +### ConfirmationUIResult + +Result of the confirmation UI interaction. + +**Parameters:** + +- **action** (str) – The action taken by the user such as "confirm", "reject", or "modify". + This action type is not enforced to allow for custom actions to be implemented. +- **feedback** (str | None) – Optional feedback message from the user. For example, if the user rejects the tool execution, + they might provide a reason for the rejection. +- **new_tool_params** (dict\[str, Any\] | None) – Optional set of new parameters for the tool. For example, if the user chooses to modify the tool parameters, + they can provide a new set of parameters here. + +### ToolExecutionDecision + +Decision made regarding tool execution. + +**Parameters:** + +- **tool_name** (str) – The name of the tool to be executed. +- **execute** (bool) – A boolean indicating whether to execute the tool with the provided parameters. +- **tool_call_id** (str | None) – Optional unique identifier for the tool call. This can be used to track and correlate the decision with a + specific tool invocation. +- **feedback** (str | None) – Optional feedback message. + For example, if the tool execution is rejected, this can contain the reason. Or if the tool parameters were + modified, this can contain the modification details. +- **final_tool_params** (dict\[str, Any\] | None) – Optional final parameters for the tool if execution is confirmed or modified. + +#### to_dict + +```python +to_dict() -> dict[str, Any] +``` + +Convert the ToolExecutionDecision to a dictionary representation. + +**Returns:** + +- dict\[str, Any\] – A dictionary containing the tool execution decision details. + +#### from_dict + +```python +from_dict(data: dict[str, Any]) -> ToolExecutionDecision +``` + +Populate the ToolExecutionDecision from a dictionary representation. + +**Parameters:** + +- **data** (dict\[str, Any\]) – A dictionary containing the tool execution decision details. + +**Returns:** + +- ToolExecutionDecision – An instance of ToolExecutionDecision. + +## human_in_the_loop/hooks + +### ConfirmationHook + +A `before_tool` Agent hook that applies Human-in-the-Loop confirmation strategies to pending tool calls. + +Register it on an `Agent` to confirm, modify, or reject tool calls before they run: + +```python +from haystack.components.agents import Agent +from haystack.hooks.human_in_the_loop import ( + AlwaysAskPolicy, + BlockingConfirmationStrategy, + ConfirmationHook, + NeverAskPolicy, + RichConsoleUI, + SimpleConsoleUI, +) + +hook = ConfirmationHook( + confirmation_strategies={ + "my_tool": BlockingConfirmationStrategy( + confirmation_policy=NeverAskPolicy(), confirmation_ui=SimpleConsoleUI() + ) + } +) +agent = Agent(chat_generator=..., tools=[...], hooks={"before_tool": [hook]}) +``` + +A key may be a single tool name, a tuple of tool names sharing one strategy, or the wildcard `"*"` which applies +to any tool without a more specific entry. More specific keys win, so you can set a default for all tools and +override individual ones: + +```python +hook = ConfirmationHook( + confirmation_strategies={ + "delete_file": BlockingConfirmationStrategy( + confirmation_policy=AlwaysAskPolicy(), confirmation_ui=RichConsoleUI() + ), + "*": BlockingConfirmationStrategy( + confirmation_policy=NeverAskPolicy(), confirmation_ui=SimpleConsoleUI() + ), + } +) +``` + +Request-scoped resources for the strategies (e.g. a WebSocket or queue) are passed per run via the Agent's +`hook_context` argument (`agent.run(messages=[...], hook_context={...})`) and read by the hook with +`state.data.get("hook_context")`. + +This hook only makes sense at the `before_tool` hook point, where the pending tool calls exist (between the model +requesting tools and those tools running); the Agent enforces this and raises if it is registered elsewhere. Use a +single ConfirmationHook with one entry per tool (or per tuple of tools) in `confirmation_strategies` rather than +registering several hooks. + +#### __init__ + +```python +__init__( + confirmation_strategies: dict[str | tuple[str, ...], ConfirmationStrategy], +) -> None +``` + +Initialize the hook with its per-tool confirmation strategies. + +**Parameters:** + +- **confirmation_strategies** (dict\[str | tuple\[str, ...\], ConfirmationStrategy\]) – Mapping of tool name (or a tuple of tool names) to its `ConfirmationStrategy`. + The wildcard key `"*"` applies to any tool without a more specific entry. + +#### run + +```python +run(state: State) -> None +``` + +Confirm the pending tool calls, rewriting the `messages` in `state` to reflect modifications and rejections. + +**Parameters:** + +- **state** (State) – The Agent's live `State`. Reads the available tools (`state.data.get("tools")`) and the per-run + context (`state.data.get("hook_context")`), and the pending tool calls from the last message; writes the + updated conversation back to `messages`. Reads go through `state.data` rather than `state.get`, which + deep-copies and would break non-copyable resources (e.g. a WebSocket or client) in `hook_context`. + +#### run_async + +```python +run_async(state: State) -> None +``` + +Async version of `run`. + +#### to_dict + +```python +to_dict() -> dict[str, Any] +``` + +Serialize the hook, including its confirmation strategies (tuple keys become JSON-array strings). + +#### from_dict + +```python +from_dict(data: dict[str, Any]) -> ConfirmationHook +``` + +Deserialize the hook, reconstructing its confirmation strategies. + +## human_in_the_loop/policies + +### AlwaysAskPolicy + +Bases: ConfirmationPolicy + +Always ask for confirmation. + +#### should_ask + +```python +should_ask( + tool_name: str, tool_description: str, tool_params: dict[str, Any] +) -> bool +``` + +Always ask for confirmation before executing the tool. + +**Parameters:** + +- **tool_name** (str) – The name of the tool to be executed. +- **tool_description** (str) – The description of the tool. +- **tool_params** (dict\[str, Any\]) – The parameters to be passed to the tool. + +**Returns:** + +- bool – Always returns True, indicating confirmation is needed. + +### NeverAskPolicy + +Bases: ConfirmationPolicy + +Never ask for confirmation. + +#### should_ask + +```python +should_ask( + tool_name: str, tool_description: str, tool_params: dict[str, Any] +) -> bool +``` + +Never ask for confirmation, always proceed with tool execution. + +**Parameters:** + +- **tool_name** (str) – The name of the tool to be executed. +- **tool_description** (str) – The description of the tool. +- **tool_params** (dict\[str, Any\]) – The parameters to be passed to the tool. + +**Returns:** + +- bool – Always returns False, indicating no confirmation is needed. + +### AskOncePolicy + +Bases: ConfirmationPolicy + +Ask only once per tool with specific parameters. + +#### __init__ + +```python +__init__() -> None +``` + +Creates an instance of AskOncePolicy. + +#### should_ask + +```python +should_ask( + tool_name: str, tool_description: str, tool_params: dict[str, Any] +) -> bool +``` + +Ask for confirmation only once per tool with specific parameters. + +**Parameters:** + +- **tool_name** (str) – The name of the tool to be executed. +- **tool_description** (str) – The description of the tool. +- **tool_params** (dict\[str, Any\]) – The parameters to be passed to the tool. + +**Returns:** + +- bool – True if confirmation is needed, False if already asked with the same parameters. + +#### update_after_confirmation + +```python +update_after_confirmation( + tool_name: str, + tool_description: str, + tool_params: dict[str, Any], + confirmation_result: ConfirmationUIResult, +) -> None +``` + +Store the tool and parameters if the action was "confirm" to avoid asking again. + +This method updates the internal state to remember that the user has already confirmed the execution of the +tool with the given parameters. + +**Parameters:** + +- **tool_name** (str) – The name of the tool that was executed. +- **tool_description** (str) – The description of the tool. +- **tool_params** (dict\[str, Any\]) – The parameters that were passed to the tool. +- **confirmation_result** (ConfirmationUIResult) – The result from the confirmation UI. + +## human_in_the_loop/strategies + +### BlockingConfirmationStrategy + +Confirmation strategy that blocks execution to gather user feedback. + +#### __init__ + +```python +__init__( + *, + confirmation_policy: ConfirmationPolicy, + confirmation_ui: ConfirmationUI, + reject_template: str = REJECTION_FEEDBACK_TEMPLATE, + modify_template: str = MODIFICATION_FEEDBACK_TEMPLATE, + user_feedback_template: str = USER_FEEDBACK_TEMPLATE +) -> None +``` + +Initialize the BlockingConfirmationStrategy with a confirmation policy and UI. + +**Parameters:** + +- **confirmation_policy** (ConfirmationPolicy) – The confirmation policy to determine when to ask for user confirmation. +- **confirmation_ui** (ConfirmationUI) – The user interface to interact with the user for confirmation. +- **reject_template** (str) – Template for rejection feedback messages. It should include a `{tool_name}` placeholder. +- **modify_template** (str) – Template for modification feedback messages. It should include `{tool_name}` and `{final_tool_params}` + placeholders. +- **user_feedback_template** (str) – Template for user feedback messages. It should include a `{feedback}` placeholder. + +#### run + +```python +run( + *, + tool_name: str, + tool_description: str, + tool_params: dict[str, Any], + tool_call_id: str | None = None, + confirmation_strategy_context: dict[str, Any] | None = None +) -> ToolExecutionDecision +``` + +Run the human-in-the-loop strategy for a given tool and its parameters. + +**Parameters:** + +- **tool_name** (str) – The name of the tool to be executed. +- **tool_description** (str) – The description of the tool. +- **tool_params** (dict\[str, Any\]) – The parameters to be passed to the tool. +- **tool_call_id** (str | None) – Optional unique identifier for the tool call. This can be used to track and correlate the decision with a + specific tool invocation. +- **confirmation_strategy_context** (dict\[str, Any\] | None) – Optional dictionary for passing request-scoped resources. Useful in web/server environments + to provide per-request objects (e.g., WebSocket connections, async queues, Redis pub/sub clients) + that strategies can use for non-blocking user interaction. + +**Returns:** + +- ToolExecutionDecision – A ToolExecutionDecision indicating whether to execute the tool with the given parameters, or a + feedback message if rejected. + +#### run_async + +```python +run_async( + *, + tool_name: str, + tool_description: str, + tool_params: dict[str, Any], + tool_call_id: str | None = None, + confirmation_strategy_context: dict[str, Any] | None = None +) -> ToolExecutionDecision +``` + +Async version of run. Calls the sync run() method by default. + +**Parameters:** + +- **tool_name** (str) – The name of the tool to be executed. +- **tool_description** (str) – The description of the tool. +- **tool_params** (dict\[str, Any\]) – The parameters to be passed to the tool. +- **tool_call_id** (str | None) – Optional unique identifier for the tool call. +- **confirmation_strategy_context** (dict\[str, Any\] | None) – Optional dictionary for passing request-scoped resources. + +**Returns:** + +- ToolExecutionDecision – A ToolExecutionDecision indicating whether to execute the tool with the given parameters. + +#### to_dict + +```python +to_dict() -> dict[str, Any] +``` + +Serializes the BlockingConfirmationStrategy to a dictionary. + +**Returns:** + +- dict\[str, Any\] – Dictionary with serialized data. + +#### from_dict + +```python +from_dict(data: dict[str, Any]) -> BlockingConfirmationStrategy +``` + +Deserializes the BlockingConfirmationStrategy from a dictionary. + +**Parameters:** + +- **data** (dict\[str, Any\]) – Dictionary to deserialize from. + +**Returns:** + +- BlockingConfirmationStrategy – Deserialized BlockingConfirmationStrategy. + +## human_in_the_loop/user_interfaces + +### RichConsoleUI + +Bases: ConfirmationUI + +Rich console interface for user interaction. + +#### __init__ + +```python +__init__(console: Console | None = None) -> None +``` + +Creates an instance of RichConsoleUI. + +#### get_user_confirmation + +```python +get_user_confirmation( + tool_name: str, tool_description: str, tool_params: dict[str, Any] +) -> ConfirmationUIResult +``` + +Get user confirmation for tool execution via rich console prompts. + +**Parameters:** + +- **tool_name** (str) – The name of the tool to be executed. +- **tool_description** (str) – The description of the tool. +- **tool_params** (dict\[str, Any\]) – The parameters to be passed to the tool. + +**Returns:** + +- ConfirmationUIResult – ConfirmationUIResult based on user input. + +#### to_dict + +```python +to_dict() -> dict[str, Any] +``` + +Serializes the RichConsoleConfirmationUI to a dictionary. + +**Returns:** + +- dict\[str, Any\] – Dictionary with serialized data. + +### SimpleConsoleUI + +Bases: ConfirmationUI + +Simple console interface using standard input/output. + +#### get_user_confirmation + +```python +get_user_confirmation( + tool_name: str, tool_description: str, tool_params: dict[str, Any] +) -> ConfirmationUIResult +``` + +Get user confirmation for tool execution via simple console prompts. + +**Parameters:** + +- **tool_name** (str) – The name of the tool to be executed. +- **tool_description** (str) – The description of the tool. +- **tool_params** (dict\[str, Any\]) – The parameters to be passed to the tool. + ## protocol ### Hook