Documentation
¶
Overview ¶
Package evals is the case-authoring surface for integration tests, agent evaluations, and load tests. Suites written against this package are picked up by the deployed TestServiceServer and executed via three LRO-backed RPCs (RunIntegrationTest, RunAgentEval, RunLoadTest).
The framework is split into a small authoring package (this one) and a set of runtime subpackages that consumers rarely import directly: suite, registry, [runner], [mapper], [report], execution, loadgen, and the case-adjacent helpers in [env] and [adk]. See the top-level README for a wiring diagram and the end-to-end lifecycle.
Suites and cases ¶
Everything is organised around Suites — named groups of Cases that share optional environment setup, lifecycle hooks, and caller identity. Three kinds of suite exist, one per run type on the TestService RPC:
- Integration test suite (NewIntegrationSuite / RegisterIntegration) — cases assert against a live deployment; results surface as `Checks`.
- Agent-eval suite (NewAgentEvalSuite / RegisterEval) — cases exercise an agent transcript and grade with rubrics/scores; results surface as `Metrics`.
- Load-test suite (NewLoadSuite / RegisterLoad) — the framework generates traffic against a target function and evaluates SLOs on the aggregate metrics; results surface as per-case `Summary` + `Checks`.
Every case is qualified as `{suite}.{case}` at registration and can be selected from the RPC via case_ids ("suite" for the whole suite, "suite.case" for one case).
Integration tests ¶
An integration case is a func(ctx, *T) that measures the SUT with Call and records assertions on T. Every recording method on T returns whether the leaf passed, so authors guard-and-return without any custom flow control:
func Register() {
s := evals.MustNewIntegrationSuite("example-v1",
evals.WithEnv("example-v1"),
evals.WithSetup(seedExample),
evals.WithTeardown(cleanupExample),
)
s.MustCase("get-item", func(ctx context.Context, t *evals.T) {
r := evals.Call(ctx, func(ctx context.Context) (*examplepb.Item, error) {
return clients.Example.GetItem(ctx, &examplepb.GetItemRequest{Name: rootItem})
})
if !t.NoErr("grpc", r.Err) {
return
}
t.Max("latency", r.Latency, 500*time.Millisecond)
t.Check("has-name", r.Resp.GetName() != "")
})
if err := evals.RegisterIntegration(s); err != nil {
panic(err)
}
}
Agent evaluations ¶
Eval cases receive the same T but their recorded leaves are surfaced as `Metric`s on the wire, so T.Score is the primary tool. Authors bring their own scoring: a canned unigram scorer is available via Rouge1F1 and LLM-judges are plain Go calls that feed a score into t.Score.
s := evals.MustNewAgentEvalSuite("example-agent-v1",
evals.WithEnv("agent-runtime"),
)
s.MustCase("golden-summary", func(ctx context.Context, t *evals.T) {
r := evals.Call(ctx, func(ctx context.Context) (*agentpb.Reply, error) {
return clients.Agent.Chat(ctx, prompt)
})
if !t.NoErr("transport", r.Err) {
return
}
t.Score("rouge-1", evals.Rouge1F1(r.Resp.GetText(), golden), 0.5, "vs golden")
})
if err := evals.RegisterEval(s); err != nil {
panic(err)
}
Agent evaluations can also be sourced lazily via RegisterAgent + registry.AgentEvalProvider; the [adk] subpackage provides a provider that discovers eval sets from a deployed ADK agent.
Load tests ¶
Load suites are shaped differently: cases are not func(ctx, *T) but a single Target the framework invokes many times under a resolved Profile. There is no T; the assertions are SLOs declared alongside the target. See SLOLatencyP50, SLOLatencyP95, SLOLatencyP99, SLOErrorRate, and SLOMinQPS.
s := evals.MustNewLoadSuite("example-v1-load", evals.WithLoadEnv("example-v1"))
s.MustLoadCase("list-items",
func(ctx context.Context) error {
_, err := clients.Example.ListItems(ctx, &examplepb.ListItemsRequest{PageSize: 5})
return err
},
evals.SLOLatencyP99(500*time.Millisecond),
evals.SLOErrorRate(0.01),
)
if err := evals.RegisterLoad(s); err != nil {
panic(err)
}
The `mode` field on RunLoadTest (MINIMAL … LUDICROUS) picks a preset profile via DefaultLoadProfile. Suites can override presets with WithLoadProfile when a specific case needs bespoke concurrency, duration, or warmup. A resolved profile fully replaces the default (no field-level merging); this keeps intent explicit at high modes.
Suite options ¶
Test and eval suites share a SuiteOption set:
- WithEnv(names...) — declare shared environments the suite requires. Environments must have been registered via [env.Register] before the suite is constructed.
- WithSetup(hook) / WithTeardown(hook) — run before/after the suite's cases. Setup failure fails every case with a setup-error marker and skips teardown.
- WithContext(fn) — install a ContextDecorator that transforms the outgoing context handed to setup, teardown, and every case in the suite. This is the framework's only auth-adjacent surface; callers stamp caller identity, auth headers, tracing state, or any other request-scoped values here.
- StopOnFailure() — mark the suite so a failing case causes the remaining cases to be recorded NOT_EVALUATED. Use for stateful flows where later cases have no meaning after a preceding step fails.
Load suites use a separate LoadSuiteOption set to keep semantics clear: WithLoadEnv, WithLoadSetup, WithLoadTeardown, WithLoadProfile. There is no `StopOnFailure` for load — load cases within a suite run sequentially anyway (concurrent load windows would contaminate each other's measurements), and one case failing does not invalidate the next case's measurement.
Environments ¶
Environments are shared setup steps identified by name. Register them with [env.Register] once (typically in package init) and reference by name in every suite that needs the state:
env.MustRegister("example-v1",
env.WithSetup(seedExample),
env.WithTeardown(cleanupExample),
)
Environments are activated once per RunTest/RunEval/RunLoad LRO, not per suite. This lets several suites share expensive setup (seeding a database, warming a cache) without paying the cost repeatedly.
Context and authentication ¶
The framework never attaches auth to outgoing calls itself. Callers wire whatever auth they use — bearer tokens, oauth2, IAM identity headers, mTLS, etc. — by supplying a ContextDecorator via WithContext at the suite level, or via runner-level context decoration for a cross-suite default. The decorator receives the caller-supplied ctx and returns a derived ctx used for every hook and case body in the suite. Whatever the decorator attaches (metadata, tokens, values) propagates through Go's normal context inheritance to every outbound call the case body makes.
Case authors always retain the escape hatch of further decorating the ctx they receive inside the case body. The ctx handed to a case is always a descendant of the ctx passed to the LRO, so deadlines, cancellation, and existing values are preserved.
Assertion primitives ¶
T exposes a small vocabulary that covers what production suites typically need:
- `Check(id, pass)` / `Checkf(id, pass, format, ...)` — boolean.
- `NoErr(id, err)` — records `err.Error()` on failure.
- `Max(id, got, limit)` — records the observed vs limit duration.
- `Score(id, score, threshold, rationale)` — for eval cases.
Every method returns the pass boolean so authors can chain guards:
if !t.NoErr("grpc", r.Err) { return }
if !t.Max("latency", r.Latency, budget) { return }
t.Check("shape", r.Resp.GetName() != "")
Duplicate check IDs within one case are surfaced as a single DuplicateCheckIDName leaf so results stay parseable downstream.
Registration and execution ¶
Suites are published to a process-wide registry via RegisterIntegration, RegisterEval, RegisterLoad, and RegisterAgent (lazy providers). The default registry is accessible via DefaultRegistry and is what TestServiceServer consumes when it starts a run — the wiring matches http.DefaultServeMux.
Each RunTest/RunEval/RunLoad RPC starts an LRO, selects matching suites from the registry, hands them to [runner.Runner], maps completed suites to `evalspb.Run` via [mapper], and emits every Run to [report.Reporter].
ADK launcher requirement ¶
The evals framework serves its HTTP surface (agent eval discovery, run_eval, and the LRO callbacks) under the `/api/` prefix. That mux is installed by the sublauncher at go.alis.build/adk/launchers/evals: binaries embedding this framework must call the launcher during startup or the RPCs will 404. Add the launcher import once alongside your other neuron wiring:
import _ "go.alis.build/adk/launchers/evals"
See the README for the end-to-end flow, including how consumers wire custom reporters and override load profiles.
Index ¶
- Constants
- func DefaultLoadProfile(mode evalspb.RunLoadTestRequest_Mode) (loadgen.Profile, bool)
- func DefaultRegistry() *registry.Registry
- func RegisterAgent(p registry.AgentEvalProvider) error
- func RegisterEval(s *Suite) error
- func RegisterIntegration(s *Suite) error
- func RegisterLoad(s *LoadSuite) error
- func ResolveLoadProfile(mode evalspb.RunLoadTestRequest_Mode, ...) (loadgen.Profile, bool)
- func Rouge1F1(hypothesis, reference string) float64
- type CaseFunc
- type ContextDecorator
- type ErrNilCaseFunc
- type ErrNilProvider
- type ErrNilTarget
- type ErrUnknownSuiteKind
- type ErrWrongSuiteKind
- type LoadSuite
- type LoadSuiteOption
- type Profile
- type Result
- type SLO
- type Suite
- type SuiteKind
- type SuiteOption
- type T
- type Target
Examples ¶
Constants ¶
const ( // DuplicateCheckIDName is the id used when duplicate check IDs are detected // inside one case. DuplicateCheckIDName = "duplicate-check-id" )
Variables ¶
This section is empty.
Functions ¶
func DefaultLoadProfile ¶
func DefaultLoadProfile(mode evalspb.RunLoadTestRequest_Mode) (loadgen.Profile, bool)
DefaultLoadProfile returns the framework default profile for mode, or the zero Profile and false when mode has no default (MODE_UNSPECIFIED).
func DefaultRegistry ¶
DefaultRegistry returns the process-wide registry. TestServiceServer is constructed with this registry so all cases registered here are reachable via the TestService RPCs.
func RegisterAgent ¶
func RegisterAgent(p registry.AgentEvalProvider) error
RegisterAgent publishes a lazy agent-eval provider (for example one that discovers eval sets from a deployed ADK agent) to DefaultRegistry. Returns ErrNilProvider for a nil provider.
func RegisterEval ¶
RegisterEval publishes an agent-eval suite to DefaultRegistry. Returns suite.ErrNilSuite for a nil suite or ErrWrongSuiteKind when the suite is not KindEval.
func RegisterIntegration ¶
RegisterIntegration publishes an integration-test suite to DefaultRegistry. Returns suite.ErrNilSuite for a nil suite or ErrWrongSuiteKind when the suite is not KindTest.
func RegisterLoad ¶
RegisterLoad publishes a load-test suite to DefaultRegistry. Returns suite.ErrNilSuite for a nil suite.
func ResolveLoadProfile ¶
func ResolveLoadProfile(mode evalspb.RunLoadTestRequest_Mode, overrides map[evalspb.RunLoadTestRequest_Mode]loadgen.Profile) (loadgen.Profile, bool)
ResolveLoadProfile returns the effective profile for mode after applying any suite override on top of the framework default. Overrides fully replace the default; there is no field-level merging (a partially specified override could easily produce nonsense at high modes).
Types ¶
type CaseFunc ¶
CaseFunc is the shape of a case body: measure the SUT via Call, then record leaves on T.
type ContextDecorator ¶ added in v0.1.3
type ContextDecorator = suite.ContextDecorator
ContextDecorator transforms an outgoing context before the runner hands it to suite hooks and case bodies. Use it with WithContext to stamp caller identity, auth tokens, tracing state, or any other request-scoped value on outgoing calls made from inside a case.
type ErrNilCaseFunc ¶ added in v0.1.1
type ErrNilCaseFunc struct {
Case string
}
ErrNilCaseFunc is returned when a case is registered with a nil case function on a Suite.
func (ErrNilCaseFunc) Error ¶ added in v0.1.1
func (e ErrNilCaseFunc) Error() string
func (ErrNilCaseFunc) GRPCStatus ¶ added in v0.1.1
func (e ErrNilCaseFunc) GRPCStatus() *status.Status
func (ErrNilCaseFunc) Is ¶ added in v0.1.1
func (e ErrNilCaseFunc) Is(target error) bool
type ErrNilProvider ¶ added in v0.1.1
type ErrNilProvider struct{}
ErrNilProvider is returned when RegisterAgent is called with a nil provider.
func (ErrNilProvider) Error ¶ added in v0.1.1
func (e ErrNilProvider) Error() string
func (ErrNilProvider) GRPCStatus ¶ added in v0.1.1
func (e ErrNilProvider) GRPCStatus() *status.Status
func (ErrNilProvider) Is ¶ added in v0.1.1
func (e ErrNilProvider) Is(target error) bool
type ErrNilTarget ¶ added in v0.1.1
type ErrNilTarget struct {
Case string
}
ErrNilTarget is returned when a load case is registered with a nil target on a LoadSuite.
func (ErrNilTarget) Error ¶ added in v0.1.1
func (e ErrNilTarget) Error() string
func (ErrNilTarget) GRPCStatus ¶ added in v0.1.1
func (e ErrNilTarget) GRPCStatus() *status.Status
func (ErrNilTarget) Is ¶ added in v0.1.1
func (e ErrNilTarget) Is(target error) bool
type ErrUnknownSuiteKind ¶ added in v0.1.1
type ErrUnknownSuiteKind struct {
Kind SuiteKind
}
ErrUnknownSuiteKind is returned when a Suite's kind field does not match any known SuiteKind. This indicates an internal invariant violation and normally cannot be produced through the public API, which sets `kind` via the exported constructors.
func (ErrUnknownSuiteKind) Error ¶ added in v0.1.1
func (e ErrUnknownSuiteKind) Error() string
func (ErrUnknownSuiteKind) GRPCStatus ¶ added in v0.1.1
func (e ErrUnknownSuiteKind) GRPCStatus() *status.Status
func (ErrUnknownSuiteKind) Is ¶ added in v0.1.1
func (e ErrUnknownSuiteKind) Is(target error) bool
type ErrWrongSuiteKind ¶ added in v0.1.1
ErrWrongSuiteKind is returned when a suite is published with the wrong registration function (for example an eval suite passed to RegisterIntegration).
func (ErrWrongSuiteKind) Error ¶ added in v0.1.1
func (e ErrWrongSuiteKind) Error() string
func (ErrWrongSuiteKind) GRPCStatus ¶ added in v0.1.1
func (e ErrWrongSuiteKind) GRPCStatus() *status.Status
func (ErrWrongSuiteKind) Is ¶ added in v0.1.1
func (e ErrWrongSuiteKind) Is(target error) bool
type LoadSuite ¶
type LoadSuite struct {
// contains filtered or unexported fields
}
LoadSuite is the author-facing handle for a load-test suite. Cases within a load suite always run sequentially and the framework owns pacing, concurrency, warmup, and aggregation — case authors only supply a target function and its SLOs.
func MustNewLoadSuite ¶ added in v0.1.1
func MustNewLoadSuite(name string, opts ...LoadSuiteOption) *LoadSuite
MustNewLoadSuite is like NewLoadSuite but panics on error.
func NewLoadSuite ¶
func NewLoadSuite(name string, opts ...LoadSuiteOption) (*LoadSuite, error)
NewLoadSuite constructs a load-test suite. Returns a typed error on invalid config (empty or dotted name, unknown environment, or a failing option). See the suite package for the typed error values.
Example ¶
ExampleNewLoadSuite shows the minimum wiring for a load suite: a target function and a small set of SLOs. The framework owns pacing, warmup, and error accounting.
package main
import (
"context"
"time"
evalspb "go.alis.build/common/alis/evals/v1"
"go.alis.build/evals"
)
// fakeItem stands in for a caller's typed protobuf response so the examples
// compile without pulling in a real client library.
type fakeItem struct {
Name string
Size int64
}
func (f *fakeItem) GetName() string { return f.Name }
func (f *fakeItem) GetSize() int64 { return f.Size }
// fetchItem is a placeholder for whatever gRPC client method a real suite
// would call. Example functions do not exercise it; they demonstrate the
// shape of the call site.
func fetchItem(ctx context.Context, name string) (*fakeItem, error) {
return &fakeItem{Name: name, Size: 42}, nil
}
func main() {
s := evals.MustNewLoadSuite("example-v1-load",
// Override the MODERATE preset for this suite specifically. Other
// modes keep the framework defaults.
evals.WithLoadProfile(evalspb.RunLoadTestRequest_MODERATE, evals.Profile{
QPS: 100,
Concurrency: 20,
Duration: 60 * time.Second,
Warmup: 10 * time.Second,
RequestTimeout: 5 * time.Second,
}),
)
s.MustLoadCase("get-item",
func(ctx context.Context) error {
_, err := fetchItem(ctx, "items/root")
return err
},
evals.SLOLatencyP99(500*time.Millisecond),
evals.SLOErrorRate(0.01),
evals.SLOMinQPS(20),
)
// evals.RegisterLoad(s) — omitted here to keep the example
// side-effect free; register at process init in real code.
_ = s
}
Output:
func (*LoadSuite) Inner ¶
Inner exposes the underlying suite.LoadSuite for the registry to consume. Not intended for case authors.
func (*LoadSuite) LoadCase ¶
LoadCase registers a case under the suite. The target is invoked once per scheduled request during the load window. Any SLOs are evaluated against the aggregate metrics after the window closes. Returns a typed error on nil suite (suite.ErrNilSuite), nil target (ErrNilTarget), an invalid case name (suite.ErrInvalidCaseName), or a duplicate (suite.ErrDuplicateCase). Use LoadSuite.MustLoadCase for fluent chaining.
func (*LoadSuite) MustLoadCase ¶ added in v0.1.1
MustLoadCase is like LoadSuite.LoadCase but panics on error and returns the suite for fluent chaining.
type LoadSuiteOption ¶
type LoadSuiteOption interface {
// contains filtered or unexported methods
}
LoadSuiteOption configures a LoadSuite at construction time.
func WithLoadEnv ¶
func WithLoadEnv(names ...string) LoadSuiteOption
WithLoadEnv declares one or more shared environments the load suite requires.
func WithLoadProfile ¶
func WithLoadProfile(mode evalspb.RunLoadTestRequest_Mode, p Profile) LoadSuiteOption
WithLoadProfile overrides the framework default profile for a specific mode when this suite is run at that mode. Other modes keep their defaults.
func WithLoadSetup ¶
func WithLoadSetup(h suite.SuiteHook) LoadSuiteOption
WithLoadSetup registers an optional suite-level setup hook.
func WithLoadTeardown ¶
func WithLoadTeardown(h suite.SuiteHook) LoadSuiteOption
WithLoadTeardown registers an optional suite-level teardown hook.
type Profile ¶
Profile re-exports loadgen.Profile so authors of load suites do not need to import the internal loadgen package.
type Result ¶
Result is what Call returns: the typed response, transport error (if any), and wall-clock latency. Assertions are the author's responsibility; Call records nothing on T.
func Call ¶
Call invokes fn and captures the response, error, and wall-clock latency. The type parameter is inferred from fn, so authors never write it explicitly.
r := evals.Call(ctx, func(ctx context.Context) (*filespb.File, error) {
return clients.Files.GetFile(ctx, req)
})
if !t.NoErr("grpc", r.Err) { return }
t.Max("latency", r.Latency, budget)
Example ¶
ExampleCall shows how to wrap a single RPC so its response, error, and latency are captured in one shot. The result is then asserted with the per-case recorder T. Call itself records nothing; every assertion is explicit.
package main
import (
"context"
"time"
"go.alis.build/evals"
)
// fakeItem stands in for a caller's typed protobuf response so the examples
// compile without pulling in a real client library.
type fakeItem struct {
Name string
Size int64
}
func (f *fakeItem) GetName() string { return f.Name }
func (f *fakeItem) GetSize() int64 { return f.Size }
// fetchItem is a placeholder for whatever gRPC client method a real suite
// would call. Example functions do not exercise it; they demonstrate the
// shape of the call site.
func fetchItem(ctx context.Context, name string) (*fakeItem, error) {
return &fakeItem{Name: name, Size: 42}, nil
}
func main() {
s := evals.MustNewIntegrationSuite("example-v1")
s.MustCase("get-item", func(ctx context.Context, t *evals.T) {
r := evals.Call(ctx, func(ctx context.Context) (*fakeItem, error) {
return fetchItem(ctx, "items/root")
})
if !t.NoErr("grpc", r.Err) {
return
}
if !t.Max("latency", r.Latency, 500*time.Millisecond) {
return
}
t.Check("has-name", r.Resp.GetName() != "")
})
// evals.RegisterIntegration(s) — omitted to keep the example
// side-effect free.
_ = s
}
Output:
type SLO ¶
type SLO struct {
// contains filtered or unexported fields
}
SLO is one pass/fail threshold check evaluated against the aggregate metrics of a load window. Every configured SLO produces one SloCheckResult per case run — passed and failed alike — so consumers see headroom on passed checks, not just breaches.
func SLOErrorRate ¶
SLOErrorRate asserts that the measured error rate stays at or below the given fraction (for example 0.01 for 1%). Observed and limit are recorded as percent so the wire values match human intuition.
func SLOLatencyP50 ¶
SLOLatencyP50 asserts that measured p50 latency stays at or below max.
func SLOLatencyP95 ¶
SLOLatencyP95 asserts that measured p95 latency stays at or below max.
func SLOLatencyP99 ¶
SLOLatencyP99 asserts that measured p99 latency stays at or below max.
Example ¶
ExampleSLOLatencyP99 shows how to declare a tail-latency guardrail alongside a load case. Every declared SLO produces one SloCheck per case run — passed or failed — so consumers can compute headroom on passing checks, not just breaches.
package main
import (
"context"
"time"
"go.alis.build/evals"
)
// fakeItem stands in for a caller's typed protobuf response so the examples
// compile without pulling in a real client library.
type fakeItem struct {
Name string
Size int64
}
func (f *fakeItem) GetName() string { return f.Name }
func (f *fakeItem) GetSize() int64 { return f.Size }
// fetchItem is a placeholder for whatever gRPC client method a real suite
// would call. Example functions do not exercise it; they demonstrate the
// shape of the call site.
func fetchItem(ctx context.Context, name string) (*fakeItem, error) {
return &fakeItem{Name: name, Size: 42}, nil
}
func main() {
slo := evals.SLOLatencyP99(300 * time.Millisecond)
s := evals.MustNewLoadSuite("example-v1-load")
s.MustLoadCase("get-item",
func(ctx context.Context) error {
_, err := fetchItem(ctx, "items/root")
return err
},
slo,
)
_ = s
}
Output:
type Suite ¶
type Suite struct {
// contains filtered or unexported fields
}
Suite is the author-facing suite handle. It wraps the internal grouping primitives in suite and adapts CaseFunc values to the erased case interfaces the runner consumes.
func MustNewAgentEvalSuite ¶ added in v0.1.1
func MustNewAgentEvalSuite(name string, opts ...SuiteOption) *Suite
MustNewAgentEvalSuite is like NewAgentEvalSuite but panics on error.
func MustNewIntegrationSuite ¶ added in v0.1.1
func MustNewIntegrationSuite(name string, opts ...SuiteOption) *Suite
MustNewIntegrationSuite is like NewIntegrationSuite but panics on error. Use only in package-init style code where a config error should halt the process.
func NewAgentEvalSuite ¶ added in v0.1.1
func NewAgentEvalSuite(name string, opts ...SuiteOption) (*Suite, error)
NewAgentEvalSuite constructs an agent-eval suite. Returns a typed error on invalid config. See the suite package for the typed error values.
func NewIntegrationSuite ¶ added in v0.1.1
func NewIntegrationSuite(name string, opts ...SuiteOption) (*Suite, error)
NewIntegrationSuite constructs an integration-test suite. Returns a typed error on invalid config (empty or dotted name, unknown environment, or a failing option). See the suite package for the typed error values.
func (*Suite) Case ¶
Case registers a case under the suite. Returns a typed error for a nil suite (suite.ErrNilSuite), a nil func (ErrNilCaseFunc), an invalid case name (suite.ErrInvalidCaseName), or a duplicate (suite.ErrDuplicateCase). Use Suite.MustCase for fluent chaining when a registration error should halt the process.
func (*Suite) MustCase ¶ added in v0.1.1
MustCase is like Suite.Case but panics on error and returns the suite for fluent chaining. Intended for package-init style registration where a bad case declaration should halt the process.
type SuiteKind ¶
type SuiteKind int
SuiteKind distinguishes integration test suites from agent-eval suites.
type SuiteOption ¶
type SuiteOption interface {
// contains filtered or unexported methods
}
SuiteOption configures a suite at construction time (excluding cases).
func StopOnFailure ¶
func StopOnFailure() SuiteOption
StopOnFailure marks the suite so remaining cases are recorded as NOT_EVALUATED once any case ends with a failed status. Use for stateful flows where later steps have no meaning after an earlier failure.
func WithContext ¶ added in v0.1.3
func WithContext(fn ContextDecorator) SuiteOption
WithContext installs a ContextDecorator applied to the context handed to the suite's setup, teardown, and every case body. It is the framework's only auth-adjacent surface: callers use it to stamp caller identity, auth headers, tracing state, or any other request-scoped values on outgoing calls issued from inside cases. The framework never inspects what a decorator attaches; it only propagates it.
Case authors can further decorate the context they receive inside a case body — the ctx handed to a case is always a descendant of the caller's ctx (deadlines, cancellation, and values are preserved).
A nil decorator is a no-op.
func WithEnv ¶
func WithEnv(names ...string) SuiteOption
WithEnv declares one or more shared environments the suite requires. Environments must have been registered with env.Register before the suite is constructed.
func WithSetup ¶
func WithSetup(h suite.SuiteHook) SuiteOption
WithSetup registers an optional suite-level setup hook.
func WithTeardown ¶
func WithTeardown(h suite.SuiteHook) SuiteOption
WithTeardown registers an optional suite-level teardown hook.
type T ¶
type T struct {
// contains filtered or unexported fields
}
T is the per-case recorder that a CaseFunc receives. Every recording method returns whether the leaf passed so authors can guard with a plain return:
if !t.NoErr("grpc", r.Err) { return }
T is not safe for concurrent use across goroutines within a single case.
func (*T) Score ¶
Score records a scored leaf that maps to execution.Metric on eval cases. Passes (and returns true) when score >= threshold. Rationale is surfaced as the metric message.
Example ¶
ExampleT_Score shows the eval-suite scoring pattern. T.Score records the observed value, the pass threshold, and any rationale so consumers see how much headroom each metric had.
package main
import (
"context"
"go.alis.build/evals"
)
func main() {
s := evals.MustNewAgentEvalSuite("example-agent-v1")
s.MustCase("golden-summary", func(ctx context.Context, t *evals.T) {
// A real case would call the agent here; the string literals stand
// in for the produced response and its golden reference.
got := "the quick brown fox"
golden := "the quick brown fox jumped"
// Deterministic scorer bundled with the framework. Feed its output
// into t.Score so both the score and its threshold land on the wire.
t.Score("rouge-1", evals.Rouge1F1(got, golden), 0.5, "vs golden reference")
})
_ = s
}
Output:
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package adk integrates the ADK (Agent Development Kit) evaluation sublauncher into the evals runtime as a lazy [registry.AgentEvalProvider].
|
Package adk integrates the ADK (Agent Development Kit) evaluation sublauncher into the evals runtime as a lazy [registry.AgentEvalProvider]. |
|
Package env holds shared, named setup/teardown hooks that suites can declare a dependency on.
|
Package env holds shared, named setup/teardown hooks that suites can declare a dependency on. |
|
Package errors bridges evals-typed errors to gRPC statuses at the RPC boundary.
|
Package errors bridges evals-typed errors to gRPC statuses at the RPC boundary. |
|
Package execution defines the in-process result types the runner emits and the mapper serialises onto `evalspb.Run`.
|
Package execution defines the in-process result types the runner emits and the mapper serialises onto `evalspb.Run`. |
|
internal
|
|
|
result
Package result builds case results and rolls up status lists.
|
Package result builds case results and rolls up status lists. |
|
Package loadgen is a small, embedded load generator for the evals runner.
|
Package loadgen is a small, embedded load generator for the evals runner. |
|
Package mapper converts the runner's in-process execution result types into the `evalspb.Run` wire type that reporters and consumers see.
|
Package mapper converts the runner's in-process execution result types into the `evalspb.Run` wire type that reporters and consumers see. |
|
Package registry holds every suite the TestServiceServer can execute and resolves case_ids filters into concrete suite runs.
|
Package registry holds every suite the TestServiceServer can execute and resolves case_ids filters into concrete suite runs. |
|
Package report defines the Reporter interface for emitting completed evalspb.Run values to external sinks, plus generic combinators for wiring multiple sinks together.
|
Package report defines the Reporter interface for emitting completed evalspb.Run values to external sinks, plus generic combinators for wiring multiple sinks together. |
|
bigquery
Package bigquery implements a [report.Reporter] that streams completed evalspb.Run values to a pre-existing BigQuery table.
|
Package bigquery implements a [report.Reporter] that streams completed evalspb.Run values to a pre-existing BigQuery table. |
|
bqschema
Package bqschema is the single source of truth for the BigQuery schema of evalspb.Run rows and for table provisioning.
|
Package bqschema is the single source of truth for the BigQuery schema of evalspb.Run rows and for table provisioning. |
|
log
Package log implements the default [report.Reporter]: a one-line summary of each completed evalspb.Run written via alog.
|
Package log implements the default [report.Reporter]: a one-line summary of each completed evalspb.Run written via alog. |
|
pubsub
Package pubsub implements a [report.Reporter] that publishes each completed evalspb.Run as JSON to Pub/Sub via google.golang.org/protobuf/encoding/protojson, on top of cloud.google.com/go/pubsub/v2.
|
Package pubsub implements a [report.Reporter] that publishes each completed evalspb.Run as JSON to Pub/Sub via google.golang.org/protobuf/encoding/protojson, on top of cloud.google.com/go/pubsub/v2. |
|
Package runner executes filtered suite runs and turns them into execution result structs the mapper can wire onto proto responses.
|
Package runner executes filtered suite runs and turns them into execution result structs the mapper can wire onto proto responses. |
|
Package suite defines the internal suite primitives that back the public authoring surface in go.alis.build/evals.
|
Package suite defines the internal suite primitives that back the public authoring surface in go.alis.build/evals. |