Agents Package Cheatsheet¶
Root namespace: Cognesy\Agents
This file is a quick, code-aligned map of the package surface.
For narrative guidance and examples, use packages/agents/docs/*.md.
1. Core Loop¶
AgentLoop(readonly)- main orchestrator, implements
CanControlAgentLoopandCanAcceptEventHandler - key API:
default(),execute(),iterate() - accessors:
tools(),toolExecutor(),driver(),eventHandler(),interceptor() - composition API:
withTool(),withTools(),withDriver(),withToolExecutor(),withInterceptor(),withEventHandler(),with() - event API:
wiretap(),onEvent() - note: terminal executions are auto-reset on entry to
execute()/iterate() CanControlAgentLoop- contract:
execute(AgentState): AgentState,iterate(AgentState): iterable
2. State Model¶
Data\AgentState- immutable runtime state
- factories:
empty(),fromArray() - identity:
agentId(),parentAgentId(),llmConfig(),executionCount(),createdAt(),updatedAt() - common mutators:
withUserMessage(string|\Stringable|Message),withSystemPrompt(string|\Stringable),withMetadata(),withMessages(),withMessageStore(),withLLMConfig(),with() - step mutators:
withCurrentStep(),withCurrentStepCompleted(),withExecutionCompleted(),withExecutionContinued() - stop/failure:
withStopSignal(),withFailure(),withExecutionStatus() - context access:
context(),store(),messages(),metadata() - result access:
finalResponse(),currentResponse(),hasFinalResponse() - execution access:
execution(),status(),stepCount(),steps(),usage(),errors(),hasErrors() - last-step accessors:
lastStep(),lastStepExecution(),lastStepToolExecutions(),lastToolExecution(),lastStepErrors(),lastStepType(),lastStepUsage(),lastStepDuration() - stop accessors:
stopSignal(),stopReason(),stopSource() - control:
shouldStop(),forNextExecution() - serialization:
debug(),toArray(),fromArray() Data\ExecutionState- per-execution transient state (
executionId, status, steps, continuation) Data\AgentStep- one loop step snapshot (
inputMessages,outputMessages,inferenceResponse,toolExecutions,errors) Data\StepExecution- completed step wrapper with timing
Data\ToolExecution- one executed tool call (
value(),hasError(),errorAsString(),wasBlocked()) Data\ExecutionBudget- optional limits:
maxSteps,maxTokens,maxSeconds,maxCost,deadline - factories:
unlimited() - queries:
isEmpty(),isExhausted() Data\AgentId,Data\ExecutionId,Data\AgentStepId,Data\ToolExecutionId- typed ID value objects
3. Enums¶
Enums\ExecutionStatus--Pending,InProgress,Completed,Stopped,FailedEnums\AgentStepType--ToolExecution,FinalResponse,Error
4. Collections¶
Collections\Tools- immutable named tool collection
- key API:
has(),get(),names(),all(),count(),isEmpty(),descriptions(),withTool(),withTools(),withToolRemoved(),merge(),toToolSchema(): ToolDefinitions Collections\AgentStepsCollections\StepExecutionsCollections\ToolExecutionsCollections\NameList
5. Tools¶
Contracts¶
Tool\Contracts\ToolInterfaceuse(mixed ...$args): ResulttoToolSchema(): ToolDefinitiondescriptor(): CanDescribeToolTool\Contracts\CanDescribeToolname(),description(),metadata(),instructions()Tool\Contracts\CanExecuteToolCallsexecuteTools(ToolCalls, AgentState): ToolExecutionsTool\Contracts\CanAccessAgentStateTool\Contracts\CanAccessToolCallTool\Contracts\CanManageTools
Base classes¶
Tool\Tools\SimpleToolTool\Tools\ReflectiveSchemaToolTool\Tools\FunctionToolTool\Tools\StateAwareToolTool\Tools\BaseToolTool\Tools\ContextAwareToolTool\Tools\FakeTool
Runtime¶
Tool\ToolExecutorTool\ToolRegistryTool\ToolDescriptor
6. Drivers¶
Drivers\CanUseToolsDrivers\CanAcceptToolRuntimeDrivers\ToolCalling\ToolCallingDriver(default)Drivers\ToolCalling\ToolExecutionFormatterDrivers\ReAct\ReActDriverDrivers\Testing\FakeAgentDriverDrivers\Testing\ScenarioStep
7. Context¶
Context\AgentContextContext\CanCompileMessagesContext\CanAcceptMessageCompilerContext\ContextSections
Compilers:
Context\Compilers\ConversationWithCurrentToolTrace(default)Context\Compilers\AllSectionsContext\Compilers\SelectedSections
8. Continuation / Stop¶
Continuation\StopReasonContinuation\StopSignalContinuation\StopSignalsContinuation\ExecutionContinuationContinuation\AgentStopException
9. Hooks / Interception¶
Hook\Contracts\HookInterfaceHook\Data\HookContextHook\Data\RegisteredHookHook\Collections\RegisteredHooksHook\Enums\HookTrigger- values:
BeforeExecution,BeforeStep,BeforeToolUse,AfterToolUse,AfterStep,OnStop,AfterExecution,OnError Hook\Collections\HookTriggersHook\HookStack
Built-in hooks:
Hook\Hooks\CallableHookHook\Hooks\StepsLimitHookHook\Hooks\TokenUsageLimitHookHook\Hooks\ExecutionTimeLimitHookHook\Hooks\FinishReasonHookHook\Hooks\ApplyContextConfigHook
Interception:
Interception\CanInterceptAgentLifecycleInterception\PassThroughInterceptor
10. Builder / Capabilities¶
Builder\AgentBuilderBuilder\AgentConfiguratorBuilder\Contracts\CanProvideAgentCapabilityBuilder\Contracts\CanConfigureAgentBuilder\Contracts\CanComposeAgentLoopBuilder\Contracts\CanProvideDeferredToolsBuilder\Collections\DeferredToolProvidersBuilder\Data\DeferredToolContext
Capability registry:
Capability\AgentCapabilityRegistryCapability\CanManageAgentCapabilities
Core capabilities:
Capability\Core\UseLLMConfigCapability\Core\UseGuardsCapability\Core\UseToolsCapability\Core\UseToolFactoryCapability\Core\UseHookCapability\Core\UseDriverCapability\Core\UseDriverDecoratorCapability\Core\UseContextCompilerCapability\Core\UseContextCompilerDecoratorCapability\Core\UseContextConfigCapability\Core\UseReActConfig
Domain capabilities:
Capability\Bash\UseBashCapability\Cancellation\UseCooperativeCancellation- adds checkpoint-based cooperative cancellation to the loop
- cancellation is cooperative: stops at
BeforeExecution/BeforeStepcheckpoints only — does not interrupt in-flight HTTP or tool calls - requires a
CanProvideCancellationSignalimplementation; built-in:InMemoryCancellationSource - stop reason reported as
StopReason::UserRequested
use Cognesy\Agents\Capability\Cancellation\UseCooperativeCancellation;
use Cognesy\Agents\Capability\Cancellation\InMemoryCancellationSource;
$source = new InMemoryCancellationSource();
$agent = AgentBuilder::base()
->withCapability(new UseCooperativeCancellation($source))
->build();
// cancel from outside (e.g. signal handler, HTTP request, timer):
$source->cancel('user pressed stop');
// custom source (Redis key, DB flag, HTTP endpoint, …):
$agent = AgentBuilder::base()
->withCapability(new UseCooperativeCancellation(
new class implements CanProvideCancellationSignal {
public function cancellationSignal(AgentState $state): ?StopSignal {
return redis_get("cancel:{$state->agentId()}")
? StopSignal::userRequested('cancelled via redis')
: null;
}
}
))
->build();
Capability\File\UseFileTools
- installs: read_file, write_file, edit_file
- standalone file tools also available: SearchFilesTool, ListDirTool
- Capability\Metadata\UseMetadataTools
- Capability\Subagent\UseSubagents
- Capability\PlanningSubagent\UsePlanningSubagent
- Capability\StructuredOutput\UseStructuredOutputs
- Capability\Summarization\UseSummarization
- Capability\SelfCritique\UseSelfCritique
- Capability\Skills\UseSkills
- Capability\Tasks\UseTaskPlanning
- Capability\Tools\UseToolRegistry
- Capability\ExecutionHistory\UseExecutionHistory
- Capability\Retrospective\UseExecutionRetrospective
- Capability\Broadcasting\UseAgentBroadcasting
11. Broadcasting¶
Broadcasting\AgentEventBroadcasterBroadcasting\AgentBroadcastObserverBroadcasting\BroadcastConfigBroadcasting\CanBroadcastAgentEvents
12. Templates¶
Template\Data\AgentDefinition- core fields:
name,description,systemPrompt,label,llmConfig,capabilities,tools,toolsDeny,skills,budget,metadata - tool semantics:
tools === nullmeans inherit all available tools Template\AgentDefinitionLoaderTemplate\AgentDefinitionRegistryTemplate\Contracts\CanManageAgentDefinitionsTemplate\Contracts\CanInstantiateAgentLoopTemplate\Contracts\CanInstantiateAgentStateTemplate\Parsers\CanParseAgentDefinitionTemplate\Factory\DefinitionStateFactoryTemplate\Factory\DefinitionLoopFactory- parsers:
Template\Parsers\MarkdownDefinitionParser,JsonDefinitionParser,YamlDefinitionParser
13. Sessions¶
Core:
Session\Data\SessionIdSession\Data\AgentSessionInfoSession\Data\AgentSession- access:
info(),definition(),state(),sessionId(),status(),version() Session\SessionRuntime-- preferred API for creating new sessions and applying actions to persisted sessionsSession\SessionRepository-- low-level persistence boundary over a store implementationSession\SessionFactory-- low-level helper for constructingAgentSessioninstances before manual persistence
Contracts:
Session\Contracts\CanManageAgentSessionsSession\Contracts\CanExecuteSessionActionSession\Contracts\CanStoreSessionsSession\Contracts\CanControlAgentSession
Stores:
Session\Store\InMemorySessionStoreSession\Store\FileSessionStore
Actions:
Session\Actions\SendMessage(acceptsstring|\Stringable|Message)Session\Actions\ForkSession(returns a new branch session object; persist that fork via repositorycreate(); for brand-new root sessions preferSessionRuntime::create())Session\Actions\ResumeSessionSession\Actions\SuspendSessionSession\Actions\ClearSessionSession\Actions\ChangeModelSession\Actions\ChangeSystemPrompt(acceptsstring|\Stringable)Session\Actions\WriteMetadataSession\Actions\UpdateTask
Enums:
Session\Enums\SessionStatus--Active,Suspended,Completed,Failed,DeletedSession\Enums\AgentSessionStage--AfterLoad,AfterAction,BeforeCreate,AfterCreate,BeforeSave,AfterSave
Session hooks:
Session\SessionHookStackSession\RegisteredSessionHookSession\PassThroughSessionControllerSession\Collections\SessionInfoList
Exceptions:
Session\Exceptions\SessionNotFoundExceptionSession\Exceptions\SessionConflictExceptionSession\Exceptions\InvalidSessionFileException
14. Events¶
Agent events include:
AgentExecutionStarted,AgentStepStarted,AgentStepCompletedAgentExecutionStopped,AgentExecutionCompleted,AgentExecutionFailedAgentStateUpdatedContinuationEvaluated,StopSignalReceived,TokenUsageReportedToolCallStarted,ToolCallCompleted,ToolCallBlockedInferenceRequestStarted,InferenceResponseReceivedSubagentSpawning,SubagentCompletedHookExecuted,DecisionExtractionFailed,ValidationFailedEvents\AgentEvent(base class)
Event support:
Events\Support\AgentEventConsoleFormatterEvents\Support\AgentEventConsoleObserver
Session events include:
SessionLoaded,SessionActionExecuted,SessionSavedSessionLoadFailed,SessionSaveFailed
15. Exceptions¶
Exceptions\AgentException(base)Exceptions\AgentNotFoundExceptionExceptions\InvalidToolExceptionExceptions\InvalidToolArgumentsExceptionExceptions\ToolCallBlockedExceptionExceptions\ToolExecutionBlockedExceptionExceptions\ToolExecutionException
16. Skills¶
Capability\Skills\Skill- immutable skill value object
- standard fields:
name,description,license,compatibility,metadata,allowedTools,body,path,resources - extension fields:
disableModelInvocation,userInvocable,argumentHint,model,context,agent - key API:
render(?string $arguments),renderMetadata(),toArray() - argument substitution:
$ARGUMENTS,$ARGUMENTS[N],$Nplaceholders Capability\Skills\SkillLibrary- discovers
SKILL.mdfiles in<path>/<skill-name>/SKILL.md - lazy-loads skill content on first access, caches result
- key API:
listSkills(modelInvocable, userInvocable),hasSkill(),getSkill(),renderSkillList() - resource discovery: scans
scripts/,references/,assets/,examples/subdirs Capability\Skills\LoadSkillTool- tool exposed to LLM:
load_skill(skill_name, list_skills, arguments) - user-invocable filtering on list mode
Capability\Skills\AppendSkillMetadataHook- injects skill names/descriptions as system message before first step
- filters out
disable-model-invocation: trueskills Capability\Skills\TrackActiveSkillHook- tracks active skill metadata (allowed-tools, model) in state after
load_skillcompletes Capability\Skills\SkillToolFilterHook- enforces
allowed-toolsrestrictions; blocks non-allowed tools (exceptload_skillitself) Capability\Skills\SkillModelOverrideHook- overrides LLMConfig when a skill with a
modelfield is active Capability\Skills\SkillForkExecutor- executes skills in a forked agent loop context
Capability\Skills\SkillPreprocessor- executes
!command`` patterns in skill body before argument substitution - configurable working directory and timeout
- opt-in: pass to
UseSkillsorLoadSkillToolconstructor Capability\Skills\UseSkills- capability that wires
LoadSkillTool+ hooks into agent - optional
?SkillPreprocessorfor shell preprocessing - follows Agent Skills Open Standard (30+ tools)
17. Testing¶
Drivers\Testing\FakeAgentDriver- scripted loop steps via
ScenarioStep - best for most deterministic agent-loop tests
Tests\Support\FakeInferenceDriver- queued raw
InferenceResponseor streamingPartialInferenceDeltafixtures - use when the test sits closer to the inference boundary
Tool\Tools\FakeTool- deterministic tool double with fixed or callable-backed results
Tests\Support\FakeSubagentProvider- in-memory subagent definition registry for capability tests
Tests\Support\TestAgentLoop- small loop harness with explicit max-iteration stop behavior
Cognesy\Sandbox\Testing\FakeSandbox(frompackages/sandbox, not agents)- deterministic process-execution seam for bash-backed tools
18. Docs Index¶
Read in this order:
packages/agents/docs/01-introduction.mdpackages/agents/docs/testing-doubles.mdpackages/agents/docs/02-basic-agent.mdpackages/agents/docs/05-tools.mdpackages/agents/docs/06-building-tools.mdpackages/agents/docs/13-agent-builder.mdpackages/agents/docs/14-agent-templates.mdpackages/agents/docs/15-subagents.mdpackages/agents/docs/16-session-runtime.mdpackages/agents/docs/19-skills.mdpackages/agents/docs/21-evals.mdpackages/agents/docs/22-eval-assertions.mdpackages/agents/docs/23-eval-judges.mdpackages/agents/docs/24-eval-traces-and-artifacts.mdpackages/agents/docs/25-running-evals.md
19. Evals¶
Behavioral evals that grade an agent target with deterministic assertions and semantic judges. Narrative docs: docs/21-evals.md through docs/25-running-evals.md.
Case definition:
Evals\AgentEval(readonly)- immutable definition of one eval case
- factories:
define(description, Closure(EvalContext): void $test, ?tags, ?judge) - key API:
withId() - accessors:
description(),test(),tags(),id(),judge() Evals\AgentEvals(readonly,Countable,IteratorAggregate)- immutable collection of
AgentEval - factories:
none() - key API:
with(),filtered(?glob, ?required, ?excluded) - accessors:
all(),count() Evals\AgentEvalSet(readonly)- groups evals built from a dataset
- factories:
fromDataset(EvalDataset, Closure(EvalDatasetRow): AgentEval $factory),of(AgentEval ...$evals) - accessors:
evals(): AgentEvals Evals\EvalTags(readonly,Countable,IteratorAggregate)- normalized (trimmed, deduped, sorted) tag set
- factories:
of(),none() - key API:
has() - accessors:
all(),count() Evals\EvalDataset(readonly,Countable,IteratorAggregate)- list of
EvalDatasetRow - factories:
fromJson(),fromYaml() Evals\EvalDatasetRow(readonly)- one dataset row
- key API:
value(key),string(key) - accessors:
toArray() Evals\EvalDiscovery(readonly)- finds
*.eval.phpfiles under a root and assigns ids - factories:
in(root) - key API:
discover(): AgentEvals - note: an eval file must
return AgentEval|AgentEvalSet|array<AgentEval>; ids are the file's path relative to the root (with a/NNNNsuffix appended when one file yields more than one eval) Evals\EvalCount(readonly)- count predicate for
calledTool()/calledSubagent()/event()assertions - factories:
atLeast(),atMost(),between(),satisfies(Closure(int): bool) - key API:
matches(int) Evals\EvalMatch(readonly)- value matcher for
outputMatches()andValueExpectation::matches() - factories:
partial(array),regex(pattern),satisfies(Closure) - key API:
matches(mixed) Evals\EvalMatcher(readonly)- static matching helpers used throughout:
matches()(exact equality unless given anEvalMatchor array),partial()(recursive partial-array match; lists require equal length, maps require only the listed keys)
Execution context & assertions:
Evals\EvalContext- passed into every eval's test closure; owns the session, assertion collector, and log collector for one eval run
- key API:
send(),run(): AgentRun,expect(mixed): ValueExpectation,judge(): AgentJudgeAssertions,check(),require()(throwsEvalRequirementFailedon failure),skip()(throwsEvalSkipped),log(),newSession() - built-in assertions, each returning
AssertionHandle:succeeded(),stopped(),messageIncludes(),outputEquals(),outputMatches(),calledTool(),notCalledTool(),toolOrder(),usedNoTools(),maxToolCalls(),stepCount(),maxSteps(),totalTokensAtMost(),noFailedActions(),calledSubagent(),event(),notEvent(),eventOrder(),eventsSatisfy() - accessors:
assertions(),logs() - note:
newSession()shares this context's collectors with the new session --EvalRunner's repeated trials deliberately construct a brand-newEvalContextinstead, so trials never share collectors Evals\AssertionCollector- records and defer-resolves assertion results for one eval run
- key API:
record(),recordLazy(placeholder, Closure(): AssertionResult $resolve),replace(),at(index),results(): AssertionResults - note:
recordLazy()'s resolver runs at most once, at first read viaat()orresults()-- this is the mechanism that makes a judge run at most once Evals\AssertionHandle(readonly)- fluent handle returned by every
EvalContext/ValueExpectationassertion - key API:
gate(),soft(),atLeast(threshold),label(),result(): AssertionResult,replace() Evals\AssertionResult(readonly)- one assertion's outcome
- factories:
pass(),fail() - key API:
withSeverity(),withScore(),withThreshold(),withLabel(),withJudgeScore(),passed(): bool(score >= threshold ?? 1.0) - accessors:
name(),score(),severity(),threshold(),message(),label(),judgeScore(),judgeClass(),toArray() Evals\AssertionResults(readonly,Countable,IteratorAggregate)- immutable collection of
AssertionResult - key API:
with(),hasFailedGate(),hasFailedSoft() - accessors:
all(),count() Evals\AssertionSeverity--Gate,SoftEvals\ValueExpectation- fluent value assertion returned by
EvalContext::expect() - key API:
includes(),equals(),matches(string|EvalMatch),similarity()(Levenshtein-based, alwaysSoft),satisfies(Closure); chain modifiersgate(),soft(),atLeast(),label() - note: the chain modifiers apply only to the LAST assertion this expectation recorded, not to every assertion the expectation has made
Evals\EvalRequirementFailed(extendsRuntimeException) -- thrown byEvalContext::require()on failure; caught internally byEvalRunner, not user-visibleEvals\EvalSkipped(extendsRuntimeException) -- thrown byEvalContext::skip(); caught internally byEvalRunnerand turned intoEvalVerdict::Skipped
Target & sessions:
Evals\CanRunAgentEvalTarget-- contract:open(?EvalSessionRequest): CanUseAgentEvalSessionEvals\LocalAgentTarget(readonly)- runs eval sessions in-process
- factories:
fromFactory(Closure(): CanControlAgentLoop $factory, ?EvalTracePolicy) Evals\HttpAgentTarget(readonly)- runs eval sessions against a remote agent server over HTTP
- key API:
open(),attach(sessionId),sendTurn(),policy() - note: applies its
EvalTracePolicy(defaultsafe()) to whatever the remote server sends, so the HTTP path is safe by default rather than degrading to verbatim serialization Evals\CanUseAgentEvalSession-- contract:send(message): EvalTurn,run(): AgentRunEvals\LocalEvalSession--CanUseAgentEvalSessionover an in-processCanControlAgentLoopEvals\HttpEvalSession--CanUseAgentEvalSessionoverHttpAgentTarget; accessor:sessionId()Evals\HttpTargetException(extendsRuntimeException) -- thrown on a non-2xx response, malformed JSON, or a missingsessionIdEvals\EvalSessionRequest(readonly) -- optionalcaseId/descriptionpassed toCanRunAgentEvalTarget::open()Evals\EvalTurn(readonly)- one turn of an eval session
- accessors:
index(),message(),run(): AgentRun,reply()
Run trace:
Evals\AgentRun(readonly)- immutable accumulated projection of an eval session, across turns
- factories:
fromState(),empty(),fromArray() - accessors:
reply(),status(),succeeded(),tools(),events(),turns(),errors(),steps(),usage(),duration(),stepCount(),stopSignal(),llmProfile() - note:
stopSignal()is the LAST turn's resolved signal and does NOT aggregate across turns -- per-turn signals live onEvalStep::stopSignal() Evals\EvalStep(readonly)- immutable safe projection of one
StepExecution - factories:
fromStepExecution(),fromArray() - accessors:
id(),turn(),index(),type(),outputMessages(),requestedToolCalls(),toolExecutions(),finishReason(),usage(),duration(),stopSignal(),errors(),hasErrors(),toArray() - note: carries no input messages and never serializes the raw
InferenceResponse Evals\EvalSteps(readonly,Countable,IteratorAggregate) -- orderedEvalStepcollection; key API:with(),last(),usage(),duration(),toArray()/fromArray()Evals\EvalToolExecutions(readonly,Countable,IteratorAggregate) -- collection ofData\ToolExecutionEvals\EvalEvents(readonly,Countable,IteratorAggregate) -- collection of arbitrary agent event objects captured during a runEvals\EvalTracePolicy(readonly)- controls how much of a tool payload lands in a serialized trace
- factories:
safe()(default everywhere),full()(explicit opt-in, never a default) - key API:
digest(mixed): array{hash, bytes, preview},isDigest(),withPreviewBytes(),toArray()/fromArray() - accessors:
isFull(),previewBytes()(DEFAULT_PREVIEW_BYTES = 120) - note:
safe()digests tool call arguments, tool results, AND error messages -- there is no size threshold, short values are digested too;previewrenders the value's SHAPE (<string:N>,<int>,<array:N>,<object:N>pastMAX_PREVIEW_DEPTH = 6), never the payload itself
Judging:
Evals\CanJudgeAgentEval-- contract:judge(JudgeRequest): JudgeScoreEvals\AgentLoopJudge- agentic judge: runs a bounded
AgentLoopthat inspects the target'sAgentRunand submits a verdict via thesubmit_judgmentterminal tool - factories:
fromBuilder(callable(): CanComposeAgentLoop $builderFactory)-- the factory must return a FRESH, not-yet-built builder on every call - accessors:
llmProfile(),guardProfile(): array{configured, hooks} - note: every
judge()call gets a fresh builder/loop/state/event-list/JudgeSubmissionInbox-- nothing leaks between calls, even repeated calls on the same instance - note: installs NO guards of its own --
warnIfGuardsMissing()only inspects the built loop's profile forUseGuardsand, if absent, dispatchesEvents\JudgeGuardsNotConfiguredat most once per instance; it never substitutes a limit. InstallCapability\Core\UseGuardsexplicitly Evals\PolyglotAgentJudge(readonly) -- lightweight judge backed by a raw LLM call expected to return{"score":..,"reason":..}JSON; factories:fromInference(Inference),fromInvoker(Closure(string): string)Evals\FakeAgentJudge(readonly) -- deterministic judge double; factories:fromScore(),fromClosure(Closure(JudgeRequest): JudgeScore)Evals\JudgeRequest(readonly) --criterion,output,run: AgentRun(required, not optional),input,referenceEvals\JudgeScore(readonly) --score(validated[0,1]),reason(non-empty),evidence: JudgeEvidence,?run: AgentRunEvals\JudgeEvidence(readonly,Countable,IteratorAggregate) -- ordered evidence strings backing aJudgeScore; factories:none(),of(); note: developer-visible support for the score, never hidden model reasoningEvals\JudgeCriterion--Factuality,Summarizes,ClosedQa,SqlEvals\AgentJudgeAssertions(readonly)- returned by
EvalContext::judge(); built-in criteria - key API:
factuality(reference),summarizes(source),closedQa(question),sql(reference)-- each returnsJudgeExpectation Evals\JudgeExpectation- fluent judge assertion chain
- key API:
on(output)(replaces only the graded output; retains the run),gate(),soft(),atLeast(),label() - note: the chain only accumulates state -- the judge runs AT MOST ONCE, on first read of the recorded result (
AssertionCollector::results()/at());.on()never re-runs or re-judges. Severity defaults toGatewith no judge configured,Softwith one; a judge exception always forcesGateregardless of priorgate()/soft()calls Evals\SubmitJudgmentTool(extendsTool\Tools\SimpleTool)- the judge's terminal tool (
submit_judgment); validatesscore/reason/evidenceand records aJudgeSubmissioninto itsJudgeSubmissionInbox - constant:
TOOL_NAME Evals\JudgeSubmission(readonly) -- one validatedsubmit_judgmentcall:score,reason,evidenceEvals\JudgeSubmissionInbox- mailbox shared between
SubmitJudgmentToolandJudgeProtocolHookfor onejudge()call - key API:
submit(),has(),get(),attempts() - note: holds at most one submission --
submit()never overwrites;attempts()counts only tool-body invocations, so a call blocked byJudgeProtocolHookdoes NOT increment it Evals\JudgeProtocolHook(readonly, implementsHook\Contracts\HookInterface)- enforces the terminal-submission protocol on
BeforeToolUse/AfterStep: blocks a secondsubmit_judgmentcall, skips (does not block) any other tool call once a submission is recorded, and adds aStopReason::Completedstop signal after the submission step Evals\JudgeProtocolException(extendsRuntimeException) -- thrown byAgentLoopJudge::judge()when the protocol was violated (no submission, a blocked second submission, or a failed run); always converted to aGatefailure byJudgeExpectation::resolve()Evals\JudgePromptRenderer(readonly) -- renders the judge's fixed system prompt and per-request user prompt; wraps the target trace in<untrusted-target-trace>markers (a labeling reduction, not a security boundary)Evals\UseJudgeInference(readonly, implementsBuilder\Contracts\CanProvideAgentCapability)- recommended driver capability for judge builders passed to
AgentLoopJudge::fromBuilder(): installsToolCallingDriverwithtemperature: 0.0by default (caller-suppliedoptionswin) - note:
AgentLoopJudgenever installs this on the developer's behalf -- it is documented as the recommended judge driver, not injected
Repetition:
Evals\EvalRepetition(readonly)- the N trials of one repeated case; present only when a case ran more than once
- factories:
fromTrials(list<EvalResult>, passRate) - accessors:
trials(),trialCount(),passCount(),requiredPasses(),satisfied(),allSkipped(),judgeScoreMean()(null when nothing was judged),judgeScoreStdDev()(POPULATION deviation -- divided by N, not N-1; 0.0 for a single score, never a division by zero),representative()(first non-Passedtrial, else the first trial),toArray()
Verdict, running & config:
Evals\EvalVerdict--Passed,Failed,Scored,SkippedEvals\EvalVerdictResolver(readonly)- key API:
resolve(AssertionResults, skipped, ?error): EvalVerdict(error or failed gate ->Failed; skipped ->Skipped; failed soft ->Scored; elsePassed),resolveRepeated(EvalRepetition): EvalVerdict(all-skipped ->Skipped; satisfied k-of-N ->Passed; elseFailed) - static:
requiredPasses(trials, passRate): int--ceil(passRate * trials - 1e-9)clamped to[1, trials], guarding against IEEE-754 near-integer error Evals\EvalExitCode--Success = 0,EvalFailure = 1,ConfigurationError = 2Evals\EvalRunner(readonly)- key API:
run(AgentEvals, ?EvalRunOptions): EvalRunResult - note: each repeated trial opens a FRESH
EvalContext/session (neverEvalContext::newSession(), which shares collectors);repeat=1returns the trial'sEvalResultunchanged, not wrapped; the cooperative timeout is a per-trial budget, not per-case Evals\EvalRunOptions(readonly)- factories:
default() - key API:
withFilter(),withTags(),withExcludedTags(),withStrict(),withSkipReport(),withVerbose(),withTimeout(),withRepeat(),withPassRate() - accessors:
filter(),tags(),excludedTags(),strict(),skipReport(),verbose(),timeout(),repeat(),passRate() - note: constructor validates
repeat >= 1andpassRatein(0, 1]; repetition only measures TARGET variance when the judge is separately pinned to a fixed temperature (e.g. viaUseJudgeInference) --AgentLoopJudgenever installs that for you Evals\EvalConfig(readonly)- factories:
default() - key API:
withTarget(),withJudge(),withReporters(),withReporter() - accessors:
target(),judge(),reporters() Evals\EvalApplication(readonly)- CLI entry point
- key API:
run(argv, ?callable $stdout, ?callable $stderr): int - flags:
--filter=<glob>,--tag=<tag>(repeatable),--exclude-tag=<tag>(repeatable),--strict,--timeout=<seconds>,--repeat=<n>,--pass-rate=<r>,--junit=<path>,--list,--verbose,--json,--skip-report,-h/--help - note: loads
<root>/evals.config.phpwhen present (mustreturn EvalConfig);--repeatrejects a non-whole-number or fractional value outright rather than silently truncating or casting it
Logging:
Evals\EvalLog(readonly) -- one log entry:message(),context(),toArray()Evals\EvalLogs(readonly,Countable,IteratorAggregate) -- immutableEvalLogcollection; factories:none(); key API:with()Evals\EvalLogCollector-- mutable collector behindEvalContext::log(); key API:record(),logs(): EvalLogs
Reporting:
Evals\CanReportAgentEvals-- contract:id(),onRunStarted(caseCount),onEvalCompleted(EvalResult),onRunCompleted(EvalRunResult)Evals\CanFailAgentEvalTestSuite(extendsCanReportAgentEvals) -- marker for reporters that propagate the final assertion into the host test runnerEvals\ConsoleEvalReporter(readonly)- factories:
fromWriter(Closure(string): void, verbose = false) - key API:
withVerbose() - note: a repeated case prints a rate line (
PASS 4/5 ... judge=0.88+/-0.06) instead of a single verdict; thejudge=field is omitted -- not printed as a fabricated0.00-- when nothing in the case was judged Evals\ArtifactEvalReporter- writes a full run's artifacts to disk under
.instructor/evals/<run>/: per-evaldetails.json,events.ndjson,target-trace.json,target-steps.jsonl, per-judged-assertionjudges/NNN.json(+-steps.jsonl), per-trialtrials/NNN/for repeated cases, and run-levelsummary.json/results.jsonl - constructor:
root,?ClockInterface $clock,?Closure(): ?string $gitShaResolver,?Closure(): ?string $packageVersionResolver - accessors:
runDirectory() - note: never writes a raw
target-messages.jsonconversation snapshot -- that would bypassEvalTracePolicy::safe()'s digesting and reintroduce the exact leak class the trace hardening closed Evals\JUnitEvalReporter-- writes JUnit XML to thepathgiven at constructionEvals\PHPUnitEvalReporter(implementsCanFailAgentEvalTestSuite) -- factories:default(); assertsEvalExitCode::SuccessviaPHPUnit\Framework\AssertEvals\PestEvalReporter(implementsCanFailAgentEvalTestSuite) -- factories:default(); assertsEvalExitCode::Successvia a PestExpectationEvals\EvalReporters(readonly,IteratorAggregate)- immutable, id-deduplicated reporter collection
- factories:
none() - key API:
with(),withVerboseConsole()(upgrades anyConsoleEvalReporterin the collection in place) Evals\EvalTestFailureMessage-- staticfromResult(EvalRunResult): string; renders a CI-friendly multi-line failure summary (counts, per-eval failures, repetition rate, judge evidence)
Result:
Evals\EvalResult(readonly)- outcome of one eval case, possibly a repeated case's aggregate
- accessors:
id(),description(),verdict(),assertions(),run(),duration(),error(),skipReason(),logs(),repetition(): ?EvalRepetition,trials(),trialCount(),passCount(),judgeScoreMean(),judgeScoreStdDev(),provenance(),tokens(): array{target, judge, total},toArray(?envelope) - note:
provenance()['judge']['temperature']is always null --AgentLoopJudge's built loop exposes no temperature accessor, and reporting an assumed default would fabricate a value the judge may not have used;guardsWarningObservedis derived only from the presence of aJudgeGuardsNotConfiguredevent on the judge's own run, never from its absence Evals\EvalRunResult(readonly,Countable,IteratorAggregate)- full result of one
EvalRunner::run()call - key API:
exitCode(?bool $strict = null): EvalExitCode(EvalFailureif any resultFailed, or effective-strict with any resultScored; elseEvalFailureifreporterErrors() !== []; elseSuccess),provenance(),tokens(),toArray(?envelope) - accessors:
all(),reporterErrors(),strict()
Events:
Evals\Events\JudgeGuardsNotConfigured(extendsEvents\AgentEvent) -- dispatched at most once perAgentLoopJudgeinstance when its built judge loop has noUseGuardscapability;capability,suggestedFix