session

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 7, 2026 License: Apache-2.0 Imports: 35 Imported by: 0

Documentation

Overview

Package session is the agent harness's session runner: it runs an agent's session for an assignment on a turn executor, in a git worktree of its own, with the session gates installed and every event logged under the run's trace.

The runner is a library. It owns no process: the binary that mounts it grants the process capability every git, gh and Claude Code child starts through, names the state directory and supplies the command Claude Code calls for each gate.

Index

Constants

View Source
const (
	// KeyAffect is the reading, an affect.Reading object.
	KeyAffect = "affect"
	// KeyTargetTurn is the turn whose reply the message answers; 0 when the
	// message opens the session.
	KeyTargetTurn = "target_turn"
)

The keys of an operator affect record beyond the common ones.

View Source
const (
	// ContainerUser is the user every session container runs as.
	ContainerUser = "1000:1000"
	// ContainerNetwork is the Docker network mode a session container joins:
	// the default bridge, which reaches the internet and the tailnet.
	ContainerNetwork = "default"
	// ContainerExecutor is the executor's name on the session image's PATH.
	ContainerExecutor = "claude"
	// ContainerCopilotExecutor is the Copilot CLI's name on the session
	// image's PATH, for a recipe that chooses Copilot. It authenticates with
	// gh's credential, which every session container mounts.
	ContainerCopilotExecutor = "copilot"
	// DefaultDockerExecutable attaches the executor to its container.
	DefaultDockerExecutable = "docker"
	// SessionImageFile is where a repository pins its session image.
	SessionImageFile = "bazel/session_image.txt"
	// DefaultSessionImage is the fallback for a worktree that pins no image:
	// the tag bazel/session_image/build.sh gives the last image it built on
	// this host.
	DefaultSessionImage = "csf-session:latest"
	// LabelAssignment is the label every session container carries: its
	// assignment, which is its run directory's name.
	LabelAssignment = "csf.assignment"
)

Container sessions: each session's executor runs inside one container of the session image, started through the container capability and removed when the session closes.

View Source
const (
	// EventTypeContainerStarted records the session container and how long it
	// took to start.
	EventTypeContainerStarted = "harness_container_started"
	// EventTypeLaunchReceipt records, when a session closes, how it was
	// launched (KeyLaunch) and, for a container session, what its container
	// spent. A host session is one the operator chose explicitly.
	EventTypeLaunchReceipt = "harness_launch_receipt"
	// KeyLaunch names how a session was launched: LaunchContainer or
	// LaunchHost.
	KeyLaunch       = "launch"
	LaunchContainer = "container"
	LaunchHost      = "host"
)

The launch receipt and the container's start, as the event log records them.

View Source
const (
	DefaultContainerMemoryBytes int64 = 9 << 30
	DefaultContainerNanoCPUs    int64 = 28_000_000_000
	DefaultContainerPidsLimit   int64 = 2048
)

The per-session container limits, derived on 2026-10-05 from measured session peaks on the 32-core, 67 GB build host. Inputs: a 45-minute sample of all 46 host sessions every 5 s (executor process tree plus the cgroups of the Bazel containers mounting its run directory), and the receipts of three container sessions (a cold in-container Bazel test plus go test -race: 5.49 GB and 5.98 GB peaks; a real gofmt slice: 1.23 GB).

  • memory: largest peak 5.98 GB = 5.57 GiB, x1.5 headroom = 8.36, rounded up to 9 GiB (the sampled median is 0.25 GiB, so peaks rarely coincide);
  • cpu: largest 5 s rate 25.0 cores, rounded up to a multiple of 4: 28, leaving 4 of the 32 cores to the host;
  • pids: largest task count 838 (threads included, which pids.max counts), x2 rounded up to a power of two: 2048.
View Source
const (
	// EventTypeSessionSuspended records that an open session was suspended: its
	// turn executor closed, the session open on its recorded conversation.
	EventTypeSessionSuspended = "harness_session_suspended"
	// EventTypeSessionResumed records that a suspended session was resumed: its
	// turn executor opened again on the recorded conversation for the next turn.
	EventTypeSessionResumed = "harness_session_resumed"
	// EventTypeTurnResumed records, after the first turn on a resumed session,
	// what the resume cost: the time to the turn's first token.
	EventTypeTurnResumed = "harness_turn_resumed"
	// KeyIdleSeconds is how long the session had been between turns when its
	// session was suspended.
	KeyIdleSeconds = "idle_seconds"
	// KeySuspendedSeconds is how long the session was suspended before it resumed.
	KeySuspendedSeconds = "suspended_seconds"
	// KeyTimeToFirstToken is the resumed turn's time to its first assistant
	// event, in milliseconds.
	KeyTimeToFirstToken = "time_to_first_token_ms"
)

The session hypervisor's suspend and resume records. The router reads none of them as a close of the conversation: a suspended session still holds it and resumes on it.

View Source
const (
	// DefaultDockerUpstream is the host's Docker Engine socket the per-session
	// proxy forwards allowed calls to.
	DefaultDockerUpstream = "/var/run/docker.sock"

	// EventTypeSandboxReceipt records a confined session's cgroup usage when it
	// closes, so the ops view can show what it spent.
	EventTypeSandboxReceipt = "harness_sandbox_receipt"
)

Sandbox files under a run directory and the receipt event.

View Source
const (
	KeyTraceID      = "trace_id"
	KeySpanID       = "span_id"
	KeyParentSpanID = "parent_span_id"
	KeySessionID    = "session_id"
	KeyTurn         = "turn"
	KeySequence     = "sequence"
	KeyEventType    = "event_type"
	KeyElapsed      = "elapsed_ms"
	KeyError        = "error"
	// KeyExecutor is the turn executor a run started on, on its run started
	// record.
	KeyExecutor = "executor"
)

The keys every event log record carries. The turn executor's own records (ipc/model/claudecode) use the same spellings, so one log reads as one trace.

View Source
const (
	EventTypeRunStarted          = "harness_run_started"
	EventTypeWorktreeReady       = "harness_worktree_ready"
	EventTypeBuildContainerReady = "harness_build_container_ready"
	EventTypeTurnRequested       = "harness_turn_requested"
	EventTypeRunFinished         = "harness_run_finished"
	EventTypeGateDecision        = "session_gate_decision"
	EventTypeReceiptWritten      = "harness_receipt"
	// EventTypeControlAction records one control-plane operation on the
	// session — submit, send, cancel, ready, merge_started or merge — whichever client called
	// it: the CLI, an MCP client or the Workbench page.
	EventTypeControlAction = "harness_control_action"
	// EventTypeGitHubCall records one GitHub operation the session called
	// through CSF's typed GitHub tools, with its outcome.
	EventTypeGitHubCall = "github_call"
)

