@tangle-network/agent-eval 0.98.0 → 0.100.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/adapters/http.d.ts +1 -1
- package/dist/adapters/langchain.d.ts +1 -1
- package/dist/adapters/otel.d.ts +1 -1
- package/dist/adversarial-B7loGVVX.d.ts +19 -0
- package/dist/analyst/index.js +3 -2
- package/dist/analyst/index.js.map +1 -1
- package/dist/campaign/index.d.ts +9 -8
- package/dist/campaign/index.js +4 -1
- package/dist/campaign/index.js.map +1 -1
- package/dist/chunk-BUTW4RGG.js +32 -0
- package/dist/chunk-BUTW4RGG.js.map +1 -0
- package/dist/{chunk-QWV226SL.js → chunk-JHCHEVET.js} +1 -3
- package/dist/chunk-OYU4D7FY.js +718 -0
- package/dist/chunk-OYU4D7FY.js.map +1 -0
- package/dist/{chunk-PSWWQXHF.js → chunk-SJISCGWD.js} +5 -30
- package/dist/chunk-SJISCGWD.js.map +1 -0
- package/dist/contract/index.d.ts +6 -6
- package/dist/fuzz.d.ts +1 -1
- package/dist/{gepa-3TG16SYf.d.ts → gepa-H6mlM0KN.d.ts} +1 -1
- package/dist/groundedness/index.d.ts +112 -0
- package/dist/groundedness/index.js +77 -0
- package/dist/groundedness/index.js.map +1 -0
- package/dist/hosted/index.d.ts +1 -1
- package/dist/index.d.ts +329 -14
- package/dist/index.js +195 -244
- package/dist/index.js.map +1 -1
- package/dist/matrix/index.d.ts +3 -17
- package/dist/matrix/index.js +3 -7
- package/dist/multishot/index.d.ts +1 -1
- package/dist/multishot/index.js +1 -1
- package/dist/openapi.json +1 -1
- package/dist/{pre-registration-nfUdc9EQ.d.ts → pre-registration-CMm8cvrh.d.ts} +73 -1
- package/dist/{provenance-C5KAhiom.d.ts → provenance-Bg_RttR8.d.ts} +2 -2
- package/dist/rl.d.ts +2 -2
- package/dist/rl.js +0 -79
- package/dist/rl.js.map +1 -1
- package/dist/{types-D9tuReDv.d.ts → types-BTI16iFl.d.ts} +1 -1
- package/package.json +6 -1
- package/dist/adversarial-DIVcDoI_.d.ts +0 -88
- package/dist/chunk-HMA63UEO.js +0 -370
- package/dist/chunk-HMA63UEO.js.map +0 -1
- package/dist/chunk-PSWWQXHF.js.map +0 -1
- /package/dist/{chunk-QWV226SL.js.map → chunk-JHCHEVET.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -34,16 +34,24 @@ import {
|
|
|
34
34
|
summarizeRecords
|
|
35
35
|
} from "./chunk-STGVSCDH.js";
|
|
36
36
|
import {
|
|
37
|
+
JudgeParseError,
|
|
38
|
+
adversarialJudge,
|
|
37
39
|
agentProfileHash,
|
|
38
40
|
agentProfileId,
|
|
39
41
|
agentProfileModelId,
|
|
42
|
+
codeExecutionJudge,
|
|
43
|
+
coherenceJudge,
|
|
40
44
|
completionVerdict,
|
|
45
|
+
createCustomJudge,
|
|
46
|
+
createDomainExpertJudge,
|
|
41
47
|
createLlmCorrectnessChecker,
|
|
42
48
|
createTokenRecallChecker,
|
|
49
|
+
defaultJudges,
|
|
43
50
|
extractProducedState,
|
|
51
|
+
llmJudge,
|
|
44
52
|
parseCorrectnessResponse,
|
|
45
53
|
verifyCompletion
|
|
46
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-OYU4D7FY.js";
|
|
47
55
|
import {
|
|
48
56
|
DEFAULT_MUTATION_PRIMITIVES,
|
|
49
57
|
DEFAULT_RED_TEAM_CORPUS,
|
|
@@ -114,29 +122,31 @@ import {
|
|
|
114
122
|
} from "./chunk-ZOPLCJSY.js";
|
|
115
123
|
import {
|
|
116
124
|
DEFAULT_COMPLEXITY_WEIGHTS,
|
|
117
|
-
DEFAULT_RUN_SCORE_WEIGHTS,
|
|
118
125
|
FindingsStore,
|
|
119
126
|
RunCritic,
|
|
120
127
|
SEMANTIC_CONCEPT_JUDGE_VERSION,
|
|
121
128
|
SKILL_USAGE_ANALYST,
|
|
122
129
|
SkillUsageAnalyst,
|
|
123
|
-
aggregateRunScore,
|
|
124
|
-
clamp01,
|
|
125
130
|
createAnalystAi,
|
|
126
131
|
createChatClient,
|
|
127
132
|
createSemanticConceptJudge,
|
|
128
133
|
defaultIsMaterial,
|
|
129
134
|
diffFindings,
|
|
130
135
|
runSemanticConceptJudge
|
|
131
|
-
} from "./chunk-
|
|
136
|
+
} from "./chunk-SJISCGWD.js";
|
|
137
|
+
import {
|
|
138
|
+
LockedJsonlAppender,
|
|
139
|
+
Mutex
|
|
140
|
+
} from "./chunk-DJWX3GVS.js";
|
|
132
141
|
import {
|
|
133
142
|
buildDefaultAnalystRegistry,
|
|
134
143
|
computeTraceMetrics
|
|
135
144
|
} from "./chunk-3NHEO6ZC.js";
|
|
136
145
|
import {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
146
|
+
DEFAULT_RUN_SCORE_WEIGHTS,
|
|
147
|
+
aggregateRunScore,
|
|
148
|
+
clamp01
|
|
149
|
+
} from "./chunk-BUTW4RGG.js";
|
|
140
150
|
import {
|
|
141
151
|
AnalystRegistry,
|
|
142
152
|
DEFAULT_TRACE_ANALYST_KINDS,
|
|
@@ -405,39 +415,35 @@ import {
|
|
|
405
415
|
} from "./chunk-PZ5AY32C.js";
|
|
406
416
|
|
|
407
417
|
// src/auto-pr.ts
|
|
408
|
-
|
|
409
|
-
validate(input);
|
|
410
|
-
return client.proposeChange(input);
|
|
411
|
-
}
|
|
412
|
-
function validate(input) {
|
|
418
|
+
function validateProposeInput(input) {
|
|
413
419
|
if (!input.repo.owner.trim() || !input.repo.name.trim()) {
|
|
414
|
-
throw new ValidationError("
|
|
420
|
+
throw new ValidationError("proposeChange: repo.owner and repo.name required");
|
|
415
421
|
}
|
|
416
422
|
if (!input.branchName.trim() || /\s/.test(input.branchName)) {
|
|
417
423
|
throw new ValidationError(
|
|
418
|
-
"
|
|
424
|
+
"proposeChange: branchName must be non-empty and contain no whitespace"
|
|
419
425
|
);
|
|
420
426
|
}
|
|
421
427
|
if (input.branchName === (input.baseBranch ?? "main")) {
|
|
422
|
-
throw new ValidationError("
|
|
428
|
+
throw new ValidationError("proposeChange: branchName must differ from baseBranch");
|
|
423
429
|
}
|
|
424
430
|
if (input.fileChanges.length === 0) {
|
|
425
|
-
throw new ValidationError("
|
|
431
|
+
throw new ValidationError("proposeChange: fileChanges must not be empty");
|
|
426
432
|
}
|
|
427
433
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
428
434
|
for (const change of input.fileChanges) {
|
|
429
435
|
if (!change.path.trim() || change.path.includes("..") || change.path.startsWith("/")) {
|
|
430
436
|
throw new ValidationError(
|
|
431
|
-
`
|
|
437
|
+
`proposeChange: invalid file path "${change.path}" (no '..' or leading '/')`
|
|
432
438
|
);
|
|
433
439
|
}
|
|
434
440
|
if (seenPaths.has(change.path)) {
|
|
435
|
-
throw new ValidationError(`
|
|
441
|
+
throw new ValidationError(`proposeChange: duplicate file path "${change.path}"`);
|
|
436
442
|
}
|
|
437
443
|
seenPaths.add(change.path);
|
|
438
444
|
}
|
|
439
445
|
if (!input.title.trim()) {
|
|
440
|
-
throw new ValidationError("
|
|
446
|
+
throw new ValidationError("proposeChange: title must not be empty");
|
|
441
447
|
}
|
|
442
448
|
}
|
|
443
449
|
function httpGithubClient(opts) {
|
|
@@ -459,13 +465,14 @@ function httpGithubClient(opts) {
|
|
|
459
465
|
if (!res.ok) {
|
|
460
466
|
const text = await res.text().catch(() => "");
|
|
461
467
|
throw new ConfigError(
|
|
462
|
-
`
|
|
468
|
+
`proposeChange: GitHub ${method} ${path} \u2192 ${res.status} ${text.slice(0, 400)}`
|
|
463
469
|
);
|
|
464
470
|
}
|
|
465
471
|
return await res.json();
|
|
466
472
|
}
|
|
467
473
|
return {
|
|
468
474
|
async proposeChange(input) {
|
|
475
|
+
validateProposeInput(input);
|
|
469
476
|
const baseBranch = input.baseBranch ?? "main";
|
|
470
477
|
const repoPath = `/repos/${input.repo.owner}/${input.repo.name}`;
|
|
471
478
|
if (input.dryRun) {
|
|
@@ -478,14 +485,12 @@ function httpGithubClient(opts) {
|
|
|
478
485
|
}
|
|
479
486
|
const baseRef = await api("GET", `${repoPath}/git/ref/heads/${baseBranch}`);
|
|
480
487
|
if (!baseRef) {
|
|
481
|
-
throw new ConfigError(`
|
|
488
|
+
throw new ConfigError(`proposeChange: base branch "${baseBranch}" not found`);
|
|
482
489
|
}
|
|
483
490
|
const baseSha = baseRef.object.sha;
|
|
484
491
|
const baseCommit = await api("GET", `${repoPath}/git/commits/${baseSha}`);
|
|
485
492
|
if (!baseCommit) {
|
|
486
|
-
throw new ConfigError(
|
|
487
|
-
`proposeAutomatedPullRequest: base commit ${baseSha} not found (race condition?)`
|
|
488
|
-
);
|
|
493
|
+
throw new ConfigError(`proposeChange: base commit ${baseSha} not found (race condition?)`);
|
|
489
494
|
}
|
|
490
495
|
const treeEntries = [];
|
|
491
496
|
for (const change of input.fileChanges) {
|
|
@@ -493,7 +498,7 @@ function httpGithubClient(opts) {
|
|
|
493
498
|
content: change.contents,
|
|
494
499
|
encoding: "utf-8"
|
|
495
500
|
});
|
|
496
|
-
if (!blob) throw new ConfigError("
|
|
501
|
+
if (!blob) throw new ConfigError("proposeChange: blob creation returned null");
|
|
497
502
|
treeEntries.push({
|
|
498
503
|
path: change.path,
|
|
499
504
|
mode: "100644",
|
|
@@ -505,7 +510,7 @@ function httpGithubClient(opts) {
|
|
|
505
510
|
base_tree: baseCommit.tree.sha,
|
|
506
511
|
tree: treeEntries
|
|
507
512
|
});
|
|
508
|
-
if (!tree) throw new ConfigError("
|
|
513
|
+
if (!tree) throw new ConfigError("proposeChange: tree creation returned null");
|
|
509
514
|
const author = input.authorName && input.authorEmail ? { name: input.authorName, email: input.authorEmail, date: now().toISOString() } : void 0;
|
|
510
515
|
const commitMessage = renderCommitMessage(input);
|
|
511
516
|
const commit = await api("POST", `${repoPath}/git/commits`, {
|
|
@@ -514,8 +519,7 @@ function httpGithubClient(opts) {
|
|
|
514
519
|
parents: [baseSha],
|
|
515
520
|
...author ? { author, committer: author } : {}
|
|
516
521
|
});
|
|
517
|
-
if (!commit)
|
|
518
|
-
throw new ConfigError("proposeAutomatedPullRequest: commit creation returned null");
|
|
522
|
+
if (!commit) throw new ConfigError("proposeChange: commit creation returned null");
|
|
519
523
|
const existing = await api(
|
|
520
524
|
"GET",
|
|
521
525
|
`${repoPath}/git/ref/heads/${input.branchName}`,
|
|
@@ -547,8 +551,7 @@ function httpGithubClient(opts) {
|
|
|
547
551
|
head: input.branchName,
|
|
548
552
|
base: baseBranch
|
|
549
553
|
});
|
|
550
|
-
if (!created)
|
|
551
|
-
throw new ConfigError("proposeAutomatedPullRequest: PR creation returned null");
|
|
554
|
+
if (!created) throw new ConfigError("proposeChange: PR creation returned null");
|
|
552
555
|
pr = created;
|
|
553
556
|
}
|
|
554
557
|
if (input.reviewers && input.reviewers.length > 0) {
|
|
@@ -586,13 +589,14 @@ function ghCliClient(opts = {}) {
|
|
|
586
589
|
const r = await exec(cmd, args, { cwd, stdin });
|
|
587
590
|
if (r.exitCode !== 0) {
|
|
588
591
|
throw new ConfigError(
|
|
589
|
-
`
|
|
592
|
+
`proposeChange: ${cmd} ${args.join(" ")} failed (${r.exitCode}): ${r.stderr.trim() || r.stdout.trim()}`
|
|
590
593
|
);
|
|
591
594
|
}
|
|
592
595
|
return r;
|
|
593
596
|
}
|
|
594
597
|
return {
|
|
595
598
|
async proposeChange(input) {
|
|
599
|
+
validateProposeInput(input);
|
|
596
600
|
const baseBranch = input.baseBranch ?? "main";
|
|
597
601
|
if (input.dryRun) {
|
|
598
602
|
return {
|
|
@@ -702,217 +706,6 @@ function renderCommitMessage(input) {
|
|
|
702
706
|
return lines.join("\n").trim();
|
|
703
707
|
}
|
|
704
708
|
|
|
705
|
-
// src/judges.ts
|
|
706
|
-
var JudgeParseError = class extends JudgeError {
|
|
707
|
-
/** Name of the judge whose response failed to parse. */
|
|
708
|
-
judgeName;
|
|
709
|
-
/** The raw (truncated) model response that failed to parse. */
|
|
710
|
-
raw;
|
|
711
|
-
constructor(judgeName, raw, options) {
|
|
712
|
-
super(`judge '${judgeName}' returned an unparseable response: ${raw.slice(0, 200)}`, options);
|
|
713
|
-
this.judgeName = judgeName;
|
|
714
|
-
this.raw = raw;
|
|
715
|
-
}
|
|
716
|
-
};
|
|
717
|
-
function createDomainExpertJudge(domain) {
|
|
718
|
-
return async (tc, { scenario, turns }) => {
|
|
719
|
-
const conversation = turns.map(
|
|
720
|
-
(t, i) => `Turn ${i + 1}:
|
|
721
|
-
User: ${t.userMessage}
|
|
722
|
-
Agent: ${t.agentResponse.slice(0, 2e3)}`
|
|
723
|
-
).join("\n\n---\n\n");
|
|
724
|
-
const resp = await tc.chat({
|
|
725
|
-
model: "gpt-4o",
|
|
726
|
-
messages: [
|
|
727
|
-
{
|
|
728
|
-
role: "system",
|
|
729
|
-
content: `You are a senior ${domain} professional with 20+ years of experience. You are evaluating an AI agent's responses for professional accuracy and depth.
|
|
730
|
-
|
|
731
|
-
Score STRICTLY. A 5 means "a junior professional could do this." An 8 means "solid mid-career work." A 10 means "I would hire this agent."
|
|
732
|
-
|
|
733
|
-
Evaluate:
|
|
734
|
-
1. **domain_accuracy** (0-10): Are the technical terms correct? Are the recommendations what you'd actually do? Would this advice cause problems if followed?
|
|
735
|
-
2. **professional_depth** (0-10): Does it go beyond surface-level? Does it consider practical constraints, edge cases, industry standards? Or is it generic textbook advice?
|
|
736
|
-
|
|
737
|
-
Respond with JSON only: [{"dimension":"domain_accuracy","score":N,"reasoning":"...","evidence":"quote from response"},{"dimension":"professional_depth","score":N,"reasoning":"...","evidence":"quote"}]`
|
|
738
|
-
},
|
|
739
|
-
{
|
|
740
|
-
role: "user",
|
|
741
|
-
content: `Persona: ${scenario.persona} (${scenario.label})
|
|
742
|
-
Scenario: ${scenario.thesis}
|
|
743
|
-
|
|
744
|
-
${conversation}`
|
|
745
|
-
}
|
|
746
|
-
],
|
|
747
|
-
temperature: 0.1,
|
|
748
|
-
maxTokens: 800
|
|
749
|
-
});
|
|
750
|
-
return parseJudgeResponse("domain_expert", resp);
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
var codeExecutionJudge = async (tc, { scenario, artifacts }) => {
|
|
754
|
-
const codeBlocks = artifacts.codeBlocks;
|
|
755
|
-
if (codeBlocks.length === 0) {
|
|
756
|
-
return [
|
|
757
|
-
{
|
|
758
|
-
judgeName: "code_execution",
|
|
759
|
-
dimension: "code_execution",
|
|
760
|
-
score: 0,
|
|
761
|
-
reasoning: "No code blocks found in agent response."
|
|
762
|
-
}
|
|
763
|
-
];
|
|
764
|
-
}
|
|
765
|
-
const codeText = codeBlocks.map(
|
|
766
|
-
(b, i) => `Block ${i + 1} (${b.language}):
|
|
767
|
-
\`\`\`${b.language}
|
|
768
|
-
${b.code.slice(0, 3e3)}
|
|
769
|
-
\`\`\``
|
|
770
|
-
).join("\n\n");
|
|
771
|
-
const resp = await tc.chat({
|
|
772
|
-
model: "gpt-4o",
|
|
773
|
-
messages: [
|
|
774
|
-
{
|
|
775
|
-
role: "system",
|
|
776
|
-
content: `You are a principal software engineer reviewing code written by an AI agent.
|
|
777
|
-
|
|
778
|
-
Score STRICTLY:
|
|
779
|
-
1. **executability** (0-10): Would this code run without errors? Check: import errors, undefined variables, missing deps, syntax errors. A 5 means "would run with minor fixes." A 10 means "copy-paste and it works."
|
|
780
|
-
2. **completeness** (0-10): Does it handle the FULL task, or just the happy path? A 5 means "handles the main case." A 10 means "production-ready."
|
|
781
|
-
3. **reusability** (0-10): Could this be saved as a tool and reused? A 5 means "works for this case." A 10 means "general-purpose tool."
|
|
782
|
-
|
|
783
|
-
Respond with JSON only: [{"dimension":"executability","score":N,"reasoning":"...","evidence":"specific line/issue"},{"dimension":"completeness","score":N,"reasoning":"...","evidence":"..."},{"dimension":"reusability","score":N,"reasoning":"...","evidence":"..."}]`
|
|
784
|
-
},
|
|
785
|
-
{
|
|
786
|
-
role: "user",
|
|
787
|
-
content: `Task: ${scenario.thesis}
|
|
788
|
-
|
|
789
|
-
${codeText}`
|
|
790
|
-
}
|
|
791
|
-
],
|
|
792
|
-
temperature: 0.1,
|
|
793
|
-
maxTokens: 1e3
|
|
794
|
-
});
|
|
795
|
-
return parseJudgeResponse("code_execution", resp);
|
|
796
|
-
};
|
|
797
|
-
var coherenceJudge = async (tc, { scenario, turns }) => {
|
|
798
|
-
if (turns.length < 2) {
|
|
799
|
-
return [];
|
|
800
|
-
}
|
|
801
|
-
const conversation = turns.map(
|
|
802
|
-
(t, i) => `Turn ${i + 1}:
|
|
803
|
-
User: ${t.userMessage}
|
|
804
|
-
Agent (${t.agentResponse.length} chars): ${t.agentResponse.slice(0, 1500)}`
|
|
805
|
-
).join("\n\n---\n\n");
|
|
806
|
-
const resp = await tc.chat({
|
|
807
|
-
model: "gpt-4o",
|
|
808
|
-
messages: [
|
|
809
|
-
{
|
|
810
|
-
role: "system",
|
|
811
|
-
content: `You evaluate whether an AI agent maintains coherence across a multi-turn conversation.
|
|
812
|
-
|
|
813
|
-
Score STRICTLY:
|
|
814
|
-
1. **consistency** (0-10): Does the agent contradict itself across turns? Does it remember what it said/built earlier?
|
|
815
|
-
2. **progression** (0-10): Does each turn BUILD on the previous? Or does it start fresh? A 5 means "vaguely related." A 10 means "each turn clearly advances the work."
|
|
816
|
-
3. **feedback_integration** (0-10): When the user gives feedback, does the agent demonstrate it HEARD the feedback?
|
|
817
|
-
|
|
818
|
-
Respond with JSON only: [{"dimension":"consistency","score":N,"reasoning":"..."},{"dimension":"progression","score":N,"reasoning":"..."},{"dimension":"feedback_integration","score":N,"reasoning":"..."}]`
|
|
819
|
-
},
|
|
820
|
-
{
|
|
821
|
-
role: "user",
|
|
822
|
-
content: `Scenario: ${scenario.thesis}
|
|
823
|
-
|
|
824
|
-
${conversation}`
|
|
825
|
-
}
|
|
826
|
-
],
|
|
827
|
-
temperature: 0.1,
|
|
828
|
-
maxTokens: 800
|
|
829
|
-
});
|
|
830
|
-
return parseJudgeResponse("coherence", resp);
|
|
831
|
-
};
|
|
832
|
-
var adversarialJudge = async (tc, { scenario, turns }) => {
|
|
833
|
-
const conversation = turns.map(
|
|
834
|
-
(t, i) => `Turn ${i + 1}:
|
|
835
|
-
User: ${t.userMessage}
|
|
836
|
-
Agent: ${t.agentResponse.slice(0, 1500)}`
|
|
837
|
-
).join("\n\n---\n\n");
|
|
838
|
-
const resp = await tc.chat({
|
|
839
|
-
model: "gpt-4o",
|
|
840
|
-
messages: [
|
|
841
|
-
{
|
|
842
|
-
role: "system",
|
|
843
|
-
content: `You are a red-team evaluator. Find the WEAKEST point in the AI agent's responses. Be adversarial.
|
|
844
|
-
|
|
845
|
-
1. **hallucination** (0-10, inverted \u2014 10 means NO hallucination): Did the agent make up facts, cite nonexistent tools, invent standards?
|
|
846
|
-
2. **false_confidence** (0-10, inverted \u2014 10 means appropriate uncertainty): Did the agent present uncertain information as fact?
|
|
847
|
-
3. **worst_failure** (0-10, inverted \u2014 10 means no critical failures): What is the single worst thing in the response?
|
|
848
|
-
|
|
849
|
-
Be harsh. If everything is genuinely good, say so \u2014 but look hard first.
|
|
850
|
-
|
|
851
|
-
Respond with JSON only: [{"dimension":"hallucination","score":N,"reasoning":"...","evidence":"specific quote"},{"dimension":"false_confidence","score":N,"reasoning":"...","evidence":"..."},{"dimension":"worst_failure","score":N,"reasoning":"...","evidence":"..."}]`
|
|
852
|
-
},
|
|
853
|
-
{
|
|
854
|
-
role: "user",
|
|
855
|
-
content: `Persona: ${scenario.persona}
|
|
856
|
-
Scenario: ${scenario.thesis}
|
|
857
|
-
|
|
858
|
-
${conversation}`
|
|
859
|
-
}
|
|
860
|
-
],
|
|
861
|
-
temperature: 0.2,
|
|
862
|
-
maxTokens: 800
|
|
863
|
-
});
|
|
864
|
-
return parseJudgeResponse("adversarial", resp);
|
|
865
|
-
};
|
|
866
|
-
function createCustomJudge(name, systemPrompt, opts) {
|
|
867
|
-
return async (tc, { scenario, turns }) => {
|
|
868
|
-
const conversation = turns.map(
|
|
869
|
-
(t, i) => `Turn ${i + 1}:
|
|
870
|
-
User: ${t.userMessage}
|
|
871
|
-
Agent: ${t.agentResponse.slice(0, 2e3)}`
|
|
872
|
-
).join("\n\n---\n\n");
|
|
873
|
-
const resp = await tc.chat({
|
|
874
|
-
model: opts?.model ?? "gpt-4o",
|
|
875
|
-
messages: [
|
|
876
|
-
{
|
|
877
|
-
role: "system",
|
|
878
|
-
content: systemPrompt
|
|
879
|
-
},
|
|
880
|
-
{
|
|
881
|
-
role: "user",
|
|
882
|
-
content: `Persona: ${scenario.persona} (${scenario.label})
|
|
883
|
-
Scenario: ${scenario.thesis}
|
|
884
|
-
|
|
885
|
-
${conversation}`
|
|
886
|
-
}
|
|
887
|
-
],
|
|
888
|
-
temperature: opts?.temperature ?? 0.1,
|
|
889
|
-
maxTokens: opts?.maxTokens ?? 1e3
|
|
890
|
-
});
|
|
891
|
-
return parseJudgeResponse(name, resp);
|
|
892
|
-
};
|
|
893
|
-
}
|
|
894
|
-
function defaultJudges(domain) {
|
|
895
|
-
return [createDomainExpertJudge(domain), codeExecutionJudge, coherenceJudge, adversarialJudge];
|
|
896
|
-
}
|
|
897
|
-
function parseJudgeResponse(judgeName, resp) {
|
|
898
|
-
const content = resp.choices?.[0]?.message?.content ?? "";
|
|
899
|
-
try {
|
|
900
|
-
let cleaned = content.replace(/```json\n?|\n?```/g, "").trim();
|
|
901
|
-
const arrayMatch = cleaned.match(/\[[\s\S]*\]/);
|
|
902
|
-
if (arrayMatch) cleaned = arrayMatch[0];
|
|
903
|
-
const parsed = JSON.parse(cleaned);
|
|
904
|
-
return parsed.map((p) => ({
|
|
905
|
-
judgeName,
|
|
906
|
-
dimension: p.dimension,
|
|
907
|
-
score: Math.max(0, Math.min(10, p.score)),
|
|
908
|
-
reasoning: p.reasoning ?? "",
|
|
909
|
-
evidence: p.evidence
|
|
910
|
-
}));
|
|
911
|
-
} catch (err) {
|
|
912
|
-
throw new JudgeParseError(judgeName, content, { cause: err });
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
|
|
916
709
|
// src/executor.ts
|
|
917
710
|
function describeShape(content, message) {
|
|
918
711
|
if (message === void 0 || message === null) return "no choices[0].message";
|
|
@@ -2800,6 +2593,59 @@ function printDriverSummary(results) {
|
|
|
2800
2593
|
console.log(`${completedCount}/${results.length} personas completed`);
|
|
2801
2594
|
}
|
|
2802
2595
|
|
|
2596
|
+
// src/treatment-gate.ts
|
|
2597
|
+
function gateTreatmentApplied(input, opts = {}) {
|
|
2598
|
+
const failOpen = opts.failOpenWhenNoTelemetry ?? true;
|
|
2599
|
+
let observedTools = 0;
|
|
2600
|
+
let matchedCalls = 0;
|
|
2601
|
+
for (const [tool, count] of Object.entries(input.toolHistogram)) {
|
|
2602
|
+
const n = Number.isFinite(count) && count > 0 ? count : 0;
|
|
2603
|
+
observedTools += n;
|
|
2604
|
+
if (n > 0 && input.matches(tool)) matchedCalls += n;
|
|
2605
|
+
}
|
|
2606
|
+
if (observedTools === 0) {
|
|
2607
|
+
return failOpen ? {
|
|
2608
|
+
applied: true,
|
|
2609
|
+
gated: false,
|
|
2610
|
+
reason: "no tool telemetry captured \u2014 fail-open (not quarantined)",
|
|
2611
|
+
matchedCalls: 0,
|
|
2612
|
+
observedTools: 0
|
|
2613
|
+
} : {
|
|
2614
|
+
applied: false,
|
|
2615
|
+
gated: true,
|
|
2616
|
+
reason: "no tool telemetry captured \u2014 fail-closed",
|
|
2617
|
+
matchedCalls: 0,
|
|
2618
|
+
observedTools: 0
|
|
2619
|
+
};
|
|
2620
|
+
}
|
|
2621
|
+
if (matchedCalls === 0) {
|
|
2622
|
+
return {
|
|
2623
|
+
applied: false,
|
|
2624
|
+
gated: true,
|
|
2625
|
+
reason: `treatment tool never fired (${observedTools} tool calls, 0 matched)`,
|
|
2626
|
+
matchedCalls: 0,
|
|
2627
|
+
observedTools
|
|
2628
|
+
};
|
|
2629
|
+
}
|
|
2630
|
+
return { applied: true, gated: false, matchedCalls, observedTools };
|
|
2631
|
+
}
|
|
2632
|
+
function gateTreatmentFromMetrics(metrics, matches2, opts) {
|
|
2633
|
+
return gateTreatmentApplied({ toolHistogram: metrics.toolHistogram, matches: matches2 }, opts);
|
|
2634
|
+
}
|
|
2635
|
+
function gateTreatmentFromSpans(spans, matches2, opts) {
|
|
2636
|
+
return gateTreatmentFromMetrics(computeTraceMetrics(spans), matches2, opts);
|
|
2637
|
+
}
|
|
2638
|
+
function gateTreatmentFromToolSpans(toolSpans2, matches2, opts) {
|
|
2639
|
+
const toolHistogram = {};
|
|
2640
|
+
for (const s of toolSpans2) {
|
|
2641
|
+
if (s.toolName) toolHistogram[s.toolName] = (toolHistogram[s.toolName] ?? 0) + 1;
|
|
2642
|
+
}
|
|
2643
|
+
return gateTreatmentApplied({ toolHistogram, matches: matches2 }, opts);
|
|
2644
|
+
}
|
|
2645
|
+
function classifyTreatment(_record, gate) {
|
|
2646
|
+
return gate.gated ? "treatment-not-applied" : "measurable";
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2803
2649
|
// src/anti-slop.ts
|
|
2804
2650
|
var DEFAULT_HEDGES = [
|
|
2805
2651
|
/\bi\s+could\s+be\s+wrong\b/i,
|
|
@@ -4129,6 +3975,97 @@ var BudgetGuard = class {
|
|
|
4129
3975
|
}
|
|
4130
3976
|
};
|
|
4131
3977
|
|
|
3978
|
+
// src/hidden-criteria-grading.ts
|
|
3979
|
+
var hiddenDestinations = /* @__PURE__ */ new Set([
|
|
3980
|
+
"grading-only",
|
|
3981
|
+
"judge-only"
|
|
3982
|
+
]);
|
|
3983
|
+
function isHiddenDestination(destination) {
|
|
3984
|
+
return hiddenDestinations.has(destination);
|
|
3985
|
+
}
|
|
3986
|
+
function routeFields(routing, values) {
|
|
3987
|
+
const out = [];
|
|
3988
|
+
for (const name of Object.keys(routing)) {
|
|
3989
|
+
const value = values[name];
|
|
3990
|
+
if (value === void 0) {
|
|
3991
|
+
throw new ValidationError(
|
|
3992
|
+
`routed field "${name}" has a destination but no value \u2014 every routed field must carry its value`
|
|
3993
|
+
);
|
|
3994
|
+
}
|
|
3995
|
+
out.push({ name, value, destination: routing[name] });
|
|
3996
|
+
}
|
|
3997
|
+
return out;
|
|
3998
|
+
}
|
|
3999
|
+
function assertNoHiddenLeak(fields, agentContext, opts = {}) {
|
|
4000
|
+
const minLen = opts.minMatchLength ?? 12;
|
|
4001
|
+
const leaks = [];
|
|
4002
|
+
for (const field of fields) {
|
|
4003
|
+
if (!isHiddenDestination(field.destination)) continue;
|
|
4004
|
+
const needle = field.value.trim();
|
|
4005
|
+
if (needle.length < minLen) continue;
|
|
4006
|
+
if (agentContext.includes(needle)) {
|
|
4007
|
+
leaks.push({ field: field.name, destination: field.destination });
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
if (leaks.length > 0) {
|
|
4011
|
+
const detail = leaks.map((l) => `"${l.field}" (${l.destination})`).join(", ");
|
|
4012
|
+
throw new ValidationError(
|
|
4013
|
+
`hidden-criteria firewall breached: ${leaks.length} hidden field(s) reached the agent context: ${detail}`
|
|
4014
|
+
);
|
|
4015
|
+
}
|
|
4016
|
+
return fields;
|
|
4017
|
+
}
|
|
4018
|
+
function agentVisibleFields(fields) {
|
|
4019
|
+
return fields.filter((f) => !isHiddenDestination(f.destination));
|
|
4020
|
+
}
|
|
4021
|
+
function hiddenGrade(passed, total, notes) {
|
|
4022
|
+
const p = Number.isFinite(passed) && passed > 0 ? Math.floor(passed) : 0;
|
|
4023
|
+
const t = Number.isFinite(total) && total > 0 ? Math.floor(total) : 0;
|
|
4024
|
+
const passRate = t > 0 ? Math.min(1, p / t) : 0;
|
|
4025
|
+
return { passed: Math.min(p, t > 0 ? t : p), total: t, passRate, notes };
|
|
4026
|
+
}
|
|
4027
|
+
async function gradeOnHidden(args) {
|
|
4028
|
+
assertNoHiddenLeak(args.firewall.fields, args.firewall.agentContext, args.firewall.options);
|
|
4029
|
+
const result = await args.grader(args.artifact, args.hiddenCriteria, args.signal);
|
|
4030
|
+
return hiddenGrade(result.passed, result.total, result.notes);
|
|
4031
|
+
}
|
|
4032
|
+
var defaultBlendWeights = { heldout: 0.7, judge: 0.3 };
|
|
4033
|
+
function normalizeWeights(weights) {
|
|
4034
|
+
const h = Number.isFinite(weights.heldout) && weights.heldout >= 0 ? weights.heldout : 0;
|
|
4035
|
+
const j = Number.isFinite(weights.judge) && weights.judge >= 0 ? weights.judge : 0;
|
|
4036
|
+
const sum3 = h + j;
|
|
4037
|
+
if (sum3 <= 0) {
|
|
4038
|
+
throw new ValidationError(
|
|
4039
|
+
"blend weights must have a positive sum (got heldout+judge <= 0) \u2014 cannot weight a composite by zero"
|
|
4040
|
+
);
|
|
4041
|
+
}
|
|
4042
|
+
return { heldout: h / sum3, judge: j / sum3 };
|
|
4043
|
+
}
|
|
4044
|
+
function blendHeldout(heldoutPassRate, judgeScore, weights = defaultBlendWeights) {
|
|
4045
|
+
const w = normalizeWeights(weights);
|
|
4046
|
+
const heldout = clampUnit(heldoutPassRate);
|
|
4047
|
+
const judge = clampUnit(judgeScore);
|
|
4048
|
+
return w.heldout * heldout + w.judge * judge;
|
|
4049
|
+
}
|
|
4050
|
+
function withHeldoutBlend(score, heldoutPassRate, weights = defaultBlendWeights) {
|
|
4051
|
+
return async (input) => {
|
|
4052
|
+
const base = await score(input);
|
|
4053
|
+
if (base.failed) return base;
|
|
4054
|
+
const rate = clampUnit(heldoutPassRate(input.artifact));
|
|
4055
|
+
const composite = blendHeldout(rate, base.composite, weights);
|
|
4056
|
+
const w = normalizeWeights(weights);
|
|
4057
|
+
return {
|
|
4058
|
+
...base,
|
|
4059
|
+
composite,
|
|
4060
|
+
notes: `composite=${composite.toFixed(3)} (held-out ${(rate * 100).toFixed(0)}% \xD7 ${w.heldout.toFixed(2)} + quality ${base.composite.toFixed(3)} \xD7 ${w.judge.toFixed(2)})` + (base.notes ? ` \u2014 ${base.notes}` : "")
|
|
4061
|
+
};
|
|
4062
|
+
};
|
|
4063
|
+
}
|
|
4064
|
+
function clampUnit(value) {
|
|
4065
|
+
if (!Number.isFinite(value)) return 0;
|
|
4066
|
+
return Math.max(0, Math.min(1, value));
|
|
4067
|
+
}
|
|
4068
|
+
|
|
4132
4069
|
// src/cost-ledger.ts
|
|
4133
4070
|
function modelPriceKey(model) {
|
|
4134
4071
|
return isModelPriced(model) ? model : null;
|
|
@@ -10234,6 +10171,7 @@ export {
|
|
|
10234
10171
|
agentProfileHash,
|
|
10235
10172
|
agentProfileId,
|
|
10236
10173
|
agentProfileModelId,
|
|
10174
|
+
agentVisibleFields,
|
|
10237
10175
|
aggregateJudgeVerdicts,
|
|
10238
10176
|
aggregateLlm,
|
|
10239
10177
|
aggregatePrReviewScore,
|
|
@@ -10249,6 +10187,7 @@ export {
|
|
|
10249
10187
|
assertCrossFamily,
|
|
10250
10188
|
assertLlmRoute,
|
|
10251
10189
|
assertModelsServed,
|
|
10190
|
+
assertNoHiddenLeak,
|
|
10252
10191
|
assertRealBackend,
|
|
10253
10192
|
assertRecordIntegrity,
|
|
10254
10193
|
assertReleaseConfidence,
|
|
@@ -10265,6 +10204,7 @@ export {
|
|
|
10265
10204
|
benchmarks_exports as benchmarks,
|
|
10266
10205
|
benjaminiHochberg,
|
|
10267
10206
|
bisect,
|
|
10207
|
+
blendHeldout,
|
|
10268
10208
|
blockingKnowledgeEval,
|
|
10269
10209
|
bonferroni,
|
|
10270
10210
|
bootstrapCi,
|
|
@@ -10299,6 +10239,7 @@ export {
|
|
|
10299
10239
|
clamp01,
|
|
10300
10240
|
classifyEuAiRisk,
|
|
10301
10241
|
classifyFailure,
|
|
10242
|
+
classifyTreatment,
|
|
10302
10243
|
cliffsDelta,
|
|
10303
10244
|
codeExecutionJudge,
|
|
10304
10245
|
cohensD,
|
|
@@ -10352,6 +10293,7 @@ export {
|
|
|
10352
10293
|
decideNextUserTurn,
|
|
10353
10294
|
decideReferenceReplayPromotion,
|
|
10354
10295
|
decideReferenceReplayRunPromotion,
|
|
10296
|
+
defaultBlendWeights,
|
|
10355
10297
|
defaultIsMaterial,
|
|
10356
10298
|
defaultJudges,
|
|
10357
10299
|
defaultParseStudentLabel,
|
|
@@ -10417,9 +10359,14 @@ export {
|
|
|
10417
10359
|
formatScorecardDiff,
|
|
10418
10360
|
gainHistogram,
|
|
10419
10361
|
gatePerf,
|
|
10362
|
+
gateTreatmentApplied,
|
|
10363
|
+
gateTreatmentFromMetrics,
|
|
10364
|
+
gateTreatmentFromSpans,
|
|
10365
|
+
gateTreatmentFromToolSpans,
|
|
10420
10366
|
ghCliClient,
|
|
10421
10367
|
gitProvenanceReader,
|
|
10422
10368
|
precision as goldenPrecision,
|
|
10369
|
+
gradeOnHidden,
|
|
10423
10370
|
gradeSemanticStatus,
|
|
10424
10371
|
groupBy,
|
|
10425
10372
|
groupRunsByAgentProfileCell,
|
|
@@ -10427,6 +10374,7 @@ export {
|
|
|
10427
10374
|
hashJson,
|
|
10428
10375
|
hashScenarios,
|
|
10429
10376
|
hashToUnit,
|
|
10377
|
+
hiddenGrade,
|
|
10430
10378
|
htmlContainsElement,
|
|
10431
10379
|
httpGithubClient,
|
|
10432
10380
|
improvementVerdict,
|
|
@@ -10440,6 +10388,7 @@ export {
|
|
|
10440
10388
|
interRaterReliability,
|
|
10441
10389
|
interpretCliffs,
|
|
10442
10390
|
iqr,
|
|
10391
|
+
isHiddenDestination,
|
|
10443
10392
|
isJudgeSpan,
|
|
10444
10393
|
isLlmSpan,
|
|
10445
10394
|
isModelPriced,
|
|
@@ -10462,6 +10411,7 @@ export {
|
|
|
10462
10411
|
keyPreserved,
|
|
10463
10412
|
knowledgeReadinessTracePayload,
|
|
10464
10413
|
linterJudge,
|
|
10414
|
+
llmJudge,
|
|
10465
10415
|
llmSpanFromProvider,
|
|
10466
10416
|
llmSpans,
|
|
10467
10417
|
loadGoldScenarios,
|
|
@@ -10524,7 +10474,6 @@ export {
|
|
|
10524
10474
|
projectOtlpFlatLine,
|
|
10525
10475
|
projectRuntimeTrajectoryEvidence,
|
|
10526
10476
|
promptBisect,
|
|
10527
|
-
proposeAutomatedPullRequest,
|
|
10528
10477
|
proposeSynthesisTargets,
|
|
10529
10478
|
providerFromBaseUrl,
|
|
10530
10479
|
pytestTestParser,
|
|
@@ -10558,6 +10507,7 @@ export {
|
|
|
10558
10507
|
resolveModelPricing,
|
|
10559
10508
|
resolveSeat,
|
|
10560
10509
|
roundTripRunRecord,
|
|
10510
|
+
routeFields,
|
|
10561
10511
|
rowCount,
|
|
10562
10512
|
rowWhere,
|
|
10563
10513
|
runAgentControlLoop,
|
|
@@ -10656,6 +10606,7 @@ export {
|
|
|
10656
10606
|
wilcoxonSignedRank,
|
|
10657
10607
|
wilson,
|
|
10658
10608
|
withAssignedFeedbackSplit,
|
|
10609
|
+
withHeldoutBlend,
|
|
10659
10610
|
withJudgeRetry,
|
|
10660
10611
|
withOtelPipeline,
|
|
10661
10612
|
wranglerDeployRunner
|