@mce-bt/microagents-testing 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.
Files changed (57) hide show
  1. package/dist/evaluators/content.d.ts +6 -0
  2. package/dist/evaluators/content.d.ts.map +1 -0
  3. package/dist/evaluators/content.js +31 -0
  4. package/dist/evaluators/content.js.map +1 -0
  5. package/dist/evaluators/index.d.ts +6 -0
  6. package/dist/evaluators/index.d.ts.map +1 -0
  7. package/dist/evaluators/index.js +6 -0
  8. package/dist/evaluators/index.js.map +1 -0
  9. package/dist/evaluators/llm-judge.d.ts +6 -0
  10. package/dist/evaluators/llm-judge.d.ts.map +1 -0
  11. package/dist/evaluators/llm-judge.js +82 -0
  12. package/dist/evaluators/llm-judge.js.map +1 -0
  13. package/dist/evaluators/performance.d.ts +6 -0
  14. package/dist/evaluators/performance.d.ts.map +1 -0
  15. package/dist/evaluators/performance.js +17 -0
  16. package/dist/evaluators/performance.js.map +1 -0
  17. package/dist/evaluators/structural.d.ts +6 -0
  18. package/dist/evaluators/structural.d.ts.map +1 -0
  19. package/dist/evaluators/structural.js +11 -0
  20. package/dist/evaluators/structural.js.map +1 -0
  21. package/dist/evaluators/tool-usage.d.ts +6 -0
  22. package/dist/evaluators/tool-usage.d.ts.map +1 -0
  23. package/dist/evaluators/tool-usage.js +26 -0
  24. package/dist/evaluators/tool-usage.js.map +1 -0
  25. package/dist/helpers/service-check.d.ts +23 -0
  26. package/dist/helpers/service-check.d.ts.map +1 -0
  27. package/dist/helpers/service-check.js +27 -0
  28. package/dist/helpers/service-check.js.map +1 -0
  29. package/dist/index.d.ts +13 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +17 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/reporters/console.d.ts +11 -0
  34. package/dist/reporters/console.d.ts.map +1 -0
  35. package/dist/reporters/console.js +65 -0
  36. package/dist/reporters/console.js.map +1 -0
  37. package/dist/reporters/index.d.ts +7 -0
  38. package/dist/reporters/index.d.ts.map +1 -0
  39. package/dist/reporters/index.js +3 -0
  40. package/dist/reporters/index.js.map +1 -0
  41. package/dist/reporters/json.d.ts +15 -0
  42. package/dist/reporters/json.d.ts.map +1 -0
  43. package/dist/reporters/json.js +18 -0
  44. package/dist/reporters/json.js.map +1 -0
  45. package/dist/runner.d.ts +33 -0
  46. package/dist/runner.d.ts.map +1 -0
  47. package/dist/runner.js +86 -0
  48. package/dist/runner.js.map +1 -0
  49. package/dist/suite.d.ts +53 -0
  50. package/dist/suite.d.ts.map +1 -0
  51. package/dist/suite.js +199 -0
  52. package/dist/suite.js.map +1 -0
  53. package/dist/types.d.ts +207 -0
  54. package/dist/types.d.ts.map +1 -0
  55. package/dist/types.js +3 -0
  56. package/dist/types.js.map +1 -0
  57. package/package.json +42 -0
