steertest

package
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package steertest contains a deterministic ACP process fixture for foreign loop steering tests. The fixture is intentionally small and script-driven: tests control protocol races with named gates, never wall-clock sleeps.

Index

Constants

View Source
const (
	StepUpdate        = ActionUpdate
	StepTerminal      = ActionTerminal
	StepSteerReply    = ActionSteerReply
	StepTransportLoss = ActionTransportLoss
	StepWait          = ActionWait
)

Aliases make scripts read naturally in integration tests.

Variables

This section is empty.

Functions

func RunProcess

func RunProcess() error

RunProcess is the entry point used by internal/steertest/cmd. It speaks a bounded newline-delimited JSON-RPC subset over stdin/stdout and keeps all deterministic test controls on the private Unix socket.

Types

type Action

type Action struct {
	Kind         ActionKind      `json:"kind"`
	Name         string          `json:"name,omitempty"`
	Gate         string          `json:"gate,omitempty"`
	Text         string          `json:"text,omitempty"`
	Outcome      SteeringOutcome `json:"outcome,omitempty"`
	Reason       string          `json:"reason,omitempty"`
	StopReason   string          `json:"stopReason,omitempty"`
	ErrorCode    int             `json:"errorCode,omitempty"`
	ErrorMessage string          `json:"errorMessage,omitempty"`
}

Action is one process-side action. Gate, when non-empty, causes the child process to announce EventGate and wait until Agent.Release(Gate) is called. This gives tests a precise linearization point for prompt/steer/terminal races without timers.

func SteerAction

func SteerAction(outcome SteeringOutcome, gate string) Action

SteerAction creates one typed steering acknowledgement.

func TerminalAction

func TerminalAction(stopReason, gate string) Action

TerminalAction creates one prompt terminal response.

func TransportLossAction

func TransportLossAction(gate string) Action

TransportLossAction closes the ACP transport at a deterministic gate.

func UpdateAction

func UpdateAction(text, gate string) Action

UpdateAction creates one gated or immediate agent-message update.

type ActionKind

type ActionKind string

ActionKind identifies one observable process action.

const (
	ActionUpdate         ActionKind = "update"
	ActionTerminal       ActionKind = "terminal"
	ActionSteerReply     ActionKind = "steer_reply"
	ActionTransportLoss  ActionKind = "transport_loss"
	ActionWait           ActionKind = "wait"
	ActionSetSessionInfo ActionKind = "session_info"
)

type Agent

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

Agent owns the parent side of one fake ACP process control socket. It does not start an ACP child itself; use Executable and Env in the caller's ACP configuration, then use WaitForKind/Release to drive the process.

func New

func New(tb testing.TB, script Script) *Agent

New builds the tiny helper executable, allocates a private Unix control socket, and returns a reusable fixture handle. The returned handle is safe for concurrent WaitForKind, Release, Transcript, and MCPDescriptors calls.

func (*Agent) Close

func (a *Agent) Close()

Close stops control observation and releases the private Unix socket. The ACP owner remains responsible for terminating a child process launched with Env; this method never sends a target-process interrupt.

func (*Agent) Command

func (a *Agent) Command() string

Command is an alias for Executable.

func (*Agent) Continue

func (a *Agent) Continue(gate string) error

Continue is an alias for Release.

func (*Agent) ControlEndpoint

func (a *Agent) ControlEndpoint() string

ControlEndpoint returns the private Unix endpoint used by the fixture process. It is intended for security/cleanup assertions, not for model arguments.

func (*Agent) Env

func (a *Agent) Env() []string

Env returns the complete child environment. It contains only fixture control values and the explicitly configured Script.Extra values.

func (*Agent) Environment

func (a *Agent) Environment() []string

Environment is an alias for Env.

func (*Agent) Events

func (a *Agent) Events() <-chan Event

Events returns a bounded stream of observations. Consumers that need to wait for a specific kind without consuming the stream should use WaitForKind instead.

func (*Agent) Executable

func (a *Agent) Executable() string

Executable returns the absolute helper path suitable for acp.Config.

func (*Agent) MCPDescriptors

func (a *Agent) MCPDescriptors() []MCPDescriptor

