Skip to content

Commit 727bb7b

Browse files
akshayliveclaude
andauthored
feat(eval-routing): decouple judge/agent_judge backend+model from the agent's route (#137)
* feat(eval-routing): decouple judge/agent_judge backend+model from the agent's own route Adds `checker_context.api_route: {route, model}` on TaskDefinition (4-layer merged like `agent`/`simulation`), letting a task/variant pick which backend and model the evaluation side (llm_judge/agent_judge/simulator) uses, independent of the agent under test — enabling cross-vendor grading and cheaper judge models without editing every task YAML. The override is baked into the resolved ApiRoute's own `model` field before any criterion runs, so criteria stay task-blind (only ever reading CheckContext.route.model, never checker_context/TaskDefinition directly). checker_context validates its shape (unknown namespace/key/backend name raises) both at task-load time and after the experiment-layer merge. Separately, BedrockRoute/LiteLLMRoute no longer carry bearer_token/auth_token fields — those secrets now flow only through the coder_eval.config.settings singleton, read directly by each consumer (ClaudeCodeAgent._build_sdk_env, judge_bedrock.invoke_bedrock_judge_async) at the point of use, so a route object flowing through CheckContext/environment_info/logging never carries a credential. Includes fixes from a code review pass: Bedrock model_override is now region-qualified when reusing the agent's own route (previously shipped a bare alias to the Bedrock API); a missing bearer token now raises JudgeInfrastructureError instead of an assert that handle_criterion_errors was silently downgrading to a scored 0.0; eval_model is now recorded in environment_info; the two orchestrator route-resolution call sites are deduplicated into one helper. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(routing): make _resolve_backend_route's match exhaustive Addresses a CodeQL finding on PR #137: mixing explicit returns per case with an implicit fall-through return (None) reads as a possible bug. Add a raising wildcard arm so every path returns explicitly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(eval-routing): restore DEFAULT_JUDGE_MODEL floor + add litellm judge transport Addresses the PR #137 review blockers and adds the litellm-library-backed LiteLLMRoute judge transport: - resolve_evaluation_route no longer lets the agent's own env-sourced model (e.g. BEDROCK_MODEL) leak into the eval route's `model` on the no-override reuse/pin paths — route.model now means "an explicit checker_context override was given", restoring DEFAULT_JUDGE_MODEL as the judge's floor. - LLMJudgeCriterion.model is now `str | None = None` (was a materialized DEFAULT_JUDGE_MODEL default gated by model_fields_set, which doesn't survive the docker driver's model_dump/reload round trip). Precedence is now `criterion.model or route.model or DEFAULT_JUDGE_MODEL`, computed at check time. - _build_sdk_env's DirectRoute arm now neutralizes inherited Bedrock creds (AWS_BEARER_TOKEN_BEDROCK/CLAUDE_CODE_USE_BEDROCK), matching the LiteLLM arm, so an explicit `route: direct` can't silently spend the operator's Bedrock token. - Implement the `checker_context.api_route.route: litellm` judge transport via the `litellm` library (new `coder-eval[litellm]` extra), with a LiteLLMRoute.include_temperature flag to avoid a live round-trip on gateways that reject `temperature`. - Added ~15 tests covering backend_override/model_override resolution, the judge-model floor regression, docker-serialization round-tripping, and DirectRoute env neutralization — routing.py coverage 69% -> 96.5%. - Doc fixes: corrected stale claims about the judge-model fallback chain, the simulator sharing the agent's ApiRoute, and checker_context's placement/example in the guide and AB_EXPERIMENTS.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * feat(litellm-judge): support arbitrary litellm kwargs via params/auth litellm.acompletion() takes dozens of provider-specific kwargs (aws_access_key_id, vertex_project, api_version, ...) that LiteLLMRoute had no way to express, and secrets couldn't be put in task YAML anyway. Extend checker_context.api_route with two new keys, litellm-route only: - `params`: arbitrary passthrough dict merged straight into the litellm.acompletion() call — no allowlist to maintain, litellm validates param names itself. - `auth`: maps a kwarg name to the ENV VAR NAME (never the secret value) to resolve it from right before the call — so an arbitrary provider's auth shape (IAM keys, an Azure AD token, ...) is representable without a dedicated field per provider and without a secret ever landing in YAML. The plain LITELLM_AUTH_TOKEN requirement is relaxed to "LITELLM_AUTH_TOKEN OR a non-empty `auth` override", since some providers (e.g. Bedrock via IAM) have no `api_key` concept at all. `validate_checker_context_shape` rejects `params`/`auth` on any route other than `litellm` at task-load time, and type-checks `auth`'s values are env-var-name strings. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * refactor(litellm-judge): drop settings coupling, rename auth to env_params Per review: the litellm judge transport was silently reading from coder_eval.config.settings (litellm_base_url/litellm_auth_token) even though checker_context.api_route.route: litellm is meant to be fully task-author-owned and independent of the agent's own LiteLLM backend. - LiteLLMRoute no longer carries base_url at all -- the agent's own LiteLLM backend (_build_sdk_env, environment_info recording) now reads settings.litellm_base_url directly instead of storing it on the route, mirroring how the bearer token is already handled. - The checker's litellm route is built ENTIRELY from checker_context.api_route.{params,env_params} -- no implicit fallback to the agent's LITELLM_BASE_URL/LITELLM_AUTH_TOKEN. `model` is now required when route: litellm (no default open-weight/gateway model). - Renamed `auth` -> `env_params` for clarity (it's not auth-specific -- api_base, aws_region_name, etc. can all be env-sourced too). - Removed LiteLLMRoute.include_temperature and the BadRequestError retry-without-temperature logic: invoke_litellm_judge_async no longer takes a `temperature` kwarg at all -- a gateway-routed model may reject it outright (observed live against an Azure AI deployment) with no reliable way to detect that in advance, so the task author opts in via `params: {temperature: ...}` if their model accepts it. Verified end-to-end against a real Azure AI gateway (checker_context: {api_route: {route: litellm, model: azure/gpt-5.6-luna, env_params: {api_base: LITELLM_BASE_URL, api_key: LITELLM_AUTH_TOKEN}}}) -- SUCCESS, score 1.000. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * ci(fix): install litellm extra for pyright, address CodeQL findings Two CI gates (Quality Gate, Windows Smoke Test) were failing pyright: without `--extra litellm` in `uv sync`, `import litellm` in judge_litellm.py resolved to the repo's own top-level `litellm/` directory (the LiteLLM PROXY scripts, a namespace package with no `acompletion`/`exceptions`/`types.utils`) instead of the real PyPI package, since the real litellm distribution was never installed. Also fixes 4 CodeQL findings from the latest analysis: - routing.py: resolve_route()'s match (unlike its sibling _resolve_backend_route) had no `case _:`, so a 4th ApiBackend member would silently fall through and return None (mixed explicit/implicit returns) — added the same exhaustive-match guard. - test_llm_judge_criterion.py: two redundant local `import json` (already imported at module top). - test_orchestrator.py: `coder_eval.orchestrator` was imported both via `import ... as orch_mod` and `from ... import Orchestrator, ...` — patch `coder_eval.config.settings` directly instead (same singleton object orchestrator.py already imports). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(checker-context): typed model, reject litellm+agent_judge/sim, live test Addresses bai-uipath's PR #137 follow-up review: - Blocking: checker_context.api_route.route: litellm dispatches llm_judge through the litellm library in-process, but agent_judge and the simulator run as real Claude Code CLI subprocesses speaking Anthropic Messages only. Orchestrator._reject_litellm_eval_route_if_unsupported() now raises a clear error at route-resolution time when route: litellm is combined with an enabled agent_judge criterion or simulation.enabled, instead of silently misrouting onto the agent's own unrelated LiteLLM settings. - checker_context is now typed (CheckerContext/ApiRouteContext pydantic models, extra="forbid") instead of a hand-validated open dict — deletes validate_checker_context_shape and its two call sites. A YAML `model: 5` is now rejected at load time instead of being str()-ified into a model id. _resolve_checker_context merges through the shared merge_layers engine (mirroring _resolve_simulation) and records config lineage. - Added tests/test_litellm_judge_live.py: a live regression test hitting a real gateway via litellm.acompletion, reusing the existing CODEX_API_KEY/ CODEX_BASE_URL/CODEX_MODEL CI secrets, wired into the codex-live-tests CI job — closes "nothing in the repo exercises the feature". - Docs: azure_ai/ -> azure/ (matches what actually ran), api_version pinning guidance, documents the new agent_judge/simulator restriction. - Fixed a vacuous test assertion: the orchestrator secret-leak test now actually sets litellm_auth_token before asserting it's absent from environment_info. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * ci: retrigger checks (previous push did not trigger CI) * ci: retrigger checks (GH Actions appeared stalled repo-wide) --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
1 parent dd918e6 commit 727bb7b

