feat: unify ha_config_set_helper response shape (closes #1293)#1303
feat: unify ha_config_set_helper response shape (closes #1293)#1303Patch76 wants to merge 3 commits into
Conversation
Issue homeassistant-ai#1293: ha_config_set_helper exposed four distinct response shapes across create / update / flow-helper actions — three warning placements (nested helper_data, top-level singular, nested updated_data) and two wrapper keys (helper_data, updated_data) plus a flat flow-helper return. Callers using one shape for one action and assuming parity missed data on the others. Converge all three branches onto: - 'data': dict — the post-write payload wrapper key, replacing helper_data (create) and updated_data (update); added to the flow-helper return for cross-action uniformity (flat entry_id/title preserved as convenience accessors) - 'warnings': list[str] — top-level plural list, omitted when empty; replaces the singular 'warning' string that lived in three different nested/top-level positions Per .gemini/styleguide.md: 'Return value restructuring (as long as data still accessible) is NOT a breaking change — these are improvements, encourage them.' Every previous value remains reachable at the new key. Closes homeassistant-ai#1293 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request standardizes the response shape of the ha_config_set_helper tool to improve consistency and simplify client-side integration. By replacing multiple legacy response formats with a single, predictable contract, it ensures that callers can reliably access entity data and warnings regardless of the action performed. The changes maintain backward compatibility by ensuring all previous values remain reachable at the new keys. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request standardizes the response format for helper configuration tools—covering create, update, and flow-helper actions—by introducing a uniform "data" wrapper key and a top-level "warnings" list. These changes resolve inconsistencies where legacy keys like "helper_data", "updated_data", and singular "warning" strings were used across different code paths. Corresponding updates were applied to the E2E and unit test suites, including a new test file to lock in this contract. Feedback suggests ensuring the "tag" update branch also includes the "warnings" key to maintain total consistency with the other branches.
Adopts Gemini medium-priority finding: the tag update branch of ha_config_set_helper was returning a dict literal without the conditional warnings handling that the create + registry-update branches already use (lines 2697, 3346). No tag-path producer appends to warnings today, but the conditional mirrors the sibling pattern so future warnings flow through the uniform contract instead of getting dropped silently. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request standardizes the response structure for helper configuration tools by renaming legacy keys like helper_data and updated_data to a uniform data wrapper and consolidating warnings into a top-level warnings list. These changes are reflected across the codebase and verified with a new unit test suite. Feedback suggests further improving the uniform contract by ensuring that flow helper responses include metadata like area_id and labels within the data object, and addressing potential leaks of category_warning into the payload to maintain a clean and consistent API response across all logic branches.
…o data Closes the three follow-up Gemini findings on PR homeassistant-ai#1303: - create + update branches now route apply_entity_category through a temp dict (cat_result). On success, category lands in data; on failure, the message is appended to the top-level warnings list instead of leaking nested as category_warning inside data. Mirrors the precedent already used by _handle_flow_helper at lines 1395-1407. - update branch (simple/registry path) now propagates area_id and labels to updated_data after a successful entity_registry/update, matching the create branch. Icon stays out for now to match the create branch's current behavior; documenting the icon-propagation asymmetry as a separate future-improvement. - Two new contract tests assert that a failed apply_entity_category on create / update surfaces the warning at the top level (never nested in data) and does not set data['category']. The flow-helper data shape (entry_id + title only) is intentionally left as-is: flow helpers can create N entities, so per-entity registry outcomes belong in the flat applied[] list, not in the single data wrapper. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request standardizes the response schema for helper configuration tools (Issue #1293) by renaming the "helper_data" and "updated_data" keys to a uniform "data" key and consolidating various warning formats into a top-level "warnings" list. These changes affect the create, update, and flow-helper branches in tools_config_helpers.py, with corresponding updates across the E2E and unit test suites. Review feedback suggests optimizing _handle_flow_helper by caching dictionary lookups and removing redundant .get() guards, as well as ensuring consistent key ordering in response dictionaries to maintain a stable API contract.
Implementation SummaryChoices Made:
Problems Encountered:
Suggested Improvements (post-merge):
|
kingpanther13
left a comment
There was a problem hiding this comment.
Contract refactor is solid — cat_result temp-dict routing, the negative-invariant test, and the iterative tightening through commit 827407f all land cleanly. Items to fix before merge:
Requested changes
1. Missing unit coverage: registry-write-failure warning surfacing.
The diff edits the registry-write failure paths at tools_config_helpers.py:2670-2674 (create) and :3288-3290 (update) — both now warnings.append("Config updated but entity registry update failed: ..."). Neither path has a unit test. A regression re-nesting that string under data, or dropping the warnings.append entirely, wouldn't be caught.
A ~30-line mirror of test_create_failed_category_apply_surfaces_top_level_warning that patches the registry /update WS handler to return {"success": False, "error": "..."} and asserts both branches (create + update) surface the message at top level closes it.
2. Encode the contract in a TypedDict + builder, not just the test.
The contract currently lives in four return literals (:1571, :2680, :2796, :3357) plus _assert_uniform_shape. Your own comments at :2628 and :2755 ("No re-annotation — the create branch above already defined…") flag the parallel-construction drift risk in prose. A HelperResponse TypedDict + small _helper_response(action, helper_type, *, entity_id, data, warnings=None, **extras) builder collapses all four call sites onto one, naturally omits empty warnings, and converts the test-enforced invariant into a mypy-enforced one. Same surface area you're already touching — pull it in here rather than letting a fifth return literal accrete before someone else does it.
3. AGENTS.md "Return Values" section drift.
The documented degraded example still shows singular "warning": "...". Update to the plural-list contract this PR establishes so the styleguide doesn't contradict the merged code.
4. Stale line references in inline comments at :2681 and :3296 cite _handle_flow_helper (lines 1395-1407); the referenced precedent is now at :1400-1407. Update with the builder refactor.
5. Missing type annotation at :2798 — response = {...} literal lacks the explicit dict[str, Any] annotation its create-branch sibling at :2697 carries. The comment at :3375 claims "same binding"; the annotation makes that claim load-bearing. Moot if you do (2), but flagging in case you decline.
6. Logger asymmetry at :3286 — the update-branch registry failure does logger.warning(...) alongside warnings.append(...). The equivalent create-branch path at :2670 and the flow-helper path don't. Pick one stance for this PR's surface.
What does this PR do?
Converges the four distinct response shapes that
ha_config_set_helperexposed acrosscreate/update/_handle_flow_helperonto a single uniform contract.Before (issue #1293 finding):
"helper_data": {...}helper_data["warning"](singular string)"updated_data": {...}response["warning"](singular string)"updated_data": {...}updated_data["warning"](singular string)result["warnings"](plural list)A caller doing
result.get("warning")found it on update (top-level singular) but missed every other case. A caller doingresult.get("helper_data")missed update + flow.After:
{ "success": True, "action": "create" | "update", "helper_type": "...", "entity_id": "...", "data": { ... }, # was helper_data / updated_data "warnings": ["..."], # always top-level list; omitted when empty "message": "...", }datais the single wrapper key for the post-write payload across all three branches. Flow-helper'sdatacontains{entry_id, title}(its HA flow_result payload); flatentry_id/title/entity_ids/appliedetc. remain as convenience accessors — they're per-action metadata, not wrapper keys, and are heavily used by callers throughout the test suite.warningsis always a top-levellist[str], omitted when empty. The four nested/singular shapes are gone.Per
.gemini/styleguide.md(lines 172-179): "Return value restructuring (as long as data still accessible) is NOT a breaking change — these are improvements - encourage them." Every previous value remains reachable at the new key.Type of change
Testing
uv run pytest)uv run ruff check)Local runs (Alpine, Python 3.13 musl):
tests/src/unit/test_helper_response_shape.py: 8/8 passed — locks the uniform shape across create + update + flow-helper, assertswarningsis always a list, asserts the legacy singularwarningand thehelper_data/updated_datawrappers are gone everywhere, and asserts a failedapply_entity_categorysurfaces the warning at the top level (never nested insidedata)tools_config_helpers.pyE2E tests (run in CI): 34 mechanical key-renames across 9 e2e test files updated to read from the new
datakey; flow-helper-flat-field accessors (entry_id,entity_ids, etc.) unchanged.Future improvements
result["warning"] = "..."singular-string anti-pattern lives intools_config_scripts.py,tools_config_automations.py,tools_config_scenes.py,tools_groups.py,tools_service.py,tools_integrations.py,tools_energy.py,tools_system.py,tools_addons.py,tools_entities.py,tools_search.py,backup.py. Issue [BUG] Inconsistent response-shape across ha_config_set_helper actions (warning placement, data wrapper key) #1293 scopes onlyha_config_set_helper; sweeping the rest belongs in a follow-up so the diff stays tractable.apply_entity_categorycategory_warninglifted in helpers (this PR); still leaks in siblings. Both create + update branches intools_config_helpers.pynow routeapply_entity_categorythrough a temp dict and append anycategory_warningto the top-levelwarningslist, mirroring the precedent in_handle_flow_helper:L1403-1407. The same pattern still leaks nestedcategory_warningintools_config_scripts.py,tools_config_automations.py,tools_config_scenes.py; aligning those goes with the sibling-bug sweep above.area_id+labelsinto the response'sdataafter a successfulentity_registry/update, but neither propagatesicon. Closing that gap is a small follow-up; out of scope here to keep the diff narrow.tests/src/e2e/pre-existing ruff-format debt. The e2e test files I touched would reformat ~423 lines total underruff format; this is master-state, not introduced by this PR. CI enforces onlyruff check(verified in.github/workflows/pr.yml:45-46), so the debt is non-blocking and stays out-of-scope here.Checklist
helper_data/updated_dataas response key names — verified via grep ondocs/,README.md,AGENTS.md,.gemini/styleguide.md)