MCPDescriptors returns defensive copies of all captured MCP descriptors.

func (*Agent) Path

func (a *Agent) Path() string

Path is an alias for Executable.

func (*Agent) Release

func (a *Agent) Release(gate string) error

Release opens a named script gate. Releasing before the child reaches the gate is safe: the release is remembered by the helper process.

func (*Agent) ReleaseGate

func (a *Agent) ReleaseGate(gate string) error

ReleaseGate is an alias for Release.

func (*Agent) Transcript

func (a *Agent) Transcript() Transcript

Transcript returns a defensive bounded snapshot. String() is safe to use directly in test failure output.

func (*Agent) WaitFor

func (a *Agent) WaitFor(ctx context.Context, kind EventKind) (Event, error)

WaitFor is the idiomatic tuple-returning form of WaitForKind.

func (*Agent) WaitForCount

func (a *Agent) WaitForCount(ctx context.Context, kind EventKind, count int) error

WaitForCount waits until at least count events of kind have been recorded.

func (*Agent) WaitForKind

func (a *Agent) WaitForKind(ctx context.Context, kind EventKind) WaitResult

WaitForKind waits until the first recorded event of kind appears. The method does not consume Events, so multiple assertions can independently inspect the same observation history.

func (*Agent) WaitForMCPDescriptors

func (a *Agent) WaitForMCPDescriptors(ctx context.Context, count int) error

WaitForMCPDescriptors waits until at least count descriptors have been captured. It is useful when session/new and session/load are issued back to back and their control events are delivered asynchronously.

func (*Agent) WaitForNth

func (a *Agent) WaitForNth(ctx context.Context, kind EventKind, occurrence int) (Event, error)

WaitForNth waits for the zero-based occurrence of kind. Unlike WaitForKind, it is suitable for scripts that issue multiple prompts or steering calls.

type Event

type Event struct {
	Kind      EventKind       `json:"kind"`
	Name      string          `json:"name,omitempty"`
	Gate      string          `json:"gate,omitempty"`
	Method    string          `json:"method,omitempty"`
	SessionID string          `json:"sessionId,omitempty"`
	RequestID json.RawMessage `json:"requestId,omitempty"`
	Text      string          `json:"text,omitempty"`
	Outcome   SteeringOutcome `json:"outcome,omitempty"`
	Reason    string          `json:"reason,omitempty"`
	MCP       []MCPDescriptor `json:"mcp,omitempty"`
	ErrorCode int             `json:"errorCode,omitempty"`
}

Event is one bounded, process-side fixture observation. Request IDs are retained only for test correlation and are never put into model-facing ACP arguments by the fixture.

type EventKind

type EventKind string

EventKind identifies a child-process observation delivered over the private fixture control socket.

const (
	EventReady           EventKind = "ready"
	EventInitialize      EventKind = "initialize"
	EventNewSession      EventKind = "session_new"
	EventLoadSession     EventKind = "session_load"
	EventPrompt          EventKind = "prompt"
	EventSteer           EventKind = "steer"
	EventUpdate          EventKind = "update"
	EventTerminal        EventKind = "terminal"
	EventMCPDescriptor   EventKind = "mcp_descriptor"
	EventGate            EventKind = "gate"
	EventTransportLoss   EventKind = "transport_loss"
	EventSessionInfo     EventKind = "session_info"
	EventSessionCanceled EventKind = "session_cancel"
	EventClosed          EventKind = "closed"
)

type MCPDescriptor

type MCPDescriptor struct {
	Name    string           `json:"name,omitempty"`
	Command string           `json:"command,omitempty"`
	Args    []string         `json:"args,omitempty"`
	Env     []MCPEnvironment `json:"env,omitempty"`
}

MCPDescriptor is the captured session/new or session/load MCP server descriptor. Values are retained for assertions through EnvValue; String and Transcript always redact them.

func (MCPDescriptor) EnvValue

func (d MCPDescriptor) EnvValue(name string) string

EnvValue returns the captured value for name, or an empty string if absent.

func (MCPDescriptor) String

func (d MCPDescriptor) String() string

String formats a descriptor with all captured environment values redacted. Tests can safely include it in failure messages; use EnvValue for an explicit assertion on a value.

