wenjin272 opened a new pull request, #1176: URL: https://github.com/apache/flink-agents/pull/1176
Linked issue: #1093 ### Purpose of change Function tools now validate arguments before executing user code in Java, Python, and both cross-language directions. For example, an integer argument supplied as `"2"` fails validation; omitted arguments receive declared defaults, and nested JSON objects are bound to native parameter types. #### Runtime flow Plan-layer `FunctionTool` builds a `FunctionSchema` from the function signature. It publishes a metadata view with injected fields hidden. At invocation, `tool_call_action` resolves framework values and overwrites matching model arguments, then calls `Tool.call`. `FunctionSchema` validates the complete argument object, applies defaults, and binds native values before the function executes. Cross-language adapters call a cached `FunctionTool` in the function's language and preserve tool-response envelopes. #### Key decisions Keep schema derivation and binding in `plan`, preserving `runtime -> plan -> api`. Execution validates the full signature without tracking argument provenance; injection declarations only drive value resolution and metadata visibility. Preserve complete JSON Schema in Python metadata instead of reconstructing lossy Pydantic models. Remove Java `SchemaUtils`/`ToolMetadataFactory` and duplicated compilation in `AgentPlan`. Cache compiled bridge tools to avoid rebuilding validators on each call. ### Behavioral Semantics #### Interaction decisions | Inputs / declaration | Behavior | |---|---| | Argument omitted, default declared | Apply the default before binding. | | Argument omitted, no default | Required-argument failure. | | Explicit null | Does not select the default; must satisfy the declared schema. | | Model supplies an injected name, framework value available | Framework value wins, then undergoes normal validation. | | Model supplies an injected name, framework source missing | Fail resolution; no fallback to the model value. | | Same function called locally or across languages | Validate in the owning language through `FunctionTool.call`. | #### Behavioral contracts 1. Missing required arguments, extra object fields, wrong types, and violated constraints fail before user code runs. 2. Numeric strings and booleans are not coerced to numbers; integral JSON numbers are accepted as integers within native bounds. 3. Defaults apply only to omitted fields; nested objects bind to native models/POJOs. 4. Injected fields are hidden from model metadata but retain their full execution constraints. Injection does not mutate the original request arguments. 5. Python metadata serialization and bridge transport retain complete schema keywords. 6. Explicit tool success/failure responses survive cross-language transport. #### Failure behavior Invalid defaults and unsupported declarations fail schema construction. Argument validation reports `INVALID_ARGUMENT` with a JSON-pointer path and keyword; native binding failures report `BINDING_ERROR`. Java tool calls return failed `ToolResponse`s for ordinary exceptions; Python direct calls raise, and tool actions convert failures into tool responses. Java interruption restores the interrupt flag and propagates cancellation. There is no new retry or validation fallback. ### Tests | Contract | Coverage | |---|---| | 1. Reject invalid input before invocation | Shared `function-schema-cases.json`; Java `FunctionSchemaTest`, Python `test_function_contract`; invocation counters | | 2. Numeric policy and bounds | Shared string/boolean/fraction/integral cases; `retainsNativeNumericBounds` | | 3. Defaults, null, nested binding | Shared defaults/null/nested cases; native field access in contract functions | | 4. Injection visibility, overwrite, validation, request isolation | `FunctionSchemaMetadataTest`, both hidden-parameter contract tests, Java/Python `ToolCallActionTest` suites | | 5. Lossless schemas | `test_metadata_generation_and_roundtrip_are_lossless`, API metadata tests, bridge tests | | 6. Response envelopes | Java adapter tests and Python `test_python_java_utils.py` | Focused verification covers schema compilation, plan registration/serialization, actions, and real bidirectional Pemja calls. Latest applicable runs: Python plan/bridge **277 passed, 1 skipped**; Java schema/tool/action/cache/bridge **64 passed**; clean schema/tool/Ollama run **31 passed**; clean Plan registration/schema run **123 passed, 2 skipped**. Ruff, Spotless and whitespace checks passed. Not verified: full distributed E2E and external model services; dedicated concurrent-validator stress tests; cache invalidation during function replacement; dynamic cache growth. Java's cache has no size bound and lives with the adapter; Python's interpreter-local LRU holds up to 256 entries and has no automatic definition-change invalidation. <details> <summary>Implementation details and earlier regression evidence</summary> Java uses Draft 2020-12 validation and Jackson binding; Python uses Draft202012Validator followed by Pydantic binding. Invocation passes complete arguments without injection-name lists. Metadata cache keys include hidden names; invocation uses the full-signature tool. Cache entries do not store invocation arguments or results. Earlier revisions passed Java API/Plan/Runtime suites (1927 passed, 14 skipped) and Python non-integration suites (1617 passed, 14 skipped). Those broad suites were not rerun after the final focused cleanup. Clean Maven builds for the cleanup removed stale deleted classes before testing. </details> ### API Python `ToolMetadata.args_schema` now stores `dict[str, Any]`; supplied Pydantic model classes are converted on input. Callers accessing it as a model class must adapt. The generic Python schema utility module and Java schema/factory helpers are removed. Java `@ToolParam` gains nullability, numeric/length/item bounds, and `NO_DEFAULT`; explicit defaults are JSON literals. `required=false` without a default is rejected. Calls previously relying on coercion or unknown fields now fail. `Tool.call` remains the execution entry point; serialized metadata still carries JSON Schema, now preserving its complete content. ### 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: Codex 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]
