fix: Comprehensive v2.4.0 quality pass — 24 review findings + review agent fixes

Phase A — Critical:
- Remove dual timeout stacking in coordinator._send_to_api
- Add Gemini-specific asyncio.timeout (sync SDK via to_thread)
- Store full text in history for context; cap per-field at 32KB on disk
- Fix instance lookup to match by normalized_name
- Add Bearer/sk-/x-api-key credential sanitization patterns

Phase B — Dead code removal:
- Merge async_ask_question/async_process_question into single method
- Remove dead is_anthropic flag from coordinator and __init__
- Remove unused DEFAULT_TIMEOUT and API_TIMEOUT constants
- Remove redundant _create_history_dir calls
- Consolidate async_check_api to use provider registry

Phase C — Config flow correctness:
- Truncate name before uniqueness check (prevent post-truncation collisions)
- Add async_set_unique_id + _abort_if_unique_id_configured
- Extract shared _build_parameter_schema for ConfigFlow/OptionsFlow dedup

Phase D — UX improvements:
- Optimize history write: serialize from memory, single file write
- Show last 5 history entries in sensor attributes (was 1)
- Return actual error type in ask_question service response
- Add dedicated api_key_required error for provider/endpoint changes
- Pass config_entry to DataUpdateCoordinator (HA 2024.8+)

Phase E — Cleanup:
- Extract _apply_structured_output for OpenAI/DeepSeek dedup
- Reduce ABSOLUTE_MAX_HISTORY_SIZE to 200 with Final annotation
- Remove dead translation keys (queued, invalid_characters)
- Migrate to _attr_has_entity_name = True
- Add from __future__ import annotations to all modules
- Remove redundant api_status sensor attribute
- Add missing translation keys (last_model, last_timestamp, etc.)

Review agent fixes:
- Add archive file cleanup (max 3 archives) to prevent disk exhaustion
- Per-entry storage cap (32KB per field) for history on disk
This commit is contained in:
SMKRV
2026-03-12 02:24:09 +03:00
parent 9cdeb9f417
commit a8a91972ba
13 changed files with 272 additions and 275 deletions
+5 -4
View File
@@ -6,6 +6,8 @@ Sensor platform for HA Text AI.
@github: https://github.com/smkrv/ha-text-ai
@source: https://github.com/smkrv/ha-text-ai
"""
from __future__ import annotations
import logging
import math
from typing import Any, Dict
@@ -42,7 +44,6 @@ from .const import (
ATTR_API_PROVIDER,
ATTR_MODEL,
ATTR_SYSTEM_PROMPT,
ATTR_API_STATUS,
ATTR_RESPONSE,
ATTR_QUESTION,
ATTR_CONVERSATION_HISTORY,
@@ -126,9 +127,10 @@ class HATextAISensor(CoordinatorEntity, SensorEntity):
self._conversation_history = []
self._system_prompt = None
self._attr_name = f"HA Text AI {self._instance_name}"
self._attr_has_entity_name = True
self._attr_name = self._instance_name
self.entity_id = f"sensor.ha_text_ai_{self._normalized_name}"
self._attr_unique_id = f"{config_entry.entry_id}"
self._attr_unique_id = config_entry.entry_id
_LOGGER.debug("Created sensor with entity_id: %s", self.entity_id)
_LOGGER.debug("Sensor name: %s", self._attr_name)
@@ -238,7 +240,6 @@ class HATextAISensor(CoordinatorEntity, SensorEntity):
attributes = {
ATTR_MODEL: self._config_entry.data.get(CONF_MODEL, "Unknown"),
ATTR_API_PROVIDER: self._config_entry.data.get(CONF_API_PROVIDER, "Unknown"),
ATTR_API_STATUS: self._current_state,
ATTR_TOTAL_ERRORS: metrics.get("total_errors", 0),
"instance_name": self._instance_name,
"normalized_name": self._normalized_name,