Event types the harness itself writes; the turn executor writes the stream-json types of the events it forwards.

View Source
const (
	KeyAction           = "action"
	KeyOperatorAuthored = "operator_authored"
	// KeyQuestionWanted marks a send by which the operator overrides the
	// question gate: the operator wanted the question it last refused.
	KeyQuestionWanted = "question_wanted"
	KeyTurnID         = "turn_id"
	KeyPullRequestURL = keyPullRequestURL

	ActionSubmit = "submit"
	ActionSend   = "send"
	ActionCancel = "cancel"
	ActionReady  = "ready"
	ActionMerge  = "merge"
	// ActionMergeStarted is written when a merge begins, before the merge
	// path runs, so a reader of the log knows one is in flight until the
	// merge record that ends it.
	ActionMergeStarted = "merge_started"
)

The fields and values of a control action record.

View Source
const (
	KeyTaskID        = "task_id"
	KeyToolUseID     = "tool_use_id"
	KeyTaskStatus    = "status"
	KeyTaskSummary   = "summary"
	KeyTaskElapsed   = "task_elapsed_ms"
	KeyTaskExitCode  = "exit_code"
	KeyTaskOutputEnd = "output_tail"

	// OutputTailBytes bounds the output a background result carries: the end
	// of the task's output, where a command's verdict and exit status are. It
	// is a size bound for the record, not a measured threshold.
	OutputTailBytes = 2048
)

The fields of a background result record.

View Source
const (
	// EventTypeProviderApplied records the provider a session was launched
	// through and the spelling its model resolved to, with no credential.
	EventTypeProviderApplied = "harness_provider_applied"
	// EventTypeProviderFallback records a turn the provider's first spelling
	// could not serve, retried on the next one.
	EventTypeProviderFallback = "harness_provider_fallback"
	// KeyProviderBaseURL is the provider's endpoint.
	KeyProviderBaseURL = "provider_base_url"
	// KeyProviderModel is the provider spelling the session's model resolved
	// to, and KeyProviderNextModel the spelling a fallback moved to.
	KeyProviderModel     = "provider_model"
	KeyProviderNextModel = "provider_next_model"
	// KeyProviderReason is why the provider could not serve the spelling, as
	// the executor reported it.
	KeyProviderReason = "provider_reason"
	// KeyModel is the CSF model name the recipe asked for.
	KeyModel = "model"
)

The inference provider's records on a session's event log.

View Source
const (
	EventTypeUser      = "user"
	EventTypeAssistant = "assistant"
	EventTypeResult    = "result"
	EventTypeSystem    = "system"

	DirectionIn  = "in"
	DirectionOut = "out"

	BlockText       = "text"
	BlockToolUse    = "tool_use"
	BlockToolResult = "tool_result"

	// MaxRecordBytes bounds one event log line read back; a tool input can
	// carry a whole file.
	MaxRecordBytes = 16 << 20
)

The stream-json event types, directions and content block types the harness reads back from its own event log, spelled as Claude Code spells them.

View Source
const (

	// MCPServerName is the name sessions reach the host's own MCP server by,
	// so its tools are spelled mcp__csf__<tool> in a recipe's allowed tools.
	MCPServerName = "csf"
	// AssignmentHeader carries a session's assignment on every request it
	// makes to the host's MCP server, so an operation names its actor.
	AssignmentHeader = "X-CSF-Assignment"
)

Executables and arguments of the children the runner starts.

View Source
const (
	HookPreToolUse  = "PreToolUse"
	HookPostToolUse = "PostToolUse"
	// HookStop is the turn executor's end-of-turn event: the reply gate's.
	HookStop = "Stop"
	// ToolBash is the tool the two tool gates watch.
	ToolBash = "Bash"
)

The Claude Code hook events the harness installs gates on, spelled as Claude Code's settings and hook input spell them.

View Source
const (
	// ToolAskUserQuestion is the turn executor's tool for putting a question
	// to the operator; the question gate judges it before it is shown.
	ToolAskUserQuestion = "AskUserQuestion"
	// ReadyToolName is the CSF GitHub tool that marks a draft ready, and
	// ToolReadyPullRequest its name as a session's turn executor calls it.
	ReadyToolName        = "MarkPullRequestReady"
	ToolReadyPullRequest = "mcp__" + MCPServerName + "__" + ReadyToolName
	// ToolGrep and ToolGlob are the turn executor's search tools; a chain of
	// them is the search gate's.
	ToolGrep = "Grep"
	ToolGlob = "Glob"
)
View Source
const (
	// RunStateFile records the run for its gates and for a resumed turn.
	RunStateFile = "run.json"
	// SettingsFile is the Claude Code settings the session starts with.
	SettingsFile = "settings.json"
	// EventsFile is the run's event log, one JSON object per line.
	EventsFile = "events.jsonl"
	// WorktreeDirectory is the git worktree the session works in.
	WorktreeDirectory = "worktree"
)

The files of one run directory, <state directory>/<assignment id>.

View Source
const (
	// ResearchCheckFence tags the fenced block holding one research check as
	// a JSON object, or several as a JSON array.
	ResearchCheckFence = "research-check"

	FitsGoalYes    = "yes"
	FitsGoalNo     = "no"
	FitsGoalPartly = "partly"

	LikelySourceAgentOutput = "agent output"
	LikelySourcePaper       = "paper"
	LikelySourcePerson      = "person"
	LikelySourceUnknown     = "unknown"
)

The research check protocol between the message and the reply gate: what a reply carries for each unvetted term before acting on it.

View Source
const (
	VerdictFieldPass    = "pass"
	VerdictFieldDefects = "defects"
)

The verdict's field names, as Incomplete reports a missing one.

View Source
const EventTypeBackgroundResult = "harness_background_result"

EventTypeBackgroundResult records a turn the turn executor started on its own, between turns, because a task it ran in the background ended: the harness counts it as the session's next turn, and the record carries what woke it.

View Source
const EventTypeOperatorAffect = "operator_affect"

EventTypeOperatorAffect records, for a turn whose message is the operator's own words, the message's operator affect as pkg/affect reads it: strain, kind, whether it is an operator correction, whether the operator reports strain, and the features. It is the label of the agent turn the message answers, which the record names as its target turn.

View Source
const EventTypeRulings = "rulings"

