Documentation
¶
Overview ¶
Package extensions publishes per-request extension runtime seams: the hook bus, plugin-facing service facades, and narrow views used by the executor without pulling concrete feature plugins into orchestration packages.
Grouped facade ([RequestRuntimeSnapshot]) ¶
RequestRuntimeSnapshot is an intentional grouped facade (hexagonal spec task 5.1): one immutable binding per build for hook chains plus the service families extension stages consume together—state and auxiliary requests, traffic observation and raw capture, workspace resolution, session openers, tool catalog filters, request transforms, route hint providers, completion gates, and traffic redactors. Split a consumer onto a narrower interface (for example CompletionGatesView or RequestRuntimeSnapshot.TrafficPortBundle) only when it demonstrably depends on unrelated capabilities; otherwise keep the snapshot to avoid ceremony without coupling reduction.
Composition roots construct snapshots via NewRequestRuntimeSnapshot; the executor attaches them with WithRequestRuntimeSnapshot.
Index ¶
- Constants
- Variables
- func BuildDecisionContext(views execctx.Views, stage, providerID string, opts DecisionContextOptions) policydecision.Context
- func BuildSecretDecisionEvent(meta secretguard.Meta, call *lipapi.Call, guardID string, ...) secretguard.DecisionEvent
- func CanonicalStageMetricLabels(stage, outcome string) (string, string)
- func CompletionGateBufferExceeded(limits completion.BufferLimits, n int) bool
- func CompletionGatesFromContext(ctx context.Context, fallback CompletionGatesView) []completion.Gate
- func EmitSecretGuardAudit(ctx context.Context, audit *SecretGuardAudit, meta secretguard.Meta, ...) error
- func FailurePolicyLabel(p FailurePolicy) string
- func HandleControlTool(ctx context.Context, in ControlToolHandleRequest) (controltool.Outcome, error)
- func IsContextCancellation(ctx context.Context, err error) bool
- func LegalPipelineStageNames() []string
- func LegalStageDescriptors() []feature.StageDescriptor
- func NewSubmitEvidenceFunc(ev *DecisionEvidence) hooks.SubmitEvidenceFunc
- func NewToolReactorEvidenceFunc(ev *DecisionEvidence) hooks.ToolReactorEvidenceFunc
- func PolicyErrorFromFailClosed(stage, providerID, reasonCode, clientMessage string) error
- func PolicyErrorFromMalformed(stage, providerID string, cause error) error
- func PolicyErrorFromProviderFailure(stage, providerID string, behavior policydecision.FailureBehavior, cause error) error
- func PolicyErrorFromTimeout(stage, providerID string, behavior policydecision.FailureBehavior) error
- func ProjectAttemptObservation(ctx policydecision.Context, providerID string, err error) (policydecision.Record, bool)
- func ProjectCompletionOutcome(ctx policydecision.Context, providerID string, outcome completion.Outcome) policydecision.Record
- func ProjectPreRequestDecision(ctx policydecision.Context, providerID string, decision prerequest.Decision) policydecision.Record
- func ProjectRequestTransformResult(ctx policydecision.Context, providerID string, mutated bool, err error) policydecision.Record
- func ProjectRouteHintOutcome(ctx policydecision.Context, providerID string, changed bool, err error) (policydecision.Record, bool)
- func ProjectSecretGuardDecision(ctx policydecision.Context, providerID string, decision secretguard.Decision) policydecision.Record
- func ProjectSubmitOutcome(ctx policydecision.Context, providerID string, rejected bool, ...) (policydecision.Record, bool)
- func ProjectToolCatalogOutcome(ctx policydecision.Context, providerID string, mutated bool, err error) (policydecision.Record, bool)
- func ProjectToolPolicyDecision(ctx policydecision.Context, providerID string, decision toolpolicy.Decision) policydecision.Record
- func ProjectToolReactorDecision(ctx policydecision.Context, providerID string, decision sdkhooks.ToolDecision) policydecision.Record
- func RecordStageObservation(obs StageMetrics, stage, outcome string, seconds float64, count, bytes int64)
- func RunCompactionPreserverAfterResponseRelease(ctx context.Context, log *slog.Logger, obs StageMetrics, ...) error
- func RunCompactionPreserverBeforeRequest(ctx context.Context, log *slog.Logger, obs StageMetrics, ...) error
- func RunCompactionPreserverBeforeResponseRelease(ctx context.Context, log *slog.Logger, obs StageMetrics, ...) error
- func RunCompactionPreserverRequestOpenFailed(ctx context.Context, log *slog.Logger, obs StageMetrics, ...) error
- func RunCompactionPreserverRequestOpened(ctx context.Context, log *slog.Logger, obs StageMetrics, ...) error
- func RunFinalStreamObservationStage(ctx context.Context, log *slog.Logger, obs StageMetrics, ...) error
- func RunPreRequestStage(ctx context.Context, log *slog.Logger, obs StageMetrics, ...) (err error)
- func RunRequestTransformStage(ctx context.Context, log *slog.Logger, obs StageMetrics, ...) (err error)
- func RunRouteHintStage(ctx context.Context, log *slog.Logger, providers []routehint.Provider, ...) ([]string, error)
- func RunSessionClassificationStage(ctx context.Context, log *slog.Logger, ...) session.Classification
- func RunSessionOpenStage(ctx context.Context, log *slog.Logger, obs StageMetrics, ...) session.OpenResult
- func RunToolCatalogFilterStage(ctx context.Context, log *slog.Logger, obs StageMetrics, ...) (err error)
- func RunToolPolicyStage(in ToolPolicyStageInput) (err error)
- func SafeCallReasoningObserveBytes(call *lipapi.Call) int64
- func SafeEventObserveBytes(ev lipapi.Event) int64
- func StageDescriptorByID(id string) (feature.StageDescriptor, bool)
- func StreamFinished(events []lipapi.Event) bool
- func ValidateDecisionRecord(record policydecision.Record) error
- func ValidateStageID(id string) bool
- func WithAttemptEvidence(ctx context.Context, fn AttemptEvidenceFunc) context.Context
- func WithDecisionEvidence(ctx context.Context, ev *DecisionEvidence) context.Context
- func WithRequestRuntimeSnapshot(ctx context.Context, snap *RequestRuntimeSnapshot) context.Context
- type AttemptEvidenceFunc
- type AttemptTransformStageResult
- type CompletionGateChainResult
- type CompletionGatesView
- type ControlToolHandleRequest
- type ControlToolProjection
- type ControlToolProjectionRequest
- type DecisionContextOptions
- type DecisionEvidence
- type DefaultTimeoutBudgetSource
- type EvidenceEmitter
- type FailurePolicy
- type FinalStreamObservationSession
- type ProviderTimeoutGuard
- type RequestRuntimeSnapshot
- func (s *RequestRuntimeSnapshot) AttemptTransforms() []request.AttemptTransform
- func (s *RequestRuntimeSnapshot) Aux() auxiliary.Client
- func (s *RequestRuntimeSnapshot) CompactionObservers() []compaction.Observer
- func (s *RequestRuntimeSnapshot) CompactionPreservers() []compaction.Preserver
- func (s *RequestRuntimeSnapshot) CompletionGates() []completion.Gate
- func (s *RequestRuntimeSnapshot) ControlToolProvider() controltool.Provider
- func (s *RequestRuntimeSnapshot) ControlToolProviderIdentity() (string, bool)
- func (s *RequestRuntimeSnapshot) Generation() int64
- func (s *RequestRuntimeSnapshot) HookBus() *hooks.Bus
- func (s *RequestRuntimeSnapshot) LocalTurnHandlers() []localturn.Handler
- func (s *RequestRuntimeSnapshot) LocalTurnHandlersExecution() []localturn.Handler
- func (s *RequestRuntimeSnapshot) PolicyObserver() policydecision.Observer
- func (s *RequestRuntimeSnapshot) PreRequestHandlers() []prerequest.Handler
- func (s *RequestRuntimeSnapshot) ProviderTimeoutGuard() *ProviderTimeoutGuard
- func (s *RequestRuntimeSnapshot) RawCapture() traffic.RawCaptureSink
- func (s *RequestRuntimeSnapshot) RequestTransforms() []request.Transform
- func (s *RequestRuntimeSnapshot) RouteHintProviders() []routehint.Provider
- func (s *RequestRuntimeSnapshot) SecretGuardExecutionPlane() SecretGuardPlane
- func (s *RequestRuntimeSnapshot) SecretGuardPlane() SecretGuardPlane
- func (s *RequestRuntimeSnapshot) SecretGuards() []secretguard.Guard
- func (s *RequestRuntimeSnapshot) SecretGuardsExecution() []secretguard.Guard
- func (s *RequestRuntimeSnapshot) SessionOpeners() []session.Opener
- func (s *RequestRuntimeSnapshot) State() state.Store
- func (s *RequestRuntimeSnapshot) StreamObserverFactories() []response.StreamObserverFactory
- func (s *RequestRuntimeSnapshot) TerminalDecisionProvider() terminaldecision.Provider
- func (s *RequestRuntimeSnapshot) TerminalDecisionProviderIdentity() (string, bool)
- func (s *RequestRuntimeSnapshot) TimeoutBudgetSource() TimeoutBudgetSource
- func (s *RequestRuntimeSnapshot) ToolCallFinalizers() []toolcall.Finalizer
- func (s *RequestRuntimeSnapshot) ToolCallFinalizersExecution() []toolcall.Finalizer
- func (s *RequestRuntimeSnapshot) ToolCallPolicies() []toolpolicy.Policy
- func (s *RequestRuntimeSnapshot) ToolCallPoliciesExecution() []toolpolicy.Policy
- func (s *RequestRuntimeSnapshot) ToolCatalogFilters() []toolcatalog.Filter
- func (s *RequestRuntimeSnapshot) TrafficObserver() traffic.Observer
- func (s *RequestRuntimeSnapshot) TrafficPortBundle() traffic.PortBundle
- func (s *RequestRuntimeSnapshot) TrafficRedactors() []traffic.Redactor
- func (s *RequestRuntimeSnapshot) UsageObserver() usage.Observer
- func (s *RequestRuntimeSnapshot) Workspace() workspace.Resolver
- type SecretGuardAudit
- type SecretGuardBlockInfo
- type SecretGuardDecisionMetrics
- type SecretGuardPlane
- type SnapshotOptions
- type StageCountByteMetrics
- type StageMetrics
- type StaticTimeoutBudgetSource
- type TimeoutBudgetSource
- type TimeoutResult
- func RunDecisionProviderWithDeadline[T any](ctx context.Context, deadline time.Time, call func(context.Context) (T, error)) TimeoutResult[T]
- func RunDecisionProviderWithDeadlineGuarded[T any](ctx context.Context, deadline time.Time, guard *ProviderTimeoutGuard, ...) TimeoutResult[T]
- func RunDecisionProviderWithTimeout[T any](ctx context.Context, timeout time.Duration, ...) TimeoutResult[T]
- type ToolPolicyStageInput
Constants ¶
const ( ReasonAttemptTransformInvalidDecision = "attempt_transform_invalid_decision" ReasonAttemptTransformExcluded = "attempt_transform_excluded" ReasonAttemptTransformFailure = "attempt_transform_failure" )
const ( PolicyReasonMalformed = "policy_malformed" PolicyReasonProviderFailure = "policy_provider_failure" PolicyReasonTimeout = "policy_timeout" PolicyReasonFailClosed = "policy_fail_closed" PolicyReasonDenied = "policy_denied" )
Policy error reason codes used by the conversion helpers. They are bounded safe tokens suitable for evidence and frontend classification.
const ( ReasonPreRequestPass = "prerequest_allow" ReasonPreRequestDenied = "prerequest_denied" ReasonPreRequestFailure = "prerequest_failure" ReasonPreRequestMalformed = "prerequest_malformed" ReasonSecretGuardPass = "secret_guard_pass" ReasonSecretGuardLog = "secret_guard_log" ReasonSecretGuardRedacted = "secret_guard_redacted" ReasonSecretGuardBlocked = "secret_guard_blocked" ReasonSecretGuardFailure = "secret_guard_failure" ReasonSecretGuardMalformed = "secret_guard_malformed" ReasonRequestTransformPass = "request_transform_passthrough" ReasonRequestTransformMutated = "request_transform_mutation" ReasonRequestTransformFailure = "request_transform_failure" ReasonRequestTransformMalformed = "request_transform_malformed" ReasonToolPolicyAllow = "tool_policy_allow" ReasonToolPolicyDenied = "tool_policy_denied" ReasonToolPolicyFailure = "tool_policy_failure" ReasonToolPolicyMalformed = "tool_policy_malformed" ReasonToolReactorPass = "tool_reactor_pass" ReasonToolReactorRewrite = "tool_reactor_rewrite" ReasonToolReactorReplace = "tool_reactor_replace" ReasonToolReactorSwallow = "tool_reactor_swallow" ReasonCompletionPass = "completion_pass" ReasonCompletionReplace = "completion_replace" ReasonCompletionReplay = "completion_replay" ReasonCompletionReject = "completion_reject" ReasonCompletionFailure = "completion_failure" ReasonCompletionIgnored = "completion_ignored_post_output" ReasonCompletionMalformed = "completion_malformed" ReasonSubmitAnnotated = "submit_annotated" ReasonSubmitRejected = "submit_rejected" ReasonSubmitFailure = "submit_failure" ReasonToolCatalogMutation = "tool_catalog_mutation" ReasonToolCatalogFailure = "tool_catalog_failure" ReasonToolCatalogMalformed = "tool_catalog_malformed" ReasonRouteHintChanged = "route_hint_changed" ReasonRouteHintFailure = "route_hint_failure" ReasonAttemptFailure = "attempt_failure" )
Projection reason codes. They are bounded safe tokens ([a-z0-9_.-]) suitable for evidence and frontend classification. Each stage family uses a stable reason code so observers can distinguish projected outcomes without interpreting provider semantics.
const ( CategoryAllowed = policydecision.CategoryAllowed CategorySkipped = policydecision.CategorySkipped CategoryDenied = policydecision.CategoryDenied CategoryFailure = policydecision.CategoryFailure CategoryObserved = policydecision.CategoryObserved CategoryMalformed = policydecision.CategoryMalformed )
Client categories carried on projected records. Only ClientCategory and ClientMessage are intended for frontend use; the values mirror the stable policy error categories so a projected record can be classified the same way as an explicit policy error. The canonical owner is [policydecision.Category*]; these package-level aliases preserve the pre-existing extensions API and keep wire/JSON values unchanged.
const ( StageSessionOpen = feature.StageIDSessionOpen StageToolCatalog = feature.StageIDToolCatalog StageCandidateAttemptTransform = feature.StageIDCandidateAttemptTransform StageToolEventReaction = feature.StageIDToolEventReaction StageFinalStreamObservation = feature.StageIDFinalStreamObservation )
Stage name constants for the legal pipeline (stable ids; align with pkg/lipsdk/feature). Only aliases with non-test production users are kept; tests must use feature.StageID* directly for the remaining stages.
const ( MetricsStageSessionOpen = "session_open" MetricsStageWorkspaceResolve = "workspace_resolve" MetricsStageSecretGuard = "secret_guard" MetricsStageToolCatalog = "tool_catalog" MetricsStageRequestTransform = "request_transform" MetricsStagePreRequest = "pre_request" MetricsStageCandidateAttemptTransform = "candidate_attempt_transform" MetricsStageFinalStreamObservation = "final_stream_observation" MetricsStageCompactionPreservation = "compaction_preservation" StageOutcomeOK = "ok" StageOutcomeError = "error" StageOutcomeFailOpen = "fail_open" StageOutcomeExcluded = "excluded" StageMetricLabelUnknown = "unknown" )
Metrics stage labels for observability (distinct constant names from legal pipeline ids in failure_policy.go).
const ReasonToolReactorFailure = "tool_reactor_failure"
ReasonToolReactorFailure records a tool reactor provider failure projected to shared evidence. Tool reactors run on the stream path after backend attempt is committed, so BackendAttempted is true.
const ReasonToolReactorMalformed = "tool_reactor_malformed"
ReasonToolReactorMalformed records a tool reactor rewrite/replace whose output failed runner validation. It is distinct from a provider failure: the reactor returned a decision without error, but its replacement event was structurally illegal and the runner rejected/ignored it.
Variables ¶
var ErrControlHandleFailed = errors.New("extensions: control tool handler failed")
ErrControlHandleFailed is the single static, content-free failure every provider-side control-handler problem collapses into. It exists so a caller can classify a handled control call as failed with one sentinel while the concrete cause — a provider error carrying arbitrary text, an oversized or unknown outcome, or a handler that violates the frozen SDK contract — never reaches a client surface, a log line, or a metric label.
var ErrSecretAuditDelivery = errors.New("secret_guard: audit delivery failed")
Functions ¶
func BuildDecisionContext ¶
func BuildDecisionContext(views execctx.Views, stage, providerID string, opts DecisionContextOptions) policydecision.Context
BuildDecisionContext assembles a safe, request-scoped policydecision.Context from the trusted execution views attached to an accepted request, plus stage/provider metadata, output-committed state, and the evaluation timeout budget (requirements 2.1-2.6, 7.5).
Safety properties:
- Authoritative scope comes from views.Scope (safe-by-construction: no raw credentials, headers, resume tokens, or unvetted claims). It is carried separately from the legacy views.Principal projection (requirement 2.6).
- Internal/auxiliary origin and parent trace attribution are preserved through views.Scope.Origin and views.Scope.ParentTraceID (requirement 2.4).
- Unknown optional scope fields are preserved as unknown rather than inferred from client payloads (requirement 2.2).
- The returned context is defensively cloned: mutating its maps, slices, or embedded scope cannot affect the caller's views (requirement 7.7).
The builder does not synthesize unsafe annotation entries or pull in raw request payloads; only the views' existing annotations are carried through.
func BuildSecretDecisionEvent ¶
func BuildSecretDecisionEvent( meta secretguard.Meta, call *lipapi.Call, guardID string, decision secretguard.Decision, quarantineResult string, backendDispatched bool, accessMode string, configVersion string, turnID string, now time.Time, ) secretguard.DecisionEvent
func CanonicalStageMetricLabels ¶
CanonicalStageMetricLabels collapses unbounded/sensitive stage or outcome label values to unknown so metric cardinality stays bounded (samples are kept under unknown, not dropped).
func CompletionGateBufferExceeded ¶
func CompletionGateBufferExceeded(limits completion.BufferLimits, n int) bool
CompletionGateBufferExceeded reports whether buffering should fail open to live passthrough (R8).
func CompletionGatesFromContext ¶
func CompletionGatesFromContext(ctx context.Context, fallback CompletionGatesView) []completion.Gate
CompletionGatesFromContext returns completion gates from the request snapshot on ctx when present, otherwise from fallback. Semantics match the former [runtime.retryRecvStream.completionGatesFromContext] resolution order: context snapshot first, then executor snapshot. An empty result is always a non-nil slice so callers that iterate or serialize never see nil.
func EmitSecretGuardAudit ¶
func EmitSecretGuardAudit(ctx context.Context, audit *SecretGuardAudit, meta secretguard.Meta, call *lipapi.Call, guardID string, decision secretguard.Decision, quarantineResult string, backendDispatched bool) error
func FailurePolicyLabel ¶
func FailurePolicyLabel(p FailurePolicy) string
FailurePolicyLabel returns a stable JSON label for inventory/diagnostics.
func HandleControlTool ¶
func HandleControlTool(ctx context.Context, in ControlToolHandleRequest) (controltool.Outcome, error)
HandleControlTool invokes the pinned control provider at most once for one completed, bounded call and returns a normalized, content-free outcome.
The provider call runs behind the extension safety boundary, so a panic becomes a bounded isolated-panic error rather than an attempt-level crash. Every returned outcome is re-checked with the pure SDK validator before it leaves this stage: OutcomeInvalid must carry a bounded content-free reason and no result, OutcomeComplete must carry bounded non-empty UTF-8 result text, and an unknown kind is rejected. A provider error, an invalid outcome, and an unknown kind all collapse into ErrControlHandleFailed, so no provider text, argument byte, call ID, or result byte can reach a caller, a log, or a metric.
An already-canceled context is reported as cancellation before the provider is invoked. The caller's own context is passed through unchanged: this stage adds no goroutine, no deadline, and no new timeout budget.
func IsContextCancellation ¶
IsContextCancellation reports whether err is the parent request context being canceled or expired. The policy error conversion helpers must preserve parent cancellation as cancellation and never convert it into policy denial, failure, or malformed errors (requirement 6.4).
A bare context.DeadlineExceeded is only treated as parent cancellation when the supplied parent context has actually expired, so a child evaluation-deadline error is not misclassified as parent cancellation while the parent remains active.
func LegalPipelineStageNames ¶
func LegalPipelineStageNames() []string
LegalPipelineStageNames returns the core-owned ordered list of legal extension stages (R2). Each call allocates a fresh slice; see feature.LegalPipelineStageIDs.
func LegalStageDescriptors ¶
func LegalStageDescriptors() []feature.StageDescriptor
LegalStageDescriptors returns the SDK canonical stage descriptor table (read-only).
func NewSubmitEvidenceFunc ¶
func NewSubmitEvidenceFunc(ev *DecisionEvidence) hooks.SubmitEvidenceFunc
NewSubmitEvidenceFunc returns a hooks.SubmitEvidenceFunc that projects each submit-hook outcome into shared policy decision evidence and emits it through the seam's emitter (requirements 3.5, 4.6, 9.1, 9.5).
The returned func is intended to be attached to the request context via hooks.WithSubmitEvidence so hooks.Bus.RunSubmit can invoke it per hook without importing the extensions package. A nil seam (or nil emitter) yields a func that emits nothing, preserving the no-observer/non-interference default (requirements 7.6, 10.5).
Submit hooks may mutate the canonical call, but [sdk.SubmitDecision] does not report mutation, so the projector only emits compatible evidence for representable outcomes: reject (deny/none), annotation (allow/annotate), and provider failure (error/none). A no-op hook (no reject, no error, no added annotations) has no representable policy semantics and emits nothing; runtime behavior is still preserved (requirements 9.5, 10.5).
func NewToolReactorEvidenceFunc ¶
func NewToolReactorEvidenceFunc(ev *DecisionEvidence) hooks.ToolReactorEvidenceFunc
NewToolReactorEvidenceFunc returns a hooks.ToolReactorEvidenceFunc that projects each tool-reactor decision into shared policy decision evidence and emits it through the seam's emitter (requirements 3.3, 4.3, 9.1, 9.5).
The returned func is intended to be attached to the request context via hooks.WithToolReactorEvidence so hooks.Bus.ApplyToolReactors can invoke it per reactor without importing the extensions package. A nil seam yields a func that emits nothing.
Frontend-specific tool syntax is kept out of evidence semantics: only the canonical sdkhooks.ToolDecision enum, the reactor's error, and the runner's validation error are projected. Provider failures (err != nil) project as OutcomeError/EffectNone with ReasonToolReactorFailure. Invalid rewrite/replace output (validationErr != nil) projects as OutcomeError/EffectNone with ReasonToolReactorMalformed, so a rejected mutation is never recorded as a successful allow/mutate or allow/replace. The reactor's failure behavior is left to the caller's error policy (the runner preserves existing fail-open/fail-closed behavior; evidence is a side effect).
func PolicyErrorFromFailClosed ¶
PolicyErrorFromFailClosed converts an explicit fail-closed outcome into a stable policy denial error (requirements 6.1, 6.6). reasonCode and clientMessage must be client-safe bounded values.
func PolicyErrorFromMalformed ¶
PolicyErrorFromMalformed converts a malformed-decision validation error into a stable lipapi.PolicyDecisionError of kind malformed (requirements 1.5, 6.6). cause is preserved for diagnostics only.
func PolicyErrorFromProviderFailure ¶
func PolicyErrorFromProviderFailure(stage, providerID string, behavior policydecision.FailureBehavior, cause error) error
PolicyErrorFromProviderFailure converts a provider failure into a stable policy failure error when the configured failure behavior is fail-closed (requirements 6.1, 6.5). Parent context cancellation is never converted here; the caller must check cancellation first and pass a non-cancellation cause.
func PolicyErrorFromTimeout ¶
func PolicyErrorFromTimeout(stage, providerID string, behavior policydecision.FailureBehavior) error
PolicyErrorFromTimeout converts a provider evaluation timeout into a stable policy failure error when the configured failure behavior is fail-closed (requirements 6.1, 6.3). Fail-open timeouts return nil so the caller records a skipped record instead of surfacing a denial.
func ProjectAttemptObservation ¶
func ProjectAttemptObservation(ctx policydecision.Context, providerID string, err error) (policydecision.Record, bool)
ProjectAttemptObservation projects an attempt-lifecycle observation into a shared policy decision record (requirements 1.7, 4.5, 4.6, 9.1, 9.5). Attempt lifecycle records are observational; ok=false when the attempt succeeded with no error, since a successful observation has no policy semantics to represent. The attempt stage runs after backend attempt is committed, so BackendAttempted is true.
func ProjectCompletionOutcome ¶
func ProjectCompletionOutcome(ctx policydecision.Context, providerID string, outcome completion.Outcome) policydecision.Record
ProjectCompletionOutcome projects a completion-gate outcome into a shared policy decision record (requirements 1.7, 3.4, 4.6, 9.1, 9.5). When output is already committed, a replacement outcome is ignored at runtime (completion_run.go), so the projection records skip/none with a post-output reason rather than fabricating a replace effect. Replay is unaffected by output-committed state. The completion gate runs after backend attempt is committed, so BackendAttempted is true.
func ProjectPreRequestDecision ¶
func ProjectPreRequestDecision(ctx policydecision.Context, providerID string, decision prerequest.Decision) policydecision.Record
ProjectPreRequestDecision projects a pre-request admission handler decision into a shared policy decision record (requirements 1.7, 3.1, 4.6, 9.1, 9.5). The projection is lossy-but-compatible: allow/annotate/deny map directly to the legality table for the pre-request stage. Provider failure, timeout, skip, and no-backend-attempt denial evidence are emitted by Phase 4 runtime integration through the error and timeout helpers; this helper only projects the Decision outcome.
func ProjectRequestTransformResult ¶
func ProjectRequestTransformResult(ctx policydecision.Context, providerID string, mutated bool, err error) policydecision.Record
ProjectRequestTransformResult projects a request-wide transform outcome into a shared policy decision record (requirements 1.7, 3.2, 4.6, 9.1, 9.5). mutated reports whether the transform changed the canonical call; err is the transform's returned error. Timeout and fail-open skip evidence are emitted by Phase 4 runtime integration; this helper projects pass-through, mutation, and provider failure.
func ProjectRouteHintOutcome ¶
func ProjectRouteHintOutcome(ctx policydecision.Context, providerID string, changed bool, err error) (policydecision.Record, bool)
ProjectRouteHintOutcome projects a route-hint provider outcome into a shared policy decision record (requirements 1.7, 4.5, 4.6, 9.1, 9.5). Route hints remain advisory through existing route preference contracts; the policy record does not directly mutate route plans. ok=false when the provider returned no preferred candidates and no error: an empty advisory opinion has no policy semantics to represent.
func ProjectSecretGuardDecision ¶
func ProjectSecretGuardDecision(ctx policydecision.Context, providerID string, decision secretguard.Decision) policydecision.Record
ProjectSecretGuardDecision projects a secret-guard Evaluate decision into a shared policy decision record. Findings, FailureReason, and any secret material must never appear in ClientMessage or ReasonCode (D8/D9). BackendAttempted is always false.
func ProjectSubmitOutcome ¶
func ProjectSubmitOutcome(ctx policydecision.Context, providerID string, rejected bool, annotations map[string]string, err error) (policydecision.Record, bool)
ProjectSubmitOutcome projects a submit-hook outcome into a shared policy decision record (requirements 1.7, 4.6, 9.1, 9.5). The second return value is ok=false when the outcome has no observable policy semantics to represent without inventing new submit semantics: a submit hook that neither rejected, errored, nor annotated did not produce a policy decision the shared vocabulary can describe. Runtime behavior is still preserved; callers simply skip emission when ok is false.
func ProjectToolCatalogOutcome ¶
func ProjectToolCatalogOutcome(ctx policydecision.Context, providerID string, mutated bool, err error) (policydecision.Record, bool)
ProjectToolCatalogOutcome projects a tool-catalog filter outcome into a shared policy decision record (requirements 1.7, 4.6, 9.1, 9.5). ok=false when the filter neither mutated the advertised tool list nor errored: a pure no-op filter has no policy semantics to represent. Advertised-tool mutation behavior is unchanged; the helper only records compatible evidence.
func ProjectToolPolicyDecision ¶
func ProjectToolPolicyDecision(ctx policydecision.Context, providerID string, decision toolpolicy.Decision) policydecision.Record
ProjectToolPolicyDecision projects a canonical tool-call policy decision into a shared policy decision record (requirements 1.7, 3.3, 4.6, 9.1, 9.5). The tool policy stage runs after backend attempt is committed, so BackendAttempted is true.
func ProjectToolReactorDecision ¶
func ProjectToolReactorDecision(ctx policydecision.Context, providerID string, decision sdkhooks.ToolDecision) policydecision.Record
ProjectToolReactorDecision projects a tool reactor outcome into a shared policy decision record (requirements 1.7, 3.3, 4.6, 9.1, 9.5). Frontend-specific tool syntax is kept out of evidence semantics: only the canonical ToolDecision enum is projected. Tool reactor runs after backend attempt is committed, so BackendAttempted is true.
func RecordStageObservation ¶
func RecordStageObservation(obs StageMetrics, stage, outcome string, seconds float64, count, bytes int64)
RecordStageObservation records duration and optional safe counts/bytes with bounded labels. count<=0 and bytes<=0 are ignored so sinks never receive non-positive counter adds.
func RunCompactionPreserverAfterResponseRelease ¶
func RunCompactionPreserverAfterResponseRelease( ctx context.Context, log *slog.Logger, obs StageMetrics, preservers []compaction.Preserver, ev lipapi.Event, meta compaction.PreservationMeta, services compaction.Services, ) error
RunCompactionPreserverAfterResponseRelease invokes the optional final release-commit callback in registration order. A deep-isolated canonical event is supplied so the notification cannot mutate the event already committed by the detector and released to the client.
func RunCompactionPreserverBeforeRequest ¶
func RunCompactionPreserverBeforeRequest( ctx context.Context, log *slog.Logger, obs StageMetrics, preservers []compaction.Preserver, call *lipapi.Call, preview compaction.RequestPreview, meta compaction.PreservationMeta, services compaction.Services, ) error
RunCompactionPreserverBeforeRequest invokes ordered preservation callbacks before the primary request opens. Each callback gets its own bounded clone baseline. Callback errors, panics, and invalid mutations roll back only that callback and are isolated from primary traffic; later preservers continue.
func RunCompactionPreserverBeforeResponseRelease ¶
func RunCompactionPreserverBeforeResponseRelease( ctx context.Context, log *slog.Logger, obs StageMetrics, preservers []compaction.Preserver, ev *lipapi.Event, preview compaction.ResponsePreview, meta compaction.PreservationMeta, services compaction.Services, ) error
RunCompactionPreserverBeforeResponseRelease invokes ordered final-response preservation callbacks. Each callback is transactional against the exact pre-callback event. A failed, panicking, or invalid callback is rolled back and the committed detector can therefore observe the restored final event.
func RunCompactionPreserverRequestOpenFailed ¶
func RunCompactionPreserverRequestOpenFailed( ctx context.Context, log *slog.Logger, obs StageMetrics, preservers []compaction.Preserver, meta compaction.PreservationMeta, services compaction.Services, ) error
RunCompactionPreserverRequestOpenFailed invokes the optional failed-open lifecycle callback in registration order. Only preservers implementing the additive RequestOpenFailedPreserver interface participate; errors and panics are isolated so primary open/error authority remains in core.
func RunCompactionPreserverRequestOpened ¶
func RunCompactionPreserverRequestOpened( ctx context.Context, log *slog.Logger, obs StageMetrics, preservers []compaction.Preserver, call lipapi.Call, events []compaction.Event, meta compaction.PreservationMeta, services compaction.Services, ) error
RunCompactionPreserverRequestOpened invokes preservation callbacks after the primary request has opened. The content arguments are deep-copied per callback, so callback-local mutation cannot alter primary traffic or another callback. Errors and panics are feature-local fail-open outcomes.
func RunFinalStreamObservationStage ¶
func RunFinalStreamObservationStage(ctx context.Context, log *slog.Logger, obs StageMetrics, session *FinalStreamObservationSession, ev lipapi.Event, committed bool) error
func RunPreRequestStage ¶
func RunPreRequestStage(ctx context.Context, log *slog.Logger, obs StageMetrics, handlers []prerequest.Handler, call *lipapi.Call, meta prerequest.Meta, svc prerequest.Services) (err error)
RunPreRequestStage runs admission handlers in stable order after request shaping and before route planning.
func RunRequestTransformStage ¶
func RunRequestTransformStage(ctx context.Context, log *slog.Logger, obs StageMetrics, transforms []request.Transform, call *lipapi.Call, meta request.RequestMeta, svc request.Services) (err error)
RunRequestTransformStage runs request-wide transforms in stable order (design §5, §17). Errors from handlers with FailOpen are logged and skipped; FailClosed stops the chain. The call is re-validated after the chain completes.
func RunRouteHintStage ¶
func RunRouteHintStage(ctx context.Context, log *slog.Logger, providers []routehint.Provider, call *lipapi.Call, meta routehint.Input) ([]string, error)
RunRouteHintStage invokes route hint providers with fail-open semantics (design §17 route_hinting).
func RunSessionClassificationStage ¶
func RunSessionClassificationStage(ctx context.Context, log *slog.Logger, classifier sessionclassification.Classifier, in sessionclassification.Input) session.Classification
RunSessionClassificationStage evaluates the optional SDK classifier and returns a validated projection. An existing positive classification is immutable.
func RunSessionOpenStage ¶
func RunSessionOpenStage(ctx context.Context, log *slog.Logger, obs StageMetrics, openers []session.Opener, in session.OpenInput) session.OpenResult
RunSessionOpenStage invokes session openers in registration order with fail-open semantics (design §17 session_open default).
func RunToolCatalogFilterStage ¶
func RunToolCatalogFilterStage(ctx context.Context, log *slog.Logger, obs StageMetrics, filters []toolcatalog.Filter, call *lipapi.Call, meta toolcatalog.CatalogMeta, svc toolcatalog.Services) (err error)
RunToolCatalogFilterStage runs tool catalog filters in stable order (design §4, §17). After the chain, lipapi.ReconcileToolChoiceAfterToolListChange runs once, then the call is validated.
func RunToolPolicyStage ¶
func RunToolPolicyStage(in ToolPolicyStageInput) (err error)
RunToolPolicyStage runs provider-neutral tool-call policies before tool reactors. in.Policies must already be in execution order (as produced by toolpolicy.MaterializeSorted or by RequestRuntimeSnapshot.ToolCallPoliciesExecution); the stage does not re-sort.
func SafeCallReasoningObserveBytes ¶
SafeCallReasoningObserveBytes returns aggregate reasoning payload byte lengths for a call.
func SafeEventObserveBytes ¶
SafeEventObserveBytes returns content-safe byte totals for an observed stream event.
func StageDescriptorByID ¶
func StageDescriptorByID(id string) (feature.StageDescriptor, bool)
StageDescriptorByID returns the descriptor for a legal stage id.
func StreamFinished ¶
StreamFinished reports whether the canonical stream reached a terminal completion marker.
func ValidateDecisionRecord ¶
func ValidateDecisionRecord(record policydecision.Record) error
ValidateDecisionRecord is a thin compatibility wrapper that delegates to policydecision.ValidateRecord. It is retained because existing tests and runtime integration call it directly; new callers should use the SDK validator (requirements 1.5, 3.6, 4.4, 6.6).
func ValidateStageID ¶
ValidateStageID reports whether id is a legal pipeline stage.
func WithAttemptEvidence ¶
func WithAttemptEvidence(ctx context.Context, fn AttemptEvidenceFunc) context.Context
WithAttemptEvidence attaches fn to ctx so the runtime attempt-record boundary can emit per-attempt policy decision evidence. A nil fn means no evidence is emitted.
func WithDecisionEvidence ¶
func WithDecisionEvidence(ctx context.Context, ev *DecisionEvidence) context.Context
WithDecisionEvidence attaches ev to ctx so stage runners can project and emit per-provider policy decision evidence. A nil ev means no evidence is emitted.
func WithRequestRuntimeSnapshot ¶
func WithRequestRuntimeSnapshot(ctx context.Context, snap *RequestRuntimeSnapshot) context.Context
WithRequestRuntimeSnapshot attaches snap to ctx for the remainder of the request lifetime. snap must remain valid and unchanged for the lifetime of ctx (see RequestRuntimeSnapshot).
Types ¶
type AttemptEvidenceFunc ¶
AttemptEvidenceFunc projects an attempt-lifecycle failure into shared policy decision evidence when attached to the request context. It is invoked at the attempt-record boundary (the narrow runtime seam) for attempt failures that ProjectAttemptObservation can represent. Implementations must not change retry/failover behavior or no-output/failover invariants; evidence emission is a side effect isolated from request execution.
The func is defined in extensions (not a context seam in hooks) because the attempt lifecycle runner lives in internal/core/runtime, which already imports extensions. Carrying it on the context preserves the no-observer/ non-interference default: when no seam is attached, no evidence is emitted (requirements 7.6, 10.5).
A nil fn means no evidence is emitted.
func AttemptEvidenceFromContext ¶
func AttemptEvidenceFromContext(ctx context.Context) AttemptEvidenceFunc
AttemptEvidenceFromContext returns the evidence func attached by WithAttemptEvidence, or nil when none is attached.
func NewAttemptEvidenceFunc ¶
func NewAttemptEvidenceFunc(ev *DecisionEvidence) AttemptEvidenceFunc
NewAttemptEvidenceFunc returns an AttemptEvidenceFunc that projects an attempt-lifecycle failure into shared policy decision evidence and emits it through the seam's emitter (requirements 3.6, 4.5, 7.2, 7.5).
The returned func is intended to be attached to the request context via WithAttemptEvidence by the stream path so the attempt-record boundary can invoke it for attempt failures. A nil seam (or nil emitter) yields a func that emits nothing, preserving the no-observer/non-interference default (requirements 7.6, 10.5).
A successful attempt (err == nil) has no representable policy semantics and emits nothing; runtime behavior is still preserved (requirements 9.5, 10.5). The attempt stage runs after backend attempt is committed, so BackendAttempted is true on projected records.
type AttemptTransformStageResult ¶
func RunCandidateAttemptTransformStage ¶
func RunCandidateAttemptTransformStage( ctx context.Context, log *slog.Logger, obs StageMetrics, transforms []request.AttemptTransform, call *lipapi.Call, meta request.AttemptMeta, svc request.Services, ) (res AttemptTransformStageResult, err error)
type CompletionGateChainResult ¶
type CompletionGateChainResult struct {
Events []lipapi.Event
Replaced bool // true when OutcomeReplace was applied (not ignored after output commitment)
// EffectiveReplacement is the FINAL provenance of Events, not the historical
// fact that some gate once replaced the stream.
//
// Replaced stays true once any effective replacement happened, because
// existing consumers read it as historical evidence that replacement was
// requested. It cannot describe the effective output, though: a later
// ReplayOriginal restores the augmented original while Replaced stays true.
// EffectiveReplacement therefore tracks the last effective action: true after
// an applied Replace, false after a ReplayOriginal, and unchanged after
// PassOriginal. It is private provenance for the internal response owner; no
// public tag, event field, or wire projection depends on it.
EffectiveReplacement bool
}
CompletionGateChainResult is the outcome of running completion gates over a buffered stream.
func ApplyCompletionGateChain ¶
func ApplyCompletionGateChain(ctx context.Context, gates []completion.Gate, meta completion.Meta, original []lipapi.Event, outputCommitted bool, svc completion.Services, log *slog.Logger) (CompletionGateChainResult, error)
ApplyCompletionGateChain runs sorted gates over the buffered completion (design §6, §17). When outputCommitted is true, replacement outcomes are ignored (original buffer preserved). Handler errors honor per-gate FailureMode; the stage default is fail-open (see DefaultFailurePolicyForStage). log may be nil; when set, completion-gate panics are logged via [logFailOpenExtensionPanic] before they are returned to the runtime stream boundary (panics are not swallowed by fail-open policy).
type CompletionGatesView ¶
type CompletionGatesView interface {
CompletionGates() []completion.Gate
}
CompletionGatesView is the narrow extension seam for completion-gate discovery (hexagonal task 5.1). Callers that only need gates should depend on this interface rather than the full snapshot.
type ControlToolHandleRequest ¶
type ControlToolHandleRequest struct {
// ProviderID is the generation-frozen identity that admitted the projection.
// It is revalidated here so an unnamed owner can never handle a call.
ProviderID string
// Provider is the pinned generation provider instance. The caller must branch
// on absence before calling, because this stage always calls Handle.
Provider controltool.Provider
// Call is the one already-captured, bounded completion. Its bytes are owned by
// the caller: they are validated against MaxArgsBytes and handed to the
// provider by value, and are never logged, echoed, or retained here.
Call controltool.CompletedCall
// Meta is the frozen request/attempt provenance handed to the provider. The
// platform owns it; the provider cannot mutate it.
Meta controltool.Meta
// MaxArgsBytes is the frozen args budget from the approved projection. It is
// the only budget this stage applies, and it is never recomputed from a spec,
// a request, or a wire event.
MaxArgsBytes int
}
ControlToolHandleRequest is the generic input of the single bounded control-handler stage. Every field is frozen request/attempt provenance the caller already captured when it admitted the control contract: this stage never re-resolves a runtime snapshot, never calls Provider.ID or Provider.Spec, and never re-derives capability eligibility.
type ControlToolProjection ¶
type ControlToolProjection struct {
// ProviderID is the validated frozen identity of the pinned provider.
ProviderID string
// Provider is the pinned generation provider. It is retained so later
// response handling addresses the same generation instance, never a
// re-resolved one.
Provider controltool.Provider
// Projection is the immutable approved projection. An inactive projection
// keeps its bounded reason and never claims a proxy-owned control call.
Projection controltool.Projection
}
ControlToolProjection is the trusted, in-process result of one control projection. Everything it holds is deep-owned and request/attempt-local: it is never canonical Extensions, never serialized frontend or backend metadata, and never reconstructed from a tool name observed on the wire.
func ProjectControlTool ¶
func ProjectControlTool(in ControlToolProjectionRequest) (lipapi.Call, ControlToolProjection, error)
ProjectControlTool runs the single generic control-projection decision for one candidate call and returns the backend-effective call plus the trusted activation the caller must own for the rest of the attempt.
The provider spec is read exactly once per candidate behind the extension safety boundary, so a provider panic becomes a bounded, content-free error instead of a candidate mutation or a client-visible failure. The pure projection owns eligibility and the byte-stable contract, so this stage adds no tool-name, feature-name, or eligibility policy of its own.
An invalid spec is a generation defect, not a per-request best effort: it is returned as an error and the call is returned unchanged. Ordinary ineligibility is not an error; the projection carries its bounded reason and the call is returned exactly as supplied.
func (ControlToolProjection) Active ¶
func (p ControlToolProjection) Active() bool
Active reports whether the control tool and instruction were approved for the projected candidate.
func (ControlToolProjection) Reason ¶
func (p ControlToolProjection) Reason() string
Reason returns the bounded, content-free reason an inactive projection carries.
type ControlToolProjectionRequest ¶
type ControlToolProjectionRequest struct {
// ProviderID is the frozen identity of the generation control-tool provider.
// It is validated here so an unnamed owner can never project a contract.
ProviderID string
// Provider is the generation provider. The caller must branch on snapshot
// absence before calling, because this stage always calls the provider.
Provider controltool.Provider
// Call is the candidate call after ordinary request mutation.
Call lipapi.Call
// Caps are the candidate's own resolved backend capabilities. They are
// eligibility input for the optional control feature, never authoritative
// admission or accounting; the caller's own rederive stays authoritative.
Caps lipapi.BackendCaps
}
ControlToolProjectionRequest is the generic input of the one bounded control-projection decision taken for a single candidate call. It carries no client-derived provenance: ProviderID is the generation-frozen identity the caller already pinned, and Provider is the provider that same generation admitted.
type DecisionContextOptions ¶
type DecisionContextOptions struct {
// OutputCommitted records whether client-visible output has already been committed for
// this request (completion/stream-stage decisions). False for pre-backend stages.
OutputCommitted bool
// EvaluationTimeout is the configured decision-provider evaluation budget for the
// target stage/provider. Zero means no new timeout is applied (legacy behavior).
EvaluationTimeout time.Duration
// EvaluationDeadline is the derived evaluation deadline (now + EvaluationTimeout). Zero
// means no deadline is applied.
EvaluationDeadline time.Time
}
DecisionContextOptions carries the non-view inputs needed to assemble a policydecision.Context: lifecycle state and the evaluation timeout budget for the target stage/provider (requirements 2.1, 6.3). All fields are optional; zero values preserve legacy/local-anonymous semantics.
type DecisionEvidence ¶
type DecisionEvidence struct {
Emitter *EvidenceEmitter
Views execctx.Views
TimeoutBudget TimeoutBudgetSource
TimeoutGuard *ProviderTimeoutGuard
// OutputCommittedSource, when non-nil, returns the current client-visible
// output-committed state for stream-stage evidence. It is consulted by
// decisionContextFor only to escalate a caller-supplied false to true (never
// to downgrade an explicit true), so callers that already know the
// authoritative committed state (e.g. the completion gate) are unaffected.
//
// The func is invoked fresh on each evidence emission; runtime context caching
// must not snapshot its result, so a stream whose commitment state changes
// mid-flight is never recorded with a stale bool. nil preserves pre-backend
// behavior (OutputCommitted stays false).
OutputCommittedSource func() bool
}
DecisionEvidence is the request-scoped policy decision evidence seam carried through the context for stage runners (requirements 3.1-3.6, 4.1-4.4, 7.6). It binds the evidence emitter to the safe execution views and timeout budget source the runners use to build policydecision.Context per provider.
Stage runners look this up via DecisionEvidenceFromContext. When absent (or when Emitter is nil), runners emit no evidence, preserving the no-observer/non-interference default (requirements 9.1, 10.5).
Views carries the authoritative safe attribution used to build decision contexts. For pre-backend stages the runtime attaches a pre-backend views snapshot here (execctx views are not yet on the context). For stream stages the runtime may leave Views zero; the helper prefers execctx views already attached to the context when present.
func DecisionEvidenceFromContext ¶
func DecisionEvidenceFromContext(ctx context.Context) *DecisionEvidence
DecisionEvidenceFromContext returns the evidence seam attached by WithDecisionEvidence, or nil when none is attached.
func (*DecisionEvidence) WithViews ¶
func (ev *DecisionEvidence) WithViews(views execctx.Views) *DecisionEvidence
WithViews returns a copy of ev with Views replaced by views. The Emitter, TimeoutBudget and OutputCommittedSource are shared so callers can refresh the safe attribution snapshot between phases (e.g. submit vs post-submit pre-backend stages) without rebuilding the seam or re-resolving the emitter. Returns nil when ev is nil so callers can chain on an absent seam.
type DefaultTimeoutBudgetSource ¶
type DefaultTimeoutBudgetSource struct{}
DefaultTimeoutBudgetSource returns a zero budget for every stage/provider, preserving legacy extension behavior (requirement 6.3, 10.5).
func (DefaultTimeoutBudgetSource) TimeoutFor ¶
func (DefaultTimeoutBudgetSource) TimeoutFor(string, string) time.Duration
TimeoutFor returns zero for every stage/provider.
type EvidenceEmitter ¶
type EvidenceEmitter struct {
// contains filtered or unexported fields
}
EvidenceEmitter delivers bounded, normalized policy decision records to the configured policy observer and structured logs (requirements 7.1, 7.3, 7.4, 7.6, 7.7). Observer failures and log failures are isolated from request execution in this spec: a misbehaving observer or sink cannot change runtime outcomes.
Privileged-visibility gating: records marked EvidencePrivileged are withheld from the observer and structured logs unless DiagnosticsEnabled is true. Default (EvidenceDefault) records are always eligible for emission after normalization.
High-cardinality values such as trace and leg identifiers may be structured log attributes but must not become metric labels (this emitter does not emit metrics).
func NewEvidenceEmitter ¶
func NewEvidenceEmitter(obs policydecision.Observer, logger *slog.Logger, diagnosticsEnabled bool) *EvidenceEmitter
NewEvidenceEmitter returns an emitter that delivers records to obs (defaulting to policydecision.NoopObserver when nil) and to logger when non-nil. diagnosticsEnabled controls whether privileged-visibility records may leave the core (requirement 7.4).
func (*EvidenceEmitter) DiagnosticsEnabled ¶
func (e *EvidenceEmitter) DiagnosticsEnabled() bool
DiagnosticsEnabled reports whether privileged-visibility records may leave the core through this emitter.
func (*EvidenceEmitter) Emit ¶
func (e *EvidenceEmitter) Emit(ctx context.Context, record policydecision.Record)
Emit normalizes record and delivers it to the observer and structured logs. Privileged records are withheld unless diagnostics is enabled. Illegal records (unknown stage/outcome/effect or illegal outcome/effect pair) are dropped before normalization and delivery; the drop is logged at warn level with bounded fields and never changes request execution (requirements 1.5, 6.6, 7.3, 7.6, 7.7). The drop log is a distinct sink call, not a recursive Emit, so a malformed record cannot trigger further emission. Observer and log failures are ignored so request execution is unaffected. ctx is passed to the observer for its own lifecycle; ctx is never stored.
func (*EvidenceEmitter) Observer ¶
func (e *EvidenceEmitter) Observer() policydecision.Observer
Observer returns the bound policy observer (for composition roots that want to fan out additional observers).
type FailurePolicy ¶
type FailurePolicy uint8
FailurePolicy describes default runner behavior when a stage handler errors (design section 17).
const ( // FailurePolicyUnset means the stage id is not in the legal pipeline. FailurePolicyUnset FailurePolicy = iota FailurePolicyFailOpen FailurePolicyFailClosed )
func DefaultFailurePolicyForStage ¶
func DefaultFailurePolicyForStage(stage string) FailurePolicy
DefaultFailurePolicyForStage returns the documented default for the stage (design section 17).
type FinalStreamObservationSession ¶
type FinalStreamObservationSession struct {
Log *slog.Logger
Metrics StageMetrics
// contains filtered or unexported fields
}
func (*FinalStreamObservationSession) Finish ¶
func (s *FinalStreamObservationSession) Finish(parentCtx context.Context, outcome response.StreamOutcome)
func (*FinalStreamObservationSession) Open ¶
func (s *FinalStreamObservationSession) Open(ctx context.Context, factories []response.StreamObserverFactory, meta response.StreamMeta, svc response.Services) error
type ProviderTimeoutGuard ¶
type ProviderTimeoutGuard struct {
// contains filtered or unexported fields
}
ProviderTimeoutGuard bounds in-process providers that ignore context cancellation. It permits at most one bounded goroutine per stage/provider in a runtime snapshot, so an uncooperative provider cannot accumulate one leaked goroutine per request.
func NewProviderTimeoutGuard ¶
func NewProviderTimeoutGuard() *ProviderTimeoutGuard
NewProviderTimeoutGuard returns an empty guard for one runtime snapshot.
func (*ProviderTimeoutGuard) TryEnter ¶
func (g *ProviderTimeoutGuard) TryEnter(stage, providerID string) bool
TryEnter reserves a bounded call slot for stage/provider. A nil guard permits the call. A false result means a bounded goroutine for the same stage/provider is already running.
type RequestRuntimeSnapshot ¶
type RequestRuntimeSnapshot struct {
// contains filtered or unexported fields
}
RequestRuntimeSnapshot is a per-build binding of hook chains and service facades published onto each request context (design §15B, task 4.2). Many request goroutines may read the same pointer without synchronization; callers must treat it as frozen after construction: do not replace fields, mutate the embedded *hooks.Bus, or swap facade implementations. Config reload or rebinding must publish a new snapshot (new RequestRuntimeSnapshot value and new executor wiring from github.com/matdev83/go-llm-interactive-proxy/internal/infra/runtimebundle.Build).
func NewRequestRuntimeSnapshot ¶
func NewRequestRuntimeSnapshot(bus *hooks.Bus, opts SnapshotOptions) *RequestRuntimeSnapshot
NewRequestRuntimeSnapshot captures bus and facades for the lifetime of the returned value. bus must be non-nil (or replaced with hooks.New empty bus). The same *hooks.Bus must not be mutated after this call if the snapshot is shared across concurrent requests.
func RequestRuntimeSnapshotFromContext ¶
func RequestRuntimeSnapshotFromContext(ctx context.Context) *RequestRuntimeSnapshot
RequestRuntimeSnapshotFromContext returns the snapshot from WithRequestRuntimeSnapshot, if any.
func (*RequestRuntimeSnapshot) AttemptTransforms ¶
func (s *RequestRuntimeSnapshot) AttemptTransforms() []request.AttemptTransform
AttemptTransforms returns a defensive copy of frozen candidate attempt transforms (may be empty).
func (*RequestRuntimeSnapshot) Aux ¶
func (s *RequestRuntimeSnapshot) Aux() auxiliary.Client
Aux returns the auxiliary request client for this snapshot.
func (*RequestRuntimeSnapshot) CompactionObservers ¶
func (s *RequestRuntimeSnapshot) CompactionObservers() []compaction.Observer
CompactionObservers returns a defensive copy of the frozen compaction observer slice (may be empty). Mutating the returned slice does not affect the snapshot; the snapshot's internal backing slice must never be mutated.
func (*RequestRuntimeSnapshot) CompactionPreservers ¶
func (s *RequestRuntimeSnapshot) CompactionPreservers() []compaction.Preserver
CompactionPreservers returns a defensive copy of the frozen content-bearing preservation callback slice. Mutating the returned slice does not affect the snapshot.
func (*RequestRuntimeSnapshot) CompletionGates ¶
func (s *RequestRuntimeSnapshot) CompletionGates() []completion.Gate
CompletionGates returns a defensive copy of frozen completion gates (may be empty).
func (*RequestRuntimeSnapshot) ControlToolProvider ¶
func (s *RequestRuntimeSnapshot) ControlToolProvider() controltool.Provider
ControlToolProvider returns the generation proxy-owned model control tool provider captured by this immutable request snapshot, or nil when the generation admits no control tool. An absent provider requires zero provider method calls: callers must branch on the nil result rather than invoking it.
func (*RequestRuntimeSnapshot) ControlToolProviderIdentity ¶
func (s *RequestRuntimeSnapshot) ControlToolProviderIdentity() (string, bool)
ControlToolProviderIdentity returns the frozen identity of the generation control-tool provider captured by this immutable request snapshot, if present. It reads validated cached identity metadata and never invokes a live provider method, so a request path can pin the generation and honor plugin suppression without resolving a spec. An occupied plane without a frozen identity fails closed: a generation that cannot name its control-tool owner has no provable provenance.
func (*RequestRuntimeSnapshot) Generation ¶
func (s *RequestRuntimeSnapshot) Generation() int64
Generation is an opaque build stamp (e.g. config reload generation in a future spec).
func (*RequestRuntimeSnapshot) HookBus ¶
func (s *RequestRuntimeSnapshot) HookBus() *hooks.Bus
HookBus returns the hook bus bound at snapshot construction (brownfield compatibility).
func (*RequestRuntimeSnapshot) LocalTurnHandlers ¶
func (s *RequestRuntimeSnapshot) LocalTurnHandlers() []localturn.Handler
LocalTurnHandlers returns a defensive copy of frozen local-turn handlers (may be empty). Mutating the returned slice does not affect the snapshot.
func (*RequestRuntimeSnapshot) LocalTurnHandlersExecution ¶
func (s *RequestRuntimeSnapshot) LocalTurnHandlersExecution() []localturn.Handler
LocalTurnHandlersExecution returns the frozen local-turn handler slice in execution order (sorted by Order then ID). The returned slice must not be mutated.
func (*RequestRuntimeSnapshot) PolicyObserver ¶
func (s *RequestRuntimeSnapshot) PolicyObserver() policydecision.Observer
PolicyObserver returns the frozen policy decision observer bound at snapshot construction (requirements 7.6, 10.5). A nil snapshot returns the disabled no-op default so callers can always invoke the returned observer without nil checks. The returned observer is an interface value; it is treated as frozen for the lifetime of the snapshot.
func (*RequestRuntimeSnapshot) PreRequestHandlers ¶
func (s *RequestRuntimeSnapshot) PreRequestHandlers() []prerequest.Handler
PreRequestHandlers returns a defensive copy of frozen pre-request admission handlers (may be empty).
func (*RequestRuntimeSnapshot) ProviderTimeoutGuard ¶
func (s *RequestRuntimeSnapshot) ProviderTimeoutGuard() *ProviderTimeoutGuard
ProviderTimeoutGuard returns the snapshot-scoped guard used to contain uncooperative bounded providers. It is shared across requests for this immutable snapshot so one stuck stage/provider cannot accumulate one goroutine per request.
func (*RequestRuntimeSnapshot) RawCapture ¶
func (s *RequestRuntimeSnapshot) RawCapture() traffic.RawCaptureSink
RawCapture returns the privileged raw capture sink for this snapshot.
func (*RequestRuntimeSnapshot) RequestTransforms ¶
func (s *RequestRuntimeSnapshot) RequestTransforms() []request.Transform
RequestTransforms returns a defensive copy of frozen request-wide transforms (may be empty).
func (*RequestRuntimeSnapshot) RouteHintProviders ¶
func (s *RequestRuntimeSnapshot) RouteHintProviders() []routehint.Provider
RouteHintProviders returns a defensive copy of frozen route hint providers (may be empty).
func (*RequestRuntimeSnapshot) SecretGuardExecutionPlane ¶
func (s *RequestRuntimeSnapshot) SecretGuardExecutionPlane() SecretGuardPlane
SecretGuardExecutionPlane returns the frozen secret-guard plane without cloning the guard slice. MatcherResolver, DecisionObserver, and policy/config fields are safe to read; Guards is the snapshot's internal backing store in MaterializeSorted order and must not be mutated.
func (*RequestRuntimeSnapshot) SecretGuardPlane ¶
func (s *RequestRuntimeSnapshot) SecretGuardPlane() SecretGuardPlane
SecretGuardPlane returns a defensive copy of the SecretGuardPlane configuration (guards slice cloned). Prefer RequestRuntimeSnapshot.SecretGuardExecutionPlane for the runtime executor hot path.
func (*RequestRuntimeSnapshot) SecretGuards ¶
func (s *RequestRuntimeSnapshot) SecretGuards() []secretguard.Guard
SecretGuards returns a defensive copy of the frozen secret guard slice.
func (*RequestRuntimeSnapshot) SecretGuardsExecution ¶
func (s *RequestRuntimeSnapshot) SecretGuardsExecution() []secretguard.Guard
SecretGuardsExecution returns the frozen secret guard slice without cloning.
func (*RequestRuntimeSnapshot) SessionOpeners ¶
func (s *RequestRuntimeSnapshot) SessionOpeners() []session.Opener
SessionOpeners returns a defensive copy of the frozen session-open stage handlers (may be empty). Mutating the returned slice does not affect the snapshot.
func (*RequestRuntimeSnapshot) State ¶
func (s *RequestRuntimeSnapshot) State() state.Store
State returns the plugin state facade for this snapshot.
func (*RequestRuntimeSnapshot) StreamObserverFactories ¶
func (s *RequestRuntimeSnapshot) StreamObserverFactories() []response.StreamObserverFactory
StreamObserverFactories returns a defensive copy of frozen stream observer factories (may be empty).
func (*RequestRuntimeSnapshot) TerminalDecisionProvider ¶
func (s *RequestRuntimeSnapshot) TerminalDecisionProvider() terminaldecision.Provider
TerminalDecisionProvider returns the generation provider captured by this immutable request snapshot, or nil when no provider is active.
func (*RequestRuntimeSnapshot) TerminalDecisionProviderIdentity ¶
func (s *RequestRuntimeSnapshot) TerminalDecisionProviderIdentity() (string, bool)
TerminalDecisionProviderIdentity returns the frozen identity of the generation provider captured by this immutable request snapshot, if present.
func (*RequestRuntimeSnapshot) TimeoutBudgetSource ¶
func (s *RequestRuntimeSnapshot) TimeoutBudgetSource() TimeoutBudgetSource
TimeoutBudgetSource returns the frozen per-request decision-provider timeout budget source bound at snapshot construction (requirements 6.3, 10.5). A nil snapshot returns the default zero-budget source so callers can always invoke TimeoutFor without nil checks.
func (*RequestRuntimeSnapshot) ToolCallFinalizers ¶
func (s *RequestRuntimeSnapshot) ToolCallFinalizers() []toolcall.Finalizer
func (*RequestRuntimeSnapshot) ToolCallFinalizersExecution ¶
func (s *RequestRuntimeSnapshot) ToolCallFinalizersExecution() []toolcall.Finalizer
func (*RequestRuntimeSnapshot) ToolCallPolicies ¶
func (s *RequestRuntimeSnapshot) ToolCallPolicies() []toolpolicy.Policy
ToolCallPolicies returns a defensive copy of frozen tool-call policies (may be empty). Mutating the returned slice does not affect the snapshot.
func (*RequestRuntimeSnapshot) ToolCallPoliciesExecution ¶
func (s *RequestRuntimeSnapshot) ToolCallPoliciesExecution() []toolpolicy.Policy
ToolCallPoliciesExecution returns the frozen tool-call policy slice in execution order (the same ordering as toolpolicy.MaterializeSorted). The returned slice must not be mutated; it is the snapshot's internal backing store. Prefer RequestRuntimeSnapshot.ToolCallPolicies for a defensive copy; this accessor exists for the runtime executor hot path.
func (*RequestRuntimeSnapshot) ToolCatalogFilters ¶
func (s *RequestRuntimeSnapshot) ToolCatalogFilters() []toolcatalog.Filter
ToolCatalogFilters returns a defensive copy of frozen catalog filters (may be empty).
func (*RequestRuntimeSnapshot) TrafficObserver ¶
func (s *RequestRuntimeSnapshot) TrafficObserver() traffic.Observer
TrafficObserver returns the structured traffic observer for this snapshot.
func (*RequestRuntimeSnapshot) TrafficPortBundle ¶
func (s *RequestRuntimeSnapshot) TrafficPortBundle() traffic.PortBundle
TrafficPortBundle returns the frozen traffic emission triple for this snapshot (hexagonal task 5.1). Prefer this method over ad-hoc field access when only traffic observation ports are needed.
func (*RequestRuntimeSnapshot) TrafficRedactors ¶
func (s *RequestRuntimeSnapshot) TrafficRedactors() []traffic.Redactor
TrafficRedactors returns a defensive copy of frozen redactors for the traffic pipeline (may be empty).
func (*RequestRuntimeSnapshot) UsageObserver ¶
func (s *RequestRuntimeSnapshot) UsageObserver() usage.Observer
UsageObserver returns the usage observer for this snapshot.
func (*RequestRuntimeSnapshot) Workspace ¶
func (s *RequestRuntimeSnapshot) Workspace() workspace.Resolver
Workspace returns the workspace resolver for this snapshot.
type SecretGuardAudit ¶
type SecretGuardBlockInfo ¶
type SecretGuardBlockInfo struct {
GuardID string
Decision secretguard.Decision
}
func RunSecretGuardStage ¶
func RunSecretGuardStage(ctx context.Context, log *slog.Logger, obs StageMetrics, guards []secretguard.Guard, call *lipapi.Call, meta secretguard.Meta, svc secretguard.Services, audit *SecretGuardAudit, decisionMetrics SecretGuardDecisionMetrics) (block *SecretGuardBlockInfo, err error)
RunSecretGuardStage evaluates secret guards in caller-provided execution order. guards must already be sorted as produced by secretguard.MaterializeSorted or RequestRuntimeSnapshot.SecretGuardExecutionPlane.
func (*SecretGuardBlockInfo) DenialError ¶
func (b *SecretGuardBlockInfo) DenialError() error
type SecretGuardDecisionMetrics ¶
type SecretGuardDecisionMetrics interface {
IncDecision(action, outcome, sourceCategory string)
IncMatch(action, outcome, sourceCategory string)
IncQuarantine(action, outcome, sourceCategory string)
IncFailure(action, outcome, sourceCategory string)
IncScanLimit(action, outcome, sourceCategory string)
}
type SecretGuardPlane ¶
type SecretGuardPlane struct {
Guards []secretguard.Guard
MatcherResolver secretguard.MatcherResolver
DecisionObserver secretguard.Observer
AuditFailurePolicy secretguard.AuditFailurePolicy
AccessMode string
ConfigVersion string
}
SecretGuardPlane is the frozen secret-guard composition bound into a request snapshot.
type SnapshotOptions ¶
type SnapshotOptions struct {
State state.Store
Aux auxiliary.Client
TrafficObserver traffic.Observer
UsageObserver usage.Observer
RawCapture traffic.RawCaptureSink
Workspace workspace.Resolver
SecretGuardPlane SecretGuardPlane
// PolicyObserver receives normalized policy decision evidence. Nil defaults to a
// disabled no-op observer so deployments without policy evidence keep current request
// outcomes (requirements 7.6, 10.5).
PolicyObserver policydecision.Observer
// TimeoutBudgetSource is the frozen per-request source of decision-provider evaluation
// budgets. Nil defaults to [DefaultTimeoutBudgetSource] (zero budget for every
// stage/provider) so legacy extension behavior is unchanged (requirements 6.3, 10.5).
TimeoutBudgetSource TimeoutBudgetSource
FeaturePlanes lipfeature.FrozenPlaneSet
Generation int64
}
SnapshotOptions configures optional facades; zero value uses disabled placeholders.
type StageCountByteMetrics ¶
type StageCountByteMetrics interface {
AddStageCount(stage, outcome string, n int64)
ObserveStageBytes(stage, outcome string, n int64)
}
StageCountByteMetrics is an optional StageMetrics extension for content-safe counts/bytes.
type StageMetrics ¶
type StageMetrics interface {
ObserveStage(stage, outcome string, seconds float64)
IncFailOpenSkip(stage string)
}
StageMetrics receives extension pipeline timing and fail-open skip counts (optional on [Executor]).
type StaticTimeoutBudgetSource ¶
StaticTimeoutBudgetSource returns a fixed budget for every stage/provider. It is intended for tests and explicit configuration where one budget applies uniformly.
func (StaticTimeoutBudgetSource) TimeoutFor ¶
func (s StaticTimeoutBudgetSource) TimeoutFor(string, string) time.Duration
TimeoutFor returns the configured budget for every stage/provider.
type TimeoutBudgetSource ¶
TimeoutBudgetSource is a frozen per-request source of evaluation timeouts for decision providers (requirement 6.3). The default source returns zero for every stage/provider so legacy extension behavior remains source- and behavior-compatible unless a configured provider/stage explicitly sets a budget. Implementations must be safe for concurrent reads; composition roots must treat a source as frozen for the lifetime of a request snapshot.
type TimeoutResult ¶
type TimeoutResult[T any] struct { Value T Err error TimedOut bool ParentCanceled bool // ProviderStillRunning reports that the helper returned because the parent or // evaluation deadline fired while the provider goroutine had not completed. ProviderStillRunning bool // GuardRejected reports that a ProviderTimeoutGuard rejected the call because // another bounded goroutine for this stage/provider is already running. GuardRejected bool }
TimeoutResult carries the outcome of a bounded decision-provider call (requirements 6.1, 6.2, 6.3, 6.4). Exactly one of Value/Err is meaningful when TimedOut and ParentCanceled are both false.
func RunDecisionProviderWithDeadline ¶
func RunDecisionProviderWithDeadline[T any](ctx context.Context, deadline time.Time, call func(context.Context) (T, error)) TimeoutResult[T]
RunDecisionProviderWithDeadline invokes call with a child context that expires at the earlier of the parent deadline and the supplied deadline. It is the single source of truth for the bounding deadline: the same deadline value is used both to bound the provider (via context.WithDeadline) and, threaded explicitly through the bounded result by stage runners, to populate policydecision.Context.EvaluationDeadline on emitted evidence (requirement 6.3).
deadline must be non-zero; callers derive it once (e.g. now+timeout) and reuse the same time.Time for both bounding and evidence projection so the provider's observed ctx.Deadline() equals the record's EvaluationDeadline exactly.
When timeout is greater than zero, the helper runs call in a bounded goroutine against the derived child context and returns as soon as the call returns, the evaluation deadline expires, or the parent context is canceled. If the parent context is canceled or expires first, ParentCanceled is true and the original context error is returned in Err; no policy-denial evidence is implied. If the evaluation deadline expires while the parent is still active, TimedOut is true and Err is nil; the caller records a policy failure or fail-open skipped record according to the provider's configured failure behavior. Late provider results after timeout are ignored and never mutate live call or stream state.
func RunDecisionProviderWithDeadlineGuarded ¶
func RunDecisionProviderWithDeadlineGuarded[T any](ctx context.Context, deadline time.Time, guard *ProviderTimeoutGuard, stage, providerID string, call func(context.Context) (T, error)) TimeoutResult[T]
RunDecisionProviderWithDeadlineGuarded behaves like RunDecisionProviderWithDeadline and also tracks provider goroutines that are still running after the helper returns. While a tracked goroutine remains active, the guard rejects future launches for the same stage/provider.
func RunDecisionProviderWithTimeout ¶
func RunDecisionProviderWithTimeout[T any](ctx context.Context, timeout time.Duration, call func(context.Context) (T, error)) TimeoutResult[T]
RunDecisionProviderWithTimeout invokes call with a derived child context that expires at the earlier of the parent deadline and now+timeout (requirements 6.1, 6.2, 6.3, 6.4). The derived deadline is now+timeout.
Legacy compatibility: when timeout is zero, no child context and no goroutine are created; call runs directly against ctx and the result is returned unwrapped. This preserves existing extension behavior and avoids the per-call goroutine wrapper (design Timeout Enforcement).
Stage runners that need the same deadline value projected onto emitted evidence should derive the deadline once and call RunDecisionProviderWithDeadline instead, so the bounding deadline and the evidence EvaluationDeadline are exactly identical.
type ToolPolicyStageInput ¶
type ToolPolicyStageInput struct {
Ctx context.Context
Log *slog.Logger
Obs StageMetrics
Policies []toolpolicy.Policy // execution order; see RunToolPolicyStage
Event lipapi.ToolEvent
Meta toolpolicy.Meta
Svc toolpolicy.Services
}
ToolPolicyStageInput carries inputs for RunToolPolicyStage.
Source Files
¶
- attempt_evidence.go
- attempt_transform.go
- compaction_preserver.go
- completion_run.go
- control_tool.go
- decision_context.go
- decision_errors.go
- decision_evidence.go
- decision_evidence_context.go
- decision_failure.go
- decision_legality.go
- decision_project.go
- decision_runner.go
- decision_timeout.go
- doc.go
- failure_policy.go
- final_stream_observation.go
- pipeline.go
- pre_request.go
- request_transform.go
- route_hint.go
- seam_views.go
- secret_guard.go
- secret_guard_audit.go
- session_classification.go
- session_open.go
- snapshot.go
- stage_metrics.go
- stage_panic_log.go
- submit_evidence.go
- tool_catalog.go
- tool_policy.go
- tool_reactor_evidence.go
- trace.go