@ozperium/agentspec 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/runner.js ADDED
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MockAgent = void 0;
4
+ exports.runSuite = runSuite;
5
+ exports.runAll = runAll;
6
+ const assertions_1 = require("./assertions");
7
+ const loader_1 = require("./loader");
8
+ async function runSuite(suitePath, agent) {
9
+ const suite = (0, loader_1.loadTestSuite)(suitePath);
10
+ const results = [];
11
+ for (const test of suite.tests) {
12
+ const startTime = Date.now();
13
+ try {
14
+ const output = await agent.run(test.input, suite);
15
+ const durationMs = Date.now() - startTime;
16
+ const hasLLMJudge = test.expect.llm_judge !== undefined;
17
+ const assertions = hasLLMJudge
18
+ ? await (0, assertions_1.evaluateAssertionsAsync)(output.text, test.expect, test.input, {
19
+ tokens: output.tokens,
20
+ latencyMs: durationMs,
21
+ toolsCalled: output.toolsCalled,
22
+ })
23
+ : (0, assertions_1.evaluateAssertions)(output.text, test.expect, {
24
+ tokens: output.tokens,
25
+ latencyMs: durationMs,
26
+ toolsCalled: output.toolsCalled,
27
+ });
28
+ const passed = assertions.every(a => a.passed);
29
+ results.push({
30
+ test: test.name,
31
+ suite: suite.name,
32
+ passed,
33
+ duration_ms: durationMs,
34
+ assertions,
35
+ output: output.text,
36
+ });
37
+ }
38
+ catch (e) {
39
+ const durationMs = Date.now() - startTime;
40
+ results.push({
41
+ test: test.name,
42
+ suite: suite.name,
43
+ passed: false,
44
+ duration_ms: durationMs,
45
+ assertions: [],
46
+ error: e instanceof Error ? e.message : String(e),
47
+ });
48
+ }
49
+ }
50
+ return results;
51
+ }
52
+ async function runAll(dir, agent, filter) {
53
+ const suites = (0, loader_1.findTestSuites)(dir);
54
+ const allResults = [];
55
+ const startTime = Date.now();
56
+ for (const suitePath of suites) {
57
+ let suiteResults = await runSuite(suitePath, agent);
58
+ if (filter) {
59
+ const re = new RegExp(filter);
60
+ suiteResults = suiteResults.filter(r => re.test(r.test) || re.test(r.suite));
61
+ }
62
+ allResults.push(...suiteResults);
63
+ }
64
+ const passed = allResults.filter(r => r.passed).length;
65
+ const failed = allResults.length - passed;
66
+ return {
67
+ total: allResults.length,
68
+ passed,
69
+ failed,
70
+ results: allResults,
71
+ duration_ms: Date.now() - startTime,
72
+ };
73
+ }
74
+ // Built-in mock agent for testing AgentSpec itself
75
+ class MockAgent {
76
+ responses = {};
77
+ echo = false;
78
+ constructor(responses, echo) {
79
+ this.responses = responses || {
80
+ default: "Hello! I'm a mock agent. I can help with that.",
81
+ };
82
+ this.echo = echo || false;
83
+ }
84
+ async run(input, suite) {
85
+ await new Promise(resolve => setTimeout(resolve, 10));
86
+ const text = this.echo ? input : (this.responses[input] || this.responses.default);
87
+ return {
88
+ text,
89
+ latencyMs: 10,
90
+ tokens: Math.ceil(text.length / 4),
91
+ toolsCalled: [],
92
+ };
93
+ }
94
+ }
95
+ exports.MockAgent = MockAgent;
@@ -0,0 +1,18 @@
1
+ export interface StoredRun {
2
+ test: string;
3
+ suite: string;
4
+ passed: boolean;
5
+ output: string;
6
+ timestamp: string;
7
+ wake?: string;
8
+ }
9
+ export interface DiffEntry {
10
+ test: string;
11
+ suite: string;
12
+ status: 'regression' | 'improvement' | 'changed' | 'new' | 'removed';
13
+ old_output: string;
14
+ new_output: string;
15
+ old_passed: boolean;
16
+ new_passed: boolean;
17
+ summary: string;
18
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,58 @@
1
+ export interface TestExpect {
2
+ contains?: string;
3
+ not_contains?: string;
4
+ contains_any?: string[];
5
+ contains_all?: string[];
6
+ regex?: string;
7
+ tool_called?: string;
8
+ max_latency_ms?: number;
9
+ max_tokens?: number;
10
+ json_path?: string;
11
+ json_value?: unknown;
12
+ llm_judge?: string;
13
+ semantically_similar?: string;
14
+ min_confidence?: number;
15
+ custom?: string;
16
+ }
17
+ export interface TestCase {
18
+ name: string;
19
+ input: string;
20
+ expect: TestExpect;
21
+ setup?: Record<string, unknown>;
22
+ }
23
+ export interface TestSuite {
24
+ name: string;
25
+ description?: string;
26
+ agent?: AgentConfig;
27
+ tests: TestCase[];
28
+ }
29
+ export interface AgentConfig {
30
+ type: string;
31
+ endpoint?: string;
32
+ model?: string;
33
+ system_prompt?: string;
34
+ tools?: string[];
35
+ }
36
+ export interface AssertionResult {
37
+ assertion: string;
38
+ passed: boolean;
39
+ message: string;
40
+ expected?: string;
41
+ actual?: string;
42
+ }
43
+ export interface TestResult {
44
+ test: string;
45
+ suite: string;
46
+ passed: boolean;
47
+ duration_ms: number;
48
+ assertions: AssertionResult[];
49
+ output?: string;
50
+ error?: string;
51
+ }
52
+ export interface RunResult {
53
+ total: number;
54
+ passed: number;
55
+ failed: number;
56
+ results: TestResult[];
57
+ duration_ms: number;
58
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@ozperium/agentspec",
3
+ "version": "0.1.0",
4
+ "description": "Testing framework for AI agents — Jest for non-deterministic AI behavior",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "agentspec": "dist/cli.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "test": "node dist/cli.js run --dir tests --ci && node dist/cli.js run --dir examples --ci",
14
+ "prepublishOnly": "tsc"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "keywords": [
20
+ "ai",
21
+ "agent",
22
+ "testing",
23
+ "regression",
24
+ "llm",
25
+ "jest",
26
+ "framework",
27
+ "automation",
28
+ "ci",
29
+ "non-deterministic"
30
+ ],
31
+ "author": "Ozperium",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/Ozperium/agentspec.git"
36
+ },
37
+ "homepage": "https://agentspec.dev",
38
+ "bugs": {
39
+ "url": "https://github.com/Ozperium/agentspec/issues"
40
+ },
41
+ "files": [
42
+ "dist/",
43
+ "action.yml",
44
+ "README.md",
45
+ "LICENSE"
46
+ ],
47
+ "dependencies": {
48
+ "yaml": "^2.4.0"
49
+ },
50
+ "devDependencies": {
51
+ "typescript": "^5.4.0",
52
+ "@types/node": "^20.0.0"
53
+ },
54
+ "engines": {
55
+ "node": ">=18"
56
+ }
57
+ }