EventTypeRulings records, at the start of every turn, the rulings in force when the turn was sent: the question gate checks the turn's questions and the alternatives they offer against them.

View Source
const EventTypeRunResumed = "harness_run_resumed"

EventTypeRunResumed records that a run was reopened on its recorded conversation, after the harness restarted.

View Source
const EventTypeSessionClosed = "harness_session_closed"

EventTypeSessionClosed records that an open session's turn executor was closed.

View Source
const EventTypeUnvettedTerms = "unvetted_terms"

EventTypeUnvettedTerms records, for a turn whose message is the operator's own words, the operator's unvetted terms: the terms of the message that appear in none of the operator's earlier messages. The vocabulary of earlier messages is the union of every such record under the state directory, since every term is unvetted exactly once, at its first appearance.

View Source
const KeyRulings = "rulings"

KeyRulings is the rulings a rulings record carries.

View Source
const (
	// KeyTerms is the unvetted terms, as the operator spelled them.
	KeyTerms = "terms"
)

The keys of an unvetted terms record beyond the common ones.

View Source
const PushRemote = "origin"

PushRemote is the remote the harness pushes a work branch to and opens its pull request on.

View Source
const RecipeFile = "recipe.json"

RecipeFile holds the run's frozen recipe, so a restarted harness can reopen the run without being handed it again.

View Source
const RulingsFile = "rulings.jsonl"

RulingsFile holds every ruling the operator recorded, one JSON object per line, in the order recorded, under the harness's state directory.

View Source
const StopReasonEndTurn = "end_turn"

StopReasonEndTurn is the stop reason of the message that ends a reply.

View Source
const SubtypeBackgroundTasksChanged = "background_tasks_changed"

SubtypeBackgroundTasksChanged is the system event the turn executor writes with the whole list of its background tasks whenever one starts or ends.

View Source
const Unenforced = "UNENFORCED"

Unenforced is how a ruling no gate enforces is flagged wherever rulings are shown.

View Source
const VerdictFence = "verdict"

VerdictFence tags the fenced block holding a verifier station's typed verdict: the final message of a session that read only a slice record and its diff (#420).

View Source
const (
	VerifierAgentID = "slice-verifier"
)

The verifier station's recipe: one agent, a branch per verified head, and the one tool that reads the diff.

Variables

View Source
var (
	// ErrInvalidOption reports a nil option or an option value the runner
	// cannot use.
	ErrInvalidOption = errors.New("harness session: invalid option")
	// ErrNoLauncher reports a runner built without the process capability.
	ErrNoLauncher = errors.New("harness session: a process launcher is required")
	// ErrNoStateDirectory reports a runner built without a state directory.
	ErrNoStateDirectory = errors.New("harness session: an absolute state directory is required")
	// ErrNoGateCommand reports a runner built without the gate command.
	ErrNoGateCommand = errors.New("harness session: a gate command is required")
	// ErrInvalidRecipe reports a recipe the harness cannot run.
	ErrInvalidRecipe = errors.New("harness session: invalid recipe")
	// ErrSessionExists reports a run already started for the assignment; a
	// follow-up turn is a Resume.
	ErrSessionExists = errors.New("harness session: the assignment already has a session; resume it")
	// ErrWorktreeCollision reports a worktree path already occupied by
	// something the harness did not record.
	ErrWorktreeCollision = errors.New("harness session: the worktree path is already occupied")
	// ErrWorktree reports a worktree git could not create.
	ErrWorktree = errors.New("harness session: could not create the worktree")
	// ErrRunMismatch reports a recorded run that belongs to another recipe.
	ErrRunMismatch = errors.New("harness session: the recorded run belongs to a different recipe")
	// ErrNoPrompt reports a resumed turn with nothing to say.
	ErrNoPrompt = errors.New("harness session: a resumed turn needs a prompt")
	// ErrTurnFailed reports a turn the turn executor did not complete.
	ErrTurnFailed = errors.New("harness session: the turn failed")
	// ErrPushRemote reports a worktree whose push remote git could not name.
	ErrPushRemote = errors.New("harness session: could not read the push remote's URL")
)

The values the enumerated fields of a research check may hold.

View Source
var ErrCopilotInjectUnsupported = errors.New("session: the copilot turn executor cannot inject a message mid-turn")

copilotTurnExecutor adapts the Copilot CLI turn executor to the runner's turn shape: the runner hands every executor one stream-json user message, and Copilot takes the prompt it carries. Each turn is one Copilot process on the session, so the same executor serves a Run, a Resume and an open session. ErrCopilotInjectUnsupported means the Copilot CLI turn executor runs one process per turn and cannot take a message in the middle of one; queued messages arrive with the next turn instead.

View Source
var ErrNoRunState = errors.New("harness session: no run is recorded in this directory")

ErrNoRunState reports a run directory with no recorded run.

View Source
var ErrProviderUnavailable = errors.New("harness session: the provider could not serve the model")

ErrProviderUnavailable reports a turn the provider could not serve on the spelling it was asked for: the fallback retries it on the next spelling, and a turn with none left fails with this error.

View Source
var ErrSessionClosed = errors.New("harness session: the session is closed")

ErrSessionClosed reports a turn on an open session after Close.

View Source
var ErrSuspended = errors.New("harness session: the session is suspended; resume it before the turn")

ErrSuspended reports a turn asked of a suspended session; the caller resumes it first.

View Source
var ErrUserSettings = errors.New("harness session: the user settings cannot take the gate hook")

ErrUserSettings reports a user settings file the harness cannot merge its hook into: not a JSON object, or hooks not an object of event arrays.

Functions

func AppendRuling added in v0.3.0

func AppendRuling(stateDirectory string, ruling Ruling) error

AppendRuling records ruling after every earlier one under stateDirectory.

func InstallOperatorGates added in v0.3.0

func InstallOperatorGates(home string, gateCommand []string) ([]string, error)

InstallOperatorGates hooks the operator's own Claude Code and Copilot sessions under home up to the wait gate, so a shell command that waits on nothing is refused there as it is in a harness session. Claude Code's user settings keep every other setting and hook, and a second install changes nothing; Copilot's hooks file is the harness's own. It returns the files it wrote.

func LastFencedBlock added in v0.3.0

func LastFencedBlock(text string, tag string) (body string, found bool)

LastFencedBlock is the body of the last fenced block a text tags with tag, trimmed; found is false when it has none.

func LastReply added in v0.3.0

func LastReply(records []Record) string

LastReply is the text of the last assistant message in records that said anything, its text blocks joined by a blank line: a session's final message so far.

