Documentation
¶
Overview ¶
Package adapters defines backend-neutral agent events and the adapters that derive them from normalized terminal text.
Index ¶
- Constants
- Variables
- func IsSensitiveText(value string) bool
- type Adapter
- type AiderAdapter
- type ClaudeAdapter
- type CodexAdapter
- type Decision
- type Descriptor
- type DetectionState
- type Event
- type EventType
- type Factory
- type GenericRegexAdapter
- type GooseAdapter
- type Hooks
- type OpenInterpreterAdapter
- type Pattern
- type Processor
- func (p *Processor) Acknowledge(eventID string) error
- func (p *Processor) AnsiOutput() string
- func (p *Processor) Consume(chunk []byte) error
- func (p *Processor) DetectionWindowLen() int
- func (p *Processor) IsBlocked() bool
- func (p *Processor) MarkProcessExitEvent(exitCode *int, failed bool) Event
- func (p *Processor) NewProcessExitEvent(exitCode *int, failed bool) Event
- func (p *Processor) Output() string
- func (p *Processor) Pending() *Event
- func (p *Processor) ReconcileSnapshot(raw []byte) (*Event, bool, error)
- func (p *Processor) Resize(columns, rows int)
- func (p *Processor) Resolve(eventID string, deliver func() error) error
- func (p *Processor) Restore(event Event) error
- func (p *Processor) Revision() uint64
- func (p *Processor) Run(ctx context.Context, reader io.Reader) error
- func (p *Processor) SendLine(ctx context.Context, line string, deliver func([]byte) error) error
- func (p *Processor) WaitSemanticEvents()
- type Registry
- type RiskLevel
- type Status
Constants ¶
const (
// AiderID identifies the Aider AI pair programming adapter.
AiderID = "aider"
)
const ( // ClaudeID identifies the experimental Claude Code adapter. Its vendor // rules are intentionally limited to anonymized prompts observed with the // version documented alongside the fixtures. ClaudeID = "claude" )
const ( // CodexID is experimental and intentionally limited to interactions backed // by the anonymized captures in testdata/codex. CodexID = "codex" )
const GenericID = "generic"
const (
// GooseID identifies the Goose AI agent adapter.
GooseID = "goose"
)
const MaxLineBytes = 4096
MaxLineBytes is the maximum encoded line accepted by the safe line-input boundary, before its terminating carriage return is appended.
const (
// OpenInterpreterID identifies the Open Interpreter AI agent adapter.
OpenInterpreterID = "interpreter"
)
Variables ¶
var ( ErrUnknownAdapter = errors.New("unknown adapter") ErrDecisionUnsupported = errors.New("unsupported decision") ErrEventMismatch = errors.New("pending event mismatch") ErrProcessorTerminated = errors.New("adapter semantic stream terminated") )
var ( // ErrEventPending reports that an actionable event must be resolved before // direct instructions can be delivered. ErrEventPending = errors.New("actionable event pending") // ErrInvalidLine reports line input which cannot be encoded unambiguously. ErrInvalidLine = errors.New("invalid terminal line") // ErrLineUnsupported reports that a transport has no atomic line boundary. ErrLineUnsupported = errors.New("line send not supported") // ErrLineDeliveryUncertain reports that a transport was called but could // not prove whether zero, some, or all line bytes reached the target. The // original transport error is deliberately not retained: it may echo the // submitted text and must never escape through errors.Unwrap. ErrLineDeliveryUncertain = errors.New("line delivery uncertain") )
Functions ¶
func IsSensitiveText ¶
Types ¶
type Adapter ¶
type Adapter interface {
ID() string
Detect(state *DetectionState, chunk []byte) ([]Event, error)
EncodeDecision(event Event, decision Decision, manualInput string) ([]byte, error)
}
Adapter interprets normalized, ANSI-free terminal text. Implementations do not own processes, PTYs, tmux sessions, rendered history or audit sinks.
type AiderAdapter ¶
type AiderAdapter struct {
// contains filtered or unexported fields
}
AiderAdapter recognizes prompts generated by the Aider coding assistant CLI. Configured intercept_patterns retain configured priority and serve as fallback.
func NewAiderAdapter ¶
func NewAiderAdapter(patterns []Pattern) (*AiderAdapter, error)
NewAiderAdapter validates and copies intercept_patterns used by generic fallback.
func (*AiderAdapter) Detect ¶
func (a *AiderAdapter) Detect(state *DetectionState, chunk []byte) ([]Event, error)
Detect gives configured intercept_patterns priority. Aider prompts are matched only when no configured pattern matches.
func (*AiderAdapter) EncodeDecision ¶
func (a *AiderAdapter) EncodeDecision(event Event, decision Decision, manualInput string) ([]byte, error)
EncodeDecision encodes automated or manual responses for Aider prompts. Aider prompts expect Enter ('\r') to confirm input.
func (*AiderAdapter) ID ¶
func (*AiderAdapter) ID() string
type ClaudeAdapter ¶
type ClaudeAdapter struct {
// contains filtered or unexported fields
}
ClaudeAdapter recognizes only prompts backed by the anonymized Claude Code 2.1.59 fixtures. Configured intercept_patterns retain their configured order and take priority, preserving the semantics of existing configurations.
The adapter remains experimental: no automatic allow or deny byte sequence is claimed because the highlighted TUI selection can change independently of the prompt text visible to Relayer.
func NewClaudeAdapter ¶
func NewClaudeAdapter(patterns []Pattern) (*ClaudeAdapter, error)
NewClaudeAdapter validates both the observed rules and every configured intercept_pattern before a session starts.
func (*ClaudeAdapter) Detect ¶
func (a *ClaudeAdapter) Detect(state *DetectionState, chunk []byte) ([]Event, error)
Detect delegates bounded stream handling and legacy regex behavior to the generic adapter, then enriches only rules tied to real Claude Code fixtures.
func (*ClaudeAdapter) EncodeDecision ¶
func (a *ClaudeAdapter) EncodeDecision(event Event, decision Decision, manualInput string) ([]byte, error)
EncodeDecision preserves exact manual input compatibility. Automatic allow and deny remain unsupported until selection-independent bytes are verified.
func (*ClaudeAdapter) ID ¶
func (*ClaudeAdapter) ID() string
type CodexAdapter ¶
type CodexAdapter struct {
// contains filtered or unexported fields
}
CodexAdapter recognizes only prompts captured from the CLI version recorded in testdata/codex. Configured intercept_patterns remain a complete fallback; this wrapper does not silently replace or weaken them.
func NewCodexAdapter ¶
func NewCodexAdapter(patterns []Pattern) (*CodexAdapter, error)
NewCodexAdapter validates and copies the legacy intercept_patterns used by the generic fallback.
func (*CodexAdapter) Detect ¶
func (a *CodexAdapter) Detect(state *DetectionState, chunk []byte) ([]Event, error)
Detect gives configured intercept_patterns priority so enabling the Codex adapter cannot change an existing policy's event semantics. Verified Codex prompts are considered only when no configured pattern matches. Probes are value copies, so a chunk is committed to the bounded DetectionState exactly once.
func (*CodexAdapter) EncodeDecision ¶
func (a *CodexAdapter) EncodeDecision(event Event, decision Decision, manualInput string) ([]byte, error)
EncodeDecision supports only byte sequences verified against the captured CLI. Generic fallback events retain the established manual-input behavior.
func (*CodexAdapter) ID ¶
func (*CodexAdapter) ID() string
type Decision ¶
type Decision string
Decision is deliberately limited to actions represented by current code. Adapters may reject allow or deny when they cannot encode the action reliably; callers must then retain the pending event for human input.
type Descriptor ¶
Descriptor is safe to display in diagnostics and documentation.
type DetectionState ¶
type DetectionState struct {
SessionID string
AgentID string
AdapterID string
// contains filtered or unexported fields
}
DetectionState is the bounded, per-session state supplied to an Adapter. A state must never be shared by two terminal sessions.
func NewDetectionState ¶
func NewDetectionState(sessionID, agentID, adapterID string) *DetectionState
NewDetectionState creates independent state for one agent session.
func (*DetectionState) IsBlocked ¶
func (s *DetectionState) IsBlocked() bool
IsBlocked reports whether an actionable event still awaits a decision.
func (*DetectionState) Pending ¶
func (s *DetectionState) Pending() *Event
Pending returns a defensive copy of the current actionable event.
func (*DetectionState) UseRenderedScreen ¶
func (s *DetectionState) UseRenderedScreen(text string, burstStart int, inCodeFence bool, anchors screen.Anchors)
UseRenderedScreen hands the state the screen text for this chunk, replacing the accumulated byte window. Only the Processor calls this, and only for an agent that has repainted.
type Event ¶
type Event struct {
ID string
Signature string
Sequence uint64
SessionID string
AgentID string
Adapter string
Type EventType
Summary string
Match string
Command string
Sensitive bool
Risk RiskLevel
Timestamp time.Time
Metadata map[string]string
// contains filtered or unexported fields
}
Event is the single semantic representation shared by adapters, backends, snapshots and the TUI. ID identifies one occurrence; Signature is stable for equivalent normalized content and is used only while reconciling duplicates.
func NewProcessExitEvent ¶
func NewProcessExitEvent(sessionID, agentID, adapterID string, sequence uint64, exitCode *int, failed bool) Event
NewProcessExitEvent creates the sole lifecycle event currently represented in the semantic stream. Metadata contains only a numeric exit code.
func (Event) Actionable ¶
Actionable reports whether Relayer must pause for a human decision.
type EventType ¶
type EventType string
EventType describes an observation with a concrete meaning in Relayer. Output invalidations and backend failures intentionally remain transport signals: they are not agent events.
type GenericRegexAdapter ¶
type GenericRegexAdapter struct {
// contains filtered or unexported fields
}
GenericRegexAdapter is the stable compatibility adapter for existing intercept_patterns. It receives only normalized text from Processor.
func NewGenericRegexAdapter ¶
func NewGenericRegexAdapter(patterns []Pattern) (*GenericRegexAdapter, error)
NewGenericRegexAdapter validates and defensively copies all expressions.
func (*GenericRegexAdapter) Detect ¶
func (a *GenericRegexAdapter) Detect(state *DetectionState, chunk []byte) ([]Event, error)
Detect preserves pattern order and reports at most one actionable event while another occurrence is pending. A match may span chunks, but it must reach the active terminal line affected by the newest normalized chunk.
func (*GenericRegexAdapter) EncodeDecision ¶
func (*GenericRegexAdapter) ID ¶
func (*GenericRegexAdapter) ID() string
type GooseAdapter ¶ added in v0.3.0
type GooseAdapter struct {
// contains filtered or unexported fields
}
GooseAdapter recognizes prompts generated by the Goose CLI agent. Configured intercept_patterns retain configured priority and serve as fallback.
func NewGooseAdapter ¶ added in v0.3.0
func NewGooseAdapter(patterns []Pattern) (*GooseAdapter, error)
NewGooseAdapter validates and copies intercept_patterns used by generic fallback.
func (*GooseAdapter) Detect ¶ added in v0.3.0
func (a *GooseAdapter) Detect(state *DetectionState, chunk []byte) ([]Event, error)
Detect gives configured intercept_patterns priority. Goose prompts are matched only when no configured pattern matches.
func (*GooseAdapter) EncodeDecision ¶ added in v0.3.0
func (a *GooseAdapter) EncodeDecision(event Event, decision Decision, manualInput string) ([]byte, error)
EncodeDecision encodes automated or manual responses for Goose prompts. Goose prompts expect Enter ('\r') to confirm input.
func (*GooseAdapter) ID ¶ added in v0.3.0
func (*GooseAdapter) ID() string
type Hooks ¶
type Hooks struct {
OnOutput func()
OnEvent func(Event)
// OnEventWithdrawn reports an occurrence the agent has taken back off its
// screen before anyone decided on it. It is not a decision and it is not a
// failure: the question simply stopped being asked, and whatever is showing
// it to the operator has to stop showing it. A caller that ignores this
// leaves a card an operator can still click, and the click is refused with
// ErrEventMismatch rather than delivered.
OnEventWithdrawn func(Event)
// OnRawChunk reports the escape-sequence-aligned transport bytes, before
// this package throws the escapes away. It exists so a session transcript
// can be recorded verbatim; nothing in detection depends on it.
//
// It is called after the state lock is released, with a slice this package
// no longer references. The callee therefore owns the bytes, and must not
// block: the caller is the PTY read loop.
OnRawChunk func(at time.Time, data []byte)
}
Hooks are invoked synchronously after Processor releases its state lock. OnEvent may inspect Processor state; process termination remains the responsibility of the owning backend rather than an event callback.
type OpenInterpreterAdapter ¶ added in v0.3.0
type OpenInterpreterAdapter struct {
// contains filtered or unexported fields
}
OpenInterpreterAdapter recognizes prompts generated by the Open Interpreter CLI. Configured intercept_patterns retain configured priority and serve as fallback.
func NewOpenInterpreterAdapter ¶ added in v0.3.0
func NewOpenInterpreterAdapter(patterns []Pattern) (*OpenInterpreterAdapter, error)
NewOpenInterpreterAdapter validates and copies intercept_patterns used by generic fallback.
func (*OpenInterpreterAdapter) Detect ¶ added in v0.3.0
func (a *OpenInterpreterAdapter) Detect(state *DetectionState, chunk []byte) ([]Event, error)
Detect gives configured intercept_patterns priority. Open Interpreter prompts are matched only when no configured pattern matches.
func (*OpenInterpreterAdapter) EncodeDecision ¶ added in v0.3.0
func (a *OpenInterpreterAdapter) EncodeDecision(event Event, decision Decision, manualInput string) ([]byte, error)
EncodeDecision encodes automated or manual responses for Open Interpreter prompts. Open Interpreter prompts expect Enter ('\r') to confirm input.
func (*OpenInterpreterAdapter) ID ¶ added in v0.3.0
func (*OpenInterpreterAdapter) ID() string
type Pattern ¶
Pattern is the backward-compatible representation of intercept_patterns.
func DefaultPatterns ¶
func DefaultPatterns() []Pattern
type Processor ¶
type Processor struct {
// contains filtered or unexported fields
}
Processor separates raw transport bytes, normalized detection text and the bounded sanitized text rendered by Bubble Tea. Raw bytes are never retained.
func NewProcessor ¶
func (*Processor) Acknowledge ¶
func (*Processor) AnsiOutput ¶
AnsiOutput returns the bounded terminal output retaining ANSI escape sequences (colors, cursor motions, progress bar carriage returns) for terminal emulators such as xterm.js. If no ANSI output is buffered, it falls back to Output().
func (*Processor) Consume ¶
Consume accepts raw terminal bytes, strips fragmented ANSI sequences and sends only normalized text to the adapter.
func (*Processor) DetectionWindowLen ¶
func (*Processor) MarkProcessExitEvent ¶
MarkProcessExitEvent atomically terminates any pending interaction and reserves the next occurrence sequence under the same lock used by Detect and SendLine. It deliberately does not wait for earlier semantic hooks: a process owner can mark the transport closed immediately after Wait, perform bounded descendant cleanup, then call WaitSemanticEvents before publishing the returned process_exit event.
func (*Processor) NewProcessExitEvent ¶
NewProcessExitEvent marks the processor terminated, then preserves the historical ordering guarantee that every earlier semantic hook completes before the process_exit event is returned to its caller.
func (*Processor) ReconcileSnapshot ¶
ReconcileSnapshot uses the last active logical line for generic detection. A vendor adapter may additionally fingerprint only its verified prompt block so a resize remains idempotent while a successive prompt discovered after an attach receives a fresh occurrence ID. An unchanged snapshot after a successful acknowledgement cannot resurrect the old event.
func (*Processor) Resize ¶
Output returns what the operator should see.
For an agent that repaints, that is the rendered screen: the appended buffer holds every redraw stacked on top of the last, which is not what is on the agent's terminal. For every other agent the appended buffer is exact and is returned unchanged, so nothing that worked before changes. Resize tells the rendered screen the size of the terminal the agent is attached to. Until it is called the screen uses a default, which is wrong for wrapping but never wrong about what was erased.
The size crosses as plain integers rather than a terminal.Size: internal terminal imports this package, so the dependency cannot run the other way.
func (*Processor) Resolve ¶
Resolve serializes a decision with detection. The pending occurrence is cleared only after delivery succeeds; terminal output arriving concurrently is processed afterwards, so an immediate second prompt cannot be overwritten by rollback of the first one.
func (*Processor) Revision ¶
Revision returns the latest semantic occurrence sequence for snapshots.
func (*Processor) SendLine ¶
SendLine serializes direct instructions with event detection and process termination. It never resolves or acknowledges an event. Delivery happens under the same lock as Detect, so either the line is sent first or a prompt becomes pending first; the two outcomes cannot race past one another.
func (*Processor) WaitSemanticEvents ¶
func (p *Processor) WaitSemanticEvents()
WaitSemanticEvents waits until every actionable event reserved before process termination has reached its hook. It must stay outside p.mu because hooks are allowed to inspect Processor state.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry resolves explicit adapters and executable-name hints. Generic is always installed as the final fallback. Claude and Codex remain experimental and recognize only interactions backed by anonymized fixtures.
func NewRegistry ¶
NewRegistry builds the production registry around legacy regex patterns.
func (*Registry) Descriptors ¶
func (r *Registry) Descriptors() []Descriptor
Descriptors returns a deterministic, defensive maturity inventory.