Documentation
¶
Overview ¶
Package hooks is the agent kernel's single extension mechanism: typed hook points with explicit result semantics and error policies.
A hook point is a package-level Point[E, R] descriptor carrying both type parameters, so callers write ToolCallHook.Emit(ctx, reg, ev) without spelling out E and R. The Registry stores handlers type-erased and is copy-on-write: registration takes a mutex, dispatch is a single atomic load. Tool calls run from N goroutines concurrently, so Emit must never block on registration.
Index ¶
- Variables
- type CancelResult
- type CompactEvent
- type ContextEvent
- type ContextResult
- type ErrorPolicy
- type HandlerError
- type Kind
- type Msg
- type Point
- type Reducer
- type Registry
- type RunEndEvent
- type RunStartEvent
- type RunStartResult
- type SessionEvent
- type StopReason
- type ToolCall
- type ToolCallEvent
- type ToolCallResult
- type ToolResultEvent
- type ToolResultPatch
- type Usage
Constants ¶
This section is empty.
Variables ¶
var ( SessionStart = Point[SessionEvent, struct{}]{Kind: "session_start"} SessionEnd = Point[SessionEvent, struct{}]{Kind: "session_end"} )
var BeforeCompact = Point[CompactEvent, CancelResult]{ Kind: "before_compact", Reduce: StopWhen[CompactEvent](func(r CancelResult) bool { return r.Cancel }), }
var BeforeRun = Point[RunStartEvent, RunStartResult]{ Kind: "before_run", Reduce: Fold(func(acc *RunStartResult, ev *RunStartEvent, out RunStartResult) { if out.SystemPrompt != nil { ev.SystemPrompt = *out.SystemPrompt acc.SystemPrompt = out.SystemPrompt } acc.Prepend = append(acc.Prepend, out.Prepend...) }), }
var Context = Point[ContextEvent, ContextResult]{ Kind: "context", Reduce: Fold(func(acc *ContextResult, ev *ContextEvent, out ContextResult) { if out.Messages == nil { return } ev.Messages = out.Messages acc.Messages = out.Messages }), }
var RunEnd = Point[RunEndEvent, struct{}]{Kind: "run_end"}
var ToolCallHook = Point[ToolCallEvent, ToolCallResult]{ Kind: "tool_call", OnError: FailClosed, Reduce: StopWhen[ToolCallEvent](func(r ToolCallResult) bool { return r.Block }), }
ToolCallHook is fail-closed: a handler that errors out cannot be assumed to have approved the call, so the caller must treat any error as a denial.
var ToolResult = Point[ToolResultEvent, ToolResultPatch]{ Kind: "tool_result", Reduce: Fold(func(acc *ToolResultPatch, ev *ToolResultEvent, out ToolResultPatch) { if out.Content != nil { ev.Content = *out.Content acc.Content = out.Content } if out.IsError != nil { ev.IsError = *out.IsError acc.IsError = out.IsError } if out.Terminate != nil { ev.Terminate = *out.Terminate acc.Terminate = out.Terminate } }), }
Functions ¶
This section is empty.
Types ¶
type CancelResult ¶
type CompactEvent ¶
type ContextEvent ¶
type ContextResult ¶
type ContextResult struct {
Messages []*Msg
}
ContextResult replaces the whole message list; nil means unchanged.
type ErrorPolicy ¶
type ErrorPolicy uint8
const ( ContinueOnError ErrorPolicy = iota // collect, report, keep dispatching FailClosed // first error aborts dispatch; caller must deny )
type HandlerError ¶
HandlerError attributes a failure to the handler that produced it. Handlers are registered with a mandatory source so a hook failure never has to be traced back by hand.
func (*HandlerError) Error ¶
func (e *HandlerError) Error() string
func (*HandlerError) Unwrap ¶
func (e *HandlerError) Unwrap() error
type Msg ¶
Aliases keep event definitions readable without pulling agent in (that would be an import cycle).
type Point ¶
type Point[E any, R any] struct { Kind Kind Reduce Reducer[E, R] // nil => pure observation OnError ErrorPolicy }
func (Point[E, R]) Emit ¶
Emit runs the point's handlers sequentially in registration order and folds their results through Reduce. With no handlers it returns the zero result without allocating.
func (Point[E, R]) On ¶
func (p Point[E, R]) On(r *Registry, source string, fn func(context.Context, E) (R, error)) (unsubscribe func())
On registers fn for this point and returns an idempotent unsubscribe that is safe to call from inside a dispatch. source is mandatory: an unattributable handler cannot be reported when it fails, so an empty source (or a nil fn) is a programming error and panics. A nil registry is not — hooks are optional wiring, so registration on one is a no-op.
type Reducer ¶
Reducer folds one handler result into the accumulated result. ev is a pointer so fold-style points can let the next handler observe the previous handler's change. Returning true short-circuits the remaining handlers.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
func (*Registry) AddCleanup ¶
func (r *Registry) AddCleanup(fn func()) (remove func())
AddCleanup registers a function to run on Clear. The returned remove is idempotent.
func (*Registry) Clear ¶
func (r *Registry) Clear()
Clear drops every handler and runs the registered cleanups in registration order.
func (*Registry) Has ¶
Has is the zero-handler fast path: one atomic load plus a map lookup, no locks and no allocations.
func (*Registry) SetErrorSink ¶
func (r *Registry) SetErrorSink(fn func(*HandlerError))
SetErrorSink installs the reporter for handler failures. Passing nil disables reporting; errors are still collected and returned by Emit.
type RunEndEvent ¶
type RunStartEvent ¶
type RunStartEvent struct {
SessionID string
TurnID string
AgentName string
Model string
Turn int
SystemPrompt string
ToolNames []string
}
RunStartEvent carries the config context a handler needs in flattened form, since the event type cannot reference *agent.Config.
type RunStartResult ¶
RunStartResult replaces the system prompt (nil = keep) and prepends messages to the turn.
type SessionEvent ¶
type StopReason ¶
type StopReason string
StopReason lives here rather than in agent because run_end events carry it; agent aliases these back.
const ( StopReasonCompleted StopReason = "completed" StopReasonTerminated StopReason = "terminated" StopReasonStopped StopReason = "stopped" StopReasonBudget StopReason = "budget" StopReasonError StopReason = "error" StopReasonCanceled StopReason = "canceled" )
type ToolCall ¶
Aliases keep event definitions readable without pulling agent in (that would be an import cycle).
type ToolCallEvent ¶
type ToolCallResult ¶
type ToolResultEvent ¶
type ToolResultPatch ¶
ToolResultPatch patches individual fields; nil fields are left alone.
type Usage ¶
type Usage = aop.TokenUsage
Aliases keep event definitions readable without pulling agent in (that would be an import cycle).