@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.
Files changed (43) hide show
  1. package/dist/adapters/http.d.ts +1 -1
  2. package/dist/adapters/langchain.d.ts +1 -1
  3. package/dist/adapters/otel.d.ts +1 -1
  4. package/dist/adversarial-B7loGVVX.d.ts +19 -0
  5. package/dist/analyst/index.js +3 -2
  6. package/dist/analyst/index.js.map +1 -1
  7. package/dist/campaign/index.d.ts +9 -8
  8. package/dist/campaign/index.js +4 -1
  9. package/dist/campaign/index.js.map +1 -1
  10. package/dist/chunk-BUTW4RGG.js +32 -0
  11. package/dist/chunk-BUTW4RGG.js.map +1 -0
  12. package/dist/{chunk-QWV226SL.js → chunk-JHCHEVET.js} +1 -3
  13. package/dist/chunk-OYU4D7FY.js +718 -0
  14. package/dist/chunk-OYU4D7FY.js.map +1 -0
  15. package/dist/{chunk-PSWWQXHF.js → chunk-SJISCGWD.js} +5 -30
  16. package/dist/chunk-SJISCGWD.js.map +1 -0
  17. package/dist/contract/index.d.ts +6 -6
  18. package/dist/fuzz.d.ts +1 -1
  19. package/dist/{gepa-3TG16SYf.d.ts → gepa-H6mlM0KN.d.ts} +1 -1
  20. package/dist/groundedness/index.d.ts +112 -0
  21. package/dist/groundedness/index.js +77 -0
  22. package/dist/groundedness/index.js.map +1 -0
  23. package/dist/hosted/index.d.ts +1 -1
  24. package/dist/index.d.ts +329 -14
  25. package/dist/index.js +195 -244
  26. package/dist/index.js.map +1 -1
  27. package/dist/matrix/index.d.ts +3 -17
  28. package/dist/matrix/index.js +3 -7
  29. package/dist/multishot/index.d.ts +1 -1
  30. package/dist/multishot/index.js +1 -1
  31. package/dist/openapi.json +1 -1
  32. package/dist/{pre-registration-nfUdc9EQ.d.ts → pre-registration-CMm8cvrh.d.ts} +73 -1
  33. package/dist/{provenance-C5KAhiom.d.ts → provenance-Bg_RttR8.d.ts} +2 -2
  34. package/dist/rl.d.ts +2 -2
  35. package/dist/rl.js +0 -79
  36. package/dist/rl.js.map +1 -1
  37. package/dist/{types-D9tuReDv.d.ts → types-BTI16iFl.d.ts} +1 -1
  38. package/package.json +6 -1
  39. package/dist/adversarial-DIVcDoI_.d.ts +0 -88
  40. package/dist/chunk-HMA63UEO.js +0 -370
  41. package/dist/chunk-HMA63UEO.js.map +0 -1
  42. package/dist/chunk-PSWWQXHF.js.map +0 -1
  43. /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-HMA63UEO.js";
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-PSWWQXHF.js";
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
- LockedJsonlAppender,
138
- Mutex
139
- } from "./chunk-DJWX3GVS.js";
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
- async function proposeAutomatedPullRequest(client, input) {
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("proposeAutomatedPullRequest: repo.owner and repo.name required");
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
- "proposeAutomatedPullRequest: branchName must be non-empty and contain no whitespace"
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("proposeAutomatedPullRequest: branchName must differ from baseBranch");
428
+ throw new ValidationError("proposeChange: branchName must differ from baseBranch");
423
429
  }
424
430
  if (input.fileChanges.length === 0) {
425
- throw new ValidationError("proposeAutomatedPullRequest: fileChanges must not be empty");
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
- `proposeAutomatedPullRequest: invalid file path "${change.path}" (no '..' or leading '/')`
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(`proposeAutomatedPullRequest: duplicate file path "${change.path}"`);
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("proposeAutomatedPullRequest: title must not be empty");
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
- `proposeAutomatedPullRequest: GitHub ${method} ${path} \u2192 ${res.status} ${text.slice(0, 400)}`
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(`proposeAutomatedPullRequest: base branch "${baseBranch}" not found`);
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("proposeAutomatedPullRequest: blob creation returned null");
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("proposeAutomatedPullRequest: tree creation returned null");
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
- `proposeAutomatedPullRequest: ${cmd} ${args.join(" ")} failed (${r.exitCode}): ${r.stderr.trim() || r.stdout.trim()}`
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