@@ -0,0 +1,6 @@
1
+ import type { Trace } from '../types.js';
2
+ /**
3
+ * Content evaluator — checks response content for expected strings/patterns.
4
+ */
5
+ export declare function evaluateContent(trace: Trace, contains?: string[], notContains?: string[], matches?: string[]): string[];
6
+ //# sourceMappingURL=content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/evaluators/content.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC;;GAEG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,KAAK,EACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,EACnB,WAAW,CAAC,EAAE,MAAM,EAAE,EACtB,OAAO,CAAC,EAAE,MAAM,EAAE,GACjB,MAAM,EAAE,CA8BV"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Content evaluator — checks response content for expected strings/patterns.
3
+ */
4
+ export function evaluateContent(trace, contains, notContains, matches) {
5
+ const failures = [];
6
+ const lower = trace.content.toLowerCase();
7
+ if (contains) {
8
+ for (const keyword of contains) {
9
+ if (!lower.includes(keyword.toLowerCase())) {
10
+ failures.push(`Expected content to contain '${keyword}'`);
11
+ }
12
+ }
13
+ }
14
+ if (notContains) {
15
+ for (const keyword of notContains) {
16
+ if (lower.includes(keyword.toLowerCase())) {
17
+ failures.push(`Expected content NOT to contain '${keyword}'`);
18
+ }
19
+ }
20
+ }
21
+ if (matches) {
22
+ for (const pattern of matches) {
23
+ const regex = new RegExp(pattern, 'i');
24
+ if (!regex.test(trace.content)) {
25
+ failures.push(`Expected content to match pattern /${pattern}/i`);
26
+ }
27
+ }
28
+ }
29
+ return failures;
30
+ }
31
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/evaluators/content.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,KAAY,EACZ,QAAmB,EACnB,WAAsB,EACtB,OAAkB;IAElB,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IAE1C,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;gBAC3C,QAAQ,CAAC,IAAI,CAAC,gCAAgC,OAAO,GAAG,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,WAAW,EAAE,CAAC;QAChB,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE,CAAC;YAClC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;gBAC1C,QAAQ,CAAC,IAAI,CAAC,oCAAoC,OAAO,GAAG,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACvC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC/B,QAAQ,CAAC,IAAI,CAAC,sCAAsC,OAAO,IAAI,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { evaluateStructural } from './structural.js';
2
+ export { evaluateToolUsage } from './tool-usage.js';
3
+ export { evaluateContent } from './content.js';
4
+ export { evaluatePerformance } from './performance.js';
5
+ export { evaluateLlmJudge } from './llm-judge.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/evaluators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { evaluateStructural } from './structural.js';
2
+ export { evaluateToolUsage } from './tool-usage.js';
3
+ export { evaluateContent } from './content.js';
4
+ export { evaluatePerformance } from './performance.js';
5
+ export { evaluateLlmJudge } from './llm-judge.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/evaluators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Trace, LlmJudgeConfig, LlmJudgeResult } from '../types.js';
2
+ /**
3
+ * LLM-as-judge evaluator — uses an LLM to score response quality.
4
+ */
5
+ export declare function evaluateLlmJudge(trace: Trace, message: string, config: LlmJudgeConfig, apiKey: string): Promise<LlmJudgeResult>;
6
+ //# sourceMappingURL=llm-judge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-judge.d.ts","sourceRoot":"","sources":["../../src/evaluators/llm-judge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAgBzE;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,CAAC,CA0EzB"}
@@ -0,0 +1,82 @@
1
+ const DEFAULT_MODEL = 'openai/gpt-4.1-nano';
2
+ const DEFAULT_THRESHOLD = 7;
3
+ const JUDGE_SYSTEM_PROMPT = `You are an evaluation judge for AI agent responses. You will be given:
4
+ 1. The original user message sent to an agent
5
+ 2. The agent's response
6
+ 3. The tools the agent called (with arguments and results)
7
+ 4. Evaluation criteria to judge against
8
+
9
+ Score the response from 1-10 based on the criteria. Be strict but fair.
10
+
11
+ Respond in exactly this JSON format:
12
+ {"score": <number 1-10>, "reasoning": "<one paragraph explaining your score>"}`;
13
+ /**
14
+ * LLM-as-judge evaluator — uses an LLM to score response quality.
15
+ */
16
+ export async function evaluateLlmJudge(trace, message, config, apiKey) {
17
+ const model = config.model ?? DEFAULT_MODEL;
18
+ const threshold = config.threshold ?? DEFAULT_THRESHOLD;
19
+ const toolCallSummary = trace.toolCalls
20
+ .map((tc) => `- ${tc.name}(${JSON.stringify(tc.arguments).slice(0, 200)}) → ${JSON.stringify(tc.result).slice(0, 300)}`)
21
+ .join('\n');
22
+ const userPrompt = `## User Message
23
+ ${message}
24
+
25
+ ## Agent Response
26
+ ${trace.content}
27
+
28
+ ## Tools Called
29
+ ${toolCallSummary || '(none)'}
30
+
31
+ ## Evaluation Criteria
32
+ ${config.criteria}
33
+
34
+ Score this response 1-10 based on the criteria above.`;
35
+ const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
36
+ method: 'POST',
37
+ headers: {
38
+ 'Content-Type': 'application/json',
39
+ Authorization: `Bearer ${apiKey}`,
40
+ },
41
+ body: JSON.stringify({
42
+ model,
43
+ messages: [
44
+ { role: 'system', content: JUDGE_SYSTEM_PROMPT },
45
+ { role: 'user', content: userPrompt },
46
+ ],
47
+ max_tokens: 512,
48
+ temperature: 0,
49
+ }),
50
+ signal: AbortSignal.timeout(30_000),
51
+ });
52
+ if (!response.ok) {
53
+ const text = await response.text().catch(() => '');
54
+ return {
55
+ score: 0,
56
+ reasoning: `LLM judge request failed: HTTP ${response.status} — ${text}`,
57
+ passed: false,
58
+ };
59
+ }
60
+ const data = (await response.json());
61
+ const raw = data.choices?.[0]?.message?.content ?? '';
62
+ try {
63
+ // Extract JSON from response (handles markdown code blocks)
64
+ const jsonMatch = raw.match(/\{[\s\S]*"score"[\s\S]*"reasoning"[\s\S]*\}/);
65
+ if (!jsonMatch)
66
+ throw new Error('No JSON found');
67
+ const parsed = JSON.parse(jsonMatch[0]);
68
+ return {
69
+ score: parsed.score,
70
+ reasoning: parsed.reasoning,
71
+ passed: parsed.score >= threshold,
72
+ };
73
+ }
74
+ catch {
75
+ return {
76
+ score: 0,
77
+ reasoning: `Failed to parse judge response: ${raw.slice(0, 200)}`,
78
+ passed: false,
79
+ };
80
+ }
81
+ }
82
+ //# sourceMappingURL=llm-judge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-judge.js","sourceRoot":"","sources":["../../src/evaluators/llm-judge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Trace } from '../types.js';
2
+ /**
3
+ * Performance evaluator — checks token usage, duration, and round count.
4
+ */
5
+ export declare function evaluatePerformance(trace: Trace, durationMs: number, maxTokens?: number, maxDurationMs?: number, maxToolRounds?: number): string[];
6
+ //# sourceMappingURL=performance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance.d.ts","sourceRoot":"","sources":["../../src/evaluators/performance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,EACtB,aAAa,CAAC,EAAE,MAAM,GACrB,MAAM,EAAE,CAgBV"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Performance evaluator — checks token usage, duration, and round count.
3
+ */
4
+ export function evaluatePerformance(trace, durationMs, maxTokens, maxDurationMs, maxToolRounds) {
5
+ const failures = [];
6
+ if (maxTokens !== undefined && trace.usage.totalTokens > maxTokens) {
7
+ failures.push(`Token usage ${trace.usage.totalTokens} exceeded max ${maxTokens}`);
8
+ }
9
+ if (maxDurationMs !== undefined && durationMs > maxDurationMs) {
10
+ failures.push(`Duration ${durationMs}ms exceeded max ${maxDurationMs}ms`);
11
+ }
12
+ if (maxToolRounds !== undefined && trace.totalToolRounds > maxToolRounds) {
13
+ failures.push(`Tool rounds ${trace.totalToolRounds} exceeded max ${maxToolRounds}`);
14
+ }
15
+ return failures;
16
+ }
17
+ //# sourceMappingURL=performance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance.js","sourceRoot":"","sources":["../../src/evaluators/performance.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAY,EACZ,UAAkB,EAClB,SAAkB,EAClB,aAAsB,EACtB,aAAsB;IAEtB,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,WAAW,GAAG,SAAS,EAAE,CAAC;QACnE,QAAQ,CAAC,IAAI,CAAC,eAAe,KAAK,CAAC,KAAK,CAAC,WAAW,iBAAiB,SAAS,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,IAAI,aAAa,KAAK,SAAS,IAAI,UAAU,GAAG,aAAa,EAAE,CAAC;QAC9D,QAAQ,CAAC,IAAI,CAAC,YAAY,UAAU,mBAAmB,aAAa,IAAI,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,aAAa,KAAK,SAAS,IAAI,KAAK,CAAC,eAAe,GAAG,aAAa,EAAE,CAAC;QACzE,QAAQ,CAAC,IAAI,CAAC,eAAe,KAAK,CAAC,eAAe,iBAAiB,aAAa,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Trace } from '../types.js';
2
+ /**
3
+ * Structural evaluator — checks that the response has expected shape.
4
+ */
5
+ export declare function evaluateStructural(trace: Trace, contentNotEmpty?: boolean): string[];
6
+ //# sourceMappingURL=structural.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural.d.ts","sourceRoot":"","sources":["../../src/evaluators/structural.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAQpF"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Structural evaluator — checks that the response has expected shape.
3
+ */
4
+ export function evaluateStructural(trace, contentNotEmpty) {
5
+ const failures = [];
6
+ if (contentNotEmpty && (!trace.content || trace.content.trim().length === 0)) {
7
+ failures.push('Expected non-empty content, got empty response');
8
+ }
9
+ return failures;
10
+ }
11
+ //# sourceMappingURL=structural.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural.js","sourceRoot":"","sources":["../../src/evaluators/structural.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAY,EAAE,eAAyB;IACxE,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,eAAe,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QAC7E,QAAQ,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Trace } from '../types.js';
2
+ /**
3
+ * Tool usage evaluator — checks which tools were/weren't called.
4
+ */
5
+ export declare function evaluateToolUsage(trace: Trace, toolsCalled?: string[], toolsNotCalled?: string[], minToolCalls?: number): string[];
6
+ //# sourceMappingURL=tool-usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-usage.d.ts","sourceRoot":"","sources":["../../src/evaluators/tool-usage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,WAAW,CAAC,EAAE,MAAM,EAAE,EACtB,cAAc,CAAC,EAAE,MAAM,EAAE,EACzB,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,EAAE,CAyBV"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Tool usage evaluator — checks which tools were/weren't called.
3
+ */
4
+ export function evaluateToolUsage(trace, toolsCalled, toolsNotCalled, minToolCalls) {
5
+ const failures = [];
6
+ const calledNames = trace.toolCalls.map((tc) => tc.name);
7
+ if (toolsCalled) {
8
+ for (const expected of toolsCalled) {
9
+ if (!calledNames.includes(expected)) {
10
+ failures.push(`Expected tool '${expected}' to be called, but it wasn't. Called: [${calledNames.join(', ')}]`);
11
+ }
12
+ }
13
+ }
14
+ if (toolsNotCalled) {
15
+ for (const blocked of toolsNotCalled) {
16
+ if (calledNames.includes(blocked)) {
17
+ failures.push(`Expected tool '${blocked}' NOT to be called, but it was`);
18
+ }
19
+ }
20
+ }
21
+ if (minToolCalls !== undefined && trace.toolCalls.length < minToolCalls) {
22
+ failures.push(`Expected at least ${minToolCalls} tool calls, got ${trace.toolCalls.length}`);
23
+ }
24
+ return failures;
25
+ }
26
+ //# sourceMappingURL=tool-usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-usage.js","sourceRoot":"","sources":["../../src/evaluators/tool-usage.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAY,EACZ,WAAsB,EACtB,cAAyB,EACzB,YAAqB;IAErB,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAEzD,IAAI,WAAW,EAAE,CAAC;QAChB,KAAK,MAAM,QAAQ,IAAI,WAAW,EAAE,CAAC;YACnC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpC,QAAQ,CAAC,IAAI,CAAC,kBAAkB,QAAQ,2CAA2C,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAChH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,cAAc,EAAE,CAAC;QACnB,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;YACrC,IAAI,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClC,QAAQ,CAAC,IAAI,CAAC,kBAAkB,OAAO,gCAAgC,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,YAAY,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;QACxE,QAAQ,CAAC,IAAI,CAAC,qBAAqB,YAAY,oBAAoB,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Check if an HTTP service is reachable.
3
+ */
4
+ export declare function checkService(name: string, url: string, timeoutMs?: number): Promise<{
5
+ name: string;
6
+ reachable: boolean;
7
+ error?: string;
8
+ }>;
9
+ /**
10
+ * Check multiple services and return a summary.
11
+ */
12
+ export declare function checkServices(services: Array<{
13
+ name: string;
14
+ url: string;
15
+ }>): Promise<{
16
+ allReady: boolean;
17
+ results: Array<{
18
+ name: string;
19
+ reachable: boolean;
20
+ error?: string;
21
+ }>;
22
+ }>;
23
+ //# sourceMappingURL=service-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-check.d.ts","sourceRoot":"","sources":["../../src/helpers/service-check.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,SAAS,GAAE,MAAa,GACvB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAW/D;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7C,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAQtG"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Check if an HTTP service is reachable.
3
+ */
4
+ export async function checkService(name, url, timeoutMs = 5000) {
5
+ try {
6
+ const response = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
7
+ return { name, reachable: response.ok };
8
+ }
9
+ catch (err) {
10
+ return {
11
+ name,
12
+ reachable: false,
13
+ error: err instanceof Error ? err.message : String(err),
14
+ };
15
+ }
16
+ }
17
+ /**
18
+ * Check multiple services and return a summary.
19
+ */
20
+ export async function checkServices(services) {
21
+ const results = await Promise.all(services.map(({ name, url }) => checkService(name, url)));
22
+ return {
23
+ allReady: results.every((r) => r.reachable),
24
+ results,
25
+ };
26
+ }
27
+ //# sourceMappingURL=service-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-check.js","sourceRoot":"","sources":["../../src/helpers/service-check.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAY,EACZ,GAAW,EACX,YAAoB,IAAI;IAExB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC9E,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,IAAI;YACJ,SAAS,EAAE,KAAK;YAChB,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAA8C;IAE9C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CACzD,CAAC;IACF,OAAO;QACL,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3C,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ export { AgentTestSuite } from './suite.js';
2
+ export { HttpAgentRunner } from './runner.js';
3
+ export { ConsoleReporter, JsonReporter } from './reporters/index.js';
4
+ export { checkService, checkServices } from './helpers/service-check.js';
5
+ export { evaluateStructural } from './evaluators/structural.js';
6
+ export { evaluateToolUsage } from './evaluators/tool-usage.js';
7
+ export { evaluateContent } from './evaluators/content.js';
8
+ export { evaluatePerformance } from './evaluators/performance.js';
9
+ export { evaluateLlmJudge } from './evaluators/llm-judge.js';
10
+ export type { SuiteConfig, TestCase, TestResult, Expectation, EvaluationConfig, LlmJudgeConfig, LlmJudgeResult, Trace, TraceToolCall, ConversationCase, ConversationTurn, ConversationResult, SuiteReport, } from './types.js';
11
+ export type { Reporter } from './reporters/index.js';
12
+ export type { RunnerConfig } from './runner.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAG7D,YAAY,EACV,WAAW,EACX,QAAQ,EACR,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,KAAK,EACL,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ // ── @mce-bt/microagents-testing ──────────────────────────────────────────────────────
2
+ //
3
+ // Agentic test framework for MicroAgents agents.
4
+ // Write declarative test cases, run against live agents via HTTP,
5
+ // capture execution traces, and evaluate results programmatically.
6
+ //
7
+ export { AgentTestSuite } from './suite.js';
8
+ export { HttpAgentRunner } from './runner.js';
9
+ export { ConsoleReporter, JsonReporter } from './reporters/index.js';
10
+ export { checkService, checkServices } from './helpers/service-check.js';
11
+ // Evaluators (for advanced use — normally called by the suite)
12
+ export { evaluateStructural } from './evaluators/structural.js';
13
+ export { evaluateToolUsage } from './evaluators/tool-usage.js';
14
+ export { evaluateContent } from './evaluators/content.js';
15
+ export { evaluatePerformance } from './evaluators/performance.js';
16
+ export { evaluateLlmJudge } from './evaluators/llm-judge.js';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,EAAE;AACF,iDAAiD;AACjD,kEAAkE;AAClE,mEAAmE;AACnE,EAAE;AAEF,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEzE,+DAA+D;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { SuiteReport } from '../types.js';
2
+ import type { Reporter } from './index.js';
3
+ /**
4
+ * ConsoleReporter — pretty-prints suite results to the terminal.
5
+ */
6
+ export declare class ConsoleReporter implements Reporter {
7
+ report(report: SuiteReport): void;
8
+ private printTestResult;
9
+ private printConversationResult;
10
+ }
11
+ //# sourceMappingURL=console.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/reporters/console.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAkC,MAAM,aAAa,CAAC;AAC/E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS3C;;GAEG;AACH,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IA4BjC,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,uBAAuB;CAiBhC"}
@@ -0,0 +1,65 @@
1
+ const GREEN = '\x1b[32m';
2
+ const RED = '\x1b[31m';
3
+ const YELLOW = '\x1b[33m';
4
+ const DIM = '\x1b[2m';
5
+ const BOLD = '\x1b[1m';
6
+ const RESET = '\x1b[0m';
7
+ /**
8
+ * ConsoleReporter — pretty-prints suite results to the terminal.
9
+ */
10
+ export class ConsoleReporter {
11
+ report(report) {
12
+ console.log(`\n${BOLD}═══ Agent Test Suite: ${report.agentId} ═══${RESET}\n`);
13
+ // Individual test results
14
+ for (const r of report.results) {
15
+ this.printTestResult(r);
16
+ }
17
+ // Conversation results
18
+ for (const c of report.conversationResults) {
19
+ this.printConversationResult(c);
20
+ }
21
+ // Summary
22
+ console.log(`\n${BOLD}───────────────────────────────────${RESET}`);
23
+ const passColor = report.failed === 0 ? GREEN : RED;
24
+ console.log(`${passColor}${BOLD}${report.passed} passed${RESET}, ` +
25
+ `${report.failed > 0 ? RED : DIM}${report.failed} failed${RESET} ` +
26
+ `${DIM}(${report.total} total)${RESET}`);
27
+ console.log(`${DIM}Tokens: ${report.totalTokens.toLocaleString()} | ` +
28
+ `Duration: ${(report.totalDurationMs / 1000).toFixed(1)}s${RESET}`);
29
+ console.log();
30
+ }
31
+ printTestResult(r) {
32
+ const icon = r.passed ? `${GREEN}✓${RESET}` : `${RED}✗${RESET}`;
33
+ const duration = `${DIM}(${(r.durationMs / 1000).toFixed(1)}s)${RESET}`;
34
+ const tokens = `${DIM}[${r.trace.usage.totalTokens} tok]${RESET}`;
35
+ const tools = r.trace.toolCalls.length > 0
36
+ ? `${DIM}→ ${r.trace.toolCalls.map((tc) => tc.name).join(', ')}${RESET}`
37
+ : '';
38
+ console.log(` ${icon} ${r.name} ${duration} ${tokens} ${tools}`);
39
+ if (!r.passed) {
40
+ for (const f of r.failures) {
41
+ console.log(` ${RED}└ ${f}${RESET}`);
42
+ }
43
+ }
44
+ if (r.evaluation) {
45
+ const evalIcon = r.evaluation.passed ? `${GREEN}✓${RESET}` : `${YELLOW}⚠${RESET}`;
46
+ console.log(` ${evalIcon} ${DIM}Judge: ${r.evaluation.score}/10 — ${r.evaluation.reasoning.slice(0, 120)}${RESET}`);
47
+ }
48
+ }
49
+ printConversationResult(c) {
50
+ const icon = c.passed ? `${GREEN}✓${RESET}` : `${RED}✗${RESET}`;
51
+ const duration = `${DIM}(${(c.durationMs / 1000).toFixed(1)}s)${RESET}`;
52
+ console.log(` ${icon} ${BOLD}${c.name}${RESET} ${duration} [${c.turnResults.length} turns]`);
53
+ for (const turn of c.turnResults) {
54
+ const turnIcon = turn.passed ? `${GREEN}✓${RESET}` : `${RED}✗${RESET}`;
55
+ const tools = turn.trace.toolCalls.map((tc) => tc.name).join(', ');
56
+ console.log(` ${turnIcon} ${turn.name} ${DIM}→ ${tools || '(no tools)'}${RESET}`);
57
+ if (!turn.passed) {
58
+ for (const f of turn.failures) {
59
+ console.log(` ${RED}└ ${f}${RESET}`);
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+ //# sourceMappingURL=console.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"console.js","sourceRoot":"","sources":["../../src/reporters/console.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { SuiteReport } from '../types.js';
2
+ export interface Reporter {
3
+ report(report: SuiteReport): void;
4
+ }
5
+ export { ConsoleReporter } from './console.js';
6
+ export { JsonReporter } from './json.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reporters/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAkC,MAAM,aAAa,CAAC;AAE/E,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;CACnC;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { ConsoleReporter } from './console.js';
2
+ export { JsonReporter } from './json.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reporters/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { SuiteReport } from '../types.js';
2
+ import type { Reporter } from './index.js';
3
+ /**
4
+ * JsonReporter — outputs the full suite report as structured JSON.
5
+ * Useful for programmatic analysis, CI integration, and dashboards.
6
+ */
7
+ export declare class JsonReporter implements Reporter {
8
+ private output;
9
+ report(report: SuiteReport): void;
10
+ /**
11
+ * Get the last report (for programmatic access without console.log).
12
+ */
13
+ getLastReport(): SuiteReport | null;
14
+ }
15
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/reporters/json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;GAGG;AACH,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,MAAM,CAA4B;IAE1C,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAKjC;;OAEG;IACH,aAAa,IAAI,WAAW,GAAG,IAAI;CAGpC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * JsonReporter — outputs the full suite report as structured JSON.
3
+ * Useful for programmatic analysis, CI integration, and dashboards.
4
+ */
5
+ export class JsonReporter {
6
+ output = null;
7
+ report(report) {
8
+ this.output = report;
9
+ console.log(JSON.stringify(report, null, 2));
10
+ }
11
+ /**
12
+ * Get the last report (for programmatic access without console.log).
13
+ */
14
+ getLastReport() {
15
+ return this.output;
16
+ }
17
+ }
18
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/reporters/json.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,OAAO,YAAY;IACf,MAAM,GAAuB,IAAI,CAAC;IAE1C,MAAM,CAAC,MAAmB;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF"}
@@ -0,0 +1,33 @@
1
+ import type { Trace } from './types.js';
2
+ /**
3
+ * Configuration for the HTTP agent runner.
4
+ */
5
+ export interface RunnerConfig {
6
+ baseUrl: string;
7
+ agentId: string;
8
+ sharedSecret: string;
9
+ timeout: number;
10
+ }
11
+ /**
12
+ * HttpAgentRunner — sends messages to an agent's /process endpoint
13
+ * with HMAC authentication and captures the full execution trace.
14
+ */
15
+ export declare class HttpAgentRunner {
16
+ private readonly config;
17
+ constructor(config: RunnerConfig);
18
+ /**
19
+ * Send a message to the agent and capture the execution trace.
20
+ */
21
+ run(message: string, options?: {
22
+ sessionId?: string;
23
+ tier?: string;
24
+ timeout?: number;
25
+ }): Promise<Trace>;
26
+ /**
27
+ * Check if the agent is reachable.
28
+ */
29
+ healthCheck(): Promise<boolean>;
30
+ private sign;
31
+ private mapToTrace;
32
+ }
33
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,YAAY,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAoBD;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;gBAE1B,MAAM,EAAE,YAAY;IAIhC;;OAEG;IACG,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,KAAK,CAAC;IAwC7G;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAWrC,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,UAAU;CAkBnB"}
package/dist/runner.js ADDED
@@ -0,0 +1,86 @@
1
+ import { createHmac } from 'node:crypto';
2
+ import { randomUUID } from 'node:crypto';
3
+ /**
4
+ * HttpAgentRunner — sends messages to an agent's /process endpoint
5
+ * with HMAC authentication and captures the full execution trace.
6
+ */
7
+ export class HttpAgentRunner {
8
+ config;
9
+ constructor(config) {
10
+ this.config = config;
11
+ }
12
+ /**
13
+ * Send a message to the agent and capture the execution trace.
14
+ */
15
+ async run(message, options) {
16
+ const timeout = options?.timeout ?? this.config.timeout;
17
+ const body = JSON.stringify({
18
+ message,
19
+ ...(options?.sessionId && { sessionId: options.sessionId }),
20
+ ...(options?.tier && { tier: options.tier }),
21
+ });
22
+ const timestamp = Date.now().toString();
23
+ const signature = this.sign(body, timestamp);
24
+ const controller = new AbortController();
25
+ const timer = setTimeout(() => controller.abort(), timeout);
26
+ try {
27
+ const response = await fetch(`${this.config.baseUrl}/process`, {
28
+ method: 'POST',
29
+ headers: {
30
+ 'Content-Type': 'application/json',
31
+ 'X-Agent-Id': 'testing-framework',
32
+ 'X-Signature': signature,
33
+ 'X-Timestamp': timestamp,
34
+ 'X-Correlation-Id': randomUUID(),
35
+ },
36
+ body,
37
+ signal: controller.signal,
38
+ });
39
+ if (!response.ok) {
40
+ const text = await response.text().catch(() => '');
41
+ throw new Error(`Agent responded with HTTP ${response.status}: ${text}`);
42
+ }
43
+ const data = (await response.json());
44
+ return this.mapToTrace(data);
45
+ }
46
+ finally {
47
+ clearTimeout(timer);
48
+ }
49
+ }
50
+ /**
51
+ * Check if the agent is reachable.
52
+ */
53
+ async healthCheck() {
54
+ try {
55
+ const response = await fetch(`${this.config.baseUrl}/health`, {
56
+ signal: AbortSignal.timeout(5000),
57
+ });
58
+ return response.ok;
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ }
64
+ sign(payload, timestamp) {
65
+ const data = `${timestamp}.${payload}`;
66
+ return createHmac('sha256', this.config.sharedSecret).update(data).digest('hex');
67
+ }
68
+ mapToTrace(response) {
69
+ const toolCalls = (response.toolCalls ?? []).map((tc, i) => ({
70
+ toolCallId: tc.toolCallId ?? `tc_${i}`,
71
+ name: tc.name,
72
+ arguments: tc.arguments ?? {},
73
+ result: tc.result,
74
+ error: tc.error,
75
+ durationMs: tc.durationMs ?? 0,
76
+ }));
77
+ return {
78
+ content: response.content ?? '',
79
+ toolCalls,
80
+ totalToolRounds: response.totalToolRounds ?? toolCalls.length,
81
+ usage: response.usage ?? { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
82
+ sessionId: response.sessionId,
83
+ };
84
+ }
85
+ }
86
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { SuiteConfig, TestCase, TestResult, ConversationCase, ConversationResult, SuiteReport } from './types.js';
2
+ /**
3
+ * AgentTestSuite — declarative test framework for any MicroAgents agent.
4
+ *
5
+ * Sends messages to a running agent via HTTP, captures execution traces
6
+ * (tool calls, tokens, timing), and evaluates results against expectations.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const suite = new AgentTestSuite({
11
+ * agentId: 'watson',
12
+ * baseUrl: 'http://localhost:3029',
13
+ * sharedSecret: 'my-secret',
14
+ * });
15
+ *
16
+ * const result = await suite.run({
17
+ * name: 'web search',
18
+ * message: 'Search for TypeScript 6',
19
+ * expect: { toolsCalled: ['web_search'], contentNotEmpty: true },
20
+ * });
21
+ * ```
22
+ */
23
+ export declare class AgentTestSuite {
24
+ readonly config: SuiteConfig;
25
+ private runner;
26
+ constructor(config: SuiteConfig);
27
+ /**
28
+ * Check if the target agent is reachable.
29
+ */
30
+ isAgentReady(): Promise<boolean>;
31
+ /**
32
+ * Run a single test case against the agent.
33
+ */
34
+ run(testCase: TestCase): Promise<TestResult>;
35
+ /**
36
+ * Run a multi-turn conversation test.
37
+ * All turns share the same session — testing context retention.
38
+ */
39
+ runConversation(convCase: ConversationCase): Promise<ConversationResult>;
40
+ /**
41
+ * Run all test cases and conversations, producing an aggregated report.
42
+ */
43
+ runAll(testCases: TestCase[], conversations?: ConversationCase[]): Promise<SuiteReport>;
44
+ /**
45
+ * Run all evaluators against a trace and return failures.
46
+ */
47
+ private evaluate;
48
+ /**
49
+ * Merge test-case expectations with suite-level defaults.
50
+ */
51
+ private mergeExpectations;
52
+ }
53
+ //# sourceMappingURL=suite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suite.d.ts","sourceRoot":"","sources":["../src/suite.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EAIZ,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,cAAc;IACzB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,WAAW;IAU/B;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IAItC;;OAEG;IACG,GAAG,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAqDlD;;;OAGG;IACG,eAAe,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAgC9E;;OAEG;IACG,MAAM,CACV,SAAS,EAAE,QAAQ,EAAE,EACrB,aAAa,CAAC,EAAE,gBAAgB,EAAE,GACjC,OAAO,CAAC,WAAW,CAAC;IAoCvB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAwChB;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAkB1B"}
package/dist/suite.js ADDED
@@ -0,0 +1,199 @@
1
+ import { HttpAgentRunner } from './runner.js';
2
+ import { evaluateStructural, evaluateToolUsage, evaluateContent, evaluatePerformance, evaluateLlmJudge, } from './evaluators/index.js';
3
+ /**
4
+ * AgentTestSuite — declarative test framework for any MicroAgents agent.
5
+ *
6
+ * Sends messages to a running agent via HTTP, captures execution traces
7
+ * (tool calls, tokens, timing), and evaluates results against expectations.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const suite = new AgentTestSuite({
12
+ * agentId: 'watson',
13
+ * baseUrl: 'http://localhost:3029',
14
+ * sharedSecret: 'my-secret',
15
+ * });
16
+ *
17
+ * const result = await suite.run({
18
+ * name: 'web search',
19
+ * message: 'Search for TypeScript 6',
20
+ * expect: { toolsCalled: ['web_search'], contentNotEmpty: true },
21
+ * });
22
+ * ```
23
+ */
24
+ export class AgentTestSuite {
25
+ config;
26
+ runner;
27
+ constructor(config) {
28
+ this.config = config;
29
+ this.runner = new HttpAgentRunner({
30
+ baseUrl: config.baseUrl,
31
+ agentId: config.agentId,
32
+ sharedSecret: config.sharedSecret,
33
+ timeout: config.defaultTimeout ?? 60_000,
34
+ });
35
+ }
36
+ /**
37
+ * Check if the target agent is reachable.
38
+ */
39
+ async isAgentReady() {
40
+ return this.runner.healthCheck();
41
+ }
42
+ /**
43
+ * Run a single test case against the agent.
44
+ */
45
+ async run(testCase) {
46
+ const start = Date.now();
47
+ const expect = this.mergeExpectations(testCase.expect);
48
+ try {
49
+ const trace = await this.runner.run(testCase.message, {
50
+ sessionId: testCase.sessionId,
51
+ tier: testCase.tier,
52
+ timeout: testCase.timeout ?? this.config.defaultTimeout,
53
+ });
54
+ const durationMs = Date.now() - start;
55
+ const failures = this.evaluate(trace, expect, durationMs);
56
+ // LLM-as-judge (if configured and API key available)
57
+ let evaluation;
58
+ if (testCase.evaluate?.llmJudge && this.config.openRouterApiKey) {
59
+ evaluation = await evaluateLlmJudge(trace, testCase.message, testCase.evaluate.llmJudge, this.config.openRouterApiKey);
60
+ if (!evaluation.passed) {
61
+ failures.push(`LLM judge score ${evaluation.score}/10 below threshold: ${evaluation.reasoning}`);
62
+ }
63
+ }
64
+ return {
65
+ name: testCase.name,
66
+ passed: failures.length === 0,
67
+ failures,
68
+ trace,
69
+ durationMs,
70
+ evaluation,
71
+ tags: testCase.tags,
72
+ };
73
+ }
74
+ catch (err) {
75
+ const durationMs = Date.now() - start;
76
+ const errorMsg = err instanceof Error ? err.message : String(err);
77
+ return {
78
+ name: testCase.name,
79
+ passed: false,
80
+ failures: [`Test errored: ${errorMsg}`],
81
+ trace: emptyTrace(),
82
+ durationMs,
83
+ tags: testCase.tags,
84
+ error: errorMsg,
85
+ };
86
+ }
87
+ }
88
+ /**
89
+ * Run a multi-turn conversation test.
90
+ * All turns share the same session — testing context retention.
91
+ */
92
+ async runConversation(convCase) {
93
+ const start = Date.now();
94
+ const turnResults = [];
95
+ let sessionId;
96
+ for (let i = 0; i < convCase.turns.length; i++) {
97
+ const turn = convCase.turns[i];
98
+ const result = await this.run({
99
+ name: `${convCase.name} [turn ${i + 1}]`,
100
+ message: turn.message,
101
+ sessionId,
102
+ expect: turn.expect,
103
+ evaluate: turn.evaluate,
104
+ });
105
+ turnResults.push(result);
106
+ // Use the session from the first turn for all subsequent turns
107
+ if (i === 0 && result.trace.sessionId) {
108
+ sessionId = result.trace.sessionId;
109
+ }
110
+ }
111
+ return {
112
+ name: convCase.name,
113
+ passed: turnResults.every((r) => r.passed),
114
+ turnResults,
115
+ durationMs: Date.now() - start,
116
+ tags: convCase.tags,
117
+ };
118
+ }
119
+ /**
120
+ * Run all test cases and conversations, producing an aggregated report.
121
+ */
122
+ async runAll(testCases, conversations) {
123
+ const startedAt = new Date().toISOString();
124
+ const start = Date.now();
125
+ const results = [];
126
+ for (const tc of testCases) {
127
+ results.push(await this.run(tc));
128
+ }
129
+ const conversationResults = [];
130
+ if (conversations) {
131
+ for (const conv of conversations) {
132
+ conversationResults.push(await this.runConversation(conv));
133
+ }
134
+ }
135
+ // Flatten conversation turn results for totals
136
+ const allResults = [
137
+ ...results,
138
+ ...conversationResults.flatMap((c) => c.turnResults),
139
+ ];
140
+ return {
141
+ agentId: this.config.agentId,
142
+ passed: allResults.filter((r) => r.passed).length,
143
+ failed: allResults.filter((r) => !r.passed).length,
144
+ total: allResults.length,
145
+ results,
146
+ conversationResults,
147
+ totalTokens: allResults.reduce((sum, r) => sum + r.trace.usage.totalTokens, 0),
148
+ totalDurationMs: Date.now() - start,
149
+ startedAt,
150
+ finishedAt: new Date().toISOString(),
151
+ };
152
+ }
153
+ /**
154
+ * Run all evaluators against a trace and return failures.
155
+ */
156
+ evaluate(trace, expect, durationMs) {
157
+ const failures = [];
158
+ failures.push(...evaluateStructural(trace, expect.contentNotEmpty));
159
+ failures.push(...evaluateToolUsage(trace, expect.toolsCalled, expect.toolsNotCalled, expect.minToolCalls));
160
+ failures.push(...evaluateContent(trace, expect.contentContains, expect.contentNotContains, expect.contentMatches));
161
+ failures.push(...evaluatePerformance(trace, durationMs, expect.maxTokens, expect.maxDurationMs, expect.maxToolRounds));
162
+ if (expect.custom) {
163
+ failures.push(...expect.custom(trace));
164
+ }
165
+ return failures;
166
+ }
167
+ /**
168
+ * Merge test-case expectations with suite-level defaults.
169
+ */
170
+ mergeExpectations(caseExpect) {
171
+ if (!this.config.defaultExpect)
172
+ return caseExpect ?? {};
173
+ if (!caseExpect)
174
+ return this.config.defaultExpect;
175
+ return {
176
+ ...this.config.defaultExpect,
177
+ ...caseExpect,
178
+ // Merge arrays rather than overwrite
179
+ toolsCalled: [
180
+ ...(this.config.defaultExpect.toolsCalled ?? []),
181
+ ...(caseExpect.toolsCalled ?? []),
182
+ ],
183
+ contentContains: [
184
+ ...(this.config.defaultExpect.contentContains ?? []),
185
+ ...(caseExpect.contentContains ?? []),
186
+ ],
187
+ };
188
+ }
189
+ }
190
+ function emptyTrace() {
191
+ return {
192
+ content: '',
193
+ toolCalls: [],
194
+ totalToolRounds: 0,
195
+ usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
196
+ sessionId: '',
197
+ };
198
+ }
199
+ //# sourceMappingURL=suite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suite.js","sourceRoot":"","sources":["../src/suite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Configuration for an AgentTestSuite instance.
3
+ */
4
+ export interface SuiteConfig {
5
+ /** Agent identifier (e.g., 'watson', 'linus') */
6
+ agentId: string;
7
+ /** Base URL of the running agent (e.g., 'http://localhost:3029') */
8
+ baseUrl: string;
9
+ /** Shared HMAC secret for inter-agent auth */
10
+ sharedSecret: string;
11
+ /** Default timeout per test case in ms (default: 60_000) */
12
+ defaultTimeout?: number;
13
+ /** Default expectations applied to every test case */
14
+ defaultExpect?: Expectation;
15
+ /** OpenRouter API key — required for LLM-as-judge evaluation */
16
+ openRouterApiKey?: string;
17
+ }
18
+ /**
19
+ * A single test case to run against an agent.
20
+ */
21
+ export interface TestCase {
22
+ /** Human-readable name for this test case */
23
+ name: string;
24
+ /** The message to send to the agent */
25
+ message: string;
26
+ /** Optional: reuse an existing session */
27
+ sessionId?: string;
28
+ /** Optional: override the completion tier */
29
+ tier?: string;
30
+ /** Timeout override for this test case in ms */
31
+ timeout?: number;
32
+ /** Structural expectations to assert against the result */
33
+ expect?: Expectation;
34
+ /** LLM-based evaluation (optional, requires OpenRouter key) */
35
+ evaluate?: EvaluationConfig;
36
+ /** Optional tags for filtering/grouping */
37
+ tags?: string[];
38
+ }
39
+ /**
40
+ * Structural expectations that can be asserted against a test result.
41
+ */
42
+ export interface Expectation {
43
+ /** At least these tool names must appear in toolCalls */
44
+ toolsCalled?: string[];
45
+ /** None of these tool names should appear in toolCalls */
46
+ toolsNotCalled?: string[];
47
+ /** Response content must contain all of these substrings (case-insensitive) */
48
+ contentContains?: string[];
49
+ /** Response content must NOT contain any of these substrings (case-insensitive) */
50
+ contentNotContains?: string[];
51
+ /** Response content must match all of these regex patterns */
52
+ contentMatches?: string[];
53
+ /** Response content must not be empty */
54
+ contentNotEmpty?: boolean;
55
+ /** Total tokens must not exceed this */
56
+ maxTokens?: number;
57
+ /** Execution time must not exceed this (ms) */
58
+ maxDurationMs?: number;
59
+ /** Agent loop rounds must not exceed this */
60
+ maxToolRounds?: number;
61
+ /** Minimum number of tool calls expected */
62
+ minToolCalls?: number;
63
+ /** Custom assertion function — return string[] of failures, or empty for pass */
64
+ custom?: (trace: Trace) => string[];
65
+ }
66
+ /**
67
+ * Configuration for LLM-based evaluation.
68
+ */
69
+ export interface EvaluationConfig {
70
+ llmJudge?: LlmJudgeConfig;
71
+ }
72
+ /**
73
+ * LLM-as-judge settings.
74
+ */
75
+ export interface LlmJudgeConfig {
76
+ /** Natural language criteria the response should meet */
77
+ criteria: string;
78
+ /** Model to use for judging (default: 'openai/gpt-4.1-nano') */
79
+ model?: string;
80
+ /** Minimum score to pass (1-10, default: 7) */
81
+ threshold?: number;
82
+ }
83
+ /**
84
+ * The captured execution trace from an agent run.
85
+ */
86
+ export interface Trace {
87
+ /** Agent's final response text */
88
+ content: string;
89
+ /** All tool calls executed during the run */
90
+ toolCalls: TraceToolCall[];
91
+ /** Number of LLM rounds (tool loops) */
92
+ totalToolRounds: number;
93
+ /** Token usage across all rounds */
94
+ usage: {
95
+ promptTokens: number;
96
+ completionTokens: number;
97
+ totalTokens: number;
98
+ };
99
+ /** Session ID used for this run */
100
+ sessionId: string;
101
+ }
102
+ /**
103
+ * A single tool call captured in a trace.
104
+ */
105
+ export interface TraceToolCall {
106
+ toolCallId: string;
107
+ name: string;
108
+ arguments: Record<string, unknown>;
109
+ result: unknown;
110
+ error?: string;
111
+ durationMs: number;
112
+ }
113
+ /**
114
+ * Result of a single test case execution.
115
+ */
116
+ export interface TestResult {
117
+ /** Test case name */
118
+ name: string;
119
+ /** Whether all expectations and evaluations passed */
120
+ passed: boolean;
121
+ /** List of failure messages */
122
+ failures: string[];
123
+ /** Captured execution trace */
124
+ trace: Trace;
125
+ /** Total execution time in ms (including network) */
126
+ durationMs: number;
127
+ /** LLM-as-judge evaluation result (if configured) */
128
+ evaluation?: LlmJudgeResult;
129
+ /** Tags from the test case */
130
+ tags?: string[];
131
+ /** Error message if test errored before evaluation (e.g., timeout, HTTP error) */
132
+ error?: string;
133
+ }
134
+ /**
135
+ * Result of LLM-as-judge evaluation.
136
+ */
137
+ export interface LlmJudgeResult {
138
+ /** Score from 1-10 */
139
+ score: number;
140
+ /** Reasoning from the judge */
141
+ reasoning: string;
142
+ /** Whether the score met the threshold */
143
+ passed: boolean;
144
+ }
145
+ /**
146
+ * A multi-turn conversation test case.
147
+ */
148
+ export interface ConversationCase {
149
+ /** Human-readable name */
150
+ name: string;
151
+ /** Ordered sequence of messages + expectations */
152
+ turns: ConversationTurn[];
153
+ /** Tags for filtering */
154
+ tags?: string[];
155
+ }
156
+ /**
157
+ * A single turn in a multi-turn conversation test.
158
+ */
159
+ export interface ConversationTurn {
160
+ /** Message to send */
161
+ message: string;
162
+ /** Expectations for this turn's result */
163
+ expect?: Expectation;
164
+ /** Evaluation for this turn */
165
+ evaluate?: EvaluationConfig;
166
+ }
167
+ /**
168
+ * Result of a multi-turn conversation test.
169
+ */
170
+ export interface ConversationResult {
171
+ /** Test case name */
172
+ name: string;
173
+ /** Whether ALL turns passed */
174
+ passed: boolean;
175
+ /** Per-turn results */
176
+ turnResults: TestResult[];
177
+ /** Total duration across all turns */
178
+ durationMs: number;
179
+ /** Tags from the test case */
180
+ tags?: string[];
181
+ }
182
+ /**
183
+ * Aggregated report for a full suite run.
184
+ */
185
+ export interface SuiteReport {
186
+ /** Agent ID */
187
+ agentId: string;
188
+ /** Number of tests that passed */
189
+ passed: number;
190
+ /** Number of tests that failed */
191
+ failed: number;
192
+ /** Total number of tests */
193
+ total: number;
194
+ /** All individual results */
195
+ results: TestResult[];
196
+ /** All conversation results */
197
+ conversationResults: ConversationResult[];
198
+ /** Total tokens consumed across all tests */
199
+ totalTokens: number;
200
+ /** Total wall-clock time in ms */
201
+ totalDurationMs: number;
202
+ /** Timestamp when the suite started */
203
+ startedAt: string;
204
+ /** Timestamp when the suite finished */
205
+ finishedAt: string;
206
+ }
207
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // ── Types ─────────────────────────────────────────────────────────────────────
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,iFAAiF"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@mce-bt/microagents-testing",
3
+ "version": "0.1.0",
4
+ "description": "Agentic test framework — declarative test cases, live execution, structured evaluation",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc --build",
16
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
17
+ "test": "vitest run"
18
+ },
19
+ "dependencies": {},
20
+ "devDependencies": {
21
+ "@types/node": "^25.5.0"
22
+ },
23
+ "license": "MIT",
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/cavillo/microagents.git",
33
+ "directory": "packages/testing"
34
+ },
35
+ "homepage": "https://github.com/cavillo/microagents#readme",
36
+ "bugs": {
37
+ "url": "https://github.com/cavillo/microagents/issues"
38
+ },
39
+ "engines": {
40
+ "node": ">=20.0.0"
41
+ }
42
+ }