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

   Linked issue: #1256
   
   ### Purpose of change
   
   For a flat `RowTypeInfo` output schema with only string, boolean or numeric 
fields, the ReAct Agent now describes the schema to the model as JSON Schema 
instead of the type's string form, in both languages. For `Row(name STRING, 
count INT)` the prompt now carries 
`{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer"}},"required":["name","count"],"additionalProperties":false}`
 where it used to carry `Row(name: String, count: Integer)` (Java) or 
`RowTypeInfo(name: String, count: Integer)` (Python). The string form names the 
fields and Flink types but not the JSON shape to return. Native schema-document 
support (`AUTO` and `NATIVE` for a `RowTypeInfo`) is deferred to a follow-up PR.
   
   #### Runtime flow
   
   1. The `ReActAgent` constructor (both languages) builds the schema text 
once. For a `RowTypeInfo` it calls `RowTypeJsonSchema.render` (Java, 
`@Internal`) or `render_row_type_json_schema` (Python), and uses the string 
form, as before, when that returns `null`/`None`.
   2. The text goes into both registered prompts, schema and native-schema.
   3. `startAction` / `start_action` picks one of them, as before, and inserts 
it into the request. The stored output schema, the native capability decision 
and response conversion are unchanged.
   
   Mapping: string to `string`, boolean to `boolean`, byte/short/int/long/big 
integer to `integer`, float/double/big decimal to `number`.
   
   #### Key decisions
   
   - Same text in both languages: properties in field order, compact 
separators, non-ASCII written as is, and lowercase hex in `\u` escapes (Jackson 
writes uppercase by default, so the Java writer turns that off).
   - Char, date and instant fields have no mapping, so the row keeps the string 
form: the response is copied into the `Row` without conversion, and a `string` 
value would have the wrong type there.
   - Every field is required. The bare property types also exclude `null`; 
nullability is deferred.
   - A row built without names renders Java's default names `f0`, `f1`, ... in 
both languages. Python reads them without `get_field_names()`, which would 
start the JVM.
   - Python rows with duplicate names or a name count that differs from the 
type count, which Java rejects, keep the string form.
   
   ### Behavioral Semantics
   
   #### Interaction decisions
   
   | Row fields | Java | Python |
   |---|---|---|
   | All string, boolean or numeric | JSON Schema | JSON Schema |
   | A basic char, date, instant or void field | string form, as before | 
string form, as before (char, instant) |
   | A nested or non-basic field (Python SQL date included) | construction 
fails in `OutputSchema`, as before | string form; serializing `OutputSchema` 
fails, as before |
   
   #### Behavioral contracts
   
   - A mapped row's prompt lists the properties in field order.
   - All properties are `required`.
   - `additionalProperties` is `false`.
   - Java and Python produce the same text for the same row, including escaped 
field names.
   - A row built without names uses `f0`, `f1`, ... as property names.
   - A row with an unmapped field keeps the string form in both prompts.
   
   #### Failure behavior
   
   - An unmapped field: the renderer returns `null`/`None` and the agent falls 
back to the string form.
   - A non-basic field: unchanged (table above).
   - A Python row with duplicate or mismatched names: the renderer returns 
`None` and the agent keeps the string form, as before.
   - A Jackson serialization failure in the Java renderer is rethrown as a 
`RuntimeException`, not absorbed into the fallback.
   
   ### Tests
   
   | Contract | Tests |
   |---|---|
   | Field order | `rendersFlatRowInFieldOrder`, 
`test_renders_flat_row_in_field_order` |
   | Every field required | same two tests (shared expected string) |
   | `additionalProperties: false` | same two tests |
   | Numeric mapping | `mapsNumericTypes`, `test_maps_numeric_types` |
   | Same text in both languages, escaped names | 
`escapesFieldNamesLikePython`, `test_escapes_field_names_like_java` (shared 
expected string) |
   | Default names for an unnamed row | `rendersDefaultFieldNames`, 
`test_unnamed_row_uses_default_names_without_the_jvm` (shared expected string), 
`test_unnamed_unmapped_row_returns_none_without_the_jvm`; the Python tests fail 
if the JVM starts |
   | Duplicate or mismatched Python names keep the string form | 
`test_returns_none_for_names_java_rejects` (empty, fewer, duplicate), 
`test_row_type_info_with_duplicate_names_keeps_the_prompt_fallback` (both 
prompts) |
   | Unmapped field keeps the string form | 
`returnsNullForFieldsWithoutJsonType`, 
`test_returns_none_for_fields_without_json_type`, 
`testRowTypeSchemaWithoutJsonTypeKeepsItsText` and 
`test_row_type_info_without_json_type_keeps_the_prompt_fallback` (both prompts) 
|
   | Both prompts carry the schema | 
`testRowTypeSchemaPromptCarriesJsonSchema`, 
`testRowTypeSchemaRegistersNativeSchemaPrompt`, 
`test_row_type_info_output_schema_renders_json_schema_in_the_prompt`, 
`test_row_type_info_output_schema_registers_the_native_schema_prompt` |
   
   Coverage by risk: parity is pinned by shared expected strings, the fallbacks 
by prompt-level tests in both languages.
   
   Not verified: nested or non-basic rows on the new path (unchanged, 
untested), and any model's response to the new prompt. The response side still 
copies JSON values into the `Row` without converting them to the field types, 
and a missing field gives `null` in Java but a `KeyError` in Python; both are 
outside this PR.
   
   <details><summary>Verification runs</summary>
   
   `api` tests pass on JDK 17 (748 run, 13 skipped), the Python `api` and 
`plan` tests pass (1305), and `tools/lint.sh -c` passes on JDK 11. JDK 21 lint 
passes too, but it skips Spotless there.
   
   </details>
   
   ### API
   
   Existing signatures and accepted schema kinds are unchanged. Rows with only 
string, boolean or numeric fields get different prompt text; other rows keep 
theirs. Native support and response conversion are unchanged. 
`RowTypeJsonSchema` is new and `@Internal`; `render_row_type_json_schema` is a 
new function in `flink_agents.api.agents.types`.
   
   ### 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