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

   Fixes #1368
   
   ### Purpose of change
   
   Java internal subagents can use a parent's model router while keeping local 
model/router overrides. Previously, the routing check inspected only the child 
cache and treated an inherited router as a concrete chat model, causing 
`Resource not found`.
   
   #### Runtime flow
   
   `ctx.chat` → `ChatModelAction` → `ModelRoutingResolver` → 
`RunnerContextImpl.hasResource` now checks the current resource hierarchy. 
`ResourceCache.hasResourceInHierarchy` and `getResource` apply the same 
shadowing rule before consulting the parent.
   
   #### Key decisions
   
   Chat models and routers share a name namespace across scopes. A local 
declaration of either blocks inheritance of both types under that name. A 
recursive presence check alone would incorrectly allow a parent router to 
override a child chat model. Keep `ResourceCache.hasResource` local-only for 
callers that inspect local registrations.
   
   ### Behavioral Semantics
   
   #### Interaction decisions
   
   | Local declaration for a name | Ancestor declaration | Lookup result |
   |---|---|---|
   | None | Router or chat model | Inherit the nearest visible resource |
   | Chat model | Router | Use the local model; the ancestor router is hidden |
   | Router | Chat model | Use the local router; the ancestor model is hidden |
   | Same resource type | Same resource type | Use the local resource |
   | Unrelated resource type | Router or chat model | Resolve independently by 
type |
   
   #### Behavioral contracts
   
   - Java subagent chat calls recognize inherited routers and honor local chat 
model/router overrides.
   - Cross-type shadowing applies to providers and cached-only entries, 
including through intermediate scopes. An explicit lookup of the hidden type 
fails rather than retrieving an ancestor resource.
   - Presence checks do not construct resources. Inherited resources remain 
cached and closed by their declaring scope.
   - A local provider failure propagates; it does not trigger fallback to a 
parent resource.
   
   #### Failure behavior
   
   A missing or hidden resource raises the existing `IllegalArgumentException`. 
Provider/open failures retain their existing propagation and cleanup behavior. 
Model-call retries and routing candidate fallback are unchanged.
   
   ### Tests
   
   | Contract | Coverage |
   |---|---|
   | Inherited router and both local override directions work in a real child 
call | `ChatCallTest.chatInsideSubagentResolvesTheNearestModelName` (three 
operator-harness cases with mock models) |
   | Both resource types shadow across nested scopes, including cached-only 
entries | `ResourceCacheTest.localModelNameShadowsBothTypesInAncestors` |
   | Presence checks are lazy; inherited resources retain parent ownership; 
unrelated types remain independent | 
`ResourceCacheTest.inheritedResourcesRemainOwnedByTheirDeclaringScope` and the 
shadowing test |
   | Local provider failure does not select an ancestor resource | 
`ResourceCacheTest.failingLocalProviderDoesNotFallBackToParent` |
   
   JDK 21 / Flink 2.3.0: **389 passed, 2 skipped** across the selected API, 
plan, and runtime tests. Both skips are existing lower-JDK guards. Spotless and 
`git diff --check` passed.
   
   Not verified: live model providers, Python bridge execution, the full 
project suite, or other Flink/JDK combinations. This PR adds no Python routing 
implementation.
   
   <details>
   <summary>Validation commands and regression evidence</summary>
   
   The targeted Maven reactor rebuilds the runtime and its dependency modules 
from this checkout:
   
   ```sh
   # JDK 21
   mvn -B --no-transfer-progress -pl runtime -am \
     '-Dtest=ResourceCacheTest,ChatCallTest,*Routing*Test,*Subagent*Test' \
     -Dsurefire.failIfNoSpecifiedTests=false test
   
   # Default JDK (Spotless is skipped by the JDK 21 profile)
   mvn -B --no-transfer-progress -pl runtime -am spotless:check
   git diff --check
   ```
   
   With the two production implementations restored to base, the 
inherited-router operator case fails looking for `model` as `CHAT_MODEL`, and 
all four cross-type shadowing cases fail. Restoring the fix makes them pass. 
The existing decision-routing recovery fixture now stubs the hierarchy lookup 
used by `RunnerContextImpl`.
   
   </details>
   
   ### API
   
   No signature changes. `RunnerContext.hasResource` now includes visible 
inherited resources, matching `getResource`. An explicit lookup of an ancestor 
chat model/router hidden by the opposite local type now fails. Root-scope 
behavior and resource lookup for unrelated types are preserved. The API Javadoc 
describes the scope-aware presence check.
   
   ### Documentation
   
   - [ ] `doc-needed`
   - [ ] `doc-not-needed`
   - [x] `doc-included`
   
   Updated the model-routing documentation with subagent inheritance and 
shadowing rules.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   - [x] Yes
   - [ ] No
   
   Generated-by: Codex CLI 0.153.4 (GPT-6)
   


-- 
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