Documentation
¶
Overview ¶
Package agentbench runs multi-turn harness benchmarks aligned with industry agent/memory/tool evaluation shapes (LoCoMo-style memory, multi-hop QA, τ-bench-style domain end state, plan+interrupt, web-augmented).
Case definitions and seed worlds live in Go (see cases_*.go), not external JSONL.
Index ¶
- Constants
- Variables
- func ApplySeed(ctx context.Context, eng *brain.Engine, scope brain.Scope, world SeedWorld) error
- func DefaultGates() map[string]float64
- func EvaluateGates(rep Report, hasExa bool) (bool, []string)
- func FormatMarkdown(rep Report) string
- func KindSpecs() []brain.KindSpec
- func ListCases(w io.Writer, suite string)
- func WriteJSON(w io.Writer, rep Report) error
- type Case
- type CaseResult
- type Config
- type Expect
- type OpenAIEmbedder
- type Report
- type SeedEdge
- type SeedObject
- type SeedWorld
- type SuiteResult
- type ToolCallRecord
- type TurnTrace
Constants ¶
const ( SuiteMemory = "memory" SuiteMultihopQA = "multihop_qa" SuiteToolDomain = "tool_domain" SuiteWebAugmented = "web_augmented" SuitePlanInterrupt = "plan_interrupt" )
Suite identifiers.
const DefaultEmbedModel = "text-embedding-3-small"
DefaultEmbedModel is used when OPENAI_EMBEDDING_MODEL / -embed-model is unset.
SharedSystemPrompt steers plan + brain + web tool use without domain hardcoding.
Variables ¶
var ( IDProjectOrion = uuid.MustParse("11111111-1111-1111-1111-111111111101") IDPersonAlex = uuid.MustParse("11111111-1111-1111-1111-111111111102") IDPersonSam = uuid.MustParse("11111111-1111-1111-1111-111111111103") IDNoteAsync = uuid.MustParse("11111111-1111-1111-1111-111111111104") IDNoteLegal = uuid.MustParse("11111111-1111-1111-1111-111111111105") IDNoteNoise = uuid.MustParse("11111111-1111-1111-1111-111111111106") IDChunkLegal = uuid.MustParse("11111111-1111-1111-1111-111111111107") )
fixed IDs for multihop evidence gold (stable across runs).
var AllSuites = []string{ SuitePlanInterrupt, SuiteMemory, SuiteMultihopQA, SuiteToolDomain, SuiteWebAugmented, }
AllSuites is the default suite list for -suite all.
Functions ¶
func ApplySeed ¶
ApplySeed puts objects and links under scope. Fills nil IDs with new UUIDs in-place on a copy of the seed so gold ids in Cases that set fixed UUIDs remain stable.
func DefaultGates ¶
DefaultGates are v1 success-rate floors (non-skipped cases only).
func EvaluateGates ¶
EvaluateGates returns whether gates pass and human-readable notes.
func FormatMarkdown ¶
FormatMarkdown returns a compact scorecard for stdout.
Types ¶
type Case ¶
type Case struct {
ID string
Suite string
// RequiresExa skips the case when EXA_API_KEY is empty (not a failure).
RequiresExa bool
// RestoreSession: after the first N-1 turns, rebuild agent from session for the last turn.
RestoreSession bool
Turns []string
// InterruptChoiceTitle is matched against ask_user_choice options (case-insensitive contains).
// When empty, selectionIdx 0 is used.
InterruptChoiceTitle string
// InterruptSelectionIdx used when title is empty or unmatched.
InterruptSelectionIdx int
Seed SeedWorld
Expect Expect
}
Case is one multi-turn benchmark scenario with in-memory seed and rule expects.
func AllCases ¶
func AllCases() []Case
AllCases returns every built-in benchmark case (seed data embedded in Go).
func CasesForSuite ¶
CasesForSuite filters AllCases by suite id (empty / "all" → all).
type CaseResult ¶
type CaseResult struct {
ID string `json:"id"`
Suite string `json:"suite"`
Skipped bool `json:"skipped,omitempty"`
SkipWhy string `json:"skip_why,omitempty"`
Success bool `json:"success"`
Notes []string `json:"notes,omitempty"`
// Scores are named 0/1 or fractions for aggregation.
Scores map[string]float64 `json:"scores,omitempty"`
Turns []TurnTrace `json:"-"` // omit heavy traces from default JSON unless verbose
}
CaseResult is the judged outcome of one case.
type Config ¶
type Config struct {
Suites []string
CaseFilter string // optional exact case id
ModelURL string
ModelAPIKey string
ModelName string
// EmbedURL defaults to ModelURL. EmbedAPIKey defaults to ModelAPIKey.
// EmbedModel defaults to DefaultEmbedModel / OPENAI_EMBEDDING_MODEL.
EmbedURL string
EmbedAPIKey string
EmbedModel string
// LexicalOnly disables the dense channel (no WithEmbedder).
LexicalOnly bool
ExaAPIKey string
Timeout time.Duration // per case
DryRun bool
}
Config configures a benchmark run.
type Expect ¶
type Expect struct {
// FinalContainsAny: final assistant text must contain at least one (case-insensitive).
FinalContainsAny []string
// FinalContainsAll: every string must appear.
FinalContainsAll []string
// MustTools: each inner list is an OR group; every group must match some tool name used.
MustTools [][]string
// MustNotTools: none of these tool names may appear.
MustNotTools []string
// MustInterrupt: at least one ask_user_choice (or any interrupt) must have fired.
MustInterrupt bool
// BrainKindContains: after the case, FindObjects or list kinds via search for this kind
// with query substring must return ≥1 hit (empty Query → any of that kind via find with kind filter + broad query).
BrainKind string
BrainQuery string
// BrainTitleContains: some object of BrainKind (or any if empty) has title containing this.
BrainTitleContains string
// GoldEvidenceIDs: at least one must appear in tool args or results text (evidence hit).
GoldEvidenceIDs []uuid.UUID
}
Expect is a rule-based judge. All set fields must pass for Success.
type OpenAIEmbedder ¶
OpenAIEmbedder implements brain.QueryEmbedder via POST {baseURL}/embeddings (OpenAI-compatible, including Azure OpenAI with base …/openai/v1).
type Report ¶
type Report struct {
Model string `json:"model"`
EmbedModel string `json:"embed_model,omitempty"`
StartedAt time.Time `json:"started_at"`
Duration time.Duration `json:"duration_ms"` // wall; JSON via custom if needed
Suites map[string]SuiteResult `json:"suites"`
GatesOK bool `json:"gates_ok"`
GateNotes []string `json:"gate_notes,omitempty"`
}
Report is the full scorecard written to -out.
type SeedObject ¶
type SeedObject struct {
ID uuid.UUID
Kind string
Title string
Summary string
Content string
ParentID *uuid.UUID
Position *int
Props map[string]any
}
SeedObject is a brain row to Put before the case runs.
type SeedWorld ¶
type SeedWorld struct {
// Objects with fixed IDs (for multihop evidence gold). Empty ID → generated on seed.
Objects []SeedObject
Edges []SeedEdge
}
SeedWorld is applied under a fresh namespace before the first turn.
func WorldMeetingPrep ¶
func WorldMeetingPrep() SeedWorld
WorldMeetingPrep is a small “notes app” graph for multihop / domain cases.
type SuiteResult ¶
type SuiteResult struct {
Suite string `json:"suite"`
N int `json:"n"`
Skipped int `json:"skipped"`
Passed int `json:"passed"`
Failed int `json:"failed"`
SuccessRate float64 `json:"success_rate"` // among non-skipped
IllegalRate float64 `json:"illegal_rate"`
Cases []CaseResult `json:"cases"`
}
SuiteResult aggregates cases in one suite.
type ToolCallRecord ¶
type ToolCallRecord struct {
Name string
Arguments string
Result string // best-effort from tool_result content
}
ToolCallRecord is one observed tool invocation from the stream.