Skip to content

Commit 68f35a5

Browse files
committed
v0.2.3:
1 parent 01b98db commit 68f35a5

8 files changed

Lines changed: 64 additions & 14 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ __pycache__/
1919
# Distribution / packaging
2020
.Python
2121
build/
22+
!ui/frontend/src/app/build/
2223
develop-eggs/
2324
dist/
2425
downloads/

autochecklist/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class ChecklistItem(BaseModel):
2929

3030
id: str = Field(default_factory=lambda: str(uuid.uuid4())[:8])
3131
question: str
32-
weight: float = Field(default=100.0, ge=0.0, le=100.0) # RLCF uses 0-100
32+
weight: float = 100.0 # RLCF uses 0-100; constraint omitted for cross-provider JSON-schema compat
3333
category: Optional[str] = None # For grouping (e.g., "factuality", "format")
3434
metadata: Dict[str, Any] = Field(default_factory=dict)
3535

@@ -263,7 +263,7 @@ class GeneratedQuestion(BaseModel):
263263
class GeneratedWeightedQuestion(BaseModel):
264264
"""A single generated yes/no question with importance weight."""
265265
question: str
266-
weight: int = Field(ge=0, le=100)
266+
weight: int # 0-100; constraint omitted for cross-provider JSON-schema compat (see ChecklistItem.weight)
267267

268268

269269
class ChecklistResponse(BaseModel):

autochecklist/refiners/base.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,26 @@ def _call_model(
7575
prompt: str,
7676
system_prompt: Optional[str] = None,
7777
response_format: Optional[Dict] = None,
78+
model: Optional[str] = None,
7879
) -> str:
79-
"""Call the LLM and return the response text."""
80+
"""Call the LLM and return the response text.
81+
82+
Args:
83+
prompt: User message content.
84+
system_prompt: Optional system message.
85+
response_format: Optional structured-output spec.
86+
model: Optional model override. Defaults to ``self.model`` when
87+
not provided. Useful when a refiner has a secondary model
88+
role (e.g. ``Selector.classifier_model``).
89+
"""
8090
messages: List[Dict[str, str]] = []
8191
if system_prompt:
8292
messages.append({"role": "system", "content": system_prompt})
8393
messages.append({"role": "user", "content": prompt})
8494

8595
client = self._get_or_create_client()
8696
kwargs: Dict[str, Any] = {
87-
"model": self.model,
97+
"model": model if model is not None else self.model,
8898
"messages": messages,
8999
"temperature": self.temperature,
90100
"max_tokens": 2048,

autochecklist/refiners/selector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ def _classify_feedback(self, checklist: Checklist) -> Dict[int, Set[int]]:
281281
questions=questions_text,
282282
feedback_item=fb_item,
283283
)
284-
response = self._call_model(prompt)
284+
response = self._call_model(prompt, model=self.classifier_model)
285285

286286
# Parse question numbers from response
287287
nums = re.findall(r"\d+", response)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "autochecklist"
3-
version = "0.2.2"
3+
version = "0.2.3"
44
description = "A library of checklist generation and scoring methods for LLM evaluation"
55
authors = [{name = "ChicagoHAI"}]
66
readme = "README.pypi.md"

tests/test_models/test_core_models.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,14 @@ def test_weighted_checklist_response_valid(self):
135135
assert resp.questions[0].weight == 100
136136
assert resp.questions[1].weight == 50
137137

138-
def test_weighted_question_weight_bounds(self):
139-
# Valid bounds
138+
def test_weighted_question_accepts_full_int_range(self):
139+
# Bounds intentionally not enforced: cross-provider JSON-schema compat
140+
# (OpenAI/Anthropic/Gemini structured-output disagree on `minimum`/`maximum`).
141+
# The 0-100 range is communicated via the generator prompt instead.
140142
GeneratedWeightedQuestion(question="test?", weight=0)
141143
GeneratedWeightedQuestion(question="test?", weight=100)
142-
# Out of bounds
143-
with pytest.raises(ValidationError):
144-
GeneratedWeightedQuestion(question="test?", weight=-1)
145-
with pytest.raises(ValidationError):
146-
GeneratedWeightedQuestion(question="test?", weight=101)
144+
GeneratedWeightedQuestion(question="test?", weight=-1)
145+
GeneratedWeightedQuestion(question="test?", weight=101)
147146

148147
def test_batch_scoring_response_valid(self):
149148
resp = BatchScoringResponse(answers=[

tests/test_refiners/test_selector.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,32 @@ def test_refiner_name(self):
9393
selector = Selector()
9494
assert selector.refiner_name == "selector"
9595

96+
def test_default_classifier_model(self):
97+
"""Default classifier_model should be openai/gpt-4o-mini."""
98+
selector = Selector()
99+
assert selector.classifier_model == "openai/gpt-4o-mini"
100+
101+
def test_custom_classifier_model(self):
102+
"""Should accept custom classifier_model."""
103+
selector = Selector(classifier_model="openai/gpt-5-nano")
104+
assert selector.classifier_model == "openai/gpt-5-nano"
105+
96106

97-
class TestSelectorSmallChecklist:
107+
class TestSelectorClassifierModel:
108+
"""Tests that _classify_feedback honors classifier_model."""
109+
110+
def test_classify_uses_classifier_model_not_self_model(self, small_checklist):
111+
"""_classify_feedback should pass classifier_model, not self.model, to _call_model."""
112+
selector = Selector(
113+
model="anthropic/claude-sonnet-4.6",
114+
classifier_model="openai/gpt-4o-mini",
115+
observations=["obs A", "obs B"],
116+
)
117+
with patch.object(selector, "_call_model", return_value="0") as mock_call:
118+
selector._classify_feedback(small_checklist)
119+
assert mock_call.call_count == 2
120+
for call in mock_call.call_args_list:
121+
assert call.kwargs.get("model") == "openai/gpt-4o-mini"
98122
"""Tests when checklist is already small enough."""
99123

100124
@patch("autochecklist.refiners.selector.get_embeddings")

ui/frontend/src/app/build/page.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"use client";
2+
3+
import { PageHeader } from "@/components/layout/PageHeader";
4+
import { DimensionForm } from "@/components/checklist_builder/DimensionForm";
5+
6+
export default function BuildPage() {
7+
return (
8+
<div className="max-w-4xl mx-auto">
9+
<PageHeader
10+
title="Build a Checklist"
11+
description="Define rubric dimensions to automatically build a checklist with DeductiveGenerator."
12+
/>
13+
<DimensionForm />
14+
</div>
15+
);
16+
}

0 commit comments

Comments
 (0)