func OperatorVocabulary added in v0.3.0

func OperatorVocabulary(stateDirectory string) (*terms.Vocabulary, error)

OperatorVocabulary is every term recorded as unvetted in any run under stateDirectory: the operator's vocabulary so far. A run whose log cannot be read contributes nothing.

func ProviderUnavailable added in v0.3.0

func ProviderUnavailable(proposal *model.Proposal[claudecode.Event], err error) (string, bool)

ProviderUnavailable reports whether the provider could not serve the spelling the turn asked for, which is what a fallback retries, and the reason the executor gave. The executor reports it either way: as the result event of a proposal it completed, or inside the claudecode.TurnError of one it did not. A turn that failed for any other cause is not a fallback: the model answered and the session keeps its turn.

func PushRemoteURL

func PushRemoteURL(ctx context.Context, launcher proc.ILauncher, worktree string) (string, error)

PushRemoteURL is the URL of the worktree's push remote, as git records it: the repository gh is told to act on, so a clone whose gh default is another remote still gets its pull request where the branch was pushed.

func ReadRecipe

func ReadRecipe(directory string) (*pb.AgentAssignmentRecipe, error)

ReadRecipe reads the recipe a run recorded when it opened.

func ResearchCheckSkeleton added in v0.3.0

func ResearchCheckSkeleton(term terms.Term) string

ResearchCheckSkeleton is the check for term with its answers blank and its enumerations spelled out, as the message shows it to the agent.

func RunDirectory

func RunDirectory(stateDirectory string, assignmentID string) string

RunDirectory is the deterministic directory of an assignment's run.

func RunTrace

func RunTrace(state *RunState) *telemetryv1.TraceContext

RunTrace is the run's root span recorded in state.

func VerdictSkeleton added in v0.3.0

func VerdictSkeleton() string

VerdictSkeleton is a verdict with every field shown, as the verifier's task shows it.

func VerifierAssignmentID added in v0.3.0

func VerifierAssignmentID(author string, head string) string

VerifierAssignmentID is the verifier station's assignment for one author run at one head.

func VerifierRecipe added in v0.3.0

func VerifierRecipe(record SliceRecord, author *pb.AgentAssignmentRecipe) (*pb.AgentAssignmentRecipe, error)

VerifierRecipe is the verifier station's recipe for a slice record: a session on the author's model and repository whose task is the record and whose one tool reads its diff, in a worktree at the record's head.

func WriteRulingsView added in v0.3.0

func WriteRulingsView(writer io.Writer, rulings []Ruling) error

WriteRulingsView writes the human-readable view of the rulings in force, generated from the records: the coverage first, then each ruling under its identifier with its gate or the UNENFORCED flag, its statement, the operator's words quoted and its facts.

func WriteRunState

func WriteRunState(directory string, state *RunState) error

WriteRunState replaces the run state atomically, so a gate never reads a half-written file. Gates and hooks use this to persist state changes like push times.

Types

type AgentSessionRunner

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

AgentSessionRunner runs agent sessions for prepared assignments.

func NewAgentSessionRunner

func NewAgentSessionRunner(options ...AgentSessionRunnerOption) (*AgentSessionRunner, error)

NewAgentSessionRunner validates the whole option set before building the runner.

func (*AgentSessionRunner) Open

func (runner *AgentSessionRunner) Open(ctx context.Context, recipe *pb.AgentAssignmentRecipe, environment ...string) (*OpenSession, error)

Open prepares the assignment's session exactly as Run does, up to the first turn: the recipe is frozen, the worktree created, the gates installed and the turn executor opened on the session. The first turn is the caller's to run, with OpenSession.FirstPrompt. The worktree creation is bounded by ctx; the executor's process is bounded by the session, which Close ends.

func (*AgentSessionRunner) Reopen

func (runner *AgentSessionRunner) Reopen(ctx context.Context, recipe *pb.AgentAssignmentRecipe, environment ...string) (*OpenSession, error)

Reopen reopens a run a previous harness process left open: the same assignment, worktree, branch and trace, and the turn executor opened on the recorded conversation, resumed when a turn has run on it. No worktree is created and nothing is replayed.

func (*AgentSessionRunner) Resume

Resume runs a follow-up turn on the assignment's existing session, in the same worktree and under the same trace.

func (*AgentSessionRunner) Run

Run starts the assignment's session: it prepares the recipe, creates the worktree, installs the gates and runs the first turn on the task. The receipt is returned whenever the session was started, also when the turn failed, so its links are never lost with the error.

func (*AgentSessionRunner) StateDirectory

func (runner *AgentSessionRunner) StateDirectory() string

StateDirectory is the directory every run lives under, as <assignment id>/.

type AgentSessionRunnerOption

type AgentSessionRunnerOption func(runner *AgentSessionRunner) error

AgentSessionRunnerOption configures an AgentSessionRunner.

func WithClaudeExecutable

func WithClaudeExecutable(executable string) AgentSessionRunnerOption

WithClaudeExecutable runs Claude Code from executable instead of the name claude on PATH.

func WithContainerSessions added in v0.3.0

func WithContainerSessions(containers ISessionContainers, settings ContainerSettings) AgentSessionRunnerOption

WithContainerSessions runs every session the runner opens inside its own container of the session image, with no Docker socket.

func WithCopilotExecutable added in v0.3.0

func WithCopilotExecutable(executable string) AgentSessionRunnerOption

WithCopilotExecutable runs the Copilot CLI from executable instead of the name copilot on PATH, for a recipe that chooses Copilot.

func WithGateCommand

func WithGateCommand(arguments ...string) AgentSessionRunnerOption

WithGateCommand is the command Claude Code calls for every gated hook, with the hook event and the run directory appended. Required.

func WithLauncher

func WithLauncher(launcher proc.ILauncher) AgentSessionRunnerOption

WithLauncher grants the process capability git, gh and the turn executor start through. Required.

func WithMCPServer added in v0.3.0

func WithMCPServer(url string) AgentSessionRunnerOption

WithMCPServer gives every session the host's MCP server at url, under the name MCPServerName. A recipe still allows each tool it may call.

func WithOpenTurnExecutors

func WithOpenTurnExecutors(factory OpenTurnExecutorFactory) AgentSessionRunnerOption

WithOpenTurnExecutors replaces the open Claude Code turn executor.

func WithProvider added in v0.3.0

func WithProvider(router *provider.Router) AgentSessionRunnerOption

WithProvider launches every session through router, the host's inference provider: each turn executor is given the provider's environment, its --model is the provider's spelling of the recipe's CSF model, and a turn the first spelling cannot serve is retried on the next.

