safeguard

package
v0.61.0 Latest Latest
Warning

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

Go to latest
Published: Nov 10, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package safeguard provides fail-closed input and output screening as Core chat middleware.

Matcher is the extension boundary for substring lists, classifiers, or remote moderation services. Middleware has no global registry or default policy: callers construct and compose an explicit instance. SubstringMatcher supplies incremental scans with bounded overlap. A custom Matcher can implement StreamMatcher to keep streaming latency; otherwise the middleware buffers output and screens it once before releasing any chunks.

Example
package main

import (
	"context"
	"fmt"

	"github.com/Tangerg/scope/core/safeguard"
)

func main() {
	matcher, err := safeguard.NewSubstringMatcher(safeguard.SubstringMatcherConfig{Terms: []string{"secret"}})
	if err != nil {
		panic(err)
	}
	match, err := matcher.Match(context.Background(), "do not reveal the SECRET")
	if err != nil {
		panic(err)
	}
	fmt.Println(match.Found, match.Term)
}
Output:
true secret

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrUnsafeContent           = errors.New("safeguard: unsafe content")
	ErrInvalidMiddlewareConfig = errors.New("safeguard: invalid middleware config")
	ErrInvalidSubstringConfig  = errors.New("safeguard: invalid substring matcher config")
)

Functions

This section is empty.

Types

type Block

type Block struct {
	Direction Direction
	Term      string
}

type Direction

type Direction string

Direction identifies the single content flow rejected by a policy decision.

const (
	DirectionInput  Direction = "input"
	DirectionOutput Direction = "output"
)

func (Direction) Valid

func (d Direction) Valid() bool

type Match

type Match struct {
	Term  string
	Found bool
}

Match is a Matcher's decision for one text projection. Term should be empty when policy details must not be disclosed.

type Matcher

type Matcher interface {
	// Match evaluates one provider-neutral text projection. Found=false means the
	// text passed; a returned error means no policy decision was reached. Remote
	// implementations must honor ctx and preserve context errors.
	Match(ctx context.Context, text string) (Match, error)
}

Matcher screens a text projection, possibly through a remote policy service.

type MatcherFunc

type MatcherFunc func(ctx context.Context, text string) (Match, error)

func (MatcherFunc) Match

func (m MatcherFunc) Match(ctx context.Context, text string) (Match, error)

type Middleware

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

func NewMiddleware

func NewMiddleware(config MiddlewareConfig) (*Middleware, error)

func (*Middleware) Call

func (m *Middleware) Call(next chat.Model) chat.Model

Call is a chat.CallMiddleware. Input is screened before the model runs; output is screened before a response becomes visible to the caller.

func (*Middleware) Stream

func (m *Middleware) Stream(next chat.Streamer) chat.Streamer

Stream is a chat.StreamMiddleware. Incremental matchers screen each fragment before yielding its chunk. Other matchers screen the complete buffered output once. A completed, safe generation survives a later provider error; incomplete or rejected output is discarded. A chunk paired with an error is never exposed.

type MiddlewareConfig

type MiddlewareConfig struct {
	Matcher Matcher
	Scope   Scope
	OnBlock func(context.Context, Block)
}

MiddlewareConfig controls one immutable Middleware. Matcher is required. OnBlock runs synchronously before a rejection is returned.

type Scan added in v0.61.0

type Scan interface {
	Add(ctx context.Context, fragment string) (Match, error)
}

Scan consumes successive UTF-8 fragments. Found is a rejection of the text seen so far, and errors mean no decision was reached. A scan belongs to one sequential caller and must not be reused for another stream.

type Scope

type Scope string

Scope selects which directions a Middleware screens. Both is the zero value.

const (
	ScopeBoth Scope = ""
	// ScopeInput screens system and user text before provider I/O.
	ScopeInput Scope = Scope(DirectionInput)
	// ScopeOutput screens assistant text before it reaches the caller.
	ScopeOutput Scope = Scope(DirectionOutput)
)

func (Scope) Valid

func (s Scope) Valid() bool

type StreamMatcher added in v0.61.0

type StreamMatcher interface {
	NewScan() Scan
}

StreamMatcher optionally supplies incremental decisions. Each scan owns one stream's state; accepting a fragment must include matches across all earlier fragment boundaries. Matchers without this capability are screened once after buffering the complete output, before any output is exposed.

type SubstringMatcher

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

SubstringMatcher is immutable. It trims and deduplicates terms while preserving declaration order for the first match. Disclosure never changes the block decision.

func NewSubstringMatcher

func NewSubstringMatcher(config SubstringMatcherConfig) (*SubstringMatcher, error)

func (*SubstringMatcher) Match

func (s *SubstringMatcher) Match(ctx context.Context, text string) (Match, error)

func (*SubstringMatcher) NewScan added in v0.61.0

func (s *SubstringMatcher) NewScan() Scan

type SubstringMatcherConfig

type SubstringMatcherConfig struct {
	Terms         []string
	CaseSensitive bool
	HideMatch     bool
}

SubstringMatcherConfig names the terms to block and controls matching and disclosure. Matching uses Unicode case folding by default, including multi-rune expansions such as ß to ss. It does not normalize Unicode or equate visually similar characters. CaseSensitive compares the original bytes. HideMatch prevents a configured term from entering UnsafeError or OnBlock.

type UnsafeError

type UnsafeError struct {
	Block Block
}

UnsafeError is a policy rejection. It unwraps to ErrUnsafeContent.

func (*UnsafeError) Error

func (u *UnsafeError) Error() string

func (*UnsafeError) Unwrap

func (u *UnsafeError) Unwrap() error

Jump to

Keyboard shortcuts

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