@memberjunction/testing-engine 6.1.0-edge.6 → 6.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/drivers/AgentPromptComposer.d.ts +50 -0
- package/dist/drivers/AgentPromptComposer.d.ts.map +1 -0
- package/dist/drivers/AgentPromptComposer.js +60 -0
- package/dist/drivers/AgentPromptComposer.js.map +1 -0
- package/dist/drivers/PinnedVendorPromptRunner.d.ts +30 -0
- package/dist/drivers/PinnedVendorPromptRunner.d.ts.map +1 -0
- package/dist/drivers/PinnedVendorPromptRunner.js +30 -0
- package/dist/drivers/PinnedVendorPromptRunner.js.map +1 -0
- package/dist/drivers/PromptEvalDriver.d.ts +158 -0
- package/dist/drivers/PromptEvalDriver.d.ts.map +1 -0
- package/dist/drivers/PromptEvalDriver.js +365 -0
- package/dist/drivers/PromptEvalDriver.js.map +1 -0
- package/dist/drivers/index.d.ts +1 -0
- package/dist/drivers/index.d.ts.map +1 -1
- package/dist/drivers/index.js +1 -0
- package/dist/drivers/index.js.map +1 -1
- package/dist/engine/TestEngine.d.ts.map +1 -1
- package/dist/engine/TestEngine.js +5 -0
- package/dist/engine/TestEngine.js.map +1 -1
- package/dist/eval/corpus.d.ts +91 -0
- package/dist/eval/corpus.d.ts.map +1 -0
- package/dist/eval/corpus.js +141 -0
- package/dist/eval/corpus.js.map +1 -0
- package/dist/eval/decision.d.ts +156 -0
- package/dist/eval/decision.d.ts.map +1 -0
- package/dist/eval/decision.js +257 -0
- package/dist/eval/decision.js.map +1 -0
- package/dist/eval/expectation.d.ts +76 -0
- package/dist/eval/expectation.d.ts.map +1 -0
- package/dist/eval/expectation.js +160 -0
- package/dist/eval/expectation.js.map +1 -0
- package/dist/eval/history.d.ts +17 -0
- package/dist/eval/history.d.ts.map +1 -0
- package/dist/eval/history.js +19 -0
- package/dist/eval/history.js.map +1 -0
- package/dist/eval/index.d.ts +15 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +15 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/eval/matchers.d.ts +88 -0
- package/dist/eval/matchers.d.ts.map +1 -0
- package/dist/eval/matchers.js +119 -0
- package/dist/eval/matchers.js.map +1 -0
- package/dist/eval/subAgentTrace.d.ts +52 -0
- package/dist/eval/subAgentTrace.d.ts.map +1 -0
- package/dist/eval/subAgentTrace.js +61 -0
- package/dist/eval/subAgentTrace.js.map +1 -0
- package/dist/eval/wellFormed.d.ts +41 -0
- package/dist/eval/wellFormed.d.ts.map +1 -0
- package/dist/eval/wellFormed.js +83 -0
- package/dist/eval/wellFormed.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/oracles/AgentDecisionOracle.d.ts +54 -0
- package/dist/oracles/AgentDecisionOracle.d.ts.map +1 -0
- package/dist/oracles/AgentDecisionOracle.js +107 -0
- package/dist/oracles/AgentDecisionOracle.js.map +1 -0
- package/dist/oracles/TraceSubAgentValidatorOracle.d.ts +44 -0
- package/dist/oracles/TraceSubAgentValidatorOracle.d.ts.map +1 -0
- package/dist/oracles/TraceSubAgentValidatorOracle.js +105 -0
- package/dist/oracles/TraceSubAgentValidatorOracle.js.map +1 -0
- package/dist/oracles/index.d.ts +2 -0
- package/dist/oracles/index.d.ts.map +1 -1
- package/dist/oracles/index.js +2 -0
- package/dist/oracles/index.js.map +1 -1
- package/package.json +10 -10
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Agent-decision oracles — the centrepiece of the prompt-eval corpus (test plan §3.2).
|
|
3
|
+
* @module @memberjunction/testing-engine
|
|
4
|
+
*/
|
|
5
|
+
import { normalizeDecision } from '../eval/decision.js';
|
|
6
|
+
import { evaluateCorpusExpectation } from '../eval/corpus.js';
|
|
7
|
+
import { evaluateWellFormed } from '../eval/wellFormed.js';
|
|
8
|
+
function readActual(input) {
|
|
9
|
+
const actual = input.actualOutput;
|
|
10
|
+
// A driver that produced nothing at all still has to be judged rather than crash the run —
|
|
11
|
+
// "no output" is the single most important observation this suite makes.
|
|
12
|
+
return actual?.turn ? actual : { turn: { text: typeof actual === 'string' ? actual : '' } };
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* `agent-decision-match` — did the agent decide the right thing?
|
|
16
|
+
*
|
|
17
|
+
* Reads the decision off whichever channel the model used (envelope or native tool calls) and
|
|
18
|
+
* compares it against an encoding-independent expectation. That normalization is what lets a
|
|
19
|
+
* baseline cell and a native cell be compared on an identical corpus case: the
|
|
20
|
+
* yardstick does not move between them, only the model's behavior does.
|
|
21
|
+
*
|
|
22
|
+
* The result's `details` carry the components separately — decision kind, action accuracy, param
|
|
23
|
+
* fidelity, per-matcher outcomes — so §6.1's metrics aggregate out of persisted `ResultDetails`
|
|
24
|
+
* without re-running anything.
|
|
25
|
+
*
|
|
26
|
+
* Configuration is the {@link DecisionExpectation} itself.
|
|
27
|
+
*/
|
|
28
|
+
export class AgentDecisionOracle {
|
|
29
|
+
constructor() {
|
|
30
|
+
this.type = 'agent-decision-match';
|
|
31
|
+
}
|
|
32
|
+
async evaluate(input, config) {
|
|
33
|
+
try {
|
|
34
|
+
const expectation = config;
|
|
35
|
+
if (!expectation?.kind) {
|
|
36
|
+
return { oracleType: this.type, passed: false, score: 0, message: "Configuration requires a 'kind' (the expected decision)" };
|
|
37
|
+
}
|
|
38
|
+
const actual = readActual(input);
|
|
39
|
+
const observed = normalizeDecision(actual.turn);
|
|
40
|
+
// evaluateCorpusExpectation, NOT evaluateDecision: only the former unwraps `anyOf`.
|
|
41
|
+
// `anyOf` is a corpus-level kind — a case that legitimately admits several decisions —
|
|
42
|
+
// and evaluateDecision would compare the literal string 'anyOf' against the observed
|
|
43
|
+
// kind and fail every time, which is a scored failure the model can never avoid.
|
|
44
|
+
const evaluation = evaluateCorpusExpectation((input.test?.Name ?? 'case'), expectation, observed);
|
|
45
|
+
return {
|
|
46
|
+
oracleType: this.type,
|
|
47
|
+
passed: evaluation.passed,
|
|
48
|
+
score: evaluation.score,
|
|
49
|
+
message: evaluation.passed
|
|
50
|
+
? `decided '${observed.kind}' via ${observed.encoding} as expected`
|
|
51
|
+
: evaluation.messages.join('; '),
|
|
52
|
+
details: {
|
|
53
|
+
expectedKind: expectation.kind,
|
|
54
|
+
observedKind: observed.kind,
|
|
55
|
+
encoding: observed.encoding,
|
|
56
|
+
decisionKindMatch: evaluation.decisionKindMatch,
|
|
57
|
+
actionAccuracy: evaluation.actionAccuracy,
|
|
58
|
+
paramFidelity: evaluation.paramFidelity,
|
|
59
|
+
paramResults: evaluation.paramResults,
|
|
60
|
+
forbiddenViolations: evaluation.forbiddenViolations,
|
|
61
|
+
observedActions: observed.actions.map((a) => a.name),
|
|
62
|
+
observedSubAgents: observed.subAgents.map((s) => s.name),
|
|
63
|
+
// Surfaced so the scorecard can count dual-channel
|
|
64
|
+
// turns and concatenated envelopes without re-running anything.
|
|
65
|
+
dualChannel: observed.dualChannel ?? false,
|
|
66
|
+
payloadChanged: observed.payloadChange !== undefined,
|
|
67
|
+
narrationWithCalls: observed.narrationWithCalls ?? false,
|
|
68
|
+
placeholderCall: observed.placeholderCall ?? false,
|
|
69
|
+
shadowEnvelopeKind: observed.shadowEnvelopeKind,
|
|
70
|
+
diagnostic: observed.diagnostic
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return { oracleType: this.type, passed: false, score: 0, message: `Decision evaluation error: ${error.message}` };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* `response-well-formed` — was the output usable at all?
|
|
81
|
+
*
|
|
82
|
+
* This is the oracle that measures the malformed/discard class directly — the issue's headline
|
|
83
|
+
* number. It asks strictly less than {@link AgentDecisionOracle}: a turn can be well-formed and
|
|
84
|
+
* wrong, but never malformed and right. Keeping them apart is what lets a comparison say *which* of
|
|
85
|
+
* "malformed rate fell" and "decision accuracy rose" actually happened.
|
|
86
|
+
*
|
|
87
|
+
* Configuration is a {@link WellFormedConfig}. Note `requireEnvelope` defaults to **off**: measurement
|
|
88
|
+
* measured that a correct native tool call carries no text at all on Google, so requiring an
|
|
89
|
+
* envelope unconditionally would fail every correct native turn.
|
|
90
|
+
*/
|
|
91
|
+
export class ResponseWellFormedOracle {
|
|
92
|
+
constructor() {
|
|
93
|
+
this.type = 'response-well-formed';
|
|
94
|
+
}
|
|
95
|
+
async evaluate(input, config) {
|
|
96
|
+
try {
|
|
97
|
+
const actual = readActual(input);
|
|
98
|
+
const observed = normalizeDecision(actual.turn);
|
|
99
|
+
const result = evaluateWellFormed({ decision: observed, finishReason: actual.finishReason, executionError: actual.executionError }, config);
|
|
100
|
+
return { oracleType: this.type, passed: result.passed, score: result.score, message: result.message, details: result.details };
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
return { oracleType: this.type, passed: false, score: 0, message: `Well-formedness evaluation error: ${error.message}` };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=AgentDecisionOracle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentDecisionOracle.js","sourceRoot":"","sources":["../../src/oracles/AgentDecisionOracle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Sub-agent dispatch oracle — the shipped-but-missing `trace-validate-sub-agents`.
|
|
3
|
+
* @module @memberjunction/testing-engine
|
|
4
|
+
*/
|
|
5
|
+
import { IOracle } from './IOracle.js';
|
|
6
|
+
import { OracleInput, OracleConfig, OracleResult } from '../types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Validates which sub-agents an agent run dispatched, and how many iterations it took.
|
|
9
|
+
*
|
|
10
|
+
* **This oracle was referenced by shipped metadata before it existed.** Both stock research-agent
|
|
11
|
+
* tests configure `trace-validate-sub-agents` and weight it at 0.25 and 0.3 respectively; with no
|
|
12
|
+
* implementation registered, the engine logged `Oracle not found` and a quarter to a third of each
|
|
13
|
+
* test's weight silently vanished from the score. The tests reported green on the remaining
|
|
14
|
+
* oracles. That is the defect this closes (test plan §2, gap 5).
|
|
15
|
+
*
|
|
16
|
+
* **Traversal.** Sub-agent runs are reached through the **Sub-Agent step's `TargetLogID`**, not
|
|
17
|
+
* through `AIAgentRun.ParentRunID`. The generated ORM is explicit that ParentRunID "records
|
|
18
|
+
* parentage but is not a link the tree traverses", and the platform's own run-tree walk uses the
|
|
19
|
+
* step link — so querying by ParentRunID would find runs the platform does not consider part of
|
|
20
|
+
* this tree, and miss none that it does. The walk recurses, because a sub-agent may dispatch its
|
|
21
|
+
* own, and a required agent two levels down was still dispatched by this run.
|
|
22
|
+
*
|
|
23
|
+
* Configuration (as the shipped tests already supply it):
|
|
24
|
+
* - `requiredAgents`: names that must appear
|
|
25
|
+
* - `forbiddenAgents`: names that must not
|
|
26
|
+
* - `minIterations`: minimum Prompt steps on the top-level run
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```json
|
|
30
|
+
* { "type": "trace-validate-sub-agents", "weight": 0.3,
|
|
31
|
+
* "config": { "requiredAgents": ["Database Research Agent", "Web Research Agent"], "minIterations": 1 } }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare class TraceSubAgentValidatorOracle implements IOracle {
|
|
35
|
+
readonly type = "trace-validate-sub-agents";
|
|
36
|
+
/** Guard against a cyclic or pathologically deep run tree; real trees are 2–3 levels. */
|
|
37
|
+
private static readonly MAX_DEPTH;
|
|
38
|
+
evaluate(input: OracleInput, config: OracleConfig): Promise<OracleResult>;
|
|
39
|
+
/** Walks the run tree, collecting dispatched sub-agent names and the parent's iteration count. */
|
|
40
|
+
private collectFacts;
|
|
41
|
+
private loadSteps;
|
|
42
|
+
private loadRun;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=TraceSubAgentValidatorOracle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TraceSubAgentValidatorOracle.d.ts","sourceRoot":"","sources":["../../src/oracles/TraceSubAgentValidatorOracle.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGnE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,4BAA6B,YAAW,OAAO;IACxD,QAAQ,CAAC,IAAI,+BAA+B;IAE5C,yFAAyF;IACzF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAK;IAEhC,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAoB/E,kGAAkG;YACpF,YAAY;YA8BZ,SAAS;YAUT,OAAO;CAQxB"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Sub-agent dispatch oracle — the shipped-but-missing `trace-validate-sub-agents`.
|
|
3
|
+
* @module @memberjunction/testing-engine
|
|
4
|
+
*/
|
|
5
|
+
import { RunView } from '@memberjunction/core';
|
|
6
|
+
import { evaluateSubAgentTrace } from '../eval/subAgentTrace.js';
|
|
7
|
+
/**
|
|
8
|
+
* Validates which sub-agents an agent run dispatched, and how many iterations it took.
|
|
9
|
+
*
|
|
10
|
+
* **This oracle was referenced by shipped metadata before it existed.** Both stock research-agent
|
|
11
|
+
* tests configure `trace-validate-sub-agents` and weight it at 0.25 and 0.3 respectively; with no
|
|
12
|
+
* implementation registered, the engine logged `Oracle not found` and a quarter to a third of each
|
|
13
|
+
* test's weight silently vanished from the score. The tests reported green on the remaining
|
|
14
|
+
* oracles. That is the defect this closes (test plan §2, gap 5).
|
|
15
|
+
*
|
|
16
|
+
* **Traversal.** Sub-agent runs are reached through the **Sub-Agent step's `TargetLogID`**, not
|
|
17
|
+
* through `AIAgentRun.ParentRunID`. The generated ORM is explicit that ParentRunID "records
|
|
18
|
+
* parentage but is not a link the tree traverses", and the platform's own run-tree walk uses the
|
|
19
|
+
* step link — so querying by ParentRunID would find runs the platform does not consider part of
|
|
20
|
+
* this tree, and miss none that it does. The walk recurses, because a sub-agent may dispatch its
|
|
21
|
+
* own, and a required agent two levels down was still dispatched by this run.
|
|
22
|
+
*
|
|
23
|
+
* Configuration (as the shipped tests already supply it):
|
|
24
|
+
* - `requiredAgents`: names that must appear
|
|
25
|
+
* - `forbiddenAgents`: names that must not
|
|
26
|
+
* - `minIterations`: minimum Prompt steps on the top-level run
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```json
|
|
30
|
+
* { "type": "trace-validate-sub-agents", "weight": 0.3,
|
|
31
|
+
* "config": { "requiredAgents": ["Database Research Agent", "Web Research Agent"], "minIterations": 1 } }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export class TraceSubAgentValidatorOracle {
|
|
35
|
+
constructor() {
|
|
36
|
+
this.type = 'trace-validate-sub-agents';
|
|
37
|
+
}
|
|
38
|
+
/** Guard against a cyclic or pathologically deep run tree; real trees are 2–3 levels. */
|
|
39
|
+
static { this.MAX_DEPTH = 6; }
|
|
40
|
+
async evaluate(input, config) {
|
|
41
|
+
try {
|
|
42
|
+
const agentRun = input.targetEntity;
|
|
43
|
+
if (!agentRun?.ID) {
|
|
44
|
+
return { oracleType: this.type, passed: false, score: 0, message: 'No agent run entity provided' };
|
|
45
|
+
}
|
|
46
|
+
const facts = await this.collectFacts(agentRun.ID, input.contextUser);
|
|
47
|
+
const result = evaluateSubAgentTrace(facts, config);
|
|
48
|
+
return { oracleType: this.type, passed: result.passed, score: result.score, message: result.message, details: result.details };
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return {
|
|
52
|
+
oracleType: this.type,
|
|
53
|
+
passed: false,
|
|
54
|
+
score: 0,
|
|
55
|
+
message: `Sub-agent trace validation error: ${error.message}`
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Walks the run tree, collecting dispatched sub-agent names and the parent's iteration count. */
|
|
60
|
+
async collectFacts(rootRunID, contextUser) {
|
|
61
|
+
const dispatchedAgents = [];
|
|
62
|
+
const visited = new Set();
|
|
63
|
+
const rootSteps = await this.loadSteps(rootRunID, contextUser);
|
|
64
|
+
// Iterations are the PARENT's prompt steps only — a sub-agent's prompts are its own passes.
|
|
65
|
+
const iterations = rootSteps.filter((s) => s.StepType === 'Prompt').length;
|
|
66
|
+
const walk = async (steps, depth) => {
|
|
67
|
+
if (depth > TraceSubAgentValidatorOracle.MAX_DEPTH) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
for (const step of steps) {
|
|
71
|
+
if (step.StepType !== 'Sub-Agent' || !step.TargetLogID || visited.has(step.TargetLogID)) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
visited.add(step.TargetLogID);
|
|
75
|
+
const childRun = await this.loadRun(step.TargetLogID, contextUser);
|
|
76
|
+
// Fall back to the step name when the child run is unreadable: a dispatch that
|
|
77
|
+
// happened is a fact worth recording even if the child row cannot be loaded.
|
|
78
|
+
dispatchedAgents.push(childRun?.Agent?.trim() || step.StepName?.trim() || '(unnamed sub-agent)');
|
|
79
|
+
if (childRun) {
|
|
80
|
+
await walk(await this.loadSteps(childRun.ID, contextUser), depth + 1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
await walk(rootSteps, 1);
|
|
85
|
+
return { dispatchedAgents, iterations };
|
|
86
|
+
}
|
|
87
|
+
async loadSteps(agentRunID, contextUser) {
|
|
88
|
+
const result = await new RunView().RunView({
|
|
89
|
+
EntityName: 'MJ: AI Agent Run Steps',
|
|
90
|
+
ExtraFilter: `AgentRunID='${agentRunID}'`,
|
|
91
|
+
OrderBy: 'StepNumber',
|
|
92
|
+
ResultType: 'entity_object'
|
|
93
|
+
}, contextUser);
|
|
94
|
+
return result.Success ? (result.Results ?? []) : [];
|
|
95
|
+
}
|
|
96
|
+
async loadRun(agentRunID, contextUser) {
|
|
97
|
+
const result = await new RunView().RunView({
|
|
98
|
+
EntityName: 'MJ: AI Agent Runs',
|
|
99
|
+
ExtraFilter: `ID='${agentRunID}'`,
|
|
100
|
+
ResultType: 'entity_object'
|
|
101
|
+
}, contextUser);
|
|
102
|
+
return result.Success && result.Results?.length === 1 ? result.Results[0] : null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=TraceSubAgentValidatorOracle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TraceSubAgentValidatorOracle.js","sourceRoot":"","sources":["../../src/oracles/TraceSubAgentValidatorOracle.ts"],"names":[],"mappings":"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"}
|
package/dist/oracles/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
export * from './IOracle.js';
|
|
5
5
|
export * from './SchemaValidatorOracle.js';
|
|
6
6
|
export * from './TraceValidatorOracle.js';
|
|
7
|
+
export * from './TraceSubAgentValidatorOracle.js';
|
|
8
|
+
export * from './AgentDecisionOracle.js';
|
|
7
9
|
export * from './LLMJudgeOracle.js';
|
|
8
10
|
export * from './ExactMatchOracle.js';
|
|
9
11
|
export * from './SQLValidatorOracle.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oracles/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oracles/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC"}
|
package/dist/oracles/index.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
export * from './IOracle.js';
|
|
5
5
|
export * from './SchemaValidatorOracle.js';
|
|
6
6
|
export * from './TraceValidatorOracle.js';
|
|
7
|
+
export * from './TraceSubAgentValidatorOracle.js';
|
|
8
|
+
export * from './AgentDecisionOracle.js';
|
|
7
9
|
export * from './LLMJudgeOracle.js';
|
|
8
10
|
export * from './ExactMatchOracle.js';
|
|
9
11
|
export * from './SQLValidatorOracle.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oracles/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oracles/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/testing-engine",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "6.1.0
|
|
4
|
+
"version": "6.1.0",
|
|
5
5
|
"description": "MemberJunction Testing Framework Engine - Core test execution and evaluation engine supporting multiple test types",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -17,15 +17,15 @@
|
|
|
17
17
|
"vitest": "^4.0.18"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@memberjunction/ai": "6.1.0
|
|
21
|
-
"@memberjunction/ai-agents": "6.1.0
|
|
22
|
-
"@memberjunction/ai-core-plus": "6.1.0
|
|
23
|
-
"@memberjunction/ai-prompts": "6.1.0
|
|
24
|
-
"@memberjunction/aiengine": "6.1.0
|
|
25
|
-
"@memberjunction/core": "6.1.0
|
|
26
|
-
"@memberjunction/core-entities": "6.1.0
|
|
27
|
-
"@memberjunction/global": "6.1.0
|
|
28
|
-
"@memberjunction/testing-engine-base": "6.1.0
|
|
20
|
+
"@memberjunction/ai": "6.1.0",
|
|
21
|
+
"@memberjunction/ai-agents": "6.1.0",
|
|
22
|
+
"@memberjunction/ai-core-plus": "6.1.0",
|
|
23
|
+
"@memberjunction/ai-prompts": "6.1.0",
|
|
24
|
+
"@memberjunction/aiengine": "6.1.0",
|
|
25
|
+
"@memberjunction/core": "6.1.0",
|
|
26
|
+
"@memberjunction/core-entities": "6.1.0",
|
|
27
|
+
"@memberjunction/global": "6.1.0",
|
|
28
|
+
"@memberjunction/testing-engine-base": "6.1.0",
|
|
29
29
|
"debug": "^4.4.3",
|
|
30
30
|
"rxjs": "^7.8.2",
|
|
31
31
|
"zod": "^3.25.0"
|