func WithRouter

func WithRouter(router IRouter) AgentSessionRunnerOption

WithRouter routes every opened session: without one, each session opens a new conversation.

func WithSandbox added in v0.3.0

func WithSandbox(manager *sandbox.Manager, dockerUpstream string) AgentSessionRunnerOption

WithSandbox confines every session the runner opens: it is granted the sandbox capability and the Docker Engine socket the per-session proxy forwards to. Without it, sessions run unsandboxed, which is the default until the sandbox acceptance passes on a host.

func WithStateDirectory

func WithStateDirectory(directory string) AgentSessionRunnerOption

WithStateDirectory keeps each run under directory/<assignment id>. Required; the directory must be absolute.

func WithTurnExecutors

func WithTurnExecutors(factory TurnExecutorFactory) AgentSessionRunnerOption

WithTurnExecutors replaces the Claude Code turn executor.

type BackgroundTask added in v0.3.0

type BackgroundTask struct {
	TaskID      string `json:"task_id"`
	TaskType    string `json:"task_type"`
	Description string `json:"description"`
}

BackgroundTask is one task the turn executor runs in the background, as its background_tasks_changed event lists it.

func LiveBackgroundTasks added in v0.3.0

func LiveBackgroundTasks(records []Record) []BackgroundTask

LiveBackgroundTasks is the background tasks the turn executor last reported running in records: the list of its latest background_tasks_changed event. A closed or resumed executor runs none until it reports again.

type ContainerSettings added in v0.3.0

type ContainerSettings struct {
	// Image is the session image for a worktree that pins none in
	// [SessionImageFile].
	Image string
	// Docker is the docker CLI the executor is attached through with
	// `docker exec -i`; the harness keeps the socket, the session never sees
	// it.
	Docker string
	// MemoryBytes, NanoCPUs and PidsLimit are the per-session limits; zero
	// takes the derived default.
	MemoryBytes int64
	NanoCPUs    int64
	PidsLimit   int64
	// Credentials are the executor's and gh's, mounted read-only.
	Credentials []Credential
	// ConversationStore is the host directory the executor saves its
	// conversations under, one directory per working directory (such as
	// ~/.claude/projects). The worktree's own directory is mounted read-write
	// into the session's home, so a container session resumes a conversation
	// a host session saved, and the other way round. Empty mounts none.
	ConversationStore string
}

ContainerSettings is how every session container is built.

type ContentBlock added in v0.3.0

type ContentBlock struct {
	Type      string          `json:"type"`
	Text      string          `json:"text"`
	ID        string          `json:"id"`
	Name      string          `json:"name"`
	Input     json.RawMessage `json:"input"`
	Content   json.RawMessage `json:"content"`
	ToolUseID string          `json:"tool_use_id"`
	IsError   bool            `json:"is_error"`
}

ContentBlock is one block of a stream-json message's content: ID names a tool_use block's call, and ToolUseID and IsError are a tool_result block's call and outcome.

func (*ContentBlock) ResultText added in v0.3.0

func (block *ContentBlock) ResultText() string

ResultText is a tool_result block's content as text: a string content, or its text blocks joined by a newline.

type Credential added in v0.3.0

type Credential struct {
	// Source is the host path.
	Source string
	// Home is the path under the session's home it is mounted at, such as
	// .config/gh.
	Home string
}

Credential is one host credential mounted read-only into the session's home.

type Decision added in v0.3.0

type Decision struct {
	Statement string `json:"statement"`
	Reason    string `json:"reason"`
}

Decision is one choice the author made, with its reason.

type Defect added in v0.3.0

type Defect struct {
	Statement string   `json:"statement"`
	Field     string   `json:"field"`
	Evidence  []string `json:"evidence"`
}

Defect is one thing the verifier found wrong: the statement it contradicts (an acceptance item, a decision, the proof), where in the record that statement is, and the evidence, each a diff location (path:line) or a record field.

type EventLog

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

EventLog appends one run's records to its events.jsonl. The runner and every gate process open it for appending; each record is one write of one line, so records from the session and its hooks interleave whole.

func OpenEventLog

func OpenEventLog(directory string, trace *telemetryv1.TraceContext) (*EventLog, error)

OpenEventLog opens the event log of the run in directory for appending, under trace, the run's root span.

func (*EventLog) Close

func (log *EventLog) Close() error

Close closes the log file.

func (*EventLog) Context

func (log *EventLog) Context(ctx context.Context) (context.Context, error)

Context is ctx carrying the run's trace, so spans derived from it, the turn executor's included, belong to the run.

func (*EventLog) Failure

func (log *EventLog) Failure(ctx context.Context, session string, turn int, eventType string, message string, err error, attributes ...slog.Attr)

Failure writes one error record of eventType under a new child span.

func (*EventLog) Logger

func (log *EventLog) Logger() *slog.Logger

Logger is the structured logger writing into the event log; the turn executor reports every event it forwards through it.

func (*EventLog) Record

func (log *EventLog) Record(ctx context.Context, session string, turn int, eventType string, message string, attributes ...slog.Attr)

Record writes one record of eventType under a new child span of the run.

type Executor added in v0.3.0

type Executor string

Executor names the turn executor a session runs on, as a recipe's executor field spells it.

const (
	ExecutorClaudeCode Executor = "claude-code"
	ExecutorCopilot    Executor = "copilot"
)

The turn executors a recipe can choose. An empty executor field is Claude Code.

func ExecutorOf added in v0.3.0

func ExecutorOf(recipe *pb.AgentAssignmentRecipe) Executor

ExecutorOf is the turn executor the recipe chooses.

type IOpenTurnExecutor

type IOpenTurnExecutor interface {
	ITurnExecutor
	Interrupt(ctx context.Context) error
	Close(ctx context.Context) error
}

IOpenTurnExecutor is a turn executor kept open across turns: the Claude Code process whose stream-json input stays open in production, a double in specs. Interrupt asks it to end the running turn at its next safepoint; Inject writes a message to the executor's input; Close ends it and joins what it started.

type IRouter

type IRouter interface {
	Route(ctx context.Context, request RouteRequest) (string, error)
}

IRouter decides which real session, a Claude Code conversation, a virtual session runs on: an existing one it fits well in, which it resumes, or request.Session, a new one.

type ISessionContainers added in v0.3.0

type ISessionContainers interface {
	StartDetached(ctx context.Context, spec docker.SandboxSpec) (docker.StartedContainer, error)
	ContainerUsage(started docker.StartedContainer) (sandbox.Usage, error)
	RemoveContainer(ctx context.Context, id string) error
}