34 files changed

Lines changed: 1998 additions & 161 deletions

.github/workflows/pr-checks.yml

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ jobs:
8080
pip install uv
8181
8282
- name: Install project dependencies (hash-verified from uv.lock)
83-
run: uv sync --frozen --extra dev --extra uipath --extra codex
83+
run: uv sync --frozen --extra dev --extra uipath --extra codex --extra litellm
8484

8585
# PHASE 1: Fast checks (fail early)
8686
- name: Check code formatting (ruff format)
@@ -385,7 +385,7 @@ jobs:
385385
pip install uv
386386
387387
- name: Install project dependencies (hash-verified from uv.lock)
388-
run: uv sync --frozen --extra dev --extra uipath --extra codex
388+
run: uv sync --frozen --extra dev --extra uipath --extra codex --extra litellm
389389

390390
- name: Check code formatting (ruff format)
391391
run: .venv/Scripts/ruff format --check src/ tests/
@@ -843,8 +843,8 @@ jobs:
843843
python -m pip install --upgrade "pip>=26.2" # PYSEC-2026-3721 fix floor
844844
pip install uv
845845
846-
- name: Install project dependencies (with codex extra)
847-
run: uv sync --frozen --extra dev --extra uipath --extra codex
846+
- name: Install project dependencies (with codex + litellm extras)
847+
run: uv sync --frozen --extra dev --extra uipath --extra codex --extra litellm
848848

