Fixed
- Gemini no longer rejects the tool schemas Home Assistant's own intents produce, reported with a root-cause analysis, patch and repro tests by @hruba202 in #527. Gemini validates function declarations through protobuf and refuses an
anyOfbranch that carriesrequiredwithout beingtype: object, or one whoserequirednames a property that branch does not define (any_of[N].required: only allowed for OBJECT type).voluptuous_openapiemits exactly that shape for the "at least one target" pattern behindHassTurnOnand its siblings —vol.Required(vol.Any("name", "area", "floor"))becomes parent-level properties plus bare-requiredvariants — so a Gemini install could fail on any turn where those tools were offered. Those branches are now stripped before the declaration is sent, variants emptied by the strip are dropped (and a fully emptiedanyOfremoved) so noTYPE_UNSPECIFIEDentry reaches the proto, and what the strip drops is restated in the schema description — "At least one of: name, area, floor is required." — so the model still reads the constraint it can no longer be made to validate._ensure_array_items()(#430) already normalized the neighbouringitems/anyOfproblem but never touchedrequired. - The strip is gated on Gemini and applied to no other provider. Those branches are valid JSON Schema, and OpenAI, Anthropic and Ollama all honour them; running the pass unconditionally would advertise a schema permitting a targetless
HassTurnOn, which the model would duly emit and Home Assistant's own voluptuous validation would then reject at run time — trading a provider-specific error for a silent capability loss everywhere else. A variant carryingpropertiesbut no explicit type is treated as an object rather than stripped wholesale, and a malformedanyOforrequiredfrom a custom tool serializer is skipped rather than raised, so one bad schema cannot take down tool selection for the whole turn.