potiuk commented on PR #70433:
URL: https://github.com/apache/airflow/pull/70433#issuecomment-5149053128

   Thanks — the bug is real and well diagnosed. `_TYPE_MAP` maps `bytes` to 
`{"type": "string"}` for the tool schema, nothing converted back, so a hook 
method like `S3Hook.load_bytes` failed deep inside `BytesIO` with a `TypeError` 
that gave no hint about where the bad value came from.
   
   The implementation handles the cases I'd want: `Optional[bytes]` and `bytes 
| None` both resolve, real `bytes` values pass through untouched, and the tests 
fail without the fix since the fake hook reports the received type.
   
   **One thing to settle before this goes in: what the string actually 
contains.**
   
   The schema advertises `{"type": "string"}` with no `contentEncoding`, so the 
contract with the model is undefined. Models routinely emit base64 for binary 
payloads. If one does that here, the base64 *text* gets UTF-8 encoded and 
written to storage — wrong bytes, no error, upload reported as successful. That 
swaps a loud crash for silent data corruption, which is the worse of the two.
   
   Worth making the contract explicit rather than leaving it implied. Two 
directions, and I don't think this should be decided in a review thread alone — 
it sets the behaviour for every `bytes` parameter the toolset will ever expose:
   
   1. Declare the encoding in the schema and follow it:
   
      ```python
      bytes: {"type": "string", "contentEncoding": "base64"},
      ```
   
      with a base64 decode in `call_tool`. This is the standard JSON Schema 
mechanism, it supports genuinely binary payloads, and plain text sent by 
mistake fails loudly on decode instead of silently storing the wrong thing.
   
   2. Keep UTF-8 and say so in the schema, via a `description` on `bytes`-typed 
parameters telling the model to send plain text. Smaller change, but it caps 
these tools at text-only payloads.
   
   Either is defensible; leaving it unstated is the option I'd avoid. Input 
from whoever owns `common.ai` would be useful here, since this is a 
provider-wide behaviour decision rather than a detail of this PR.
   
   **Two smaller points:**
   
   `except Exception` around `get_type_hints` is broader than the project 
prefers — `NameError` (unresolvable forward reference) and `TypeError` are the 
realistic failures. It matters more than usual here: the fallback to 
`param.annotation` under `from __future__ import annotations` yields the 
*string* `"bytes"`, which `_resolves_to_bytes` returns `False` for, so coercion 
silently stops happening rather than failing. Worth narrowing the except and 
leaving a comment about that fallback.
   
   `_bytes_param_names` re-runs `inspect.signature` and `get_type_hints` on 
every `call_tool`. `_build_json_schema_from_signature` already does both when 
the tools are built, so the parameter names could be resolved once there and 
reused per call.
   
   ---
   Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting
   


-- 
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