849849
- name: Verify required secrets are present
850850
run: |
@@ -854,14 +854,17 @@ jobs:
854854
fi
855855
echo "CODEX_API_KEY present."
856856
857-
- name: Run Codex live tests
857+
- name: Run Codex + litellm-judge live tests
858858
run: |
859859
mkdir -p tmp
860860
# Run serially: `-n0` overrides the global `-n auto` (addopts).
861861
# Parallel xdist workers share ~/.codex and race the Codex SQLite
862862
# state migration (`duplicate column name: thread_id`); serial init
863-
# migrates the fresh DB exactly once.
864-
.venv/bin/pytest tests/test_codex_agent_live.py \
863+
# migrates the fresh DB exactly once. test_litellm_judge_live.py
864+
# reuses these same CODEX_* secrets to exercise
865+
# checker_context.api_route.route: litellm end-to-end (PR #137
866+
# review: "nothing in the repo exercises the feature").
867+
.venv/bin/pytest tests/test_codex_agent_live.py tests/test_litellm_judge_live.py \
865868
-m live -n0 -v --tb=short --strict-markers -ra \
866869
--junit-xml=tmp/junit-codex-live.xml
867870
@@ -878,7 +881,7 @@ jobs:
878881
passed = total - skipped - errors - failures
879882
print(f"codex-live passed={passed} skipped={skipped} errors={errors} failures={failures}")
880883
if passed < 1:
881-
sys.exit("test_codex_agent_live.py reported zero PASSED tests (missing API key / silent skip?)")
884+
sys.exit("Live Codex/litellm-judge tests reported zero PASSED tests (missing API key / silent skip?)")
882885
PY
883886
884887
- name: Upload Codex live-test artifacts on failure

