@sanity/ailf 0.3.0 → 0.4.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.
@@ -46,10 +46,11 @@ models:
46
46
  max_tokens: 4096
47
47
  modes: [baseline, observed, agentic-naive, agentic-optimized]
48
48
  - id: openai:chat:gpt-5.4
49
- label: GPT 5.4 (high)
49
+ label: GPT 5.4
50
50
  config:
51
- reasoning_effort: "high"
51
+ reasoning_effort: "medium"
52
52
  max_output_tokens: 4096
53
+ maxRetries: 1
53
54
  modes: [baseline, observed, agentic-naive, agentic-optimized]
54
55
 
55
56
  # ── Anthropic ───────────────────────────────────────────────
@@ -83,6 +83,14 @@ export declare function extractGraderJudgments(resultsPath: string): GraderJudgm
83
83
  * Returns a record keyed by feature area with the composite actual score.
84
84
  */
85
85
  export declare function scoreAgenticResults(resultsPath: string, weights: Record<string, number>): Record<string, ActualScoreEntry>;
86
+ /**
87
+ * Score agentic results broken down by model.
88
+ *
89
+ * Same logic as `scoreAgenticResults` but groups by provider first,
90
+ * producing a map of model → feature → ActualScoreEntry.
91
+ * Used to enrich the per-model breakdown with actual scores in full mode.
92
+ */
93
+ export declare function scoreAgenticResultsPerModel(resultsPath: string, weights: Record<string, number>): Record<string, Record<string, ActualScoreEntry>>;
86
94
  /** Options for the calculate-scores main() function. */
87
95
  export interface CalculateScoresOptions {
88
96
  /** Allowed origins for source isolation reporting */
@@ -648,6 +648,69 @@ export function scoreAgenticResults(resultsPath, weights) {
648
648
  }
649
649
  return entries;
650
650
  }
651
+ /**
652
+ * Score agentic results broken down by model.
653
+ *
654
+ * Same logic as `scoreAgenticResults` but groups by provider first,
655
+ * producing a map of model → feature → ActualScoreEntry.
656
+ * Used to enrich the per-model breakdown with actual scores in full mode.
657
+ */
658
+ export function scoreAgenticResultsPerModel(resultsPath, weights) {
659
+ const results = readAndNormalizeResults(resultsPath);
660
+ const wTask = weights["task-completion"] ?? 0.5;
661
+ const wCode = weights["code-correctness"] ?? 0.25;
662
+ const wDoc = weights["doc-coverage"] ?? 0.25;
663
+ // Group by model, then feature
664
+ const byModel = {};
665
+ for (const result of results) {
666
+ const modelId = result.providerId ?? result.providerLabel ?? "unknown";
667
+ const feature = result.vars.__featureArea || detectFeatureArea(result.description);
668
+ if (!byModel[modelId])
669
+ byModel[modelId] = {};
670
+ if (!byModel[modelId][feature])
671
+ byModel[modelId][feature] = [];
672
+ byModel[modelId][feature].push(result);
673
+ }
674
+ const perModel = {};
675
+ for (const [modelId, features] of Object.entries(byModel)) {
676
+ perModel[modelId] = {};
677
+ for (const [feature, featureResults] of Object.entries(features)) {
678
+ let totalTask = 0;
679
+ let totalCode = 0;
680
+ let totalDoc = 0;
681
+ let featureCost = 0;
682
+ const count = featureResults.length || 1;
683
+ for (const test of featureResults) {
684
+ featureCost += test.cost;
685
+ for (const comp of test.gradingResult.componentResults) {
686
+ if (comp.assertion?.type !== "llm-rubric")
687
+ continue;
688
+ const score = parseRubricScore(comp);
689
+ const kind = classifyRubric(comp);
690
+ if (kind === "taskCompletion")
691
+ totalTask += score;
692
+ else if (kind === "codeCorrectness")
693
+ totalCode += score;
694
+ else if (kind === "docCoverage")
695
+ totalDoc += score;
696
+ }
697
+ }
698
+ const avgTask = totalTask / count;
699
+ const avgCode = totalCode / count;
700
+ const avgDoc = totalDoc / count;
701
+ const actualScore = Math.round(avgTask * wTask + avgCode * wCode + avgDoc * wDoc);
702
+ perModel[modelId][feature] = {
703
+ actualScore,
704
+ codeCorrectness: Math.round(avgCode),
705
+ docCoverage: Math.round(avgDoc),
706
+ taskCompletion: Math.round(avgTask),
707
+ testCount: featureResults.length,
708
+ totalCost: featureCost,
709
+ };
710
+ }
711
+ }
712
+ return perModel;
713
+ }
651
714
  // ---------------------------------------------------------------------------
652
715
  // Score merging — combine baseline floor/ceiling with agentic actual
653
716
  // ---------------------------------------------------------------------------
@@ -736,6 +799,16 @@ export function calculateAndWriteScores(options) {
736
799
  });
737
800
  scores = mergeScores(baselineScores, agenticScores);
738
801
  evaluationMode = "full";
802
+ // Merge agentic actual scores into the per-model breakdown
803
+ if (perModel) {
804
+ const agenticPerModel = scoreAgenticResultsPerModel(agenticResultsPath, rubricConfig.weights);
805
+ for (const entry of perModel) {
806
+ const modelAgentic = agenticPerModel[entry.modelId];
807
+ if (modelAgentic) {
808
+ entry.scores = mergeScores(entry.scores, modelAgentic);
809
+ }
810
+ }
811
+ }
739
812
  // Aggregate agent behavior and source isolation from agentic results
740
813
  agentBehavior = aggregateAgentBehavior(agenticResultsPath);
741
814
  sourceIsolation = aggregateSourceIsolation(agenticResultsPath, options?.allowedOrigins);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/ailf",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "restricted"
@@ -40,9 +40,9 @@
40
40
  "@types/node": "^22.13.1",
41
41
  "tsx": "^4.19.2",
42
42
  "typescript": "^5.7.3",
43
+ "@sanity/ailf-core": "0.1.0",
43
44
  "@sanity/ailf-shared": "0.1.0",
44
- "@sanity/ailf-tasks": "0.1.4",
45
- "@sanity/ailf-core": "0.1.0"
45
+ "@sanity/ailf-tasks": "0.1.4"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "tsc && tsx scripts/bundle-workspace-deps.ts",