Help us shape the future of Go! Take the 2026 Go Developer Survey

steer

package
v2.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package steer is stream rules and the watchdog for one session (2.0 W3, #175): Session implements loop.Steering. A session is a chat (across its turns), an agent run, or one MCP chat call.

Index

Constants

View Source
const (
	QOnTrack      = "on_track"
	QLooping      = "looping"
	QDrifting     = "drifting_from_goal"
	QPersonaBreak = "persona_break"
	QUnverified   = "claims_unverified_success"
	QUnsafe       = "unsafe_next_action"
)

The watchdog ballot's questions (spec §5 W3).

View Source
const (
	ActAt   = 0.70
	LogFrom = 0.30
)

The band: a flag at or above ActAt is acted on; one from LogFrom up to ActAt is logged only (spec: 0.30–0.70 is logged, not acted on).

View Source
const (
	QDestructive  = "destructive"
	QExfiltration = "exfiltration"
	QBeyondScope  = "beyond_requested_scope"
)

The tool gate's questions (spec §5 W3).

View Source
const DefaultEvery = 3

DefaultEvery is the ballot's cadence, in requests (spec: every 3 turns).

Variables

This section is empty.

Functions

func BallotQuestions

func BallotQuestions() []decide.Question

BallotQuestions is the fixed ballot, with heuristic answers where the transcript alone can tell (the default oracle).

func NewToolGate

func NewToolGate(mode, workspace string, goal func() string, logf func(string)) tools.AskAdvisor

NewToolGate is ToolGate on Jev (decide.NewJev, "gate" in the stats), or nil when jev_gate is off: no key is read for a gate that is off. Paths in the pending call are sent relative to workspace, or as <path>.

func ToolGate

func ToolGate(mode string, o decide.Oracle, goal func() string, logf func(string)) tools.AskAdvisor

ToolGate is jev_gate as a tools.AskAdvisor (spec §5 W3). It asks the oracle (Jev, falling back to the heuristic) about each call the policy allows that is not read-only, plus web_fetch (a read that can carry data out in its URL). "on": any answer at or above ActAt turns the call into an Ask, never the reverse. "shadow": it logs what it would do. goal is read per call (the chat's goal changes per turn). Nil when mode is off.

Types

type Finding

type Finding struct {
	ID       string
	P        float64 // the flag, 0..1 (on_track: how far off track)
	Severity Severity
	Source   string // the oracle that answered
}

Finding is one flagged answer.

type Options

type Options struct {
	Rules     *rules.Set
	RulesMode string // config.StreamRulesMode(): off, shadow or on
	// RuntimeVerifies: an agent run with verification commands (the
	// task-complete-before-verify rule stands down).
	RuntimeVerifies bool
	// Watchdog is config.WatchdogMode(): off, shadow or on.
	Watchdog string
	// Oracle answers the ballot; nil is the heuristic.
	Oracle decide.Oracle
	// Every is the ballot cadence in requests; 0 is DefaultEvery.
	Every int
	// Goal is what the session is for (the agent goal, the MCP prompt).
	// The chat sets it per turn with SetGoal.
	Goal string
	// FinalRepliesToGate: an agent run, whose completion gate asks its own
	// ballot at a final reply; the background ballot skips final replies
	// (it runs at the next request's end instead).
	FinalRepliesToGate bool
	// Context is the run's: cancelling it cancels a background ballot, as
	// Close does. nil: context.Background().
	Context context.Context
	// Logf gets shadow lines, fires and verdicts. nil: none.
	Logf func(string)
}

Options configure a Session.

type Session

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

Session is one session's steering. Safe for concurrent use.

func New

func New(o Options) *Session

New returns a Session, or nil when there is nothing to steer: stream rules off (or none loaded) and the watchdog off. Use Steering to put it on a Loop, and Close it when the session ends.

func (*Session) Ballot

func (s *Session) Ballot(ctx context.Context) (v Verdict, acting bool)

Ballot asks the ballot now and waits for the answer: the agent's completion gate (spec: "before a completion is accepted"). acting is false when the watchdog is off or in shadow (the verdict is then logged only). The oracle is Guarded, so this waits at most decide.Timeout. Nil-safe.

func (*Session) Calls

func (s *Session) Calls(_ int, calls []loop.ToolCall) bool

func (*Session) Close

func (s *Session) Close()

Close ends the session: a background ballot is cancelled and its verdict dropped, no new one starts, and Close returns once it has finished (so nothing logs after the run). Nil-safe.

func (*Session) EndStream

func (s *Session) EndStream() bool

EndStream scans the reply text the matcher's batching held back (loop.StreamEnder).

func (*Session) Observe

func (s *Session) Observe(ev loop.Event) bool

func (*Session) Reminders

func (s *Session) Reminders(b loop.Boundary) []loop.Reminder

Reminders hands out what is due at b. A run's start also takes appended reminders a final reply left behind, and any boundary but a retry takes interrupt reminders whose interrupt the loop did not honour (the turn had used its re-runs), so no reminder is lost. Batched watchdog nits ride on the first reminder handed out, or go alone at a run's start.

func (*Session) Request

func (s *Session) Request(_ int, interrupt func())

func (*Session) SetGoal

func (s *Session) SetGoal(goal string)

SetGoal sets what the ballot judges progress against (the chat: each turn's prompt). A changed goal drops watchdog reminders and nits not yet handed out, the verdict of a ballot still running, and the turns the watchdog saw (the same call under two prompts is not a loop); the request cadence carries on. Nil-safe.

func (*Session) Settle

func (s *Session) Settle(id string)

Settle says a finding was acted on another way (the completion gate's veto names unverified success): watchdog reminders about it that are pending lose its advice, and ballots in the next steerGap requests do not repeat it. Nil-safe.

func (*Session) Steering

func (s *Session) Steering() loop.Steering

Steering is s as a loop.Steering: a nil Session gives a nil interface, never a non-nil interface holding a nil pointer.

func (*Session) Wait

func (s *Session) Wait()

Wait blocks until a background ballot finishes (tests). Nil-safe.

type Severity

type Severity int

Severity is how a flagged answer is acted on.

const (
	Nit     Severity = iota + 1 // batched into the next reminder
	Concern                     // a reminder at the next tool boundary
	Blocker                     // interrupts the request in flight
)

func (Severity) String

func (s Severity) String() string

type Verdict

type Verdict struct {
	Act    []Finding // at or above ActAt, most severe first
	Logged []Finding // in the band, logged only
}

Verdict is one ballot's outcome.

func Judge

func Judge(ans map[string]decide.Answer) Verdict

Judge turns ballot answers into a verdict.

func (Verdict) Has

func (v Verdict) Has(id string) bool

Has reports an acted-on finding for question id.

func (Verdict) Highest

func (v Verdict) Highest() Severity

Highest is the most severe acted-on finding (0: none).

func (Verdict) Reminder

func (v Verdict) Reminder() string

Reminder is the watchdog's reminder text for the acted-on findings.

func (Verdict) String

func (v Verdict) String() string

Jump to

Keyboard shortcuts

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