HsbcJone opened a new pull request, #1375: URL: https://github.com/apache/flink-agents/pull/1375
Linked issue: #1334 Closes #1334 ### Purpose of change #### Outcome YAML can declare model routers under `model_routers`, on an agent or as shared resources. Both loaders register them as `MODEL_ROUTER` descriptors, and a chat request that names the router uses the existing routing execution. #### Intent Router configuration was programmatic only. YAML needs the same descriptor arguments — candidates, descriptions, strategy, default model, and fallback — checked by the existing plan validation. #### Runtime flow The parser accepts `model_routers` as a list of `DescriptorSpec`. The loader resolves `clazz`, including the `model_router` alias, copies every other field into a resource descriptor, and registers it as `MODEL_ROUTER` on the agent or the execution environment. Shared routers join the agent with the existing environment-then-agent merge when the plan is built. Plan construction runs the existing routing checks. The existing resource provider then constructs `ModelRouter`, and the existing resolver runs the declared strategy. #### Key decisions The section reuses `DescriptorSpec`, so strategy settings stay the descriptor keys the builder already emits. The alias is `model_router` in both languages. Cross-language declarations are rejected by the loaders' existing language allow-lists: Java YAML sets `type: java`, and Python YAML keeps the default Python implementation. An unsupported strategy fails inside the plan check used for the same programmatic descriptor. ### Behavioral Semantics #### Interaction decisions | Scope | Language | Strategy supported by that runtime | Result | |---|---|---|---| | Agent-local or shared | Loader's own language | Yes | Registered; plan checks and routing execution proceed | | Agent-local or shared | The other language | Either | Load fails before registration | | Same name as a chat model | Either | Either | Existing name-collision error | | Loader's own language | Unsupported or invalid | Plan build fails with the same exception and message as that descriptor registered programmatically | A shared router and an agent-local router with different names are both visible after the merge. An agent-local resource of the same type and name still wins. #### Behavioral contracts 1. Agent-local and shared `model_routers` become `MODEL_ROUTER` descriptors for `ModelRouter`, preserving candidates, descriptions, strategy type, strategy arguments, executor class, default model, and fallback. 2. `clazz: model_router` resolves to the Java or Python `ModelRouter` class for the selected language. A fully qualified class name is kept. 3. Omitting `model_routers` leaves that map empty, so existing YAML documents still load. 4. A YAML router and the same descriptor registered programmatically fail plan construction with the same exception type and message. 5. A loaded rule router selects the matching candidate, abstains to `default_model` otherwise, and a custom router runs `strategy_executor_class`. 6. Fallback and candidate order on the resolved route follow the declaration. #### Failure behavior Missing `name` or `clazz`, or an unknown document key, fails while the file is parsed. The other implementation language raises `IllegalArgumentException` (Java) or `ValueError` (Python) from the existing `type` check, and the router is not registered. A router name that is already a chat model raises the existing registration error. A missing strategy, unknown strategy tag, rule target outside the candidates, Python `llm_judge` or `decision_model`, or a missing custom executor raises during plan construction and is not retried or replaced with another strategy. A candidate that is not declared in the file still fails when a request resolves that model. ### Tests | Contract | Tests | |---|---| | 1. Arguments at both scopes | `YamlModelRouterLoaderTest.declaresAgentLocalAndSharedRouters`, `test_model_router_declarations_keep_descriptor_arguments`, `test_load_yaml_registers_shared_model_router` | | 2. Alias and class name | `AliasesTest.clazzAliasCoversModelRouterInBothLanguages`, `test_resolve_clazz_covers_model_router_in_both_languages`, and the loader tests above | | 3. Omitted section | `SchemaParityTest`, `test_checked_in_schema_matches_pydantic_models`, existing fixture loads | | 4. Same plan failure as a programmatic descriptor | `YamlModelRouterDeclarationTest.invalidYamlFailsLikeTheSameProgrammaticDescriptor`, `test_invalid_yaml_fails_like_the_same_programmatic_descriptor`, name-collision tests | | 5 and 6. Selection, abstention, custom execution, fallback order | `yamlRoutersExecuteRulesAndCustomStrategies`, `test_yaml_routers_execute_rules_and_custom_strategies` | Covered: loader, plan check, and route resolution for rule and custom strategies, including an invalid tag, a bad rule target, unsupported Python strategies, and a missing executor. Not verified: a live chat-model call after selection, LLM-judge and decision-model execution, Java annotations, and recovery replay. Those paths are unchanged. <details> <summary>Implementation invariants</summary> The loader does not interpret strategy arguments. `DescriptorSpec` extras are copied into the descriptor, and `JavaResourceProvider` or `PythonResourceProvider` constructs `ModelRouter`. Shared entries merge through `Agent.addResourcesIfAbsent` in Java and the same environment-then-agent map merge in Python. Python plan validation still requires a Python descriptor; Java `type: java` produces a Java descriptor. Schema copies: `docs/yaml-schema.json` and `dev/agent-skills/flink-agents-dev/assets/yaml-schema.json`. </details> ### API #### Compatibility impact Existing YAML is unchanged: `model_routers` is optional and defaults to an empty list. Programmatic registration, plan validation, and routing execution are unchanged. Declaring the section in the other implementation language fails at load. Java annotations and Python decorators remain unavailable. ### Documentation - [x] `doc-included` - [ ] `doc-needed` - [ ] `doc-not-needed` ### Was this patch authored or co-authored using generative AI tooling? - [x] Yes - [ ] No Generated-by: Cursor Grok 4.7 (Grok 4.7) -- 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]