docs/AB_EXPERIMENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ From `ExperimentVariant` (`coder_eval/models/experiment.py`):
130130
| `initial_prompt_file` | str | Prompt replacement loaded from a file |
131131
| `run_limits` | block | Per-key cap overrides (`max_turns`, `task_timeout`, token/USD budgets) |
132132
| `driver` | `tempdir`/`docker` | Sandbox driver — enables tempdir-vs-docker arms |
133+
| `checker_context` | dict | Backend/model override for the evaluation side (judge, simulator) — see [Checker Context](TASK_DEFINITION_GUIDE.md#checker-context); **not** currently `-D`-reachable |
133134

134135
The `agent` dict is the lever for most A/B tests. Anything on `AgentConfig` is
135136
fair game: `model`, `permission_mode`, `allowed_tools`, `disallowed_tools`,

docs/DIALOG_MODE.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,11 @@ The mechanics:
6060
- The simulator is a **tools-disabled Claude Code agent** with `allowed_tools: []`, an explicit
6161
deny-list, and no plugins or settings sources. It is pure text-in / text-out, and it **cannot see
6262
the sandbox** — no files, no terminal, no agent reasoning. Only what the agent writes in the chat.
63-
- The simulator shares the coding agent's resolved `ApiRoute`, so backend and model come from the
64-
run's routing (`--backend direct` / `--backend bedrock`) rather than from the `simulation:` block.
65-
There is no model field here to set.
63+
- The simulator runs on the run's resolved *evaluation* `ApiRoute` — the coding agent's own route
64+
(`--backend direct` / `--backend bedrock`) unless `checker_context.api_route.route` overrides it
65+
(see [Checker Context](TASK_DEFINITION_GUIDE.md#checker-context)). The **model** is separately
66+
pinned by `simulation.model` (see [Simulation](TASK_DEFINITION_GUIDE.md#simulation)), not inherited
67+
from the route — so an A/B varying the subject model doesn't silently vary the simulated user too.
6668

6769
**Agent-kind constraint.** The *subject* agent can be any registered kind — the dialog driver only
6870
calls the agent's `communicate()`, so Codex and plugin agents work. The *simulator*, however, is

docs/TASK_DEFINITION_GUIDE.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Complete reference for defining evaluation tasks in Coder Eval.
3535
- [llm_judge](#llm_judge)
3636
- [agent_judge](#agent_judge)
3737
- [skill_triggered](#skill_triggered)
38+
- [Checker Context](#checker-context)
3839
- [Reference Solutions](#reference-solutions)
3940
- [Pre-Run Commands](#pre-run-commands)
4041
- [Post-Run Commands](#post-run-commands)
@@ -63,6 +64,7 @@ reference: { ... } # Optional reference solution (a directory
6364
pre_run: [ ... ] # Optional pre-run commands (before agent starts)
6465
post_run: [ ... ] # Optional post-run commands
6566
dataset: { ... } # Optional dataset fan-out (one task -> N row-tasks)
67+
checker_context: { ... } # Optional: backend/model for the evaluation side (judge, simulator)
6668
```
6769
6870
### `dataset`
@@ -1295,6 +1297,40 @@ Observed label is `"yes"` when either signal is found, else `"no"`. Expected lab
12951297

12961298
**Typical pattern.** Label each dataset row with its true skill (`expected_skill`, `""` for negatives) and stack one `skill_triggered` criterion per skill against the same dataset — each gets its own confusion matrix from the same agent traces. This is the natural companion to a skill A/B experiment (skill plugin on vs. off); see the [A/B Experiment Guide](AB_EXPERIMENTS.md#recipe-ab-a-skill).
12971299

1300+
## Checker Context
1301+
1302+
`checker_context` carries task-authored config for the success-checking side, namespaced by reserved key. Currently the only recognized namespace is **`api_route`**:
1303+
1304+
```yaml
1305+
success_criteria:
1306+
- type: llm_judge
1307+
prompt: "Grade the fix for correctness."
1308+
1309+
checker_context:
1310+
api_route:
1311+
route: bedrock # which backend the whole eval side (llm_judge/agent_judge/simulator) uses
1312+
model: claude-haiku-4-5 # model override for that route
1313+
```
1314+
1315+
- `route` selects which backend the WHOLE evaluation side calls (`llm_judge`, `agent_judge`, and the simulator all share one resolved eval route per run — this isn't per-criterion), **decoupled from the agent's own route** (a Claude agent can be graded by a differently-backed judge, or vice versa). This is a backend *name* (`direct` / `bedrock` / `litellm`), not a route object. For `direct`/`bedrock` credentials are never read from the task, always from the matching environment variables (`ANTHROPIC_API_KEY` for `direct`, `AWS_BEARER_TOKEN_BEDROCK`/`AWS_REGION` for `bedrock`). An unconfigured or unknown backend name raises at dispatch rather than silently falling back. **`route: litellm` dispatches `llm_judge` through the `litellm` library** (the `coder-eval[litellm]` extra, `litellm.acompletion`) rather than assuming one wire protocol — a gateway-routed judge model (e.g. an Azure AI `/openai/v1` deployment) rarely speaks Anthropic Messages, so this lets `model` carry its own provider hint (e.g. `azure/gpt-5.6-luna`) and get that provider's actual request/response shape handled by the library. Unlike the other two backends, `route: litellm` has NO implicit env-var fallback — see `params`/`env_params` below, which is how it's configured. `model` is required for `route: litellm` (there is no default open-weight/gateway model).
1316+
- `model` overrides the model that resolved route uses for **`llm_judge` only** — when the criterion itself leaves `model:` unset (precedence: an explicit per-criterion `model:` always wins; below that, `checker_context.api_route.model`; below that, the built-in `DEFAULT_JUDGE_MODEL`). This floor is deliberate and never the agent's own model — an unpinned judge must grade identically regardless of which model the agent under test is using, so `resolve_evaluation_route` never lets the agent's env-configured model (e.g. `BEDROCK_MODEL`) leak into `route.model` on its own; `route.model` is set only when this override was actually given. This works because every `ApiRoute` (`DirectRoute`/`BedrockRoute`/`LiteLLMRoute`) carries its own `model` field; the orchestrator bakes the override into the resolved route's `model` before any criterion runs, so `llm_judge` just reads `context.route.model` — it never reads `checker_context` directly. **`agent_judge` and the simulator do not honor this override** — `agent_judge`'s sub-agent model comes from the criterion's own `agent:` block (defaulted to a fixed judge model), and the simulator's model is pinned by `SimulationConfig.model` (see [Simulation](#simulation) below) — both independent of `checker_context.api_route.model` by design, for the same "measuring instrument stays fixed" reason.
1317+
- `params`/`env_params` (**`route: litellm` only**) are how the call is actually configured — there is no fallback to the agent's own `LITELLM_BASE_URL`/`LITELLM_AUTH_TOKEN` env vars, since a gateway-routed judge model rarely reuses the agent's own LiteLLM proxy/credential. They also cover any of the dozens of other provider-specific kwargs `litellm.acompletion` accepts (`aws_access_key_id`, `vertex_project`, `api_version`, ...), which have no dedicated field on `LiteLLMRoute`:
1318+
```yaml
1319+
checker_context:
1320+
api_route:
1321+
route: litellm
1322+
model: azure/gpt-5.6-luna
1323+
params: # arbitrary literal passthrough kwargs to litellm.acompletion
1324+
api_version: "2024-05-01"
1325+
env_params: # param name -> ENV VAR NAME (never the secret itself)
1326+
api_base: LITELLM_BASE_URL
1327+
api_key: LITELLM_AUTH_TOKEN
1328+
```
1329+
`params` is merged straight into the `litellm.acompletion(**kwargs)` call — litellm validates the param names itself, so there's no allowlist to keep in sync here. `env_params` maps a kwarg name to the *name* of an environment variable; the value is resolved right before the call, so no secret is ever written into task/experiment YAML — this is how an arbitrary provider's config, including secrets (IAM keys, an Azure AD token, a service-account path, ...), is representable without a dedicated field per provider. `env_params` is resolved after `params`, so it always wins for the same key. Rejected at task-load time if given without `route: litellm`. For an Azure deployment, pin `api_version` via `params` to whatever API version the agent side is actually configured for (e.g. Codex's `CODEX_API_VERSION`) — the judge has no way to inherit it, and a mismatched version can hit a different shape of the same endpoint.
1330+
**`route: litellm` is `llm_judge`-only** — `agent_judge` and the simulator run as real Claude Code CLI subprocesses that speak the Anthropic Messages protocol, so pointing them at an arbitrary litellm-fronted gateway (which may speak an entirely different wire protocol) isn't representable. The orchestrator rejects the combination at resolution time (a clear error, not a silent misroute) if the task has an enabled `agent_judge` criterion or `simulation.enabled: true` alongside `route: litellm` — use `route: bedrock`/`direct` for those instead.
1331+
1332+
`checker_context` merges shallow-per-namespace across `default_experiment.defaults.checker_context` → `experiment.defaults.checker_context` → `task.checker_context` → `variant.checker_context` (same 4-layer precedence as `agent`/`simulation`). So a judge-model A/B, or a judge-backend A/B, is a variant-level config change, not an edit to every task YAML.
1333+
12981334
## Reference Solutions
12991335

13001336
A reference solution is always a **directory**, given relative to the task YAML's own directory:
@@ -1577,7 +1613,7 @@ simulation:
15771613
| `check_criteria` | `end_of_dialog` | `end_of_dialog`, `every_turn`, or `both`. |
15781614
| `model` | `anthropic.claude-sonnet-4-6` | Model that plays the simulated user. Auto-translated to the run's backend (Bedrock inference profile / bare Anthropic alias), the same way [`llm_judge`](#llm_judge)'s `model` is. |
15791615

1580-
The simulator runs as a tools-disabled Claude Code agent sharing the coding agent's `ApiRoute`, so temperature and sampling are resolved at the route level (same `-b` flag as the coding agent) and are not configured on this block. The **model is not**: it is pinned by `model` above. Inheriting it from the route meant `BEDROCK_MODEL` decided who the simulated user was, so an A/B varying the subject model silently varied its interlocutor too. Hold `model` fixed across variants for the same reason you hold a judge model fixed — the simulator is part of the measuring instrument, not the thing being measured.
1616+
The simulator runs as a tools-disabled Claude Code agent on the run's resolved *evaluation* `ApiRoute` (the coding agent's own route unless [`checker_context.api_route.route`](#checker-context) overrides it), so temperature and sampling are resolved at the route level (same `-b` flag as the coding agent by default) and are not configured on this block. The **model is not**: it is pinned by `model` above. Inheriting it from the route meant `BEDROCK_MODEL` decided who the simulated user was, so an A/B varying the subject model silently varied its interlocutor too. Hold `model` fixed across variants for the same reason you hold a judge model fixed — the simulator is part of the measuring instrument, not the thing being measured.
15811617

15821618
**Semantics:**
15831619

plugins/coder-eval/reference/criteria.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ Optional:
209209
| `include_tool_calls` | When true, include a summary of the latest agent turn's tool calls (via summarize_commands). No-op when turn_records is unavailable. |
210210
| `include_dialog` | When true, include the full user<->agent conversation across all turns in the judge prompt. In simulation mode the user side is generated by an LLM simulator and may invent premises — the judge should treat any claim made only by the simulated user as possibly fabricated, and not penalize the agent for going along with it unless the task description contradicts it. |
211211
| `max_dialog_chars` | Aggregate cap on dialog text rendered into the judge prompt. Prevents an N-turn simulation from blowing out the judge's context window. Per-message truncation uses max_file_chars; trailing turns are dropped when this aggregate budget is exceeded (a degraded note is recorded). |
212-
| `model` | Judge model id (e.g. 'anthropic.claude-sonnet-4-6'). On a BedrockRoute / DirectRoute the value is auto-translated: trailing '-vN[:M]' suffixes and the 'anthropic.' prefix are stripped where the backend doesn't accept them; on Bedrock the cross-region inference-profile prefix is added based on AWS_REGION. |
212+
| `model` | Judge model id (e.g. 'anthropic.claude-sonnet-4-6'). Leave unset to fall back to checker_context.api_route.model when set, else the built-in default ('anthropic.claude-sonnet-4-6') — the fallback is never the agent's own model, so an unpinned judge grades identically across agent-model A/Bs. On a BedrockRoute / DirectRoute the value is auto-translated: trailing '-vN[:M]' suffixes and the 'anthropic.' prefix are stripped where the backend doesn't accept them; on Bedrock the cross-region inference-profile prefix is added based on AWS_REGION. |
213213
| `temperature` | Sampling temperature for the judge model. 0.0 keeps grading deterministic. |
214214
| `max_tokens` | Output token cap. Defaults to 2000 — large enough for the verbose verdict (score + rationale + a handful of findings) without runaway. |
215215
| `max_file_chars` | Per-file content truncation applied before building the prompt. |

pyproject.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,19 @@ dev = [
8989
uipath = [
9090
"uipath>=2.10.31",
9191
]
92+
# Optional extra that enables the `checker_context.api_route.route: litellm`
93+
# judge backend (llm_judge only) via the `litellm` library's `acompletion` —
94+
# it normalizes provider-specific quirks (Azure AI's api_base/api_key shape,
95+
# max_tokens vs max_completion_tokens naming, unsupported-param drops, ...)
96+
# so the judge transport doesn't hand-roll per-provider HTTP. NOT the same
97+
# thing as the LiteLLM PROXY (litellm/start-litellm.sh) the AGENT's own
98+
# `route: litellm` points at over HTTP — this extra calls the library
99+
# in-process. Without this extra, the framework still installs and runs;
100+
# the litellm-route judge path fails at dispatch with a clear hint pointing
101+
# back here.
102+
litellm = [
103+
"litellm>=1.95.0,<2.0.0",
104+
]
92105
# Optional extra that enables Codex agent support:
93106
# - CodexAgent implementation using official openai-codex SDK
94107
# Without this extra, the framework still installs and runs; Codex-dependent

0 commit comments

Comments
 (0)