purushah opened a new pull request, #1042:
URL: https://github.com/apache/flink-agents/pull/1042

   ## What
   
   Implements the `Strategies.llm(...)` follow-up promised in discussion #897 
and documented as the framework-managed follow-up in the #964 javadocs: **the 
engine — not the strategy — executes the judge call**, on the same durable, 
metered, observable chat path as any model call.
   
   ```java
   env.addResource("judge", ResourceType.CHAT_MODEL, judgeModelDescriptor);  // 
any chat model
   
   env.addResource("router", ResourceType.MODEL_ROUTER,
       ModelRouter.of("small", "big")
           .describe("small", "fast and cheap: chit-chat, lookups")
           .describe("big",   "expensive: code, SQL, multi-step reasoning")
           .strategy(Strategies.llm("judge"))
           .defaultModel("small")
           .fallback(true)
           .build());
   ```
   
   ## Design (per the #897 agreement)
   
   - `LlmJudgeRoutingStrategy` carries configuration plus two pure functions 
(prompt build, verdict parse); `route()` is never invoked — the resolver 
detects the strategy and runs the judge chat under durable id 
`"judge:<router>"` (engine retries, trace events, token attribution to the 
judge model), then persists the decision — with its source and judge-inclusive 
`decision_ms` — under the standard `"route:<router>"` id. Judge abstains 
persist as abstains, so replay after a candidate-set change resolves to the 
current default exactly like the strategy path.
   - **Verdicts are constrained to candidate names**: the judge prompt is built 
from the router's candidates + `describe(...)` lines; an unparseable, ambiguous 
(multiple distinct candidates named), or non-candidate verdict abstains to the 
default model with the cause recorded. A hijacked judge cannot steer routing 
outside the declared candidates.
   - **Failure policy**: a judge call that exhausts its retries honors the 
request's error-handling strategy (`FAIL` surfaces the outage loudly, `IGNORE` 
abstains to the default with the cause recorded); interrupts/cancellation 
propagate and are never persisted as routing outcomes (including the 
`InterruptedIOException` shapes HTTP stacks use — with `SocketTimeoutException` 
explicitly treated as an ordinary failure, not cancellation).
   - **Fail-fast validation**: `build()` constructs the strategy so its 
argument rules apply at the registration call site, and `AgentPlan` validates 
at plan construction — by instantiating the strategy exactly as the runtime 
does — that the judge name resolves to a registered `CHAT_MODEL`. A judge setup 
with a bound prompt, tools, or skills is rejected (it would silently corrupt 
every verdict).
   - **Python**: `add_resource(..., MODEL_ROUTER)` now raises an explicit 
not-yet-supported error instead of dropping silently (flagged in the #964 
review); a cross-language test proves Java plans carrying the new strategy args 
still deserialize in Python.
   
   ## Compatibility impact
   
   - Additive only: plain-chat agents and existing rule/custom routers are 
untouched.
   - Event consumers see a new `decision_source` value `llm_judge` and new 
optional metadata keys (`judge_model`, `judge_prompt_tokens`, 
`judge_completion_tokens`, `decision_source`).
   - Deliberate trade-off: the judge path performs a second durable write 
(`route:<router>` in addition to `judge:<router>`) to keep the route-record 
schema uniform across router types and preserve replayed `decision_ms`.
   
   ## Test evidence
   
   - 684 Java tests green (new: verdict routing incl. durable ids + metadata, 
ambiguity/injection/parse table, judge retry budget, failure policy under FAIL 
and IGNORE, prompt-bound judge rejection and IGNORE degradation, plan-time 
validation incl. subclasses and null tolerance, prompt-template handling, 
promptArgs-shaped requests); Python suites green incl. the cross-language 
round-trip.
   - End-to-end on a standalone Flink 2.3.0 cluster (dist jar + `flink run` of 
the new `ModelRoutingJudgeExample`, local Ollama): judge verdicts routed 
correctly with full metadata; fallback composition exercised live.
   
   Generative AI was used for this change.
   
   Generated-by: Claude Code 2.1.239 (Claude Fable 5)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to