Documentation
¶
Overview ¶
Package hooks defines in-process extension points for the turn loop. Today it covers tool gating (approve/deny) and tool lifecycle observation; the interfaces are deliberately transport-agnostic so an external implementation (e.g. an Aether-ACL-driven approver, or an OTel observer) can satisfy the same contracts later without changing the turn loop.
Index ¶
- Constants
- Variables
- func ExecutionBranchIDFrom(ctx context.Context) (string, bool)
- func ExecutionLedgerDisabled(ctx context.Context) bool
- func NotifyTurn(ctx context.Context, ev TurnEvent, observers []TurnObserver)
- func WithExecutionBranchID(ctx context.Context, branchID string) context.Context
- func WithRecursionGuard(ctx context.Context) context.Context
- func WithoutExecutionLedger(ctx context.Context) context.Context
- type AllowList
- type CWDEvent
- type CWDWatcher
- type CommandHook
- type Config
- type Decision
- type EventName
- type Executor
- type FileChangeKind
- type FileEvent
- type HookOutput
- type Invocation
- type PollingWatcher
- type Result
- type RetryStrategy
- type Runtime
- func (r *Runtime) ApproveTool(ctx context.Context, call ToolCall) Decision
- func (r *Runtime) Dispatch(ctx context.Context, inv Invocation) ([]Result, error)
- func (r *Runtime) EmitToolEvent(ctx context.Context, event tools.ToolEvent) error
- func (r *Runtime) ObserveTurn(ctx context.Context, ev TurnEvent)
- func (r *Runtime) ToolFinished(ctx context.Context, call ToolCall, isError bool, err error)
- func (r *Runtime) ToolStarted(ctx context.Context, call ToolCall)
- type ToolApprover
- type ToolCall
- type ToolObserver
- type ToolResultObserver
- type TurnEvent
- type TurnObserver
- type TurnPhase
Constants ¶
const ( DecisionAllow = "allow" DecisionDeny = "deny" )
Variables ¶
Functions ¶
func ExecutionBranchIDFrom ¶ added in v0.0.2
ExecutionBranchIDFrom returns the turn branch carried on ctx.
func ExecutionLedgerDisabled ¶ added in v0.0.2
func NotifyTurn ¶
func NotifyTurn(ctx context.Context, ev TurnEvent, observers []TurnObserver)
NotifyTurn fans an event out to every observer, best-effort (nil-safe).
func WithExecutionBranchID ¶ added in v0.0.2
WithExecutionBranchID installs the stable branch selected for one turn.
Types ¶
type AllowList ¶
type AllowList struct {
// contains filtered or unexported fields
}
AllowList is a ToolApprover permitting only the named tools. An empty list permits everything (it is treated as "no restriction"), which is how an absent command allowed-tools frontmatter behaves.
func NewAllowList ¶
NewAllowList builds an AllowList from tool names. The reason is surfaced to the model on denial.
type CWDWatcher ¶
type CWDWatcher struct {
// contains filtered or unexported fields
}
func NewCWDWatcher ¶
func NewCWDWatcher() (*CWDWatcher, error)
type CommandHook ¶
type Decision ¶
type Decision struct {
Allow bool
Reason string // human-readable; surfaced to the model when denied
}
Decision is an approver's verdict on a tool call.
type EventName ¶
type EventName string
const ( EventPreToolUse EventName = "PreToolUse" EventPostToolUse EventName = "PostToolUse" EventPostToolUseFailure EventName = "PostToolUseFailure" EventCommand EventName = "Command" EventUserPromptSubmit EventName = "UserPromptSubmit" EventSessionStart EventName = "SessionStart" EventSessionEnd EventName = "SessionEnd" EventTaskCreated EventName = "TaskCreated" EventTaskCompleted EventName = "TaskCompleted" EventPreCompact EventName = "PreCompact" EventPostCompact EventName = "PostCompact" EventCWDChanged EventName = "CwdChanged" EventFileChanged EventName = "FileChanged" EventToolLifecycle EventName = "ToolLifecycle" )
type Executor ¶
type Executor struct {
// contains filtered or unexported fields
}
func NewExecutor ¶
func (*Executor) Dispatch ¶
func (e *Executor) Dispatch(ctx context.Context, inv Invocation, hooks []CommandHook) ([]Result, error)
type FileChangeKind ¶
type FileChangeKind string
const ( FileChangeAdd FileChangeKind = "add" FileChangeChange FileChangeKind = "change" FileChangeUnlink FileChangeKind = "unlink" )
type FileEvent ¶
type FileEvent struct {
Path string `json:"file_path"`
Kind FileChangeKind `json:"event"`
}
type HookOutput ¶
type Invocation ¶
type Invocation struct {
Event EventName `json:"event"`
Input json.RawMessage `json:"input,omitempty"`
Tool *ToolCall `json:"tool,omitempty"`
}
type PollingWatcher ¶
type PollingWatcher struct {
// contains filtered or unexported fields
}
func NewPollingWatcher ¶
func NewPollingWatcher(paths []string) (*PollingWatcher, error)
type RetryStrategy ¶ added in v0.0.2
type RetryStrategy string
RetryStrategy names what the runner is about to do about a failed provider call. It is the discriminator a renderer needs to word the notice: a model switch is a different user-facing story from waiting out a rate limit.
const ( // RetryTrimContext drops the oldest history and retries the same model. RetryTrimContext RetryStrategy = "trim_context" // RetryBackoff waits RetryIn and retries the same model. RetryBackoff RetryStrategy = "backoff" // RetryFallbackModel switches to a different model; RetryIn is zero. RetryFallbackModel RetryStrategy = "fallback_model" )
type Runtime ¶
type Runtime struct {
// contains filtered or unexported fields
}
func NewRuntime ¶
func NewRuntime(cfg Config, hooks []CommandHook) *Runtime
func (*Runtime) ApproveTool ¶
func (*Runtime) EmitToolEvent ¶
func (*Runtime) ObserveTurn ¶
ObserveTurn makes a command-hook Runtime a TurnObserver: it bridges the turn phases that HAVE a command-hook event to that event's external hooks. Phases with no corresponding event (the model-call boundaries) are dropped — the in-process TurnObserver seam still delivers them. This is what "populates" the previously-unwired UserPromptSubmit + PostCompact command-hook events.
func (*Runtime) ToolFinished ¶
type ToolApprover ¶
ToolApprover decides whether a tool call may execute. The first denial wins. External approvers (e.g. Aether-ACL-driven) implement this same interface.
type ToolCall ¶
type ToolCall struct {
CallID string
Name string
Args json.RawMessage
Addr protocol.MessageAddress
}
ToolCall is the subset of a tool invocation a hook inspects.
type ToolObserver ¶
type ToolObserver interface {
ToolStarted(ctx context.Context, call ToolCall)
ToolFinished(ctx context.Context, call ToolCall, isError bool, err error)
}
ToolObserver observes the tool lifecycle without a veto. Audit/telemetry (e.g. OTel spans) implement this.
type ToolResultObserver ¶ added in v0.0.2
type ToolResultObserver interface {
ToolResult(ctx context.Context, call ToolCall, result tools.Result, err error)
}
ToolResultObserver is an optional richer companion to ToolObserver. The turn loop calls it only after an admitted tool actually ran, allowing evidence and provenance consumers to inspect bounded result metadata without changing the existing lifecycle interface or receiving tool payload content.
type TurnEvent ¶
type TurnEvent struct {
Phase TurnPhase
Addr protocol.MessageAddress
Iteration int // tool-loop round: 0 before the first model call
Model string // model in use for this step, when known
Err error // set on model_call_finished / turn_finished on error
MessageID string // stable transcript message reference, when known
// OperationID distinguishes repeated reference/recovery events within one
// branch. Reference points at an authority-owned record without copying it.
OperationID string
Reference *tools.ResultReference
// Attempt is the 1-based ordinal of the retry about to be made, within its
// own strategy's budget. Set on PhaseProviderRetry.
Attempt int
// RetryIn is the wait the runner will observe before retrying. Zero for
// strategies that retry immediately. Set on PhaseProviderRetry.
RetryIn time.Duration
// Strategy is what the runner is about to do about the failure. Set on
// PhaseProviderRetry.
Strategy RetryStrategy
// FailureKind is the classified provider failure ("rate_limit",
// "context_overflow", …), empty when the error was not a classified
// ProviderError. Set on PhaseProviderRetry.
FailureKind string
// NextModel is the model the runner is switching to. Set only for
// RetryFallbackModel.
NextModel string
}
TurnEvent is a turn-lifecycle signal delivered to TurnObservers. It carries enough to CORRELATE and snapshot (addr, iteration, model); the message content itself lives in the history store (persisted per step via SaveHistory). Err is set on the *Finished phases when the step/turn errored.
type TurnObserver ¶
TurnObserver observes the turn lifecycle without a veto — audit, telemetry, checkpoint/sync. Best-effort: it must not block the turn, and a nil observer or empty slice is a no-op. Peer to ToolObserver (which covers the tool sub-lifecycle). A single method keyed by Phase keeps it cheap to implement (a consumer switches on the phases it cares about) and lets new phases be added without breaking implementers — the same reason the messaging spec discriminates stream events by a "phase"/"event" field.
type TurnPhase ¶
type TurnPhase string
TurnPhase identifies a point in a turn's lifecycle. It is the discriminator for TurnEvent, mirroring how EventName discriminates command-hook invocations.
const ( PhaseTurnStarted TurnPhase = "turn_started" PhaseUserPromptSubmit TurnPhase = "user_prompt_submit" PhaseModelCallStarted TurnPhase = "model_call_started" PhaseModelCallFinished TurnPhase = "model_call_finished" PhaseCompacted TurnPhase = "compacted" PhaseResourceReferenced TurnPhase = "resource_referenced" PhaseRecoveryStarted TurnPhase = "recovery_started" // PhaseProviderRetry fires when a provider call failed and the runner has // decided to try again — before the wait, so an observer can show the user // what is happening while it happens. Distinct from PhaseRecoveryStarted, // which is about resuming a turn after a process restart. PhaseProviderRetry TurnPhase = "provider_retry" PhaseTurnFinished TurnPhase = "turn_finished" )