hooks

package
v0.4.18-beta Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 23, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package hooks provides an extensibility mechanism for agent lifecycle events. It allows external executables to observe and intercept tool calls, user messages, and agent lifecycle events for audit logging, security controls, and monitoring.

Index

Constants

View Source
const DefaultTimeout = 30 * time.Second

DefaultTimeout is the default execution timeout for hooks

Variables

This section is empty.

Functions

This section is empty.

Types

type AfterToolCallPayload

type AfterToolCallPayload struct {
	BasePayload
	ToolName   string                         `json:"tool_name"`
	ToolInput  json.RawMessage                `json:"tool_input"`
	ToolOutput tooltypes.StructuredToolResult `json:"tool_output"`
	ToolUserID string                         `json:"tool_user_id"`
}

AfterToolCallPayload is sent to after_tool_call hooks

type AfterToolCallResult

type AfterToolCallResult struct {
	Output *tooltypes.StructuredToolResult `json:"output,omitempty"`
}

AfterToolCallResult is returned by after_tool_call hooks

type AgentStopPayload

type AgentStopPayload struct {
	BasePayload
	Messages []llmtypes.Message `json:"messages"`
}

AgentStopPayload is sent to agent_stop hooks

type AgentStopResult

type AgentStopResult struct {
	// FollowUpMessages contains optional messages to append to the conversation.
	// This enables LLM-based hooks to provide feedback, ask clarifying questions,
	// or request additional actions based on the agent's work.
	FollowUpMessages []string `json:"follow_up_messages,omitempty"`
}

AgentStopResult is returned by agent_stop hooks

type BasePayload

type BasePayload struct {
	Event      HookType  `json:"event"`
	ConvID     string    `json:"conv_id"`
	CWD        string    `json:"cwd"`
	InvokedBy  InvokedBy `json:"invoked_by"`
	RecipeName string    `json:"recipe_name,omitempty"` // Active recipe name, empty if none
}

BasePayload contains fields common to all hook payloads

type BeforeToolCallPayload

type BeforeToolCallPayload struct {
	BasePayload
	ToolName   string          `json:"tool_name"`
	ToolInput  json.RawMessage `json:"tool_input"`
	ToolUserID string          `json:"tool_user_id"`
}

BeforeToolCallPayload is sent to before_tool_call hooks

type BeforeToolCallResult

type BeforeToolCallResult struct {
	Blocked bool            `json:"blocked"`
	Reason  string          `json:"reason,omitempty"`
	Input   json.RawMessage `json:"input,omitempty"`
}

BeforeToolCallResult is returned by before_tool_call hooks

type Discovery

type Discovery struct {
	// contains filtered or unexported fields
}

Discovery handles hook discovery from configured directories

func NewDiscovery

func NewDiscovery(opts ...DiscoveryOption) (*Discovery, error)

NewDiscovery creates a new hook discovery instance

func (*Discovery) DiscoverHooks

func (d *Discovery) DiscoverHooks() (map[HookType][]*Hook, error)

DiscoverHooks finds all available hooks from configured directories. Hooks from plugin directories are prefixed with "org/repo/" format. Hooks are discovered in precedence order, with higher precedence hooks shadowing lower ones.

type DiscoveryOption

type DiscoveryOption func(*Discovery) error

DiscoveryOption is a function that configures a Discovery

func WithDefaultDirs

func WithDefaultDirs() DiscoveryOption

WithDefaultDirs initializes with default hook directories including plugin directories. This provides the full precedence order: repo-local standalone > repo-local plugins > global standalone > global plugins

func WithHookDirConfigs

func WithHookDirConfigs(configs ...HookDirConfig) DiscoveryOption

WithHookDirConfigs sets custom hook directories with prefix support (for testing).

func WithHookDirs

func WithHookDirs(dirs ...string) DiscoveryOption

WithHookDirs sets custom hook directories (for testing). All directories are treated as standalone (no prefix).

type Hook

type Hook struct {
	Name     string   // Filename of the executable
	Path     string   // Full path to the executable
	HookType HookType // Type returned by "hook" command
}

Hook represents a discovered hook executable

type HookDirConfig

type HookDirConfig struct {
	Dir    string // Directory path
	Prefix string // Prefix for hook names (e.g., "org/repo/" for plugins)
}

HookDirConfig represents a directory to scan for hooks with optional prefix

type HookManager

type HookManager struct {
	// contains filtered or unexported fields
}

HookManager manages hook discovery and execution

func NewHookManager

func NewHookManager(opts ...DiscoveryOption) (HookManager, error)

NewHookManager creates a new HookManager with discovered hooks Returns an empty manager (no-op) if discovery fails

func (HookManager) AllHooks

func (m HookManager) AllHooks() []*Hook

AllHooks returns all discovered hooks regardless of type.

func (HookManager) Execute

func (m HookManager) Execute(ctx context.Context, hookType HookType, payload any) ([]byte, error)

Execute runs all hooks of a given type with the provided payload. Returns the result bytes from the last successful hook execution.

func (HookManager) ExecuteAfterToolCall

func (m HookManager) ExecuteAfterToolCall(ctx context.Context, payload AfterToolCallPayload) (*AfterToolCallResult, error)

ExecuteAfterToolCall runs after_tool_call hooks and returns typed result. Empty or nil output with exit code 0 is treated as "no modification".

func (HookManager) ExecuteAgentStop

func (m HookManager) ExecuteAgentStop(ctx context.Context, payload AgentStopPayload) (*AgentStopResult, error)

