Repository navigation
feat(AIC-3534): add a TypeSafe Jev judge handler - #149
andrewklatzke wants to merge 6 commits into
Conversation
Judge variations can declare classifiers and record one score per label, with the selected label as the result reason. Co-authored-by: Cursor <cursoragent@cursor.com>
The package is registered with release-please, and this job is what builds and publishes it. Co-authored-by: Cursor <cursoragent@cursor.com>
A wildcard handler was taking the judge, the tracer name skipped evaluation recording, and Jev never received the original question. Co-authored-by: Cursor <cursoragent@cursor.com>
jeffdupont
left a comment
There was a problem hiding this comment.
Reviewed together with js-ai-sdk #122 and ai-sdks-monorepo #49. The handler matches the spec and the JS side. I checked it against typesafe_sdk 0.7.2: NoulAnswer.noul is a float, and ScoreAnswer.legend is keyed by integer levels starting at 0, so the score mapping is right. The _handler_for rewrite also fixes a real ordering bug: before, a wildcard listed first beat an exact provider match. The new skip for a judge with no matching handler matches JS runJudges.
Tests: 661 passed on this head. Merged into current main (6 conflicts: release-please files, pyproject.toml workspace members, uv.lock, and a docstring in types.py), packages/typesafe plus packages/client give 1586 passed, 1 skipped.
1. Should fix: deferred callers don't know to track metrics. run_judge now returns results / metrics / event_key, and the docstring says to track each metrics entry instead of evaluation_metric_key. But the only deferred guidance in the README is run_judge(task, handlers) on your own thread. A worker written the way it works today tracks evaluation_metric_key with result.score. For a TypeSafe judge, that tracks nothing (no metric key) or tracks the first label under the wrong key. JS #122 updated examples/judge-worker.ts with the pattern. Python needs the same, in the README or an example.
2. Should fix: create_typesafe_handler reports no helper usage. TESTING.md §3.27 makes report_usage(...) the first statement of every public factory, with an ID in api-surface/usage-ids.txt. Every handler on main does it (for example openai-messages/handler.py:231).
Nice to have: questions.py imports FORMATTING_INSTRUCTIONS from the internal module launchdarkly_ai_server.judge_scoring, while JS #122 makes it a public root export. The two languages should agree on whether it's public API.
…-handler Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # .github/workflows/release-please.yml # .release-please-manifest.json # packages/client/src/launchdarkly_ai_server/types.py # pyproject.toml # release-please-config.json # uv.lock
…erred judge metrics Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3cd5635. Configure here.
…e as a judge provider Co-authored-by: Cursor <cursoragent@cursor.com>
jeffdupont
left a comment
There was a problem hiding this comment.
Spec-wise this lines up with §1.12 / A.18 and the api-surface list 👍 One thing: judges.py:192/448 now pass input to every online judge, but TESTING.md:1476 still says online judges get message_history + response_to_evaluate "and nothing else". Probably just needs that line updated in monorepo #49 so the spec agrees with §1.12.

Summary
launchdarkly-ai-typesafe, a judge handler that sends a variation'sclassifiersto Jev in one call.judge_resultsentry, tracked on that label'seventKey, with the selected label as the reason.https://launchdarkly.atlassian.net/browse/AIC-3534
Test plan
pytest packages/typesafe/tests packages/client/tests/test_judges.py packages/client/tests/test_conversation.py packages/client/tests/test_judge_scoring.py packages/client/tests/test_schema.pyresponseMade with Cursor