type MCPEnvironment

type MCPEnvironment struct {
	Name  string `json:"name,omitempty"`
	Value string `json:"value,omitempty"`
}

MCPEnvironment is one captured MCP environment variable.

type PromptScript

type PromptScript struct {
	Actions []Action `json:"actions,omitempty"`
	// Steps is accepted as a readable alias for Actions. When both are set,
	// Actions wins.
	Steps []Action `json:"steps,omitempty"`
}

PromptScript controls one session/prompt request. Actions execute in order. An empty action list means "respond with end_turn".

type Script

type Script struct {
	AgentName    string          `json:"agentName,omitempty"`
	AgentVersion string          `json:"agentVersion,omitempty"`
	AgentTitle   string          `json:"agentTitle,omitempty"`
	Metadata     json.RawMessage `json:"metadata,omitempty"`
	SessionID    string          `json:"sessionId,omitempty"`

	// Prompts and Steers are consumed in request order. PromptPlans and
	// Steering are accepted aliases for callers that prefer explicit names.
	Prompts     []PromptScript `json:"prompts,omitempty"`
	PromptPlans []PromptScript `json:"promptPlans,omitempty"`
	Steers      []SteerScript  `json:"steers,omitempty"`
	SteerPlans  []SteerScript  `json:"steerPlans,omitempty"`
	Steering    []SteerScript  `json:"steering,omitempty"`

	// Values advertised in session/new. They make native Claude connector
	// selection usable without a real adapter. Empty values receive stable
	// fixture defaults.
	ModelValues  []string `json:"modelValues,omitempty"`
	EffortValues []string `json:"effortValues,omitempty"`

	// Extra is copied into the fake process environment. Reserved STEERTEST_*
	// names are rejected so fixture control cannot be overridden accidentally.
	Extra map[string]string `json:"extra,omitempty"`

	// MaxRecords bounds the parent-side transcript. Zero selects the default.
	MaxRecords int `json:"maxRecords,omitempty"`
}

Script is the serializable process behavior. It is copied and normalized by New, so callers can safely mutate their original after construction.

func ClaudeScript

func ClaudeScript() Script

ClaudeScript is an alias for DefaultScript.

func CodexScript

func CodexScript() Script

CodexScript returns the current Codex ACP identity. Every Codex version remains steering-disabled in the production driver -- as of 1.2.0 the adapter still answers an idle steer by starting a turn the host cannot correlate -- making this useful for queued fallback tests.

The inherited metadata deliberately advertises more than real Codex does (the shipping adapter advertises `steering.supported` with no idle behavior at all), so the fixture proves the driver refuses Codex steering even against the most permissive advertisement it could receive.

func DefaultScript

func DefaultScript() Script

DefaultScript returns the Claude ACP 0.65.0 compatibility profile with advertised steering support and a host-owned promptRequired idle behavior.

type SteerScript

type SteerScript struct {
	Actions []Action `json:"actions,omitempty"`
	Steps   []Action `json:"steps,omitempty"`
}

SteerScript controls one _session/steering request. An empty action list means an immediate typed injected reply.

type SteeringOutcome

type SteeringOutcome string

SteeringOutcome is the typed outcome emitted by a scripted _session/steering response. Unknown strings are permitted so callers can exercise the driver's fail-closed classification path.

const (
	OutcomeInjected       SteeringOutcome = "injected"
	OutcomePromptRequired SteeringOutcome = "promptRequired"
	OutcomeStartedNewTurn SteeringOutcome = "startedNewTurn"
	OutcomeFailed         SteeringOutcome = "failed"
)

type Step

type Step = Action

Step is a compatibility spelling for Action.

type Transcript

type Transcript struct {
	Records   []Event
	Truncated bool
	// contains filtered or unexported fields
}

Transcript is a bounded snapshot of process observations. Its String form is deliberately redacted and suitable for test failures.

func (Transcript) String

func (t Transcript) String() string

String formats a transcript with environment values redacted and all fields bounded. It never returns raw child wire payloads.

type WaitResult

type WaitResult struct {
	Event Event
	Err   error
}

WaitResult is the result of WaitForKind. Err is context cancellation, fixture shutdown, or a control transport failure.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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