Tab: Hooks
The Hooks tab attaches deterministic code to a conversation’s lifecycle. A hook is not a tool: the agent never decides whether it runs. The engine runs every enabled hook at the event it subscribes to, in a fixed order, on every turn.
Reading the hook list requires agent.governance:read. Creating, changing, or deleting a hook requires agent.governance:write.
The four lifecycle events
| Event | When it runs |
|---|---|
conversation_start | Before the model is called, on the conversation’s first persisted turn only. |
message_received | Before the model is called, on every turn. |
response_generated | After the response exists, before it is delivered. |
response_sent | After delivery, at the end of the turn. |
The two pre-model events run after the governance input gate, so a hook never observes content that governance blocked.
What a hook is made of
A hook binds one event to one hook function — a named handler registered by the engine or by an installed plugin. The catalogue of registered functions is served by GET /api/hook-functions and populates the function selector in the dialog. A hook whose function is no longer registered is flagged in the list and is skipped at runtime.
Each hook row carries:
- Event — one of the four above.
- Function — the registered hook function to execute.
- Enabled — whether the hook participates in the turn.
- Position — integer ordering. Hooks for the same event run sequentially in ascending position.
- Timeout — per-hook budget, between 1,000 ms and 30,000 ms (default 10,000 ms).
A hook function only receives the secrets it declared, and a hook whose required secrets are unconfigured is not executed — the misconfiguration is audited instead.
Failures never block the turn
The hook runner is observe-only by contract: a load error, a handler exception, or a timeout is logged and audited, and the pipeline continues. One failing hook does not stop the hooks after it, and it does not stop the reply.
The audit record keeps the outcome, duration, and error, but never the rendered arguments — those can carry personal data.
The four control returns
A hook function may return a control signal instead of just observing. The first hook to request a given signal wins; later hooks requesting the same one are ignored.
injectContext— pre-model only. Adds one-shot text to this turn’s model input (truncated at 4,000 characters). Use it to hand the model a looked-up fact without giving it a tool call.halt— pre-model only. Skips the model entirely and replies with the hook’s message. The persisted reply is badged as hook-authored.replaceResponse— post-model. Swaps the generated text for the hook’s message.regenerate— post-model. Replays the whole turn (system prompt, tools, model call) up to 5 times before the last output is delivered anyway.
replaceResponse and regenerate require the hook function to declare mutatesResponse. replaceResponse is honoured with a warning when the declaration is missing; regenerate is dropped, because a replay multiplies the turn’s cost.
Streaming caveat
replaceResponse and regenerate can only act on a response that has not left the engine yet. On a streamed turn the text has already reached the client by the time response_generated runs, so both are inert there — the dialog warns about this when you pick a post-model event. Non-streamed turns (the HTTP channel’s sync-response mode, and any turn buffered by a governance output gate) are where they take effect.
A hook’s writes to the conversation state store ride the same turn: state written by a pre-model hook is visible to the model in that turn, and the buffer is flushed when the turn commits.
Conversation-level visibility
GET /api/conversations/{conversationId}/hooks (permission conversation:read) returns the hook executions recorded for one conversation — event, function, success, duration, and any control signal requested. Use it to answer “did the hook fire on that turn, and what did it do”.
See also
- Governance — policy gates, which run before hooks on the input path.
- Conversations — where hook executions and conversation state are inspected.
- Privacy — opt-out, which is enforced before hooks run.