Hooks and Agent Inputs

Hooks are Broadway flows that the runtime runs at defined points of a turn. They let you prepare the context, enforce rules around tool calls, validate the answer and control error messages — with the full power of Broadway and Fabric, and without changing the agent's prompt.

Hook flows also define the agent's inputs: the values a client must provide when it starts a conversation, such as the customer ID.

Hook Points

hooks:
  step_start: Banking_CustomerStory
  step_end: CheckAnswer
  pre_tool_call: GuardTools
  post_tool_call: AuditTools
  on_error: FriendlyError

Each value is the name of one Broadway flow in the agent's Data Product, or LU__<lu>__<flow> for a flow in another Data Product.

Hook Runs Flow receives Flow returns
step_start Before the LLM sees the user's message. Not run when a paused turn resumes. query (the user message), step_id, sessionId, agentName result: a rewritten message for the LLM. Empty leaves the message unchanged. The original text is kept as the turn's user message.
step_end After the final answer. Not run when the turn paused on a question to the user. final_answer, query, step_id, sessionId, agentName result: when not empty, the agent continues working with this text as a follow-up instruction (up to max_step_continuations, default 3).
pre_tool_call Before every tool call. tool_name, arguments, tool_call_id, iteration decision: ALLOW (default) or BLOCK.
post_tool_call After every tool call. tool_name, tool_call_id, result, duration_ms stop: true ends the run; the optional result becomes the answer. The hook cannot change the tool result seen by the LLM.
on_error When the agent run fails (not for tool errors, which are returned to the LLM). error (message, type, stackTrace), default_error_message, agentName, sessionId, step_id, iteration result: the message shown to the user.

In addition, every hook flow receives the agent inputs as externals.

Per-tool before and after hooks, configured on a single entry of tools:, use the pre_tool_call and post_tool_call contracts. See Tools.

Failure Behavior

Hooks fail closed: if a hook flow fails, the turn fails. A failing pre_tool_call hook blocks the tool call rather than allowing it. Keep hook flows simple and fast, and handle expected conditions inside the flow.

Building a Hook Flow

Each hook type has a pair of Broadway actors, found under the agent_hooks tag:

Hook First actor (inputs) Last actor (outputs)
step_start StepStartHookInput StepStartHookOutput — message → external result
step_end StepEndHookInput StepEndHookOutput — continuation → external result
pre_tool_call PreToolCallHookInput PreToolCallHookOutput — decision → external decision
post_tool_call PostToolCallHookInput PostToolCallHookOutput — stop, result → matching externals
on_error OnErrorHookInput OnErrorHookOutput — message → external result

Place the input actor first and the output actor last, and map the output actor's ports to the flow's output externals as shown.

Agent Inputs

There is no input-parameter list in agent.yaml. Instead, the external inputs declared by the agent's hook flows are the agent's inputs:

  • An external marked mandatory becomes a required input. A request without it fails ("Missing required input(s)").
  • The inputs are listed by the agents web service (input_params), shown in the Studio New chat dialog (Agent inputs).
  • Clients pass them as the initParams JSON object when calling the agent, for example {"customerId":"1001"}.
  • They are injected as externals into every hook flow and every tool flow the agent calls, and forwarded to sub-agents.

Do not declare an external with a reserved name — query, step_id, sessionId, agentName, final_answer, tool_name, arguments, tool_call_id, iteration, result, duration_ms, error, default_error_message. Such inputs are ignored, with a warning in the log.

Trusted Inputs: the AgentInitParams Actor

For a sub-agent, an input may also be supplied by the calling LLM in the task or delegate arguments, so hook externals are not a trustworthy source for authorization scope. The AgentInitParams actor returns the inputs that the client passed to the top-level agent, which the model can never change:

  • initParams — the full map; add an output named after a key (for example customerId) to read it directly.
  • sessionId, stepId, agentName, luName.

Use AgentInitParams in any hook or tool flow that needs the customer identity for data access. It works in flows that the runtime calls directly, not in their inner flows.

Example: Loading the Customer in step_start

The most common hook loads the entity the conversation is about, so the query tool works on its data. In the banking demo:

  • The main agent's step_start flow, Banking_CustomerStory, declares the mandatory external customerId, loads the customer instance with the GetWithSnap actor (which also supports evaluation snapshots), builds a short customer profile, and returns it together with the user's message as result.
  • Each sub-agent's step_start flow, LoadCustomerScope, declares the mandatory customerId and loads the instance with FabricGet.

Because both flows declare customerId as mandatory, the client must choose the customer before the first message, and the main agent's sub-agent catalog shows inputs: customerId for every specialist.

To make conversations reproducible in Evaluation, load the entity in the main agent's step_start hook with GetWithSnap, so that snapshots of the data are captured with the test case.

More Hook Examples

  • Guard a privileged tool — a pre_tool_call flow returns BLOCK when tool_name is fabric and the command is not on an allow list.
  • Audit operations — an after hook on updateCreditCardLimit writes the arguments and result to an audit table.
  • Check the answer — a step_end flow verifies that the answer does not contain account numbers and, if it does, returns "Rewrite the answer without account numbers" as a continuation.
  • Friendly errors — an on_error flow returns a localized message with a reference number.

Next article: Sessions and Context