ExecuteAgentStop runs agent_stop hooks and returns typed result. Empty or nil output with exit code 0 is treated as "no follow-up". Accumulates follow_up_messages from all hooks.

func (HookManager) ExecuteBeforeToolCall

func (m HookManager) ExecuteBeforeToolCall(ctx context.Context, payload BeforeToolCallPayload) (*BeforeToolCallResult, error)

ExecuteBeforeToolCall runs before_tool_call hooks and returns typed result. Empty or nil output with exit code 0 is treated as "no action" (not blocked, no modification). Uses deny-fast semantics: if any hook blocks, execution stops immediately.

func (HookManager) ExecuteTurnEnd

func (m HookManager) ExecuteTurnEnd(ctx context.Context, payload TurnEndPayload) (*TurnEndResult, error)

ExecuteTurnEnd runs turn_end hooks. Empty or nil output with exit code 0 is treated as "no action".

func (HookManager) ExecuteUserMessageSend

func (m HookManager) ExecuteUserMessageSend(ctx context.Context, payload UserMessageSendPayload) (*UserMessageSendResult, error)

ExecuteUserMessageSend runs user_message_send hooks and returns typed result. Empty or nil output with exit code 0 is treated as "no action" (not blocked). Uses deny-fast semantics: if any hook blocks, execution stops immediately.

func (HookManager) GetHookByName

func (m HookManager) GetHookByName(name string) *Hook

GetHookByName returns a hook by its name, searching across all hook types. Returns nil if the hook is not found.

func (HookManager) GetHooks

func (m HookManager) GetHooks(hookType HookType) []*Hook

GetHooks returns all hooks registered for the given type

func (HookManager) HasHooks

func (m HookManager) HasHooks(hookType HookType) bool

HasHooks returns true if there are any hooks registered for the given type

func (*HookManager) SetTimeout

func (m *HookManager) SetTimeout(timeout time.Duration)

SetTimeout sets the execution timeout for hooks

type HookType

type HookType string

HookType represents the type of lifecycle hook

const (
	HookTypeBeforeToolCall  HookType = "before_tool_call"
	HookTypeAfterToolCall   HookType = "after_tool_call"
	HookTypeUserMessageSend HookType = "user_message_send"
	HookTypeAgentStop       HookType = "agent_stop"
	HookTypeTurnEnd         HookType = "turn_end"
)

Hook type constants define the lifecycle events that can be hooked

type InvokedBy

type InvokedBy string

InvokedBy indicates whether the hook was triggered by main agent or subagent

const (
	InvokedByMain     InvokedBy = "main"
	InvokedBySubagent InvokedBy = "subagent"
)

InvokedBy constants indicate the source of hook invocation

type Trigger

type Trigger struct {
	Manager        HookManager
	ConversationID string
	IsSubAgent     bool
	WorkingDir     string
	RecipeName     string // Active recipe name, empty if none
}

Trigger provides methods to invoke lifecycle hooks. It encapsulates the common hook triggering logic shared across LLM providers. A zero-value Trigger is safe to use and acts as a no-op.

func NewTrigger

func NewTrigger(manager HookManager, conversationID string, isSubAgent bool, args ...string) Trigger

func (*Trigger) SetConversationID

func (t *Trigger) SetConversationID(id string)

SetConversationID updates the conversation ID for the trigger. This is useful when the conversation ID is set after thread creation.

func (Trigger) TriggerAfterToolCall

func (t Trigger) TriggerAfterToolCall(ctx context.Context, toolName, toolInput, toolUserID string, toolOutput tooltypes.StructuredToolResult) *tooltypes.StructuredToolResult

TriggerAfterToolCall invokes after_tool_call hooks. Returns modified output or nil to use original. A zero-value Trigger returns nil.

func (Trigger) TriggerAgentStop

func (t Trigger) TriggerAgentStop(ctx context.Context, messages []llmtypes.Message) []string

TriggerAgentStop invokes agent_stop hooks. Returns follow-up messages that can be appended to the conversation. A zero-value Trigger returns nil.

func (Trigger) TriggerBeforeToolCall

func (t Trigger) TriggerBeforeToolCall(ctx context.Context, toolName, toolInput, toolUserID string) (bool, string, string)

TriggerBeforeToolCall invokes before_tool_call hooks. Returns (blocked, reason, input) - input is the potentially modified tool input. A zero-value Trigger returns (false, "", toolInput).

func (Trigger) TriggerTurnEnd

func (t Trigger) TriggerTurnEnd(ctx context.Context, response string, turnNumber int)

TriggerTurnEnd invokes turn_end hooks. A zero-value Trigger is a no-op.

func (Trigger) TriggerUserMessageSend

func (t Trigger) TriggerUserMessageSend(ctx context.Context, message string) (bool, string)

TriggerUserMessageSend invokes user_message_send hooks. Returns (blocked, reason). A zero-value Trigger returns (false, "").

type TurnEndPayload

type TurnEndPayload struct {
	BasePayload
	Response   string `json:"response"`    // The assistant's response text
	TurnNumber int    `json:"turn_number"` // Which turn in the conversation (1-indexed)
}

TurnEndPayload is sent when an assistant turn completes

type TurnEndResult

type TurnEndResult struct {
}

TurnEndResult is returned by turn_end hooks

type UserMessageSendPayload

type UserMessageSendPayload struct {
	BasePayload
	Message string `json:"message"`
}

UserMessageSendPayload is sent to user_message_send hooks

type UserMessageSendResult

type UserMessageSendResult struct {
	Blocked bool   `json:"blocked"`
	Reason  string `json:"reason,omitempty"`
}

UserMessageSendResult is returned by user_message_send hooks

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL