ExperimentConfig
AgentInvoker
Single-method interface — implement this to plug in any agent:- Blocking: returns when agent completes, times out, or fails
- Thread-safe: callable from multiple threads
- NOT responsible for: timeout enforcement, workspace setup, result tracking
Template Invokers
The agent-experiment-template provides a hierarchy of ready-made invokers. Choose based on your orchestration needs:| Class | Extends | Use When |
|---|---|---|
TemplateAgentInvoker | AbstractTemplateAgentInvoker | Single-phase agent via AgentClient (rename to {Domain}AgentInvoker) |
TwoPhaseTemplateAgentInvoker | AbstractTemplateAgentInvoker | Two-phase explore + act via ClaudeSyncClient |
WorkflowAgentInvoker | AbstractTemplateAgentInvoker | Single-step workflow — simplest workflow entry point |
WorkflowInvoker<S> | AgentInvoker (direct) | Multi-step typed workflow with cost tracking |
AbstractTemplateAgentInvoker provides:
- Pre/post invoke hooks (
preInvoke,postInvoke) - Knowledge file injection into workspaces
- Phase capture collection
WorkflowAgentInvoker wraps a single ClaudeStep in a Workflow with journal integration wired automatically — step events are recorded as WorkflowStepEvent entries via WorkflowJournal. The experiment name is pulled from context.metadata("experimentId").
WorkflowInvoker<S> is the base for multi-step workflows with typed state. Journal and cost tracking are built in. Subclasses implement three methods:
InvocationContext
What the runner passes to your agent:| Field | Type | Description |
|---|---|---|
workspacePath | Path | Directory where agent operates |
prompt | String | Fully constructed prompt |
systemPrompt | String | Optional additional system instructions |
model | String | Model identifier |
timeout | Duration | Timeout hint |
metadata | Map | Pass-through (experimentId, itemId, etc.) |
runDir | Path | Optional directory for trace artifacts |
InvocationResult
What your agent returns:| Field | Type | Description |
|---|---|---|
success | boolean | Agent completed without error |
status | TerminalStatus | COMPLETED, ERROR, TIMEOUT |
inputTokens | int | Total input tokens consumed |
outputTokens | int | Total output tokens produced |
totalCostUsd | double | Estimated cost |
durationMs | long | Wall-clock execution time |
ExecutionDetail
Marker interface that decouples shared experiment infrastructure (ComparisonEngine, ResultStore, VerdictExtractor) from domain-specific per-item execution details.| Implementation | Used By | Contains |
|---|---|---|
InvocationResult | AgentExperiment | Agent invocation output, tokens, cost, phases |
JudgeExecutionDetail | JudgeExperiment | Candidate judgment, expected label, scorer result |
ItemResult.executionDetail() returns @Nullable ExecutionDetail. Consumers use instanceof pattern matching to access domain-specific fields:
Dataset Format
dataset.json
item.json
Directory layout
ItemFilter
ResultStore
| Implementation | Use case |
|---|---|
FileSystemResultStore(path) | Production — persists to disk |
InMemoryResultStore() | Testing — HashMap-backed |
ExperimentResult
| Method | Type | Description |
|---|---|---|
experimentId() | String | Unique run ID |
experimentName() | String | Experiment name from config |
items() | List<ItemResult> | Per-item results |
passCount() | int | Items that passed all judges |
failCount() | int | Items that failed |
passRate() | double | Pass count / total (0.0–1.0) |
Re-Evaluation
Re-evaluate stored experiment results with a different jury without re-invoking the system under test.ReEvaluationContextFactory
Functional interface that reconstructs aJudgmentContext from a stored ItemResult:
Optional.empty() when re-evaluation is not possible (failed item, missing execution detail, workspace not preserved).
AgentReEvaluationContextFactory
Default implementation for agent experiment results. Pattern-matches onInvocationResult to reconstruct the context:
TerminalStatus to ExecutionStatus (COMPLETED → SUCCESS, TIMEOUT → TIMEOUT, ERROR → FAILED). Preserves original costUsd and totalTokens.
ReEvaluator
Orchestrates post-hoc re-scoring of stored experiment results:| Method | Description |
|---|---|
reEvaluate(ExperimentResult, Jury) | Re-score a loaded result with a new jury |
reEvaluate(String experimentId, Jury) | Load by ID, then re-score |
agentDefaults(ResultStore) | Convenience factory with AgentReEvaluationContextFactory |
reEvaluated=true, systemReinvoked=false, originalCostUsd, reEvaluationJury, originalTimestamp. Skipped items carry reEvaluationSkipped=true with a reason.
Judge Experiment
Run a judge as the system under test against a labeled dataset to measure agreement rate.JudgeScorer
Functional interface that scores a candidate judge’sJudgment against the expected label:
JudgeScoringInput
JudgeScorerResult
JudgeScorers
Built-in scoring implementations:| Factory Method | Scoring Rule |
|---|---|
exactVerdictMatch() | PASS/FAIL must exactly match expected "PASS"/"FAIL" label |
exactCategoryMatch() | CategoricalScore value must match expected label (case-insensitive) |
numericalTolerance(double) | NumericalScore within tolerance of expected numeric value |
JudgeExecutionDetail
Domain evidence preserved for each item:JudgeExperiment
Builder-based experiment runner where the system under test is aJudge:
| Builder Method | Required | Description |
|---|---|---|
name(String) | Yes | Experiment name |
candidate(Judge) | Yes | Judge to evaluate |
items(List<DatasetItem>) | Yes | Labeled dataset items |
input(Function<DatasetItem, JudgmentContext>) | Yes | Builds context from item |
expected(Function<DatasetItem, String>) | Yes | Extracts expected label from item |
scorer(JudgeScorer) | Yes | Scoring strategy |
resultStore(ResultStore) | Yes | Persistence |
datasetVersion(String) | No | Defaults to "1.0.0" |
List<DatasetItem> directly — judge datasets do not require filesystem loading.
JudgeExperimentResult
| Method | Description |
|---|---|
agreementRate() | Fraction of items where judge agreed with expected label |
disagreements() | Items where judge disagreed |
from(ExperimentResult) | Create from an ExperimentResult containing JudgeExecutionDetail items |
asExperimentResult() | Unwrap for ComparisonEngine and ResultStore compatibility |