Documentation
¶
Overview ¶
Package bench implements the scenario benchmark harness: a controlled, local-first, reproducible comparison of direct-MCP vs Ozy-brokered agent performance against a frozen incident scenario.
Index ¶
- Constants
- func ComputeFixtureHash(dir string) (string, error)
- func Execute(args []string, stdout, stderr io.Writer) int
- func GenerateIncidentDB(targetDir string) error
- func ResolveRunCount(cliRuns int, cfg *ScenarioConfig) int
- func SanitizeBaseURL(raw string) string
- func ServeMCP(toolset, fixtureDir string) error
- func WriteBreakdown(path string, bd *ContextBreakdown) error
- func WriteComparison(dir string, c *SurfaceComparison) error
- func WriteGradingResult(path string, result *GradingResult) error
- func WriteProvenance(path string, record *EnvironmentRecord) error
- func WriteSurfaceMetrics(path string, m *SurfaceMetrics) error
- type CategoryTokens
- type ContextBreakdown
- type ContextSpy
- type CriterionResult
- type EnvironmentRecord
- type FixtureMeta
- type GradingResult
- type GroundTruth
- type LedgerItem
- type LedgerWriter
- type Orchestrator
- type RequestTokens
- type RunResult
- type Runner
- type ScenarioConfig
- type SurfaceComparison
- type SurfaceMetrics
- type ToolCallLog
- type ToolSurface
- type ToolTokens
Constants ¶
const ( LedgerKindSystemPrompt = "system_prompt" LedgerKindAgentInstruction = "agent_instruction" LedgerKindToolSchema = "tool_schema" LedgerKindToolCall = "tool_call" LedgerKindToolResult = "tool_result" LedgerKindAssistantMessage = "assistant_message" LedgerKindUserMessage = "user_message" LedgerKindError = "error" LedgerKindFinalAnswer = "final_answer" )
LedgerKind values categorize ledger entries by their role in the context.
const ( TokenSourceMeasured = "measured" TokenSourceEstimated = "estimated" )
TokenSource values label how token counts were obtained.
const Version = "0.1.0-dev"
Version is the build version reported by `ozy-bench --version`.
Variables ¶
This section is empty.
Functions ¶
func ComputeFixtureHash ¶
ComputeFixtureHash returns a SHA-256 hash of the fixture directory contents, used to detect fixture changes across runs.
func Execute ¶
Execute runs the CLI with the given args and writers, returning the process exit code.
func GenerateIncidentDB ¶
GenerateIncidentDB creates the read-only incident SQLite database with rows for suspended accounts incorrectly invoiced on 2026-06-14.
func ResolveRunCount ¶
func ResolveRunCount(cliRuns int, cfg *ScenarioConfig) int
ResolveRunCount returns the effective run count: CLI flag, then BENCH_RUNS env, then scenario config default.
func SanitizeBaseURL ¶
SanitizeBaseURL strips path and query components, keeping only scheme://host[:port].
func ServeMCP ¶
ServeMCP creates an MCP server for the given toolset and serves it over stdio. fixtureDir is used by toolsets that need access to the fixture directory (code-search, git, incident-db, filesystem).
func WriteBreakdown ¶
func WriteBreakdown(path string, bd *ContextBreakdown) error
WriteBreakdown writes a context breakdown as indented JSON.
func WriteComparison ¶
func WriteComparison(dir string, c *SurfaceComparison) error
WriteComparison writes the surface comparison as JSON and Markdown.
func WriteGradingResult ¶
func WriteGradingResult(path string, result *GradingResult) error
WriteGradingResult writes the grading result as JSON to path.
func WriteProvenance ¶
func WriteProvenance(path string, record *EnvironmentRecord) error
WriteProvenance writes the environment record as JSON to the given path.
func WriteSurfaceMetrics ¶
func WriteSurfaceMetrics(path string, m *SurfaceMetrics) error
WriteSurfaceMetrics writes surface metrics to path.
Types ¶
type CategoryTokens ¶
type CategoryTokens struct {
SystemPrompt int `json:"systemPrompt"`
ToolDefinitions int `json:"toolDefinitions"`
ToolResults int `json:"toolResults"`
FileContents int `json:"fileContents"`
ConversationHistory int `json:"conversationHistory"`
CurrentUserMessage int `json:"currentUserMessage"`
AssistantPrefill int `json:"assistantPrefill"`
Uncategorized int `json:"uncategorized"`
TotalInput int `json:"totalInput"`
TotalOutput int `json:"totalOutput"`
}
CategoryTokens is ContextSpy's per-request input/output token split by role in the context window. Fields mirror the requests table's tokens_* columns.
type ContextBreakdown ¶
type ContextBreakdown struct {
Session string `json:"session"`
Requests []RequestTokens `json:"requests"`
Totals CategoryTokens `json:"totals"`
Tools []ToolTokens `json:"tools,omitempty"`
}
ContextBreakdown is the per-run capture: every request's breakdown (the tool surface is re-sent each turn, so any single request shows its share), the summed totals, and the per-tool schema cost.
type ContextSpy ¶
type ContextSpy struct {
// contains filtered or unexported fields
}
ContextSpy drives a ContextSpy proxy over its HTTP API: it opens a named session per run (so the proxy tags that run's model requests with it) and reads the per-run token breakdown back from the API. It is best-effort — when CONTEXTSPY_API is unset, New returns a disabled spy whose methods no-op so the bench still runs; it just won't emit context-breakdown.json.
This is the containerized path: the bench runs hermetically in Docker and reaches a host-side ContextSpy over HTTP (e.g. host.docker.internal:5173), never touching the host filesystem.
func NewContextSpy ¶
func NewContextSpy() *ContextSpy
NewContextSpy reads CONTEXTSPY_API (e.g. "http://host.docker.internal:5173"). The spy is disabled (a no-op) when it is unset.
func (*ContextSpy) Breakdown ¶
func (c *ContextSpy) Breakdown(ctx context.Context, name string) (*ContextBreakdown, error)
Breakdown fetches the active session's per-request breakdown and per-tool token totals from the ContextSpy API. Returns nil (no error) when the spy is disabled, no session is active, or the session captured no requests.
func (*ContextSpy) EndSession ¶
func (c *ContextSpy) EndSession(ctx context.Context)
EndSession closes the active session. Best-effort.
func (*ContextSpy) StartSession ¶
func (c *ContextSpy) StartSession(ctx context.Context, name string)
StartSession opens a named session and remembers its id, so requests during the run are tagged with it. Best-effort: on failure the run proceeds with no active session (Breakdown then no-ops). Runs are sequential, so a single active session id on the struct is sufficient.
type CriterionResult ¶
type CriterionResult struct {
Name string `json:"name"`
Pass bool `json:"pass"`
Detail string `json:"detail"`
}
CriterionResult is a single pass/fail check with a description.
type EnvironmentRecord ¶
type EnvironmentRecord struct {
ModelName string `json:"modelName"`
ModelBaseURL string `json:"modelBaseURL"`
Temperature string `json:"temperature"`
MaxTokens int `json:"maxTokens"`
ContextWindow int `json:"contextWindow"`
Timestamp string `json:"timestamp"`
OzyGitSHA string `json:"ozyGitSHA"`
ScenarioHash string `json:"scenarioHash"`
Modes []string `json:"modes"`
RunCount int `json:"runCount"`
}
EnvironmentRecord captures the model and runtime provenance for a benchmark run.
func BuildProvenance ¶
func BuildProvenance(cfg *ScenarioConfig, modes []string, runCount int) (*EnvironmentRecord, error)
BuildProvenance collects the model and runtime metadata for the run.
type FixtureMeta ¶
FixtureMeta holds resolved metadata after generating the acme-billing fixture.
func GenerateFixture ¶
func GenerateFixture(targetDir string) (*FixtureMeta, error)
GenerateFixture creates the deterministic acme-billing fixture in targetDir. It writes Java source files, documentation, initializes a git repository, creates a multi-commit history, resolves the culprit commit hash, and returns FixtureMeta.
type GradingResult ¶
type GradingResult struct {
Overall bool `json:"overall"`
Criteria []CriterionResult `json:"criteria"`
ForbiddenChecks []CriterionResult `json:"forbidden_checks"`
}
GradingResult captures per-criterion pass/fail and overall verdict.
func Grade ¶
func Grade(gt *GroundTruth, finalAnswer string, toolCalls []ToolCallLog, culpritHash string) *GradingResult
Grade scores the final answer and tool-call log against ground truth. It returns a deterministic pass/fail — no model is used.
type GroundTruth ¶
type GroundTruth struct {
RootCauseFile string `json:"root_cause_file"`
RootCauseFunction string `json:"root_cause_function"`
CulpritCommitSubject string `json:"culprit_commit_subject"`
ExpectedTest string `json:"expected_test"`
ExpectedPatchFile string `json:"expected_patch_file"`
ForbiddenBehaviors []string `json:"forbidden_behaviors"`
}
GroundTruth defines the expected answer and forbidden behaviors for a scenario.
func LoadGroundTruth ¶
func LoadGroundTruth(path string) (*GroundTruth, error)
LoadGroundTruth reads ground_truth.json from path.
type LedgerItem ¶
type LedgerItem struct {
RunID string `json:"run_id"`
Mode string `json:"mode"`
Phase string `json:"phase"`
Source string `json:"source"`
Kind string `json:"kind"`
Server string `json:"server,omitempty"`
Tool string `json:"tool,omitempty"`
Bytes int `json:"bytes"`
TokenCount int `json:"token_count"`
TokenSource string `json:"token_source"`
IncludedInModelContext bool `json:"included_in_model_context"`
}
LedgerItem is a single entry in the JSONL context ledger.
type LedgerWriter ¶
type LedgerWriter struct {
// contains filtered or unexported fields
}
LedgerWriter appends LedgerItems to a JSONL file.
func NewLedgerWriter ¶
func NewLedgerWriter(path string) (*LedgerWriter, error)
NewLedgerWriter creates a ledger writer that appends JSON lines to path.
func (*LedgerWriter) Append ¶
func (w *LedgerWriter) Append(item *LedgerItem) error
Append writes one ledger item as a JSON line.
func (*LedgerWriter) Close ¶
func (w *LedgerWriter) Close() error
Close flushes and closes the underlying file.
type Orchestrator ¶
type Orchestrator struct {
Scenario *ScenarioConfig
FixtureDir string
RunDir string
NumRuns int
Mode string // "direct", "ozy", or "both"
}
Orchestrator manages the full benchmark lifecycle.
type RequestTokens ¶
type RequestTokens struct {
Index int `json:"index"`
CategoryTokens
}
RequestTokens is one captured request's breakdown, ordered within the run.
type RunResult ¶
type RunResult struct {
RunID string `json:"runId"`
Mode string `json:"mode"`
Success bool `json:"success"`
TimedOut bool `json:"timedOut"`
DurationSec float64 `json:"durationSec"`
Transcript string `json:"-"`
FinalAnswer string `json:"finalAnswer"`
ToolCalls []ToolCallLog `json:"toolCalls"`
Grading *GradingResult `json:"grading,omitempty"`
}
RunResult captures the output of a single agent run.
type Runner ¶
type Runner struct {
OpenCodePath string
ConfigPath string
WorkDir string // volume-mounted dir for artifacts
FixtureDir string // OpenCode's working directory
Timeout time.Duration
Spy *ContextSpy // per-run ContextSpy session control (best-effort)
}
Runner launches an agent with a task prompt and captures output.
type ScenarioConfig ¶
type ScenarioConfig struct {
Name string `json:"name"`
TaskFile string `json:"taskFile"`
Fixture string `json:"fixture"`
Model struct {
NameEnv string `json:"nameEnv"`
BaseURLEnv string `json:"baseURLEnv"`
APIKeyEnv string `json:"apiKeyEnv"`
Temperature string `json:"temperature"`
MaxTokens int `json:"maxTokens"`
ContextWindow int `json:"contextWindow"`
} `json:"model"`
AgentConfigs struct {
Direct string `json:"direct"`
Ozy string `json:"ozy"`
} `json:"agentConfigs"`
Limits struct {
Runs int `json:"runs"`
TimeoutSeconds int `json:"timeoutSeconds"`
} `json:"limits"`
GroundTruth string `json:"groundTruth"`
ForbiddenTools []string `json:"forbiddenTools"`
ForbiddenBehaviors []string `json:"forbiddenBehaviors"`
// BaseDir is the directory containing the scenario config file.
// All relative paths (TaskFile, Fixture, GroundTruth) are resolved
// relative to this directory.
BaseDir string `json:"-"`
}
ScenarioConfig is the typed JSONC configuration for a benchmark scenario.
func LoadScenario ¶
func LoadScenario(path string) (*ScenarioConfig, error)
LoadScenario reads, parses, and resolves a JSONC scenario configuration from path. It substitutes {env:VAR} references using os.LookupEnv.
func (*ScenarioConfig) ResolvePath ¶
func (cfg *ScenarioConfig) ResolvePath(rel string) string
ResolvePath resolves a relative path against the scenario's base directory.
func (*ScenarioConfig) ScenarioHash ¶
func (cfg *ScenarioConfig) ScenarioHash() (string, error)
ScenarioHash computes a deterministic SHA-256 hash of the scenario's definition. The hash incorporates the task prompt content so it changes when the scenario definition or prompt changes.
type SurfaceComparison ¶
type SurfaceComparison struct {
Direct SurfaceMetrics `json:"direct"`
Ozy SurfaceMetrics `json:"ozy"`
Reduction struct {
ToolCount int `json:"toolCount"`
SchemaTokens int `json:"schemaTokens"`
Ratio float64 `json:"ratio"`
} `json:"reduction"`
}
SurfaceComparison compares the startup surfaces of direct and ozy modes.
func CompareSurfaces ¶
func CompareSurfaces(direct, ozy *SurfaceMetrics) *SurfaceComparison
CompareSurfaces computes the reduction ratio between direct and ozy surfaces.
type SurfaceMetrics ¶
type SurfaceMetrics struct {
Mode string `json:"mode"`
ToolsVisible int `json:"toolsVisible"`
SchemaBytes int `json:"schemaBytes"`
SchemaTokens int `json:"schemaTokens"`
IrrelevantSchemaTokens int `json:"irrelevantSchemaTokens"`
Tools []ToolSurface `json:"tools"`
}
SurfaceMetrics captures the startup tool surface for one mode.
func MeasureSurface ¶
func MeasureSurface(mode string, tools []ToolSurface, estimator eval.TokenEstimator) *SurfaceMetrics
MeasureSurface enumerates the tools advertised at startup for the given mode. It takes the list of tool surfaces discovered during MCP initialization.
type ToolCallLog ¶
ToolCallLog records a tool invocation during the agent run.
type ToolSurface ¶
type ToolSurface struct {
Name string `json:"name"`
Server string `json:"server"`
Description string `json:"description"`
SchemaBytes int `json:"schemaBytes"`
SchemaTokens int `json:"schemaTokens"`
}
ToolSurface describes a single advertised tool at startup.
type ToolTokens ¶
type ToolTokens struct {
Tool string `json:"tool"`
DefinitionTokens int `json:"definitionTokens"`
ResultTokens int `json:"resultTokens"`
Occurrences int `json:"occurrences,omitempty"`
}
ToolTokens is a per-tool schema/result token total across the run, summed over every request that advertised or called the tool. Occurrences is not exposed by the HTTP API (it was a SQL COUNT) and stays zero.