ISessionContainers is the container capability a container session needs: *docker.ContainerHost in production, a double in specs.

type ITurnExecutor

type ITurnExecutor interface {
	Propose(ctx context.Context, turn *claudecode.Turn) (*model.Proposal[claudecode.Event], error)
	Inject(ctx context.Context, message string) error
}

ITurnExecutor carries out one turn of a session: the Claude Code turn executor in production, a double in specs.

type OpenSession

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

OpenSession is one assignment's session held open: its run directory, event log and worktree exist, its turn executor is open, and no turn has run until the caller asks for one. One goroutine drives it; turns never overlap.

func (*OpenSession) BackgroundResult added in v0.3.0

func (open *OpenSession) BackgroundResult(ctx context.Context, notification claudecode.TaskNotification) error

BackgroundResult counts the turn the executor started on notification as the session's next turn and records it as a typed background result: the task, how it ended, its exit code when its output names one, how long it ran and the bounded tail of its output. Nothing is sent to the executor; the turn is already running.

func (*OpenSession) BackgroundResults added in v0.3.0

func (open *OpenSession) BackgroundResults() <-chan claudecode.TaskNotification

BackgroundResults delivers the task notifications the turn executor read between turns, each of which started a turn of the executor's own. The goroutine driving the session records each with OpenSession.BackgroundResult.

func (*OpenSession) Close

func (open *OpenSession) Close(ctx context.Context) error

Close ends the turn executor, bounded by ctx, and closes the event log. It is idempotent.

func (*OpenSession) Directory

func (open *OpenSession) Directory() string

Directory is the run directory: events.jsonl, run.json, settings.json and the worktree live there.

func (*OpenSession) FirstPrompt

func (open *OpenSession) FirstPrompt() string

FirstPrompt is the task as the agent first reads it.

func (*OpenSession) Interrupt

func (open *OpenSession) Interrupt(ctx context.Context) error

Interrupt asks the running turn to end at the executor's next safepoint. An suspended session runs no turn, so there is nothing to interrupt.

func (*OpenSession) Plan

func (open *OpenSession) Plan() *pb.AgentAssignmentPlan

Plan is the frozen recipe the session runs.

func (*OpenSession) Resume added in v0.3.0

func (open *OpenSession) Resume(ctx context.Context, suspended time.Duration) error

Resume is the session hypervisor's resume: it opens the turn executor again on the recorded conversation after a suspend, on the spec it was first opened with and resumed, exactly as a restarted harness reopens a run. suspended is how long the session was suspended; the next turn's receipt carries it with the time to first token. A session whose executor is open is left as it is.

func (*OpenSession) State

func (open *OpenSession) State() RunState

State is a copy of the run's record as last written.

func (*OpenSession) Suspend added in v0.3.0

func (open *OpenSession) Suspend(ctx context.Context, idle time.Duration) error

Suspend is the session hypervisor's suspend: it ends the turn executor's process, bounded by ctx, and keeps the session open on its recorded conversation: the event log stays open, the worktree and run record stay, and OpenSession.Resume opens the executor again. idle is how long the session had been between turns. A suspended session is left as it is.

func (*OpenSession) Suspended added in v0.3.0

func (open *OpenSession) Suspended() bool

Suspended reports whether the session is suspended: its turn executor closed.

func (*OpenSession) Turn

func (open *OpenSession) Turn(ctx context.Context, prompt string, options ...TurnOption) (*pb.AgentAssignmentReceipt, error)

Turn runs prompt as the session's next turn on the open executor and returns the receipt. ctx bounds the wait for the turn's result; the executor's process outlives it.

type OpenTurnExecutorFactory

type OpenTurnExecutorFactory func(ctx context.Context, spec TurnExecutorSpec) (IOpenTurnExecutor, error)

OpenTurnExecutorFactory opens the turn executor an OpenSession holds.

func ClaudeCodeOpenTurnExecutors

func ClaudeCodeOpenTurnExecutors(launcher proc.ILauncher, executable string) OpenTurnExecutorFactory

ClaudeCodeOpenTurnExecutors opens one Claude Code process per session through launcher and keeps it across turns.

func OpenTurnExecutorsByRecipe added in v0.3.0

func OpenTurnExecutorsByRecipe(launcher proc.ILauncher, claude string, copilot string) OpenTurnExecutorFactory

OpenTurnExecutorsByRecipe opens the turn executor each recipe chooses: Claude Code from claude, or the Copilot CLI from copilot.

type OperatorCorrection added in v0.3.0

type OperatorCorrection struct {
	Assignment string
	TargetTurn int
	At         time.Time
}

OperatorCorrection is one operator correction a run recorded: the run, the turn whose reply it answers, and when the operator sent it.

func OperatorCorrections added in v0.3.0

func OperatorCorrections(stateDirectory string) ([]OperatorCorrection, error)

OperatorCorrections is every operator correction recorded in any run under stateDirectory, oldest first. A run whose log cannot be read contributes nothing.

type QuestionVerdict added in v0.3.0

type QuestionVerdict struct {
	Class   string `json:"class"`
	Blocked bool   `json:"blocked"`
}

QuestionVerdict is one question an agent put to the operator, the class the question gate placed it in and whether the gate refused it.

type Record added in v0.3.0

type Record struct {
	Time      time.Time       `json:"time"`
	Message   string          `json:"msg"`
	EventType string          `json:"event_type"`
	Turn      int             `json:"turn"`
	Direction string          `json:"direction"`
	Event     json.RawMessage `json:"event"`
	// Provider is the turn executor that reported Event.
	Provider string `json:"provider"`
	Gate     string `json:"gate"`
	Decision string `json:"decision"`
	Reason   string `json:"reason"`
	Error    string `json:"error"`
	// Action is a control action record's action: submit, send, cancel,
	// ready, merge_started or merge.
	Action  string       `json:"action"`
	Terms   []terms.Term `json:"terms"`
	Rulings []Ruling     `json:"rulings"`
	// Questions is a question gate decision's verdicts and QuestionWanted a
	// send that overrides the gate.
	Questions      []QuestionVerdict `json:"questions"`
	QuestionWanted bool              `json:"question_wanted"`
	// Affect is an operator affect record's reading; nil on every other kind.
	Affect *affect.Reading `json:"affect"`
}

Record is one event log line as the harness reads it back: the keys every record carries and the keys of the record kinds the harness acts on.

func ReadRecords added in v0.3.0

