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]
