Skip to main content

systemprompt_evaluation/models/
rubric.rs

1//! Rubric model describing judge scoring criteria.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use serde::{Deserialize, Serialize};
7use systemprompt_identifiers::EvalRubricId;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct RubricDimension {
11    pub name: String,
12    pub description: String,
13    #[serde(default = "default_weight")]
14    pub weight: f64,
15}
16
17const fn default_weight() -> f64 {
18    1.0
19}
20
21#[derive(Debug, Clone)]
22pub struct Rubric {
23    pub id: EvalRubricId,
24    pub name: String,
25    pub dimensions: Vec<RubricDimension>,
26    pub pass_threshold: i32,
27    pub prompt_template: Option<String>,
28    pub enabled: bool,
29}
30
31/// Structured output the judge model is constrained to produce.
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct JudgeVerdict {
34    pub overall_score: i32,
35    #[serde(default)]
36    pub dimension_scores: Vec<DimensionScore>,
37    pub rationale: String,
38    #[serde(default)]
39    pub repair_hint: Option<String>,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct DimensionScore {
44    pub name: String,
45    pub score: i32,
46}
47
48impl JudgeVerdict {
49    /// JSON schema the judge request is constrained with; keep in sync with
50    /// the `Deserialize` shape above.
51    #[must_use]
52    pub fn response_schema() -> serde_json::Value {
53        serde_json::json!({
54            "type": "object",
55            "properties": {
56                "overall_score": { "type": "integer", "minimum": 1, "maximum": 5 },
57                "dimension_scores": {
58                    "type": "array",
59                    "items": {
60                        "type": "object",
61                        "properties": {
62                            "name": { "type": "string" },
63                            "score": { "type": "integer", "minimum": 1, "maximum": 5 }
64                        },
65                        "required": ["name", "score"]
66                    }
67                },
68                "rationale": { "type": "string" },
69                "repair_hint": { "type": ["string", "null"] }
70            },
71            "required": ["overall_score", "rationale"]
72        })
73    }
74}