func ReadRecords(directory string, keep func(record *Record) bool) ([]Record, error)

ReadRecords reads the event log of the run in directory and returns the records keep accepts, in order. A line that is not a record is skipped.

func ReadTurnRecords added in v0.3.0

func ReadTurnRecords(directory string) ([]Record, error)

ReadTurnRecords returns the records of the turn running: the last turn start, a turn request or a background result, and every record after it. No turn started is no records.

func TurnRecords added in v0.3.0

func TurnRecords(records []Record) []Record

TurnRecords is the part of a run's records that belongs to the turn running, as ReadTurnRecords reads it.

func (*Record) Assistant added in v0.3.0

func (record *Record) Assistant() (text []string, tools []ToolUse)

Assistant is what the assistant said in the record, its text blocks joined by a blank line, and the tools it called, in order. A record that is not an assistant event has neither.

func (*Record) Stream added in v0.3.0

func (record *Record) Stream() (message StreamMessage, ok bool)

Stream decodes the executor event the record carries; ok is false for a record that carries none.

func (*Record) Text added in v0.3.0

func (record *Record) Text() []string

Text is the text blocks of the executor event the record carries, in order: what the message said, whoever sent it.

type ResearchCheck added in v0.3.0

type ResearchCheck struct {
	Term            string `json:"term"`
	WhatItIs        string `json:"what_it_is"`
	WhatItDoesNotDo string `json:"what_it_does_not_do"`
	// FitsGoal is one of FitsGoalValues: whether the term fits the
	// operator's stated goal.
	FitsGoal string `json:"fits_goal"`
	Why      string `json:"why"`
	// LikelySource is one of LikelySourceValues: where the term most likely
	// came from.
	LikelySource string `json:"likely_source"`
}

ResearchCheck is the typed record a reply carries for each unvetted term.

func (ResearchCheck) Incomplete added in v0.3.0

func (check ResearchCheck) Incomplete() []string

Incomplete names the fields a check leaves blank or outside their values; a complete check has none.

type RouteRequest

type RouteRequest struct {
	Virtual string
	// Session is the conversation the virtual session opens when no
	// existing one fits.
	Session string
	Model   string
	// Agent is the agent's identity: its id and a hash of its instructions.
	// A resumed conversation keeps the system prompt it first recorded, so
	// only a conversation with the same identity may be attached.
	Agent string
	// Key is the topic key: the assignment's ticket.
	Key string
	// Summary is the assignment in a line: its pull request title.
	Summary string
}

RouteRequest is what a router knows about a virtual session (one assignment) before it opens.

type Ruling added in v0.3.0

type Ruling struct {
	ID          string    `json:"ruling_id"`
	Statement   string    `json:"statement"`
	Excludes    []string  `json:"excludes"`
	Supersedes  string    `json:"supersedes,omitempty"`
	Quote       string    `json:"quote,omitempty"`
	RuledOn     string    `json:"ruled_on,omitempty"`
	Scope       string    `json:"scope,omitempty"`
	Why         string    `json:"why,omitempty"`
	EnforcedBy  string    `json:"enforced_by,omitempty"`
	PendingGate string    `json:"pending_gate,omitempty"`
	RecordedAt  time.Time `json:"recorded_at"`
}

Ruling is one recorded operator ruling: what it decides, the operator's own words, the day, whom it binds, why, the gate that enforces it or the one that will, the alternatives it rules out, and the ruling it replaces. An agent question, or an alternative it offers, that names an excluded alternative re-litigates the ruling.

func InForce added in v0.3.0

func InForce(content []byte) ([]Ruling, error)

InForce folds the content of a rulings file into the rulings in force, in the order first recorded: the latest record of each identifier, without the ones a later ruling supersedes.

func RulingsInForce added in v0.3.0

func RulingsInForce(stateDirectory string) ([]Ruling, error)

RulingsInForce returns the rulings in force under stateDirectory, in the order first recorded. No rulings file is no rulings.

func (Ruling) Enforced added in v0.3.0

func (ruling Ruling) Enforced() bool

Enforced reports whether a gate enforces the ruling. A ruling whose gate is only pending is not enforced.

func (Ruling) Enforcement added in v0.3.0

func (ruling Ruling) Enforcement() string

Enforcement is the ruling's gate, or the UNENFORCED flag with the gate pending when one is named.

type RulingCoverage added in v0.3.0

type RulingCoverage struct {
	Enforced int
	Total    int
}

RulingCoverage is how many of the rulings in force a gate enforces, out of all of them.

func CoverageOf added in v0.3.0

func CoverageOf(rulings []Ruling) RulingCoverage

CoverageOf counts the rulings a gate enforces.

func (RulingCoverage) Unenforced added in v0.3.0

func (coverage RulingCoverage) Unenforced() int

Unenforced is the rulings in force that no gate enforces.

type RunState

type RunState struct {
	AssignmentID     string `json:"assignment_id"`
	AgentID          string `json:"agent_id"`
	TicketURL        string `json:"ticket_url"`
	SessionID        string `json:"session_id"`
	TraceID          string `json:"trace_id"`
	SpanID           string `json:"span_id"`
	Repository       string `json:"repository"`
	Worktree         string `json:"worktree"`
	Branch           string `json:"branch"`
	BaseBranch       string `json:"base_branch"`
	PullRequestTitle string `json:"pull_request_title"`
	// WorkspaceMode is the workspace configuration: "normal" or "patch".
	WorkspaceMode string `json:"workspace_mode"`
	// Turns counts the turns started on the session, so a gate attributes its
	// decisions to the turn that is running.
	Turns int `json:"turns"`
	// LastPushTime records the Unix timestamp of the most recent push,
	// initialized when the session starts and updated by the commit gate.
	LastPushTime int64 `json:"last_push_time,omitempty"`
	// Model is the LLM model the session runs on, needed by the commit hook.
	Model string `json:"model,omitempty"`
	// Executor is the turn executor the session runs on. A run recorded
	// before executors were chosen has none and ran on Claude Code.
	Executor Executor `json:"executor,omitempty"`
	// BuildContainerID is the ID of the long-lived build container for this session.
	BuildContainerID string `json:"build_container_id,omitempty"`
}

RunState is what the harness records about a run so its session gates and a later resumed turn act on the same session, trace and branch. Gates read it; only the runner writes it.

func ReadRunState

func ReadRunState(directory string) (*RunState, error)

ReadRunState reads the run recorded in directory.

func (*RunState) TurnExecutor added in v0.3.0

func (state *RunState) TurnExecutor() Executor