Hooks and Agent Inputs

Hooks are Broadway flows that the runtime runs at defined points of a turn. They let you prepare the context, enforce rules around tool calls, validate the answer and control error messages — with the full power of Broadway and Fabric, and without changing the agent's prompt.

Hook flows also define the agent's inputs: the values a client must provide when it starts a conversation, such as the customer ID.

Hook Points

hooks:
  step_start: Banking_CustomerStory
  step_end: CheckAnswer
  pre_tool_call: GuardTools
  post_tool_call: AuditTools
  on_error: FriendlyError

Each value is the name of one Broadway flow in the agent's Data Product, or LU__<lu>__<flow> for a flow in another Data Product.

Hook Runs Flow receives Flow returns
step_start Before the LLM sees the user's message. Not run when a paused turn resumes. query (the user message), step_id, sessionId, agentName result: a rewritten message for the LLM. Empty leaves the message unchanged. The original text is kept as the turn's user message.
step_end After the final answer. Not run when the turn paused on a question to the user. final_answer, query, step_id, sessionId, agentName result: when not empty, the agent continues working with this text as a follow-up instruction (up to max_step_continuations, default 3).
pre_tool_call Before every tool call. tool_name, arguments, tool_call_id, iteration decision: ALLOW (default) or BLOCK.
post_tool_call After every tool call. tool_name, tool_call_id, result, duration_ms stop: true ends the run; the optional result becomes the answer. The hook cannot change the tool result seen by the LLM.
on_error When the agent run fails (not for tool errors, which are returned to the LLM). error (message, type, stackTrace), default_error_message, agentName, sessionId, step_id, iteration result: the message shown to the user.

In addition, every hook flow receives the agent inputs as externals.

Per-tool before and after hooks, configured on a single entry of tools:, use the pre_tool_call and post_tool_call contracts. See Tools.

Failure Behavior

Hooks fail closed: if a hook flow fails, the turn fails. A failing pre_tool_call hook blocks the tool call rather than allowing it. Keep hook flows simple and fast, and handle expected conditions inside the flow.

Building a Hook Flow

Each hook type has a pair of Broadway actors, found under the agent_hooks tag:

Hook First actor (inputs) Last actor (outputs)
step_start StepStartHookInput StepStartHookOutput — message → external result
step_end StepEndHookInput StepEndHookOutput — continuation → external result
pre_tool_call PreToolCallHookInput PreToolCallHookOutput — decision → external decision
post_tool_call PostToolCallHookInput PostToolCallHookOutput — stop, result → matching externals
on_error OnErrorHookInput OnErrorHookOutput — message → external result

Place the input actor first and the output actor last, and map the output actor's ports to the flow's output externals as shown.

Agent Inputs

There is no input-parameter list in agent.yaml. Instead, the external inputs declared by the agent's hook flows are the agent's inputs:

  • An external marked mandatory becomes a required input. A request without it fails ("Missing required input(s)").
  • The inputs are listed by the agents web service (input_params), shown in the Studio New chat dialog (Agent inputs).
  • Clients pass them as the initParams JSON object when calling the agent, for example {"customerId":"1001"}.
  • They are injected as externals into every hook flow and every tool flow the agent calls, and forwarded to sub-agents.

Do not declare an external with a reserved name — query, step_id, sessionId, agentName, final_answer, tool_name, arguments, tool_call_id, iteration, result, duration_ms, error, default_error_message. Such inputs are ignored, with a warning in the log.

Trusted Inputs: the AgentInitParams Actor

For a sub-agent, an input may also be supplied by the calling LLM in the task or delegate arguments, so hook externals are not a trustworthy source for authorization scope. The AgentInitParams actor returns the inputs that the client passed to the top-level agent, which the model can never change:

  • initParams — the full map; add an output named after a key (for example customerId) to read it directly.
  • sessionId, stepId, agentName, luName.

Use AgentInitParams in any hook or tool flow that needs the customer identity for data access. It works in flows that the runtime calls directly, not in their inner flows.

Example: Loading the Customer in step_start

The most common hook loads the entity the conversation is about, so the query tool works on its data. In the banking demo:

  • The main agent's step_start flow, Banking_CustomerStory, declares the mandatory external customerId, loads the customer instance with the GetWithSnap actor (which also supports evaluation snapshots), builds a short customer profile, and returns it together with the user's message as result.
  • Each sub-agent's step_start flow, LoadCustomerScope, declares the mandatory customerId and loads the instance with FabricGet.

Because both flows declare customerId as mandatory, the client must choose the customer before the first message, and the main agent's sub-agent catalog shows inputs: customerId for every specialist.

To make conversations reproducible in Evaluation, load the entity in the main agent's step_start hook with GetWithSnap, so that snapshots of the data are captured with the test case.

More Hook Examples

  • Guard a privileged tool — a pre_tool_call flow returns BLOCK when tool_name is fabric and the command is not on an allow list.
  • Audit operations — an after hook on updateCreditCardLimit writes the arguments and result to an audit table.
  • Check the answer — a step_end flow verifies that the answer does not contain account numbers and, if it does, returns "Rewrite the answer without account numbers" as a continuation.
  • Friendly errors — an on_error flow returns a localized message with a reference number.

Next article: Sessions and Context