yunfengzhou-hub opened a new issue, #1131:
URL: https://github.com/apache/flink-agents/issues/1131

   ### Search before asking
   
   - [x] I searched in the 
[issues](https://github.com/apache/flink-agents/issues) and found nothing 
similar.
   
   ### Description
   
   **Scenario.** A job that uses an external sub-agent, deployed to a real 
Flink cluster. Local, mini-cluster, and in-process runs are all fine.
   
   **Symptom.** On a real cluster the job crashes in the TaskManager operator's 
`open()` and enters a restart loop. Jackson cannot reconstruct the user's 
sub-agent class:
   
   ```
   MismatchedInputException: Cannot construct instance of `...ReviewSubagent`
     (no delegate- or property-based Creator)
       at ActionExecutionOperator.open
       -> registerSubagentSetups
       -> JavaSerializableResourceProvider.provide
       -> ObjectMapper.readValue(json, ReviewSubagent.class)
   ```
   
   The defining characteristic: it reproduces **only** across the real 
JobManager→TaskManager process boundary and never triggers locally.
   
   **Root cause.** An external sub-agent registered programmatically as a live 
instance — `addResource(name, AGENT, new MySubagent(...))`, a user 
`SubagentSetup`/`BaseDeferredSubagentSetup` subclass — is carried by 
`JavaSerializableResourceProvider`. At plan build time the provider writes the 
live object into the plan JSON via `writeValueAsString` and keeps the object 
itself in an `@JsonIgnore` field. In-process, `provide()` returns that live 
object directly and never deserializes. Across a real cluster the `@JsonIgnore` 
object is lost (`null`), so `provide()` falls into `readValue(json, 
concreteClass)` and Jackson must construct the concrete subclass.
   
   A user subclass normally declares a single parameterized constructor (e.g. 
`MySubagent(String description)`) — no no-arg constructor and no 
`@JsonCreator`. The base `SubagentSetup` has a no-arg constructor, but Java 
constructors are not inherited, so a subclass that declares its own 
parameterized constructor has no no-arg constructor at all. Jackson then has no 
creator and throws.
   
   Nothing catches this at registration: 
`SerializableResource.validateSerializable()` only checks the write side and is 
never called (dead code), and no test performs a JSON round-trip of a plan 
containing a real `(String)`-only sub-agent — the framework's 
`TestSubagentSetup` double is equipped with no-arg, `@JsonCreator`, and 
descriptor rebuild paths, and the one test that resolves a live-instance 
sub-agent goes through the in-process `provide()`.
   
   **Scope.**
   - Affected: only external user `SubagentSetup` subclasses registered as live 
instances — which is exactly the documented authoring pattern (subclass a base 
setup, register a live instance).
   - Not affected: YAML/descriptor-declared sub-agents; internal sub-agents 
(`Agent` subclasses compiled to a sub-plan, rebuilt by 
`InternalSubagentProvider` via `(String, AgentPlan)`); descriptor-path 
resources (`@ChatModelSetup`, `@VectorStore`, etc., requiring a 
`(ResourceDescriptor, ResourceContext)` constructor, not Jackson); and 
resources that also travel as live objects but whose concrete class the 
framework owns (`Tool`→`FunctionTool` has a custom `@JsonDeserialize`, 
`Prompt`→`LocalPrompt` has an `@JsonCreator`).
   - In short, an external user sub-agent is the single combination of "the 
framework does not own the concrete class" + "travels as a live-object JSON 
round-trip", which is why it is the sole victim. Note the framework's own 
external HTTP sub-agent is currently a test demonstration rather than shipped 
production code, which bears on severity triage.
   - Python: external sub-agents go through the analogous 
`PythonSerializableResourceProvider` live-object round-trip; whether the Python 
rebuild path has the same gap should be checked alongside the Java fix (it does 
not use Jackson, so the identical failure is not assumed).
   
   
   ### How to reproduce
   
   Real cluster (user-facing):
   1. Implement an external sub-agent as a 
`SubagentSetup`/`BaseDeferredSubagentSetup` subclass with only a parameterized 
constructor (e.g. `(String description)` or a base URL) — no no-arg 
constructor, no `@JsonCreator`.
   2. Register an instance programmatically: `addResource(name, 
ResourceType.AGENT, new MySubagent(...))`.
   3. Deploy to a real cluster (JobManager and TaskManager in separate 
processes). The job crash-loops at `ActionExecutionOperator.open()` with the 
Jackson `MismatchedInputException` above. Declaring the same sub-agent in YAML 
works.
   
   Deterministic (no cluster needed):
   - Compile a plan registering such a live-instance sub-agent, serialize the 
plan to JSON, and resolve the resource back with the provider's live object 
forced to `null` (as the cross-process transfer does) — `readValue` throws for 
want of a creator. An in-process run that never nulls the live object does not 
surface it.
   
   
   ### Version and environment
   
   - Flink Agents: current `main` (toward 0.4.0), where programmatic external 
sub-agent registration exists; exact affected version to be confirmed.
   - Flink version / deployment: independent of Flink version, but requires a 
real JobManager→TaskManager cross-process plan transfer. Local / mini-cluster / 
in-process never triggers it.
   - Language: confirmed on Java; the Python provider path is analogous and to 
be verified.
   
   
   ### Are you willing to submit a PR?
   
   - [x] I'm willing to submit a PR!


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