Files
boshu2__agentops/cli/internal/commands/eval/module.go

1025 lines
51 KiB
Go

// Package eval owns Cobra presentation for the eval command family.
package eval
import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/spf13/cobra"
"github.com/boshu2/agentops/cli/internal/clicontract"
aoeval "github.com/boshu2/agentops/cli/internal/eval"
"github.com/boshu2/agentops/cli/internal/evalsubstrate"
scenarioapp "github.com/boshu2/agentops/cli/internal/scenario"
)
type CoreUseCases interface {
Run(context.Context, aoeval.CoreRunRequest) (aoeval.CoreRunResult, error)
Compare(context.Context, aoeval.CoreCompareRequest) (aoeval.CoreCompareResult, error)
PromoteBaseline(context.Context, aoeval.CoreBaselineRequest) (*aoeval.RunRecord, error)
AuditBaseline(context.Context, aoeval.CoreBaselineAuditRequest) (*aoeval.BaselineAuditReport, error)
Scorecard(context.Context, aoeval.CoreScorecardRequest) (*aoeval.Scorecard, error)
Coverage(context.Context, aoeval.CoreCoverageRequest) (*aoeval.CoverageReport, error)
}
type CleanupUseCases interface {
Execute(context.Context, aoeval.CleanupRequest) (aoeval.CleanupReport, error)
}
type TaskUseCases interface {
Add(context.Context, aoeval.TaskAddRequest) (aoeval.TaskAddResult, error)
List(context.Context) (aoeval.TaskListResult, error)
Show(context.Context, string) (*evalsubstrate.Task, error)
Run(context.Context, aoeval.TaskRunRequest) (aoeval.TaskRunResult, error)
}
type SuiteUseCases interface {
Verdict(context.Context, aoeval.SuiteVerdictRequest) (aoeval.SuiteVerdictResult, error)
NRequired(context.Context, aoeval.SuiteNRequiredRequest) (aoeval.SuiteNRequiredResult, error)
}
type OutcomesUseCases interface {
Compile(context.Context, string) (evalsubstrate.Rubric, error)
Ingest(context.Context, aoeval.OutcomesIngestRequest) (aoeval.OutcomesIngestResult, error)
}
type ScenarioUseCases interface {
Add(context.Context, aoeval.ScenarioAddRequest) (*scenarioapp.CreateResult, error)
Init(context.Context) (string, error)
List(context.Context, string) (aoeval.ScenarioListResult, error)
Validate(context.Context) (aoeval.ScenarioValidationResult, error)
Evaluate(context.Context, aoeval.ScenarioEvaluateRequest) (*aoeval.ScenarioEvaluateReport, error)
}
type ScenarioABUseCases interface {
Run(context.Context, aoeval.ScenarioABRequest) (aoeval.ScenarioABResult, error)
Moat(context.Context, aoeval.ScenarioMoatRequest) (aoeval.MoatClaimResult, error)
}
type UseCases struct {
Core CoreUseCases
Cleanup CleanupUseCases
Task TaskUseCases
Suite SuiteUseCases
Outcomes OutcomesUseCases
Scenario ScenarioUseCases
ScenarioAB ScenarioABUseCases
Aliases aoeval.AliasUseCases
Bench aoeval.BenchUseCases
}
type Module struct {
useCases UseCases
host clicontract.HostOptions
}
func NewModule(useCases UseCases, host clicontract.HostOptions) Module {
return Module{useCases: useCases, host: host}
}
func (Module) Contract() clicontract.CommandContract {
return clicontract.CommandContract{
ID: "ao.eval",
Profiles: clicontract.ProfileDefault | clicontract.ProfileFlywheel |
clicontract.ProfileLegacy | clicontract.ProfileCombined,
Args: clicontract.ArgsPolicy{Name: "no-args", Validate: cobra.NoArgs},
Output: clicontract.OutputNone,
Effects: clicontract.EffectFilesystem | clicontract.EffectProcess | clicontract.EffectEnvironment | clicontract.EffectClock,
ExitClasses: map[int]clicontract.ExitClass{0: clicontract.ExitSuccess, 1: clicontract.ExitFailure},
}
}
// RunContract declares the real behavior of the `ao eval run <suite.json>`
// leaf. It takes exactly one positional suite path, emits a human text summary
// (JSON under -o json), reads the suite and writes a run record while executing
// the deterministic runtime (filesystem, process, environment, clock), and
// exits 0 on success or 1 on failure.
func (Module) RunContract() clicontract.CommandContract {
return clicontract.CommandContract{
ID: "ao.eval.run",
Profiles: clicontract.ProfileDefault | clicontract.ProfileFlywheel |
clicontract.ProfileLegacy | clicontract.ProfileCombined,
Args: clicontract.ArgsPolicy{Name: "exact", Validate: cobra.ExactArgs(1)},
Output: clicontract.OutputText,
Effects: clicontract.EffectFilesystem | clicontract.EffectProcess | clicontract.EffectEnvironment | clicontract.EffectClock,
ExitClasses: map[int]clicontract.ExitClass{0: clicontract.ExitSuccess, 1: clicontract.ExitFailure},
}
}
type runOptions struct {
output, runID, runtime, baseline, baselineMode string
contextMode, contextOffDir, contextOnDir, deltaOut string
}
type compareOptions struct {
output string
maxAggregate, maxDimension float64
}
type baselineOptions struct{ output, promotedBy, rationale string }
type baselineAuditOptions struct{ root, baselineDir string }
type scorecardOptions struct {
output, kind string
maxCategory float64
}
type coverageOptions struct {
root string
domains, evidenceKinds, dimensions, runtimes []string
}
func (module Module) Command() *cobra.Command {
command := &cobra.Command{
Use: "eval", Short: "Run deterministic local evaluation suites",
Long: `Run deterministic AgentOps evaluation suites and compare run records.
The eval surface intentionally supports only offline deterministic runs in this
release. Live Claude and Codex adapters are evaluated by a later runtime tier.`,
}
command.GroupID = "workflow"
command.AddCommand(module.runCommand(), module.compareCommand(), module.baselineCommand(), module.baselineAuditCommand(), module.scorecardCommand(), module.coverageCommand())
if module.useCases.Cleanup != nil {
command.AddCommand(module.cleanupCommand())
}
if module.useCases.Task != nil {
command.AddCommand(module.taskCommand())
}
if module.useCases.Suite != nil {
command.AddCommand(module.suiteCommand())
}
if module.useCases.Outcomes != nil {
command.AddCommand(module.outcomesCommand())
}
if module.useCases.Scenario != nil {
command.AddCommand(module.scenarioCommand())
}
if module.useCases.ScenarioAB != nil {
command.AddCommand(module.scenarioABCommand(), module.scenarioMoatCommand())
}
if module.useCases.Aliases != nil {
command.AddCommand(module.sessionOutcomeCommand(), module.chaosCommand())
}
if module.useCases.Bench != nil {
command.AddCommand(module.benchCommand())
}
return command
}
func (module Module) outputMode() string {
if module.host.OutputMode == nil {
return ""
}
return module.host.OutputMode()
}
func (module Module) runCommand() *cobra.Command {
options := runOptions{baselineMode: string(aoeval.BaselineModeSkillOn), contextMode: string(aoeval.ContextModeNone)}
command := &cobra.Command{
Use: "run <suite.json>",
Short: "Run a deterministic eval suite",
Long: "Run a deterministic eval suite.\n\n" +
"The suite file must conform to the JSON Schema at schemas/eval-suite.v1.schema.json.\n" +
"See evals/agentops-core for working example suites (e.g. evals/agentops-core/rpi-behavior.json).\n\n" +
"Example:\n ao eval run evals/agentops-core/rpi-behavior.json",
Args: cobra.ExactArgs(1),
}
flags := command.Flags()
flags.StringVar(&options.output, "out", "", "write eval run record to path")
flags.StringVar(&options.runID, "run-id", "", "stable run id to use in the run record")
flags.StringVar(&options.runtime, "runtime", "", "runtime override (static, mock, shell, claude, codex)")
flags.StringVar(&options.baseline, "baseline", "", "compare the run against a baseline run record")
flags.StringVar(&options.baselineMode, "baseline-mode", string(aoeval.BaselineModeSkillOn), "skill-on | skill-off | both — runs the suite once with skills loaded, once with hooks suppressed, or both for a delta scorecard")
flags.StringVar(&options.contextMode, "context-mode", string(aoeval.ContextModeNone), "none | ab — run context-off/context-on legs over isolated AO_AGENTS_DIR roots")
flags.StringVar(&options.contextOffDir, "context-off-agents-dir", "", "AO_AGENTS_DIR root for the context-off leg (defaults to suite fixtures)")
flags.StringVar(&options.contextOnDir, "context-on-agents-dir", "", "AO_AGENTS_DIR root for the context-on leg (defaults to suite fixtures)")
flags.StringVar(&options.deltaOut, "delta-out", "", "write delta scorecard JSON to path (with --baseline-mode=both or --context-mode=ab)")
_ = command.RegisterFlagCompletionFunc("runtime", staticCompletion("static", "mock", "shell", "claude", "codex"))
_ = command.RegisterFlagCompletionFunc("baseline-mode", staticCompletion(aoeval.AllBaselineModes()...))
_ = command.RegisterFlagCompletionFunc("context-mode", staticCompletion(aoeval.AllContextModes()...))
command.RunE = func(command *cobra.Command, args []string) error {
result, err := module.useCases.Core.Run(command.Context(), aoeval.CoreRunRequest{SuitePath: args[0], RunID: options.runID, Runtime: options.runtime, OutputPath: options.output, BaselinePath: options.baseline, BaselineMode: options.baselineMode, ContextMode: options.contextMode, ContextOffDir: options.contextOffDir, ContextOnDir: options.contextOnDir, DeltaOut: options.deltaOut})
if err != nil {
return annotateSuiteParseError(err)
}
return module.renderRun(command, result)
}
return command
}
func (module Module) compareCommand() *cobra.Command {
var options compareOptions
command := &cobra.Command{Use: "compare <candidate-run.json> <baseline-run.json>", Short: "Compare an eval run against a baseline", Args: cobra.ExactArgs(2)}
command.Flags().StringVar(&options.output, "out", "", "write compared eval run record to path")
command.Flags().Float64Var(&options.maxAggregate, "max-aggregate-regression", 0, "allowed aggregate regression before verdict becomes regression")
command.Flags().Float64Var(&options.maxDimension, "max-dimension-regression", 0, "allowed per-dimension regression before verdict becomes regression")
command.RunE = func(command *cobra.Command, args []string) error {
result, err := module.useCases.Core.Compare(command.Context(), aoeval.CoreCompareRequest{CandidatePath: args[0], BaselinePath: args[1], OutputPath: options.output, MaxAggregateRegression: options.maxAggregate, MaxDimensionRegression: options.maxDimension})
if err != nil {
return err
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), result.Candidate)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), result.Candidate)
}
delta := 0.0
if result.Candidate.BaselineComparison != nil {
delta = result.Candidate.BaselineComparison.AggregateDelta
}
fmt.Fprintf(command.OutOrStdout(), "Eval compare %s vs %s: %s (aggregate delta %.4f)\n", result.Candidate.RunID, result.Baseline.RunID, result.Candidate.Verdict, delta)
if result.OutputPath != "" {
fmt.Fprintf(command.OutOrStdout(), "Comparison record: %s\n", result.OutputPath)
}
return nil
}
return command
}
func (module Module) baselineCommand() *cobra.Command {
var options baselineOptions
command := &cobra.Command{Use: "baseline <run.json>", Short: "Promote an eval run record as a baseline", Args: cobra.ExactArgs(1)}
command.Flags().StringVar(&options.output, "out", "", "write promoted baseline run record to path")
command.Flags().StringVar(&options.promotedBy, "promoted-by", "", "identity promoting the baseline")
command.Flags().StringVar(&options.rationale, "rationale", "", "rationale for promoting the baseline")
command.RunE = func(command *cobra.Command, args []string) error {
result, err := module.useCases.Core.PromoteBaseline(command.Context(), aoeval.CoreBaselineRequest{RunPath: args[0], OutputPath: options.output, PromotedBy: options.promotedBy, Rationale: options.rationale})
if err != nil {
return err
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), result)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), result)
}
path := ""
if result.Baseline != nil {
path = result.Baseline.BaselinePath
}
fmt.Fprintf(command.OutOrStdout(), "Eval baseline promoted: %s\n", path)
return nil
}
return command
}
func (module Module) baselineAuditCommand() *cobra.Command {
options := baselineAuditOptions{root: "evals/agentops-core", baselineDir: ".agents/evals/baselines"}
command := &cobra.Command{Use: "baseline-audit [suite.json ...]", Short: "Audit eval suite baseline policy against promoted baselines", Args: cobra.ArbitraryArgs}
command.Flags().StringVar(&options.root, "root", options.root, "suite root to scan when no suite paths are provided")
command.Flags().StringVar(&options.baselineDir, "baseline-dir", options.baselineDir, "promoted baseline directory")
command.RunE = func(command *cobra.Command, args []string) error {
report, err := module.useCases.Core.AuditBaseline(command.Context(), aoeval.CoreBaselineAuditRequest{SuitePaths: args, Root: options.root, BaselineDir: options.baselineDir})
if err != nil {
return err
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), report)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), report)
}
fmt.Fprintf(command.OutOrStdout(), "Eval baseline audit: %d suites, %d baselines, %d policy mismatches\n", report.SuiteCount, report.BaselineCount, report.PolicyMismatchCount)
if len(report.MissingCompareBaselines) > 0 {
fmt.Fprintf(command.OutOrStdout(), "Missing compare baselines: %d\n", len(report.MissingCompareBaselines))
}
if len(report.UnexpectedBaselinesForNone) > 0 {
fmt.Fprintf(command.OutOrStdout(), "Unexpected baselines for none policy: %d\n", len(report.UnexpectedBaselinesForNone))
}
if len(report.OrphanBaselines) > 0 {
fmt.Fprintf(command.OutOrStdout(), "Orphan baselines: %d\n", len(report.OrphanBaselines))
}
if len(report.StaleSuiteHashes) > 0 {
fmt.Fprintf(command.OutOrStdout(), "Stale suite hashes: %d\n", len(report.StaleSuiteHashes))
}
return nil
}
return command
}
func (module Module) scorecardCommand() *cobra.Command {
options := scorecardOptions{kind: string(aoeval.ScorecardKindRPI)}
command := &cobra.Command{Use: "scorecard <candidate-run.json> [baseline-run.json]", Short: "Build an eval scorecard from run records", Args: cobra.RangeArgs(1, 2)}
command.Flags().StringVar(&options.output, "out", "", "write scorecard JSON to path")
command.Flags().StringVar(&options.kind, "kind", options.kind, "scorecard kind (rpi, skill-change)")
command.Flags().Float64Var(&options.maxCategory, "max-category-regression", 0, "allowed per-category regression before verdict becomes regression")
_ = command.RegisterFlagCompletionFunc("kind", staticCompletion(string(aoeval.ScorecardKindRPI), string(aoeval.ScorecardKindSkillChange)))
command.RunE = func(command *cobra.Command, args []string) error {
baselinePath := ""
if len(args) == 2 {
baselinePath = args[1]
}
card, err := module.useCases.Core.Scorecard(command.Context(), aoeval.CoreScorecardRequest{CandidatePath: args[0], BaselinePath: baselinePath, OutputPath: options.output, Kind: options.kind, MaxCategoryRegression: options.maxCategory})
if err != nil {
return err
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), card)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), card)
}
fmt.Fprintf(command.OutOrStdout(), "Eval scorecard %s: %s (%s, categories %d)\n", card.CandidateRunID, card.Verdict, card.Kind, len(card.Categories))
if options.output != "" {
fmt.Fprintf(command.OutOrStdout(), "Scorecard: %s\n", options.output)
}
return nil
}
return command
}
func (module Module) coverageCommand() *cobra.Command {
options := coverageOptions{root: "evals/agentops-core", domains: append([]string(nil), aoeval.DefaultCoverageDomains...), dimensions: append([]string(nil), aoeval.DefaultCoverageDimensions...), runtimes: append([]string(nil), aoeval.DefaultCoverageRuntimes...)}
command := &cobra.Command{Use: "coverage [suite.json ...]", Short: "Summarize eval suite coverage", Args: cobra.ArbitraryArgs}
command.Flags().StringVar(&options.root, "root", options.root, "suite root to scan when no suite paths are provided")
command.Flags().StringArrayVar(&options.domains, "require-domain", options.domains, "required product domain for missing-domain reporting")
command.Flags().StringArrayVar(&options.evidenceKinds, "require-evidence-kind", nil, "required evidence kind for missing-evidence-kind reporting")
command.Flags().StringArrayVar(&options.dimensions, "require-dimension", options.dimensions, "required score dimension for missing-dimension reporting")
command.Flags().StringArrayVar(&options.runtimes, "require-runtime", options.runtimes, "required deterministic runtime for missing-runtime reporting")
command.RunE = func(command *cobra.Command, args []string) error {
report, err := module.useCases.Core.Coverage(command.Context(), aoeval.CoreCoverageRequest{SuitePaths: args, Root: options.root, RequiredDomains: options.domains, RequiredEvidenceKinds: options.evidenceKinds, RequiredDimensions: options.dimensions, RequiredRuntimes: options.runtimes})
if err != nil {
return err
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), report)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), report)
}
fmt.Fprintf(command.OutOrStdout(), "Eval coverage: %d suites, %d cases, %d critical cases\n", report.SuiteCount, report.CaseCount, report.CriticalCaseCount)
renderCoverage(command, "domains", report.MissingRequiredDomains, report.RequiredDomains)
renderCoverage(command, "evidence kinds", report.MissingRequiredEvidenceKinds, report.RequiredEvidenceKinds)
renderCoverage(command, "dimensions", report.MissingRequiredDimensions, report.RequiredDimensions)
renderCoverage(command, "runtimes", report.MissingRequiredRuntimes, report.RequiredRuntimes)
return nil
}
return command
}
func (module Module) cleanupCommand() *cobra.Command {
options := aoeval.CleanupRequest{TmpAgeSeconds: 60}
command := &cobra.Command{
Use: "cleanup", Short: "Recover stale Runs (state transitions, --delete, --tmp-files)",
Long: `Per SCHEMA.md §4 cleanup state-transition rule (rc2):
Stale pending (no running transition within 60s)
-> aborted (retraction_reason=never_started)
Stale running (no heartbeat within 5min OR Inspect process not alive)
-> failed (retraction_reason=orphaned_process)
After transitions:
--delete Remove Run dirs whose status is failed OR aborted (NEVER retracted).
--tmp-files Sweep orphan manifest.json.tmp left from rename-step crashes.
--dry-run Print what would be done; no mutations.
The cleanup procedure honors the §4 atomic-write contract on every state
transition (temp + fsync + rename + fsync-parent-dir). Retracted Runs are
never auto-removed — retraction is an audit trail.`,
}
command.Flags().BoolVar(&options.Delete, "delete", false, "Remove Run directories whose status is failed or aborted (never retracted)")
command.Flags().BoolVar(&options.TmpFiles, "tmp-files", false, "Sweep orphan *.tmp files older than --tmp-age")
command.Flags().Int64Var(&options.TmpAgeSeconds, "tmp-age", 60, "Minimum tmp-file age in seconds before sweep (0 = sweep all)")
command.Flags().BoolVar(&options.DryRun, "dry-run", false, "Preview without mutations")
_ = command.Flags().MarkHidden("dry-run")
command.RunE = func(command *cobra.Command, _ []string) error {
report, err := module.useCases.Cleanup.Execute(command.Context(), options)
if err != nil {
return err
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), report)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), report)
}
fmt.Fprintf(command.OutOrStdout(), "Eval cleanup:\n transitions->aborted: %d\n transitions->failed: %d\n runs deleted: %d\n tmp files swept: %d\n", report.TransitionsAborted, report.TransitionsFailed, report.RunsDeleted, report.TmpFilesSwept)
verbose := module.host.Verbose != nil && module.host.Verbose()
if len(report.Touched) > 0 && verbose {
fmt.Fprintln(command.OutOrStdout(), "Touched:")
for _, touched := range report.Touched {
fmt.Fprintf(command.OutOrStdout(), " %s\n", touched)
}
}
return nil
}
return command
}
func (module Module) taskCommand() *cobra.Command {
command := &cobra.Command{Use: "task", Short: "Manage evaluation Tasks (add, list, show, run)", Long: `Operate on the §3 Task primitive of the eval substrate.
Tasks live under $AGENTOPS_EVALS_ROOT/tasks/<id>/task.yaml and define the
input/output contract a Run will be evaluated against.`}
command.AddCommand(module.taskAddCommand(), module.taskListCommand(), module.taskShowCommand(), module.taskRunCommand())
return command
}
func (module Module) taskAddCommand() *cobra.Command {
command := &cobra.Command{Use: "add <task.yaml>", Short: "Register a Task by copying its yaml + samples into the substrate", Args: cobra.ExactArgs(1)}
command.RunE = func(command *cobra.Command, args []string) error {
result, err := module.useCases.Task.Add(command.Context(), aoeval.TaskAddRequest{SourcePath: args[0]})
if err != nil {
return err
}
fmt.Fprintf(command.OutOrStdout(), "Task registered: %s\n path: %s\n min_n_samples: %d\n", result.Task.ID, result.Destination, result.Task.Stats.MinNSamples)
return nil
}
return command
}
func (module Module) taskListCommand() *cobra.Command {
command := &cobra.Command{Use: "list", Short: "List registered Task ids", Args: cobra.NoArgs}
command.RunE = func(command *cobra.Command, _ []string) error {
result, err := module.useCases.Task.List(command.Context())
if err != nil {
return err
}
ids := make([]string, 0, len(result.Tasks))
for _, summary := range result.Tasks {
ids = append(ids, summary.ID)
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), map[string]any{"tasks": ids, "root": result.Root})
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), map[string]any{"tasks": ids, "root": result.Root})
}
if len(result.Tasks) == 0 {
fmt.Fprintln(command.OutOrStdout(), "No tasks registered")
return nil
}
fmt.Fprintf(command.OutOrStdout(), "Tasks under %s:\n", result.Root)
for _, summary := range result.Tasks {
if summary.Error != "" {
fmt.Fprintf(command.OutOrStdout(), " %s\t<unreadable: %s>\n", summary.ID, summary.Error)
continue
}
task := summary.Task
fmt.Fprintf(command.OutOrStdout(), " %s\tschema_version=%d min_n_samples=%d metric=%s\n", task.ID, task.SchemaVersion, task.Stats.MinNSamples, task.Stats.Metric)
}
return nil
}
return command
}
func (module Module) taskShowCommand() *cobra.Command {
command := &cobra.Command{Use: "show <task-id>", Short: "Print a registered Task summary", Args: cobra.ExactArgs(1)}
command.RunE = func(command *cobra.Command, args []string) error {
task, err := module.useCases.Task.Show(command.Context(), args[0])
if err != nil {
return err
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), task)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), task)
}
fmt.Fprintf(command.OutOrStdout(), "Task: %s\n", task.ID)
fmt.Fprintf(command.OutOrStdout(), " schema_version: %d\n domain: %s\n description: %s\n harness_ref: %s\n", task.SchemaVersion, task.Domain, task.Description, task.HarnessRef)
fmt.Fprintf(command.OutOrStdout(), " stats.metric: %s\n stats.paired: %v\n stats.min_n_samples: %d\n stats.decision_rule: kind=%s confidence=%.2f\n", task.Stats.Metric, task.Stats.Paired, task.Stats.MinNSamples, task.Stats.DecisionRule.Kind, task.Stats.DecisionRule.Confidence)
return nil
}
return command
}
func (module Module) taskRunCommand() *cobra.Command {
options := aoeval.TaskRunRequest{InspectVersion: "0.3.216"}
command := &cobra.Command{Use: "run <task-id>", Short: "Open a new Run manifest for <task-id>; refuses on gate failure", Args: cobra.ExactArgs(1)}
flags := command.Flags()
flags.StringVar(&options.SuiteRef, "suite", "", "Suite id or path to suite.yaml (required)")
flags.StringVar(&options.RigID, "rig-id", "", "Rig identifier stamped into the Run manifest")
flags.StringVar(&options.Seeds, "seeds", "", "Comma-separated seeds (>=3, per §4)")
flags.StringVar(&options.HarnessRef, "harness", "", "Harness id (recorded into manifest)")
flags.StringVar(&options.HarnessDir, "harness-dir", "", "Path to harness source dir for snapshot + gate #8")
flags.StringVar(&options.ModelSpecID, "model-spec", "", "ModelSpec id already present in the eval substrate's model-specs store")
flags.StringVar(&options.GroundTruthRef, "ground-truth", "", "Ground-truth row id (head of supersession chain)")
flags.StringVar(&options.SampleSplit, "sample-split", "", "Sample split (dev|holdout); default from suite")
flags.IntVar(&options.NSamples, "n-samples", 0, "Override Suite.n_samples")
flags.StringVar(&options.InspectVersion, "inspect-version", options.InspectVersion, "Inspect AI version stamped into manifest")
flags.StringVar(&options.InspectCommand, "inspect-command", "", "Inspect command recorded into the Run manifest (not executed yet)")
flags.BoolVar(&options.CrossSpec, "cross-spec", false, "Allow ModelSpec drift (gate #4)")
flags.BoolVar(&options.AllowWeak, "allow-weak-labels", false, "Allow runs against confidence=weak ground-truth rows (gate #7)")
flags.BoolVar(&options.QuickSession, "quick", false, "Mark Run as quick_session=true (excluded from --vs auto-baseline pool)")
flags.BoolVar(&options.DryRun, "dry-run", false, "Run gates and exit without writing a Run manifest")
_ = flags.MarkHidden("dry-run")
command.RunE = func(command *cobra.Command, args []string) error {
options.TaskID = args[0]
result, err := module.useCases.Task.Run(command.Context(), options)
if err != nil {
var gateFailure *aoeval.TaskGateError
if errors.As(err, &gateFailure) {
fmt.Fprintln(command.ErrOrStderr(), gateFailure.Message)
}
return err
}
if result.DryRun {
fmt.Fprintln(command.OutOrStdout(), "Dry run: gates passed; no Run manifest written.")
return nil
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), result.Manifest)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), result.Manifest)
}
manifest := result.Manifest
fmt.Fprintf(command.OutOrStdout(), "Run opened: %s\n status: %s\n manifest: %s\n rig_id: %s\n task_ref: %s\n suite_ref: %s\n", manifest.ID, manifest.Status, result.Path, manifest.RigID, manifest.TaskRef, manifest.SuiteRef)
return nil
}
return command
}
func (module Module) suiteCommand() *cobra.Command {
command := &cobra.Command{Use: "suite", Short: "Suite-level operations (verdict, n-required)", Long: "Suite-level operations against the §6.5 statistical contract."}
command.AddCommand(module.suiteVerdictCommand(), module.suiteNRequiredCommand())
return command
}
func (module Module) suiteVerdictCommand() *cobra.Command {
options := aoeval.SuiteVerdictRequest{BootstrapSamples: 10000}
command := &cobra.Command{Use: "verdict <suite-id> --arms a,b --inputs <bootstrap-inputs.json>", Short: "Compute the §6.5 paired cluster-bootstrap verdict", Args: cobra.ExactArgs(1)}
command.Flags().StringVar(&options.Arms, "arms", "", "Comma-separated arm ids (default: from suite varied_axis)")
command.Flags().StringVar(&options.InputsPath, "inputs", "", "Path to canonical bootstrap-inputs JSON (REQUIRED)")
command.Flags().Float64Var(&options.MDE, "mde", 0, "Minimum detectable effect (used for inconclusive_high_variance)")
command.Flags().IntVar(&options.BootstrapSamples, "B", 10000, "Bootstrap resamples")
command.Flags().IntVar(&options.NRequired, "n-required", 0, "Override n_required (default: derived from suite power block)")
command.RunE = func(command *cobra.Command, args []string) error {
options.SuiteID = args[0]
result, err := module.useCases.Suite.Verdict(command.Context(), options)
if err != nil {
return err
}
if module.outputMode() == "yaml" {
return clicontract.JSONToYAML(command.OutOrStdout(), result.Raw)
}
if module.outputMode() == "json" {
_, err = command.OutOrStdout().Write(append(append([]byte(nil), result.Raw...), '\n'))
return err
}
value := result.Values
fmt.Fprintf(command.OutOrStdout(), "Suite verdict: %v\n delta_point: %v\n ci: [%v, %v]\n n_clusters: %v\n n_required: %v\n bootstrap_seed: %v\n bootstrap_inputs_hash: %v\n", value["verdict"], value["delta_point"], value["ci_low"], value["ci_high"], value["n_clusters"], value["n_required"], value["bootstrap_seed"], value["bootstrap_inputs_hash"])
return nil
}
return command
}
func (module Module) suiteNRequiredCommand() *cobra.Command {
options := aoeval.SuiteNRequiredRequest{BaselineRate: .5, MDE: .05, Alpha: .05, Power: .80, Paired: true}
command := &cobra.Command{Use: "n-required", Short: "Compute power-derived n_required (gate #6 input on Day 3+)"}
command.Flags().Float64Var(&options.BaselineRate, "baseline-rate", .5, "Baseline rate (binomial worst-case fallback)")
command.Flags().Float64Var(&options.MDE, "mde", .05, "Minimum detectable effect")
command.Flags().Float64Var(&options.Alpha, "alpha", .05, "Type-I error rate")
command.Flags().Float64Var(&options.Power, "power", .80, "Statistical power (1-beta)")
command.Flags().BoolVar(&options.Paired, "paired", true, "Paired comparison")
command.RunE = func(command *cobra.Command, _ []string) error {
result, err := module.useCases.Suite.NRequired(command.Context(), options)
if err != nil {
return err
}
if module.outputMode() == "yaml" {
return clicontract.JSONToYAML(command.OutOrStdout(), result.Raw)
}
if module.outputMode() == "json" {
_, err = command.OutOrStdout().Write(append(append([]byte(nil), result.Raw...), '\n'))
return err
}
fmt.Fprintf(command.OutOrStdout(), "n_required: %d (baseline_rate=%g MDE=%g alpha=%g power=%g paired=%v)\n", result.NRequired, options.BaselineRate, options.MDE, options.Alpha, options.Power, options.Paired)
return nil
}
return command
}
func (module Module) outcomesCommand() *cobra.Command {
command := &cobra.Command{Use: "outcomes", Short: "Project the locked eval substrate into Outcomes grading payloads (holdout-safe)", Long: "Outcomes is a derived projection of the locked eval substrate (SCHEMA.md), never an alternate authority."}
command.AddCommand(module.outcomesCompileCommand(), module.outcomesIngestCommand())
return command
}
func (module Module) outcomesCompileCommand() *cobra.Command {
command := &cobra.Command{Use: "compile <input.json>", Short: "Compile a holdout-safe Outcomes rubric payload from a locked Task + criteria", Args: cobra.ExactArgs(1)}
command.RunE = func(command *cobra.Command, args []string) error {
rubric, err := module.useCases.Outcomes.Compile(command.Context(), args[0])
if err != nil {
return err
}
return clicontract.WriteJSON(command.OutOrStdout(), rubric)
}
return command
}
func (module Module) outcomesIngestCommand() *cobra.Command {
var options aoeval.OutcomesIngestRequest
command := &cobra.Command{Use: "ingest <score.json>", Short: "Ingest an Outcomes score payload into the one council verdict record", Args: cobra.ExactArgs(1)}
command.Flags().StringVar(&options.ExpectedJudgeHash, "expect-judge-hash", "", "refuse the ingest if the score's judge_content_hash does not match this value (gate #2 rubric-drift parity)")
command.Flags().StringVar(&options.BurnLedgerPath, "burn-ledger", "", "path to a JSON HoldoutBurnLedger; when set, a holdout-split score registers a burn and is REFUSED if the (suite,gt) quota is exhausted (gate #3 runtime enforcement), persisted across invocations")
command.Flags().StringVar(&options.ManifestDir, "manifest-out", "", "also write an eval-run.v1 manifest to <dir>/<run-id>/manifest.json so the verdict pipeline feeds the Knowledge Flywheel (closes the Outcomes→Flywheel loop)")
command.Flags().StringVar(&options.RunID, "run-id", "", "run id for the --manifest-out manifest; defaults to the score's run_id, then source_task_id (sanitized to the eval-run.v1 pattern)")
command.RunE = func(command *cobra.Command, args []string) error {
options.ScorePath = args[0]
result, err := module.useCases.Outcomes.Ingest(command.Context(), options)
if err != nil {
return err
}
if result.Warning != "" {
fmt.Fprintln(command.ErrOrStderr(), result.Warning)
}
// ingest emits the verdict as structured output unconditionally (its
// default is JSON, not a human table); honor -o yaml when asked.
emit := clicontract.WriteJSON
if module.outputMode() == "yaml" {
emit = clicontract.WriteYAML
}
if err := emit(command.OutOrStdout(), result.Verdict); err != nil {
return err
}
if result.ManifestPath != "" {
fmt.Fprintf(command.ErrOrStderr(), "wrote eval-run manifest: %s\n", result.ManifestPath)
}
return nil
}
return command
}
func (module Module) scenarioCommand() *cobra.Command {
command := &cobra.Command{Use: "scenario", Short: "Manage holdout scenarios for behavioral validation", Long: "Create, list, validate, and evaluate holdout scenarios stored in .agents/holdout/."}
command.AddCommand(module.scenarioInitCommand(), module.scenarioAddCommand(), module.scenarioListCommand(), module.scenarioValidateCommand(), module.scenarioEvaluateCommand())
return command
}
func (module Module) scenarioInitCommand() *cobra.Command {
command := &cobra.Command{Use: "init", Short: "Initialize .agents/holdout/ directory for scenario storage"}
command.RunE = func(command *cobra.Command, _ []string) error {
path, err := module.useCases.Scenario.Init(command.Context())
if err == nil {
fmt.Fprintf(command.OutOrStdout(), "Initialized holdout directory at %s\n", path)
}
return err
}
return command
}
func (module Module) scenarioAddCommand() *cobra.Command {
options := aoeval.ScenarioAddRequest{Threshold: .8, Status: "draft", Source: "human"}
command := &cobra.Command{Use: "add <goal>", Short: "Author a holdout scenario from a goal description", Args: cobra.ExactArgs(1)}
command.Flags().StringVar(&options.Narrative, "narrative", "", "Narrative description (default: inferred from goal)")
command.Flags().StringVar(&options.ExpectedOutcome, "expected-outcome", "", "Expected observable outcome (default: inferred from goal)")
command.Flags().Float64Var(&options.Threshold, "threshold", .8, "Satisfaction threshold in [0,1]")
command.Flags().StringVar(&options.Status, "status", "draft", "Scenario status (active, draft, retired)")
command.Flags().StringVar(&options.Source, "source", "human", "Scenario source (human, agent, prod-telemetry)")
_ = command.RegisterFlagCompletionFunc("status", staticCompletion("active", "draft", "retired"))
_ = command.RegisterFlagCompletionFunc("source", staticCompletion("human", "agent", "prod-telemetry"))
command.RunE = func(command *cobra.Command, args []string) error {
options.Goal = args[0]
result, err := module.useCases.Scenario.Add(command.Context(), options)
if err != nil {
return err
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), result.Scenario)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), result.Scenario)
}
fmt.Fprintf(command.OutOrStdout(), "Created scenario %s at %s\n", result.Scenario.ID, result.Path)
return nil
}
return command
}
func (module Module) scenarioListCommand() *cobra.Command {
var status string
command := &cobra.Command{Use: "list", Short: "List holdout scenarios"}
command.Flags().StringVar(&status, "status", "", "Filter by status (active, draft, retired)")
command.RunE = func(command *cobra.Command, _ []string) error {
result, err := module.useCases.Scenario.List(command.Context(), status)
if err != nil {
return err
}
// stdout is always exactly one JSON document (`[]` for both empty
// states) so `ao eval scenario list | jq` never breaks; any human hint
// goes to stderr. Exit 0.
if result.MissingDirectory {
fmt.Fprintln(command.ErrOrStderr(), "No holdout directory found. Run 'ao eval scenario init' first.")
return clicontract.WriteJSON(command.OutOrStdout(), []aoeval.ScenarioSummary{})
}
if len(result.Scenarios) == 0 {
fmt.Fprintln(command.ErrOrStderr(), "No scenarios found.")
return clicontract.WriteJSON(command.OutOrStdout(), []aoeval.ScenarioSummary{})
}
return clicontract.WriteJSON(command.OutOrStdout(), result.Scenarios)
}
return command
}
func (module Module) scenarioValidateCommand() *cobra.Command {
command := &cobra.Command{Use: "validate", Short: "Validate holdout scenarios against schema"}
command.RunE = func(command *cobra.Command, _ []string) error {
result, err := module.useCases.Scenario.Validate(command.Context())
if err != nil {
return err
}
if result.MissingDirectory {
fmt.Fprintln(command.OutOrStdout(), "No holdout directory found. Run 'ao eval scenario init' first.")
return nil
}
if len(result.Errors) > 0 {
fmt.Fprintf(command.ErrOrStderr(), "Validation errors:\n%s\n", strings.Join(result.Errors, "\n"))
return fmt.Errorf("%d validation error(s) found", len(result.Errors))
}
if result.Validated == 0 {
fmt.Fprintln(command.OutOrStdout(), "No scenario files found to validate.")
} else {
fmt.Fprintf(command.OutOrStdout(), "Validated %d scenario(s): all pass\n", result.Validated)
}
return nil
}
return command
}
func (module Module) scenarioEvaluateCommand() *cobra.Command {
options := aoeval.ScenarioEvaluateRequest{Timeout: 2 * time.Minute, RunID: "ao-scenario-evaluate"}
var jsonOutput bool
command := &cobra.Command{Use: "evaluate", Short: "Evaluate directive-linked scenarios and record satisfaction results", Args: cobra.NoArgs}
command.Flags().StringVar(&options.DirectiveID, "directive", "", "Evaluate only the directive with this stable Directive ID")
command.Flags().BoolVar(&options.All, "all", false, "Evaluate every directive's linked scenarios")
command.Flags().BoolVar(&jsonOutput, "json", false, "Emit the machine-readable evaluation report")
command.Flags().DurationVar(&options.Timeout, "timeout", 2*time.Minute, "Per-check execution timeout")
command.Flags().StringVar(&options.RunID, "run-id", "ao-scenario-evaluate", "run_id recorded in the results artifact")
command.RunE = func(command *cobra.Command, _ []string) error {
if module.host.ProjectRoot != nil {
options.ProjectRoot = module.host.ProjectRoot()
}
if module.host.GoalsPath != nil {
options.GoalsPath = module.host.GoalsPath()
}
report, err := module.useCases.Scenario.Evaluate(command.Context(), options)
if err != nil {
return err
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), report)
}
if jsonOutput || module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), report)
}
return renderScenarioEvaluate(command, report)
}
return command
}
func renderScenarioEvaluate(command *cobra.Command, report *aoeval.ScenarioEvaluateReport) error {
for _, evaluation := range report.Evaluations {
if !evaluation.Recorded {
fmt.Fprintf(command.OutOrStdout(), "%-20s %-10s not recorded — %s\n", evaluation.ScenarioID, "-", evaluation.Note)
} else {
fmt.Fprintf(command.OutOrStdout(), "%-20s %-10s shape=%s score=%.2f threshold=%.2f\n", evaluation.ScenarioID, evaluation.Verdict, evaluation.Shape, evaluation.Score, evaluation.Threshold)
}
}
if report.Written == 0 {
fmt.Fprintln(command.OutOrStdout(), "No results recorded; artifact untouched.")
return nil
}
fmt.Fprintf(command.OutOrStdout(), "Wrote %d result(s) to %s (run %s, iteration %d)\n", report.Written, report.Artifact, report.RunID, report.Iteration)
return nil
}
func (module Module) scenarioABCommand() *cobra.Command {
var options aoeval.ScenarioABRequest
command := &cobra.Command{Use: "scenario-ab", Short: "Run a knowledge-reuse holdout scenario with vs. without the gold pull (the discriminating A/B)", Args: cobra.NoArgs, SilenceUsage: true}
command.Flags().StringVar(&options.ScenarioPath, "scenario", "", "Path to the scenario.v1 JSON file (required)")
command.Flags().StringVar(&options.OutputPath, "out", "", "Write the ScenarioDeltaScorecard JSON to this path")
command.Flags().IntVar(&options.TokenBudget, "token-budget", 0, "Fail the gate if summed arm token cost exceeds this (0 = default 200000)")
command.Flags().DurationVar(&options.Timeout, "timeout", 0, "Per-arm timeout (0 = default 5m)")
command.Flags().BoolVar(&options.ControlOnly, "control-only", false, "Run only the without-gold control arm and fail on ceiling/no-headroom")
command.RunE = func(command *cobra.Command, _ []string) error {
result, err := module.useCases.ScenarioAB.Run(command.Context(), options)
if result.Card.ScenarioID != "" {
if module.outputMode() == "yaml" {
if renderErr := clicontract.WriteYAML(command.OutOrStdout(), result.Card); renderErr != nil {
return renderErr
}
} else if module.outputMode() == "json" {
if renderErr := clicontract.WriteJSON(command.OutOrStdout(), result.Card); renderErr != nil {
return renderErr
}
} else {
renderScenarioAB(command, result.Card)
}
}
if err != nil {
var gate *aoeval.ScenarioABGateError
if errors.As(err, &gate) {
for _, reason := range gate.Reasons {
fmt.Fprintf(command.ErrOrStderr(), " FAIL: %s\n", reason)
}
}
}
return err
}
return command
}
func renderScenarioAB(command *cobra.Command, card aoeval.ScenarioDeltaScorecard) {
if card.CeilingViolation {
fmt.Fprintf(command.OutOrStdout(), "scenario-ab %s [%s]: CEILING VIOLATION (without=%.4f >= threshold=%.4f) — invalid scenario, no delta emitted\n", card.ScenarioID, card.VerdictClass, card.Without.Score, card.SatisfactionThreshold)
} else if card.ControlOnly {
fmt.Fprintf(command.OutOrStdout(), "scenario-ab %s [%s]: control-only headroom=PASS (without=%.4f < threshold=%.4f) tokens=%d gate=%s\n", card.ScenarioID, card.VerdictClass, card.Without.Score, card.SatisfactionThreshold, card.Without.TokenCost, passLabel(card.Gate.Pass))
} else {
fmt.Fprintf(command.OutOrStdout(), "scenario-ab %s [%s]: delta=%.4f (with=%.4f without=%.4f) tokens=%d gate=%s %s\n", card.ScenarioID, card.VerdictClass, card.AggregateDelta, card.With.Score, card.Without.Score, card.With.TokenCost+card.Without.TokenCost, passLabel(card.Gate.Pass), moatLabel(card.MoatEligible))
}
}
func passLabel(pass bool) string {
if pass {
return "PASS"
}
return "FAIL"
}
func moatLabel(eligible bool) string {
if eligible {
return "moat-eligible"
}
return "NOT-moat-evidence(plumbing)"
}
func (module Module) scenarioMoatCommand() *cobra.Command {
var options aoeval.ScenarioMoatRequest
command := &cobra.Command{Use: "scenario-moat", Short: "Aggregate moat-eligible scenario A/B scorecards into a publication verdict", Args: cobra.NoArgs, SilenceUsage: true}
command.Flags().StringArrayVar(&options.ScorecardPaths, "scorecard", nil, "Path to a ScenarioDeltaScorecard JSON (repeatable)")
command.Flags().StringVar(&options.OutputPath, "out", "", "Write the MoatClaimResult JSON to this path")
command.RunE = func(command *cobra.Command, _ []string) error {
result, err := module.useCases.ScenarioAB.Moat(command.Context(), options)
if err != nil {
var ineligible aoeval.ErrMoatIneligibleScorecard
if errors.As(err, &ineligible) {
fmt.Fprintf(command.ErrOrStderr(), "REJECTED: %s\n", err)
}
return err
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), result)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), result)
}
fmt.Fprintf(command.OutOrStdout(), "scenario-moat: verdict=%s scenarios=%d mean_delta=%.4f\n %s\n", result.Verdict, result.ScenarioCount, result.MeanAggregateDelta, result.Reason)
if options.OutputPath != "" {
fmt.Fprintf(command.OutOrStdout(), "Moat claim result: %s\n", options.OutputPath)
}
return nil
}
return command
}
func (module Module) sessionOutcomeCommand() *cobra.Command {
var sessionID string
command := &cobra.Command{Use: "session-outcome [transcript-path]", Short: "Analyze session transcript to derive reward signal", Args: cobra.MaximumNArgs(1)}
command.Flags().StringVar(&sessionID, "session", "", "Session ID (extracted from transcript if not provided)")
command.RunE = func(command *cobra.Command, args []string) error {
path := ""
if len(args) > 0 {
path = args[0]
}
dryRun := module.host.DryRun != nil && module.host.DryRun()
result, err := module.useCases.Aliases.SessionOutcome(command.Context(), aoeval.SessionOutcomeRequest{TranscriptPath: path, SessionID: sessionID, DryRun: dryRun})
if err != nil {
return err
}
if result.DryRun {
fmt.Fprintf(command.OutOrStdout(), "[dry-run] Would analyze transcript: %s\n", result.Transcript)
return nil
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), result)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), result)
}
fmt.Fprintln(command.OutOrStdout(), "Session Outcome Analysis\n========================")
fmt.Fprintf(command.OutOrStdout(), "Session ID: %s\nReward: %.2f\nLines: %d\n\nSignals detected:\n", result.SessionID, result.Reward, result.TotalLines)
for _, signal := range result.Signals {
status := "✗"
if signal.Value {
status = "✓"
}
fmt.Fprintf(command.OutOrStdout(), " %s %-20s (weight: %+.2f)\n", status, signal.Name, signal.Weight)
}
return nil
}
return command
}
func (module Module) chaosCommand() *cobra.Command {
command := &cobra.Command{Use: "chaos", Short: "Run a read-only smoke test of the tick membrane", Args: cobra.NoArgs}
command.RunE = func(command *cobra.Command, _ []string) error {
output, err := module.useCases.Aliases.Chaos(command.Context())
if output.Stdout != "" {
fmt.Fprint(command.OutOrStdout(), output.Stdout)
}
if output.Stderr != "" {
fmt.Fprint(command.ErrOrStderr(), output.Stderr)
}
return err
}
return command
}
func (module Module) benchCommand() *cobra.Command {
options := aoeval.BenchRequest{K: 3, SearchBackend: "local-lexical"}
command := &cobra.Command{Use: "bench", Short: "Run retrieval quality benchmarks"}
command.Flags().StringVar(&options.Corpus, "corpus", "", "Path to benchmark corpus directory")
command.Flags().BoolVar(&options.JSON, "json", false, "JSON output")
command.Flags().IntVar(&options.K, "k", 3, "K for Precision@K")
command.Flags().BoolVar(&options.Live, "live", false, "Benchmark against real .agents/learnings/ instead of synthetic corpus")
command.Flags().BoolVar(&options.Global, "global", false, "Include ~/.agents/learnings/ (cross-rig aggregated store, requires --live)")
command.Flags().StringVar(&options.SearchEval, "search-eval", "", "Path to an ao-search eval manifest with queries and ground_truth paths")
command.Flags().StringVar(&options.SearchRoot, "search-root", "", "Repo root to search for --search-eval (defaults to current directory)")
command.Flags().StringVar(&options.SearchBackend, "search-backend", "local-lexical", "Search backend for --search-eval (local-lexical, ao-auto, agentic-rg, wiki-link-expand, rerank-llamacpp)")
command.Flags().StringVar(&options.CompareBackends, "search-compare-backends", "", "Comma-separated search backends to compare for --search-eval")
command.RunE = func(command *cobra.Command, _ []string) error {
options.KChanged = command.Flags().Changed("k")
options.JSON = options.JSON || module.outputMode() == "json"
output, err := module.useCases.Bench.Bench(command.Context(), options)
if output.Stdout != "" {
fmt.Fprint(command.OutOrStdout(), output.Stdout)
}
if output.Stderr != "" {
fmt.Fprint(command.ErrOrStderr(), output.Stderr)
}
return err
}
return command
}
func (module Module) renderRun(command *cobra.Command, result aoeval.CoreRunResult) error {
var value any = result.Run
if result.Mode == aoeval.CoreRunBaselineAB {
value = result.Delta
}
if result.Mode == aoeval.CoreRunContextAB {
value = result.ContextDelta
}
if module.outputMode() == "yaml" {
return clicontract.WriteYAML(command.OutOrStdout(), value)
}
if module.outputMode() == "json" {
return clicontract.WriteJSON(command.OutOrStdout(), value)
}
switch result.Mode {
case aoeval.CoreRunContextAB:
card := result.ContextDelta
fmt.Fprintf(command.OutOrStdout(), "Eval context-AB %s: context-off=%.4f (%s) context-on=%.4f (%s) delta=%+.4f cases=%d\n", card.SuiteID, result.FirstRun.AggregateScore, result.FirstRun.Status, result.SecondRun.AggregateScore, result.SecondRun.Status, card.AggregateDelta, len(card.PerCase))
if result.OutputPath != "" {
fmt.Fprintf(command.OutOrStdout(), "Context delta scorecard: %s\n", result.OutputPath)
}
case aoeval.CoreRunBaselineAB:
card := result.Delta
fmt.Fprintf(command.OutOrStdout(), "Eval baseline-AB %s: skill-on=%.4f (%s) skill-off=%.4f (%s) delta=%+.4f cases=%d\n", card.SuiteID, result.FirstRun.AggregateScore, result.FirstRun.Status, result.SecondRun.AggregateScore, result.SecondRun.Status, card.AggregateDelta, len(card.PerCase))
if result.OutputPath != "" {
fmt.Fprintf(command.OutOrStdout(), "Delta scorecard: %s\n", result.OutputPath)
}
default:
run := result.Run
fmt.Fprintf(command.OutOrStdout(), "Eval %s: %s (aggregate %.4f, cases %d)\n", run.RunID, run.Status, run.AggregateScore, len(run.CaseResults))
if result.OutputPath != "" {
fmt.Fprintf(command.OutOrStdout(), "Run record: %s\n", result.OutputPath)
}
}
return nil
}
func renderCoverage(command *cobra.Command, label string, missing, required []string) {
if len(missing) > 0 {
fmt.Fprintf(command.OutOrStdout(), "Missing required %s: %s\n", label, strings.Join(missing, ", "))
return
}
if len(required) > 0 {
fmt.Fprintf(command.OutOrStdout(), "Required %s covered\n", label)
}
}
// suiteSchemaHint cites the authoritative suite schema and a working example so
// a failed `ao eval run` points the caller at the exact shape to fix.
const suiteSchemaHint = "see schemas/eval-suite.v1.schema.json for the suite schema and evals/agentops-core for a working example"
// annotateSuiteParseError appends the schema/example citation to the three
// suite-load failure modes surfaced by cli/internal/eval.LoadSuite — missing
// file ("read eval suite"), malformed JSON ("decode eval suite"), and
// schema-invalid ("eval suite validation failed"). Command-layer decoration
// only; the underlying error text in cli/internal/eval is unchanged.
func annotateSuiteParseError(err error) error {
if err == nil {
return nil
}
msg := err.Error()
for _, sig := range []string{"read eval suite", "decode eval suite", "eval suite validation failed"} {
if strings.Contains(msg, sig) {
return fmt.Errorf("%w (%s)", err, suiteSchemaHint)
}
}
return err
}
func staticCompletion(values ...string) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
return func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
return append([]string(nil), values...), cobra.ShellCompDirectiveNoFileComp
}
}