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]

Reply via email to