|
2988 | 2988 | { |
2989 | 2989 | "name": "ha_bulk_control", |
2990 | 2990 | "title": "Bulk Control", |
2991 | | - "description": "Manage multiple entity actions in one request.\n\nWhen NOT to use: use ``ha_call_service`` for one service call targeting a\ngroup or for service-specific payloads that do not fit device actions.\n\nUse this when one request should apply actions to multiple independent\nentities. Optional item parameters carry brightness, temperature, position,\nor other action data.\n\nCaveats: put every target in ``operations`` and call the tool once. Parallel\nexecution is the default, and invalid items are reported without aborting\nvalid operations in the same batch. A batch in which every item fails\nvalidation dispatches nothing and fails the call.", |
| 2991 | + "description": "Manage explicit operations or one deterministic structural bulk action.\n\nWhen NOT to use: use ``ha_call_service`` for service-specific payloads or\nbackend-native group targeting, and ``ha_search`` for fuzzy name discovery.\n\nUse selector mode with exact area or floor IDs when exclusions must be\napplied after recursively expanding generic aggregate membership.\n\nCaveats: selector mode resolves a frozen visible leaf set before dispatch;\nit is not transactional, so Home Assistant may still report per-leaf failures.\nSet ``dry_run`` to preview the resolved set without changing state.", |
2992 | 2992 | "inputSchema": { |
2993 | 2993 | "properties": { |
2994 | 2994 | "operations": { |
2995 | | - "type": "Annotated[list[SkipValidation[BulkControlOperation]], JSON_STRING_COERCION, Field(description=\"All entity operations to execute in this single tool call. Each item requires entity_id and action. Use action='off', not service='turn_off'; do not include domain or service. Example: [{'entity_id': 'light.hall', 'action': 'off'}, {'entity_id': 'light.cave', 'action': 'off'}]\")]" |
| 2995 | + "type": "Annotated[list[SkipValidation[BulkControlOperation]], JSON_STRING_COERCION, Field(description=\"Explicit entity operations. Use this or selector, never both. Each item requires exact entity_id and action. Use action='off', not service='turn_off'.\")]" |
2996 | 2996 | }, |
2997 | 2997 | "parallel": { |
2998 | 2998 | "type": "bool", |
2999 | 2999 | "default": true |
| 3000 | + }, |
| 3001 | + "selector": { |
| 3002 | + "type": "Annotated[SkipValidation[BulkControlSelector] | None, JSON_STRING_COERCION, Field(description='Optional exact structural scope using domain plus area_ids and/or floor_ids, with optional exclude_entity_ids.')]", |
| 3003 | + "default": null |
| 3004 | + }, |
| 3005 | + "action": { |
| 3006 | + "type": "Annotated[str | None, Field(description='One device action applied to every resolved leaf.')]", |
| 3007 | + "default": null |
| 3008 | + }, |
| 3009 | + "parameters": { |
| 3010 | + "type": "Annotated[dict[str, Any] | None, JSON_STRING_COERCION, Field(description='Optional action parameters for selector mode.')]", |
| 3011 | + "default": null |
| 3012 | + }, |
| 3013 | + "timeout_seconds": { |
| 3014 | + "type": "Annotated[float | None, Field(ge=0, le=60, allow_inf_nan=False, strict=True)]", |
| 3015 | + "default": null |
| 3016 | + }, |
| 3017 | + "validate_first": { |
| 3018 | + "type": "Annotated[bool, Field(strict=True)]", |
| 3019 | + "default": true |
| 3020 | + }, |
| 3021 | + "dry_run": { |
| 3022 | + "type": "Annotated[bool, Field(strict=True)]", |
| 3023 | + "default": false |
3000 | 3024 | } |
3001 | | - }, |
3002 | | - "required": [ |
3003 | | - "operations" |
3004 | | - ] |
| 3025 | + } |
3005 | 3026 | }, |
3006 | 3027 | "annotations": { |
3007 | 3028 | "openWorldHint": false, |
|
0 commit comments