* chore: update package-lock.json after npm install * chore: remove unused ajv-cli, keep vitest at stable 1.6.1 - Removed ajv-cli (unused dev dependency, had high severity vulnerability) - Kept vitest at 1.6.1 (stable, upgrading to v4 requires extensive refactoring) - Reduced vulnerabilities from 6 to 4 (all moderate, dev-only) - All remaining vulnerabilities are in esbuild/vite (dev server only, no production impact) - Build and tests verified working * feat(evals): add execution-balance validation to 21 OpenAgent tests and enhance agent system Major improvements to evaluation framework and agent capabilities: ## Execution Balance Evaluator Integration - Added execution-balance rule to 21 OpenAgent tests (2.7% → 31.5% coverage) - Validates "read before execute" pattern across critical rules, workflows, and edge cases - Tests now check: read operations before execution tools, healthy read/exec ratio (≥1.0) - Coverage includes: approval-gate, context-loading, stop-on-failure, report-first tests ## Agent System Enhancements - Enhanced OpenCoder agent with critical rules enforcement (approval gates, context loading) - Added structured delegation rules and workflow phases - Improved error handling with REPORT→PROPOSE→REQUEST→FIX pattern ## New Agent Creation System - Added research-backed agent creation templates and guides - Includes 8 test templates covering planning, context, incremental execution, tools - Automated agent scaffolding with /create-agent command - Complete documentation in .opencode/command/openagents/new-agents/ ## OpenCoder Test Suite - Added 8 comprehensive test cases for OpenCoder agent - Tests cover: planning, context-loading, delegation, error-handling, implementation - Includes DEBUG_GUIDE.md and QUICK_TEST_GUIDE.md for developers ## Documentation & Tooling - Added DEVELOPMENT.md guide for contributors - Enhanced CONTRIBUTING.md with quick reference and common commands - Improved event-logger with DEBUG_VERBOSE mode for detailed output - Added debug scripts: show-test-conversation.sh, run-test-verbose.sh - Removed deprecated EXTERNAL_PR_GUIDE.md ## Version Bump - Bumped version to 0.0.3 (patch) Files changed: 60+ files (21 test updates, 16 new agent templates, 8 new tests, docs, tooling) * feat(ci): add PR title validation for semantic versioning Add automated PR title validation to ensure conventional commit format. This enables proper automatic version bumping when PRs are merged. Features: - Validates PR titles against conventional commit patterns - Shows expected version bump (major/minor/patch) - Posts helpful comment with examples if validation fails - Supports all conventional commit types (feat, fix, docs, etc.) - Supports breaking changes (feat!, fix!) - Supports pre-release tags ([alpha], [beta], [rc]) When PR titles follow the format, version bumping works correctly: - feat: → minor bump (0.3.0 → 0.4.0) - fix: → patch bump (0.3.0 → 0.3.1) - feat!: → major bump (0.3.0 → 1.0.0) * fix(ci): improve PR checks workflow with sequential execution Reorganize PR checks to run in logical sequence and skip unnecessary checks: Changes: - Run PR title validation first (fast, always required) - Detect changed files to determine which checks to run - Only run build checks if evals/ files changed - Add comprehensive summary job showing all check results - Prevent cache errors when evals files not changed Benefits: - Faster PR checks (skip unnecessary builds) - Clear sequential execution (title → changes → build) - Better error messages and summaries - Reduced CI/CD costs * fix(ci): resolve PR #42 issues and refactor prompt architecture ## Fixed PR #42 Issues 1. **Prompt Validation** - Refactored to new architecture where agent files are canonical defaults 2. **Package-lock.json** - Fixed workflow to use root package-lock (npm workspaces) 3. **Git Merge Base** - Added fetch-depth: 0 to PR checks workflow ## New Prompt Architecture **Before:** - Agent files had to match .opencode/prompts/<agent>/default.md - Caused validation failures when updating prompts - Redundant duplication **After:** - Agent files (.opencode/agent/*.md) = Canonical defaults (source of truth) - Prompt variants (.opencode/prompts/<agent>/<model>.md) = Model-specific optimizations - No more default.md files needed ## Changes ### Workflows - pr-checks.yml: Added fetch-depth: 0 for full git history - validate-test-suites.yml: Fixed package-lock path for npm workspaces - validate-registry.yml: Updated validation messaging ### Scripts - validate-pr.sh: Validates prompt library structure (rejects default.md files) - use-prompt.sh: Handles 'default' as agent file, variants as model-specific - test-prompt.sh: Tests default variant correctly, saves results to prompts/results/ ### Documentation - .opencode/prompts/README.md: Updated architecture explanation - docs/contributing/CONTRIBUTING.md: Updated prompt workflow - scripts/development/demo.sh: Updated structure display ## Results - 12 files changed, 231 insertions(+), 811 deletions(-) - Net reduction: 580 lines (cleaner codebase) - All validations passing - Results directory structure preserved - Backwards compatible with existing test results |
||
|---|---|---|
| .. | ||
| docs | ||
| scripts | ||
| src | ||
| .eval-config.example.json | ||
| .gitignore | ||
| demo-enhanced-features.sh | ||
| package.json | ||
| README.md | ||
| SDK_EVAL_README.md | ||
| tsconfig.json | ||
Evaluation Framework
Overview
Reusable framework for evaluating OpenCode agent behavior. Can be used to test any agent against defined standards.
Architecture
framework/
├── src/
│ ├── collector/ # Session data collection
│ │ ├── session-reader.ts
│ │ ├── message-parser.ts
│ │ └── timeline-builder.ts
│ ├── evaluators/ # Evaluation logic
│ │ ├── base-evaluator.ts
│ │ ├── approval-gate.ts
│ │ ├── context-loading.ts
│ │ ├── delegation.ts
│ │ ├── tool-usage.ts
│ │ └── model-selection.ts
│ ├── runner/ # Test execution
│ │ ├── test-runner.ts
│ │ └── session-analyzer.ts
│ ├── reporters/ # Result reporting
│ │ ├── console-reporter.ts
│ │ ├── json-reporter.ts
│ │ └── markdown-reporter.ts
│ ├── types/ # TypeScript types
│ │ └── index.ts
│ ├── config.ts # Configuration
│ └── index.ts # Main exports
├── tests/ # Framework tests
├── package.json
├── tsconfig.json
└── README.md
Installation
npm install
Usage
Basic Example
import { SessionReader, ApprovalGateEvaluator, TimelineBuilder } from '@evals/framework';
// Read session
const reader = new SessionReader('/path/to/project');
const sessionInfo = reader.getSessionInfo('ses_xxxxx');
const messages = reader.getMessages('ses_xxxxx');
// Build timeline
const builder = new TimelineBuilder(reader);
const timeline = builder.buildTimeline('ses_xxxxx');
// Evaluate
const evaluator = new ApprovalGateEvaluator();
const result = evaluator.evaluate(timeline);
console.log(`Passed: ${result.passed}`);
console.log(`Score: ${result.score}/100`);
console.log(`Violations: ${result.violations.length}`);
Running Test Suite
import { TestRunner } from '@evals/framework';
const runner = new TestRunner({
projectPath: process.cwd(),
evaluatorsPath: './src/evaluators',
resultsPath: '../results'
});
// Load test cases
const testCases = runner.loadTestCases('../opencode/openagent/test-cases/approval-gates.yaml');
// Run tests
const suite = runner.runAll(testCases);
console.log(`Pass Rate: ${suite.summary.passRate}%`);
Components
Collector
SessionReader - Read OpenCode session files
const reader = new SessionReader(projectPath);
const info = reader.getSessionInfo(sessionId);
const messages = reader.getMessages(sessionId);
const parts = reader.getParts(sessionId, messageId);
MessageParser - Parse message structure
const parser = new MessageParser();
const agent = parser.getAgent(message);
const model = parser.getModel(message);
const metrics = parser.getMetrics(message);
TimelineBuilder - Build event timeline
const builder = new TimelineBuilder(reader);
const timeline = builder.buildTimeline(sessionId);
const toolCalls = builder.filterByType(timeline, 'tool_call');
Evaluators
All evaluators extend BaseEvaluator and implement:
evaluate(timeline: TimelineEvent[]): EvaluationResult
ApprovalGateEvaluator - Check approval before execution
const evaluator = new ApprovalGateEvaluator();
const result = evaluator.evaluate(timeline);
ContextLoadingEvaluator - Verify context loading
const evaluator = new ContextLoadingEvaluator();
const result = evaluator.evaluate(timeline);
DelegationEvaluator - Validate delegation decisions
const evaluator = new DelegationEvaluator();
const result = evaluator.evaluate(timeline);
ToolUsageEvaluator - Check tool selection
const evaluator = new ToolUsageEvaluator();
const result = evaluator.evaluate(timeline);
ExecutionBalanceEvaluator - Assess balance and ordering of read vs execution actions
import { ExecutionBalanceEvaluator } from '@evals/framework';
const evaluator = new ExecutionBalanceEvaluator();
const result = await evaluator.evaluate(timeline);
console.log(result.meta?.ratio); // read/exec ratio
Violations it may produce:
execution-before-read(error): first execution tool used before any read tools.insufficient-read(warning): fewer reads than executions overall.
Runner
TestRunner - Execute test suites
const runner = new TestRunner(config);
const testCases = runner.loadTestCases(path);
const suite = runner.runAll(testCases);
SessionAnalyzer - Analyze historical sessions
const analyzer = new SessionAnalyzer(reader);
const result = analyzer.analyze(sessionId, testCase);
Reporters
ConsoleReporter - Pretty console output
const reporter = new ConsoleReporter();
reporter.report(testSuite);
JSONReporter - Machine-readable JSON
const reporter = new JSONReporter();
reporter.export(testSuite, 'results.json');
MarkdownReporter - Documentation format
const reporter = new MarkdownReporter();
reporter.generate(testSuite, 'report.md');
Types
Core Types
interface SessionInfo {
id: string;
version: string;
title: string;
time: { created: number; updated: number };
}
interface Message {
id: string;
role: 'user' | 'assistant';
sessionID: string;
mode?: string;
modelID?: string;
providerID?: string;
tokens?: TokenUsage;
cost?: number;
time: { created: number; completed?: number };
}
interface TimelineEvent {
timestamp: number;
type: 'user_message' | 'assistant_message' | 'tool_call' | 'patch';
agent?: string;
model?: string;
data: any;
}
interface EvaluationResult {
evaluator: string;
passed: boolean;
score: number;
violations: Violation[];
evidence: Evidence[];
}
interface TestResult {
testCaseId: string;
sessionId: string;
passed: boolean;
score: number;
evaluationResults: EvaluationResult[];
metadata: any;
}
Configuration
// config.ts
export const config = {
projectPath: process.cwd(),
sessionStoragePath: '~/.local/share/opencode/',
resultsPath: '../results/',
passThreshold: 75,
evaluators: {
'approval-gate': ApprovalGateEvaluator,
'context-loading': ContextLoadingEvaluator,
'delegation': DelegationEvaluator,
'tool-usage': ToolUsageEvaluator,
}
};
Development
Setup
npm install
npm run build
Testing
# Run all tests
npm test
# Run specific test
npm test -- session-reader
# Watch mode
npm run test:watch
Building
# Build TypeScript
npm run build
# Watch mode
npm run build:watch
Linting
npm run lint
npm run lint:fix
Adding New Evaluators
- Create file in
src/evaluators/ - Extend
BaseEvaluator - Implement
evaluate()method - Add tests
- Register in config
- Export from
index.ts
For a detailed step-by-step contributor guide see: docs/contributing/ADDING_EVALUATOR.md
Example:
// src/evaluators/my-evaluator.ts
import { BaseEvaluator } from './base-evaluator';
import { EvaluationResult, TimelineEvent } from '../types';
export class MyEvaluator extends BaseEvaluator {
evaluate(timeline: TimelineEvent[]): EvaluationResult {
// Your evaluation logic
const checks = [
{ name: 'check1', passed: true, weight: 50 },
{ name: 'check2', passed: false, weight: 50 }
];
const score = this.calculateScore(checks);
const violations = this.findViolations(timeline);
return {
evaluator: 'my-evaluator',
passed: score >= 75,
score,
violations,
evidence: []
};
}
}
API Reference
See API.md for complete API documentation.
Contributing
- Fork the repository
- Create feature branch
- Add tests
- Submit pull request
License
MIT
Scripts
Development and debugging scripts are organized in the scripts/ directory:
scripts/
├── debug/ # Session and event debugging
├── test/ # Framework component tests
├── utils/ # Utility scripts (batch runner, etc.)
└── README.md # Script documentation
See scripts/README.md for detailed usage.
Quick Examples
# Run tests in batches
./scripts/utils/run-tests-batch.sh openagent 3 10
# Debug a session
node scripts/debug/inspect-session.mjs
# Test framework component
npx tsx scripts/test/test-timeline.ts