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
- func RunProcess() error
- type Action
- type ActionKind
- type Agent
- func (a *Agent) Close()
- func (a *Agent) Command() string
- func (a *Agent) Continue(gate string) error
- func (a *Agent) ControlEndpoint() string
- func (a *Agent) Env() []string
- func (a *Agent) Environment() []string
- func (a *Agent) Events() <-chan Event
- func (a *Agent) Executable() string
- func (a *Agent) MCPDescriptors() []MCPDescriptor
- func (a *Agent) Path() string
- func (a *Agent) Release(gate string) error
- func (a *Agent) ReleaseGate(gate string) error
- func (a *Agent) Transcript() Transcript
- func (a *Agent) WaitFor(ctx context.Context, kind EventKind) (Event, error)
- func (a *Agent) WaitForCount(ctx context.Context, kind EventKind, count int) error
- func (a *Agent) WaitForKind(ctx context.Context, kind EventKind) WaitResult
- func (a *Agent) WaitForMCPDescriptors(ctx context.Context, count int) error
- func (a *Agent) WaitForNth(ctx context.Context, kind EventKind, occurrence int) (Event, error)
- type Event
- type EventKind
- type MCPDescriptor
- type MCPEnvironment
- type PromptScript
- type Script
- type SteerScript
- type SteeringOutcome
- type Step
- type Transcript
- type WaitResult
Constants ¶
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 ¶
TerminalAction creates one prompt terminal response.
func TransportLossAction ¶
TransportLossAction closes the ACP transport at a deterministic gate.
func UpdateAction ¶
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 ¶
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) ControlEndpoint ¶
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 ¶
Env returns the complete child environment. It contains only fixture control values and the explicitly configured Script.Extra values.
func (*Agent) Events ¶
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 ¶
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) Release ¶
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 ¶
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) WaitForCount ¶
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 ¶
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.
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 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 Transcript ¶
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 ¶
WaitResult is the result of WaitForKind. Err is context cancellation, fixture shutdown, or a control transport failure.