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

   Linked issue: #1254
   
   ### Purpose of change
   
   #### User-visible outcome
   
   A Java native output schema now lists each enum constant under the value 
Jackson writes for it, typed as that value. An enum with `@JsonProperty` on 
only some constants lists `["in-progress", "DONE"]` instead of `["IN_PROGRESS", 
"DONE"]`, so a model reply using a listed value deserializes. An `int` 
`@JsonValue` enum gives `{"type":"integer","enum":[1,-1]}` instead of 
`{"type":"string","enum":[1,-1]}`, which no value satisfied. Every Java 
provider builds its native schema through `PojoJsonSchemaGenerator`, so all of 
them get this.
   
   The Java code change below is what the Implementation Description covers. 
The diff also updates the generator's settings comment and the structured 
output guide, which listed both cases as limitations.
   
   #### Runtime flow
   
   `PojoJsonSchemaGenerator` registers a custom definition provider for enum 
types before it adds the Jackson module. For an enum with at least one 
constant, the provider takes `ObjectMapper.valueToTree(constant)` for each 
constant, writes a non-finite float or double as the string Jackson emits for 
it, lists the results under `enum` (`const` for a single value), and sets 
`type` from their JSON types (an array if they differ). victools uses the first 
provider that returns a definition, so for these enums the Jackson module's 
flattened-enum provider no longer runs. For an enum without constants, or when 
writing a constant throws, the provider returns nothing and the Jackson module 
handles the enum as before.
   
   #### Key decisions
   
   - Use the value Jackson writes rather than re-reading `@JsonProperty` and 
`@JsonValue`. Serialization already resolves both annotations and the Java-name 
fallback for each constant.
   - Keep the Jackson module's enum options as the fallback for the two cases 
the new provider skips.
   
   ### Behavioral Semantics
   
   #### Interaction decisions
   
   | Enum | Before | After |
   |---|---|---|
   | `@JsonProperty` on every constant | mapped values, `string` | same |
   | `@JsonProperty` on some constants | Java names for all, `string` | mapped 
values where annotated, Java names otherwise, `string` |
   | String `@JsonValue` method | mapped values, `string` | same |
   | Integer `@JsonValue` method | numbers, `string` | numbers, `integer` |
   | Finite floating-point `@JsonValue` method | numbers, `string` | numbers, 
`number` |
   | Non-finite `@JsonValue` method results | strings such as `"NaN"`, `string` 
| same strings; `type` adds `string` beside `number` for finite ones |
   | `@JsonValue` on a field | Java names, `string` | the field values, typed 
as written |
   | Single constant | `const` | `const` |
   | No annotations | Java names, `string` | same |
   | No constants | `type: string`, no `enum` | same |
   
   #### Behavioral contracts
   
   1. For an enum mapped by `@JsonProperty`, by a `@JsonValue` method returning 
a `String` or an integral primitive or wrapper, or by its Java names, and 
without a custom creator or deserializer, every listed value deserializes into 
the enum with a default `ObjectMapper`.
   2. The declared `type` matches the JSON type of the listed values.
   3. An enum without constants keeps the schema the Jackson module gives it.
   
   #### Failure behavior
   
   If `valueToTree` throws `IllegalArgumentException`, for example from a 
throwing `@JsonValue` method, the provider discards the whole enum definition 
and the Jackson module's configuration applies as before. Other failures 
propagate. Values from `@JsonValue` methods with other return types, such as 
finite floating-point, `boolean`, `BigInteger` or `Object`, are listed as 
written and may require matching deserialization support, such as a 
`@JsonCreator`, to read back; that was already true of the values the module 
listed.
   
   ### Tests
   
   | Contract | Tests |
   |---|---|
   | 1 | `listsPartlyAnnotatedEnumByItsJacksonWireValues` (new), 
`listsEnumConstantsByTheirJacksonWireValues` (existing), 
`enumDefinitionWinsOverJacksonModule` (new) |
   | 2 | `enumDefinitionWinsOverJacksonModule` (new), 
`writesNonFiniteNumbersAsStringsAndSingleValuesAsConst` (new) |
   | 3 | `leavesEnumWithoutConstantsToJacksonModule` (new), through both 
`generate` and `generateAllRequired` |
   
   By risk: the two cases from the issue and the precedence over the Jackson 
module are pinned by tests that fail on main; existing tests check round-trip 
values for fully annotated and string-`@JsonValue` enums, and the all-required 
comparison checks the two methods match apart from `required`. 
`PojoJsonSchemaGeneratorTest` and the anthropic, bedrock, gemini, ollama, 
openai and watsonx module tests pass on JDK 21 (510 run, 0 failures, 2 
skipped), and `tools/lint.sh -c` passes on JDK 11 and 21.
   
   Not verified: no test covers finite-only floating-point, boolean or 
mixed-type `@JsonValue` results, `@JsonValue` on a field, or the 
throwing-`@JsonValue` fallback; the live provider tests are skipped without 
credentials.
   
   <details>
   <summary>Implementation invariants and evidence</summary>
   
   - The provider must be registered before `builder.with(new 
JacksonModule(...))`, because `with` applies the module immediately and the 
first provider that returns a definition wins. 
`enumDefinitionWinsOverJacksonModule` fails if the registration moves after the 
module.
   - The provider returns `new CustomDefinition(definition)`, the same standard 
definition type the module produces, so an enum used in several fields still 
goes through `$defs`/`$ref` as before.
   - Responses for POJO output schemas are read by `ChatModelAction`'s plain 
`ObjectMapper`. Both paths use the default `ObjectMapper` configuration; 
annotations such as a custom creator can still make serialization and 
deserialization asymmetric.
   
   </details>
   
   ### API
   
   No signature changes. `generate` and `generateAllRequired` now derive enum 
values from Jackson serialization, so the `enum`/`type` change for the rows 
above that differ, including `@JsonValue` fields and boolean or mixed-type 
results. The ReAct Agent's prompt text uses a different generator and is 
unchanged, as is the Python side.
   
   ### Documentation
   
   - [ ] `doc-needed`
   - [ ] `doc-not-needed`
   - [x] `doc-included`
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   - [x] Yes
   - [ ] No
   
   Generated-by: Claude Code 2.1.296 (Claude Opus 5.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