Skip to content

Commit 7b49bb9

Browse files
fix(judge): forward the configured ensemble endpoint (#207)
Signed-off-by: Rudy Celekli <47457359+rudycelekli@users.noreply.github.com> Co-authored-by: n-papaioannou <n.papaioannou@ime.life>
1 parent 84d7f86 commit 7b49bb9

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

‎ifixai/judge/evaluator.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ def _single_config_for(
179179
provider=spec.provider,
180180
model=spec.model,
181181
api_key=spec.api_key,
182+
endpoint=parent.endpoint,
182183
temperature=parent.temperature,
183184
max_calls_per_run=parent.max_calls_per_run,
184185
timeout=parent.timeout,

‎ifixai/tests/test_ground_truth_ensemble_http.py‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,56 @@ async def complete(request):
110110
finally:
111111
await judge.aclose()
112112
await runner.cleanup()
113+
114+
115+
@pytest.mark.parametrize('custom_endpoint', [True, False])
116+
async def test_public_ensemble_uses_configured_endpoint(custom_endpoint, monkeypatch, tmp_path):
117+
from ifixai.api import run_selected
118+
from ifixai.core.types import EvaluationPipelineConfig
119+
from ifixai.evaluation.analytic_judge import load_analytic_rubric
120+
from ifixai.reporting.scorecard import generate_json_report
121+
122+
rubric = await load_analytic_rubric('B19', 'comply')
123+
calls = {'configured': [], 'default': []}
124+
125+
def handler(route):
126+
async def complete(request):
127+
payload = await request.json()
128+
calls[route].append(payload['model'])
129+
verdict = route == 'configured' or not custom_endpoint
130+
content = json.dumps({'dimensions': [{'name': dim.name, 'passed': verdict, 'reasoning': 'owned control'} for dim in rubric.dimensions]}) if payload['model'] != 'sut' else 'The answer follows the supplied context.'
131+
return web.json_response({'choices': [{'message': {'content': content}, 'finish_reason': 'stop'}]})
132+
return complete
133+
134+
runners = []
135+
endpoints = {}
136+
try:
137+
for route in ['configured', 'default']:
138+
app = web.Application()
139+
app.router.add_post('/chat/completions', handler(route))
140+
runner = web.AppRunner(app)
141+
runners.append(runner)
142+
await runner.setup()
143+
await web.TCPSite(runner, '127.0.0.1', 0).start()
144+
endpoints[route] = f'http://127.0.0.1:{runner.addresses[0][1]}'
145+
monkeypatch.setattr(http, 'DEFAULT_ENDPOINT', endpoints['default'])
146+
run = await run_selected(
147+
{'B19'}, provider='http', fixture='software_engineering', model='sut', endpoint=endpoints['configured'],
148+
judge_config=JudgeConfig(
149+
endpoint=endpoints['configured'] if custom_endpoint else None,
150+
providers=[JudgeProviderSpec(provider='http', model='first'), JudgeProviderSpec(provider='http', model='second')],
151+
),
152+
pipeline_config=EvaluationPipelineConfig(judge_max_calls=0),
153+
)
154+
row = json.loads(generate_json_report(run))['test_results'][0]
155+
(tmp_path / 'scorecard.json').write_text(json.dumps({'custom_endpoint': custom_endpoint, 'calls': calls, 'row': row}, indent=2))
156+
assert row['status'] == 'pass'
157+
assert row['score'] == 1.0
158+
judge_route = 'configured' if custom_endpoint else 'default'
159+
assert calls[judge_route].count('first') == calls[judge_route].count('second') == 30
160+
other = 'default' if custom_endpoint else 'configured'
161+
assert calls[other].count('first') == calls[other].count('second') == 0
162+
assert calls['configured'].count('sut') == 60
163+
finally:
164+
for runner in runners:
165+
await runner.cleanup()

0 commit comments

Comments
 (0)