TurnExecutor is the turn executor the run is on: the recorded one, or Claude Code for a run recorded before executors were chosen.

type SliceDiff added in v0.3.0

type SliceDiff struct {
	Base  string   `json:"base"`
	Head  string   `json:"head"`
	Files []string `json:"files"`
}

SliceDiff is the change a slice makes: its merge base with the base branch, its head, and every path it touches.

type SliceRecord added in v0.3.0

type SliceRecord struct {
	AssignmentID  string     `json:"assignment_id"`
	TicketURL     string     `json:"ticket_url"`
	Branch        string     `json:"branch"`
	Diff          SliceDiff  `json:"diff"`
	Decisions     []Decision `json:"decisions"`
	OpenQuestions []string   `json:"open_questions"`
	Verdict       *Verdict   `json:"verdict,omitempty"`
}

SliceRecord is the slice IR (#420): the typed record every station of a slice reads and writes. The author's run gives the ticket, the branch and the diff; the author states its decisions and open questions; the verifier station adds its verdict.

func ReadSliceRecord added in v0.3.0

func ReadSliceRecord(ctx context.Context, launcher proc.ILauncher, stateDirectory string, assignment string) (SliceRecord, error)

ReadSliceRecord reads the slice record of the author run assignment in stateDirectory: its run state, its diff through git, and the verdict of the verifier station for its head when one has answered.

type StreamMessage added in v0.3.0

type StreamMessage struct {
	Type    string `json:"type"`
	Subtype string `json:"subtype"`
	// Model is the model a session's init event names.
	Model   string `json:"model"`
	Message struct {
		Content json.RawMessage `json:"content"`
		Model   string          `json:"model"`
		// StopReason is end_turn on the message that ends a turn's reply.
		StopReason string `json:"stop_reason"`
		Usage      *Usage `json:"usage"`
	} `json:"message"`
	Result     string  `json:"result"`
	IsError    bool    `json:"is_error"`
	DurationMS float64 `json:"duration_ms"`
	// TotalCostUSD is a result's cost so far, cumulative within one executor
	// process; nil when the executor reports none, as Copilot does not.
	TotalCostUSD *float64 `json:"total_cost_usd"`
	Usage        *Usage   `json:"usage"`
	// Tasks is the background tasks running, on a background_tasks_changed
	// system event.
	Tasks []BackgroundTask `json:"tasks"`
}

StreamMessage is the stream-json event an executor record carries.

func (*StreamMessage) Blocks added in v0.3.0

func (message *StreamMessage) Blocks() []ContentBlock

Blocks is the message's content as blocks: a string content is one text block, and content of neither shape is no block.

type ToolUse added in v0.3.0

type ToolUse struct {
	// ID is the call's tool_use_id.
	ID    string
	Name  string
	Input json.RawMessage
}

ToolUse is one tool call an assistant message made.

type TurnExecutorFactory

type TurnExecutorFactory func(spec TurnExecutorSpec) (ITurnExecutor, error)

TurnExecutorFactory builds the turn executor for one turn.

func ClaudeCodeTurnExecutors

func ClaudeCodeTurnExecutors(launcher proc.ILauncher, executable string) TurnExecutorFactory

ClaudeCodeTurnExecutors builds Claude Code turn executors that start executable through launcher.

func TurnExecutorsByRecipe added in v0.3.0

func TurnExecutorsByRecipe(launcher proc.ILauncher, claude string, copilot string) TurnExecutorFactory

TurnExecutorsByRecipe builds the turn executor each recipe chooses: Claude Code from claude, or the Copilot CLI from copilot.

type TurnExecutorSpec

type TurnExecutorSpec struct {
	Session   uuid.UUID
	Directory string
	// Arguments are the turn executor's extra arguments: the settings with
	// the gates, the model, the permission mode and the allowed tools.
	Arguments []string
	Logger    *slog.Logger
	// Resume is true when the session already exists.
	Resume bool
	// Environment is appended, as NAME=value, to the environment the turn
	// executor's process inherits: the Bazel cache locations, for one.
	Environment []string
	// LaunchPrefix, when set, wraps the turn executor: the process started is
	// LaunchPrefix[0] with LaunchPrefix[1:] ahead of the executor and its
	// arguments. The sandbox puts its launcher here.
	LaunchPrefix []string
	// TaskNotifications, when set, receives the task notifications an open
	// turn executor reads between turns: the background completions that wake
	// the session. It must not block.
	TaskNotifications func(notification claudecode.TaskNotification)
	// Executor is the turn executor the recipe chose.
	Executor Executor
	// RunDirectory is the run's directory, which holds the worktree.
	RunDirectory string
}

TurnExecutorSpec is what the runner asks of a turn executor.

type TurnOption added in v0.3.0

type TurnOption func(input *turnInput)

TurnOption describes the message a turn carries.

func OperatorAuthored added in v0.3.0

func OperatorAuthored() TurnOption

OperatorAuthored marks the turn's message as the operator's own words: a chat turn the operator sent, or a relayed message that quotes the operator verbatim. The harness computes the message's unvetted terms against the operator's vocabulary, records them and puts them into the turn, and the reply gate holds the reply to them. It records the message's operator affect too, and when the strain reads high it says so in the turn and the reply gate bounds the reply's length.

type Usage added in v0.3.0

type Usage struct {
	InputTokens   int64 `json:"input_tokens"`
	OutputTokens  int64 `json:"output_tokens"`
	CacheRead     int64 `json:"cache_read_input_tokens"`
	CacheCreation int64 `json:"cache_creation_input_tokens"`
}

Usage is the tokens a message or a result counted.

func (*Usage) Context added in v0.3.0

func (usage *Usage) Context() int64

Context is the tokens the model read for a message: its whole input, cached or not, which is how full its context was.

type Verdict added in v0.3.0

type Verdict struct {
	Pass    *bool    `json:"pass"`
	Defects []Defect `json:"defects"`
}

Verdict is what the verifier station returns: whether the slice record and its diff hold, and every defect it found. Pass is true exactly when there is no defect.

func ParseVerdict added in v0.3.0

func ParseVerdict(reply string) (verdict Verdict, found bool, err error)

ParseVerdict reads the last verdict block of a reply; found is false when the reply carries none, and err is set when the block is not one JSON object.

func (Verdict) Incomplete added in v0.3.0

func (verdict Verdict) Incomplete() []string

Incomplete names the fields a verdict leaves missing or inconsistent; a complete verdict has none.

Directories

Path Synopsis
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.

Jump to

Keyboard shortcuts

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