|
|
7 months ago | |
|---|---|---|
| .. | ||
| scripts | 7 months ago | |
| src | 7 months ago | |
| .eval-config.example.json | 8 months ago | |
| .gitignore | 8 months ago | |
| README.md | 7 months ago | |
| demo-enhanced-features.sh | 8 months ago | |
| package.json | 8 months ago | |
| test-path-resolution.mjs | 7 months ago | |
| tsconfig.json | 8 months ago | |
Core framework for evaluating agent behavior. For user documentation, see ../README.md.
framework/
├── src/
│ ├── sdk/ # Test execution
│ │ ├── test-runner.ts # Main orchestrator
│ │ ├── test-executor.ts # Executes individual tests
│ │ ├── client-manager.ts
│ │ └── event-stream-handler.ts
│ ├── evaluators/ # Rule validators
│ │ ├── base-evaluator.ts
│ │ ├── approval-gate-evaluator.ts
│ │ ├── context-loading-evaluator.ts
│ │ ├── execution-balance-evaluator.ts
│ │ ├── tool-usage-evaluator.ts
│ │ ├── behavior-evaluator.ts
│ │ ├── delegation-evaluator.ts
│ │ └── stop-on-failure-evaluator.ts
│ ├── collector/ # Session data
│ │ ├── session-reader.ts
│ │ └── timeline-builder.ts
│ └── types/
│ └── index.ts
└── package.json
Checks that approval is requested before risky operations (bash, write, edit, task).
Verifies context files are loaded before acting on tasks.
NEW: Supports explicit context file specification via expectedContextFiles in test YAML.
behavior.expectedContextFilesEnsures read operations happen before write operations.
Validates dedicated tools are used instead of bash antipatterns.
Checks expected tools are used and forbidden tools are avoided.
Validates complex tasks are delegated to subagents.
Ensures agent stops on errors instead of auto-fixing.
Create src/evaluators/my-evaluator.ts:
import { BaseEvaluator } from './base-evaluator.js';
import { TimelineEvent, SessionInfo, EvaluationResult } from '../types/index.js';
export class MyEvaluator extends BaseEvaluator {
name = 'my-evaluator';
description = 'What this evaluator checks';
async evaluate(timeline: TimelineEvent[], sessionInfo: SessionInfo): Promise<EvaluationResult> {
const checks = [];
const violations = [];
const evidence = [];
// Your evaluation logic here
const toolCalls = this.getToolCalls(timeline);
// Example check
const passed = toolCalls.length > 0;
checks.push({
name: 'has-tool-calls',
passed,
weight: 100,
evidence: [this.createEvidence('tool-count', `Found ${toolCalls.length} tool calls`, {})]
});
if (!passed) {
violations.push(this.createViolation(
'no-tool-calls',
'error',
'No tool calls found',
Date.now(),
{}
));
}
return this.buildResult(this.name, checks, violations, evidence, {});
}
}
Register in test-runner.ts:
import { MyEvaluator } from '../evaluators/my-evaluator.js';
// In setupEvaluators():
this.evaluatorRunner = new EvaluatorRunner({
evaluators: [
// ... existing evaluators
new MyEvaluator(),
],
});
Add to test schema in test-case-schema.ts:
export const ExpectedViolationSchema = z.object({
rule: z.enum([
// ... existing rules
'my-evaluator',
]),
// ...
});
# Install
npm install
# Build
npm run build
# Run tests
npm test
# Run SDK tests
npm run eval:sdk -- --agent=openagent --pattern="**/golden/*.yaml"
interface TimelineEvent {
timestamp: number;
type: 'user_message' | 'assistant_message' | 'tool_call' | 'text';
data: any;
}
interface EvaluationResult {
evaluator: string;
passed: boolean;
score: number;
violations: Violation[];
evidence: Evidence[];
checks: Check[];
}
interface Violation {
type: string;
severity: 'error' | 'warning' | 'info';
message: string;
timestamp: number;
evidence?: any;
}
// Get all tool calls
const toolCalls = this.getToolCalls(timeline);
// Get specific tool calls
const bashCalls = this.getToolCallsByName(timeline, 'bash');
// Get assistant messages
const messages = this.getAssistantMessages(timeline);
// Get read tools (read, glob, grep, list)
const reads = this.getReadTools(timeline);
// Get execution tools (bash, write, edit, task)
const executions = this.getExecutionTools(timeline);
// Create violation
this.createViolation(type, severity, message, timestamp, evidence);
// Create evidence
this.createEvidence(type, description, data, timestamp?);
// Build result
this.buildResult(name, checks, violations, evidence, metadata);