mirror of
https://github.com/smkrv/ha-text-ai.git
synced 2026-07-21 22:54:00 +08:00
fix: Resolve production issues — history dir creation and sensor attributes > 16KB
History: - Add defensive os.makedirs in _sync_test_directory_write to ensure directory exists before write test (fixes ERRNO 2 on fresh install) Sensor attributes (fixes Recorder 16KB limit violation): - Reduce conversation_history preview: 3 entries × 256 chars (was 5 × 4096) - Reduce last response/question truncation to 2048 chars (was 4096) - Reduce system_prompt in attributes to 512 chars (was 4096) - Full data remains accessible via ha_text_ai.get_history service
This commit is contained in:
@@ -123,6 +123,7 @@ class HistoryManager:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _sync_test_directory_write(test_file_path: str) -> None:
|
def _sync_test_directory_write(test_file_path: str) -> None:
|
||||||
try:
|
try:
|
||||||
|
os.makedirs(os.path.dirname(test_file_path), mode=0o755, exist_ok=True)
|
||||||
with open(test_file_path, "w") as f:
|
with open(test_file_path, "w") as f:
|
||||||
f.write("Permission test")
|
f.write("Permission test")
|
||||||
os.remove(test_file_path)
|
os.remove(test_file_path)
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ from .const import (
|
|||||||
ATTR_SYSTEM_PROMPT,
|
ATTR_SYSTEM_PROMPT,
|
||||||
ATTR_RESPONSE,
|
ATTR_RESPONSE,
|
||||||
ATTR_QUESTION,
|
ATTR_QUESTION,
|
||||||
ATTR_CONVERSATION_HISTORY,
|
|
||||||
METRIC_TOTAL_TOKENS,
|
METRIC_TOTAL_TOKENS,
|
||||||
METRIC_PROMPT_TOKENS,
|
METRIC_PROMPT_TOKENS,
|
||||||
METRIC_COMPLETION_TOKENS,
|
METRIC_COMPLETION_TOKENS,
|
||||||
@@ -67,7 +66,6 @@ from .const import (
|
|||||||
ENTITY_ICON_PROCESSING,
|
ENTITY_ICON_PROCESSING,
|
||||||
DEFAULT_NAME_PREFIX,
|
DEFAULT_NAME_PREFIX,
|
||||||
CONF_MAX_HISTORY_SIZE,
|
CONF_MAX_HISTORY_SIZE,
|
||||||
MAX_ATTRIBUTE_SIZE,
|
|
||||||
VERSION,
|
VERSION,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -76,6 +74,11 @@ from .utils import safe_log_data
|
|||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# HA Recorder limit is 16384 bytes for state_attributes.
|
||||||
|
# Budget per field to stay well within the limit.
|
||||||
|
_ATTR_TEXT_LIMIT = 2048
|
||||||
|
_ATTR_PROMPT_LIMIT = 512
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@@ -243,7 +246,7 @@ class HATextAISensor(CoordinatorEntity, SensorEntity):
|
|||||||
ATTR_TOTAL_ERRORS: metrics.get("total_errors", 0),
|
ATTR_TOTAL_ERRORS: metrics.get("total_errors", 0),
|
||||||
"instance_name": self._instance_name,
|
"instance_name": self._instance_name,
|
||||||
"normalized_name": self._normalized_name,
|
"normalized_name": self._normalized_name,
|
||||||
ATTR_SYSTEM_PROMPT: (data.get("system_prompt", "")[:MAX_ATTRIBUTE_SIZE]
|
ATTR_SYSTEM_PROMPT: (data.get("system_prompt", "")[:_ATTR_PROMPT_LIMIT]
|
||||||
if data.get("system_prompt") else None),
|
if data.get("system_prompt") else None),
|
||||||
ATTR_IS_PROCESSING: data.get("is_processing", False),
|
ATTR_IS_PROCESSING: data.get("is_processing", False),
|
||||||
ATTR_IS_RATE_LIMITED: data.get("is_rate_limited", False),
|
ATTR_IS_RATE_LIMITED: data.get("is_rate_limited", False),
|
||||||
@@ -253,18 +256,19 @@ class HATextAISensor(CoordinatorEntity, SensorEntity):
|
|||||||
ATTR_HISTORY_SIZE: data.get("history_size", 0),
|
ATTR_HISTORY_SIZE: data.get("history_size", 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
# History limit
|
# Conversation history preview (compact: last 3, truncated to 256 chars).
|
||||||
|
# Full history is available via ha_text_ai.get_history service.
|
||||||
conversation_history = data.get("conversation_history", [])
|
conversation_history = data.get("conversation_history", [])
|
||||||
if conversation_history:
|
if conversation_history:
|
||||||
limited_history = []
|
preview = conversation_history[-3:]
|
||||||
for entry in conversation_history:
|
attributes["conversation_history"] = [
|
||||||
limited_entry = {
|
{
|
||||||
"timestamp": entry["timestamp"],
|
"timestamp": entry["timestamp"],
|
||||||
"question": entry["question"][:MAX_ATTRIBUTE_SIZE],
|
"question": entry["question"][:256],
|
||||||
"response": entry["response"][:MAX_ATTRIBUTE_SIZE]
|
"response": entry["response"][:256],
|
||||||
}
|
}
|
||||||
limited_history.append(limited_entry)
|
for entry in preview
|
||||||
attributes[ATTR_CONVERSATION_HISTORY] = limited_history
|
]
|
||||||
|
|
||||||
# Metrics
|
# Metrics
|
||||||
if isinstance(metrics, dict):
|
if isinstance(metrics, dict):
|
||||||
@@ -283,11 +287,11 @@ class HATextAISensor(CoordinatorEntity, SensorEntity):
|
|||||||
last_response = data.get("last_response", {})
|
last_response = data.get("last_response", {})
|
||||||
if isinstance(last_response, dict):
|
if isinstance(last_response, dict):
|
||||||
attributes.update({
|
attributes.update({
|
||||||
ATTR_RESPONSE: last_response.get("response", "")[:MAX_ATTRIBUTE_SIZE],
|
ATTR_RESPONSE: last_response.get("response", "")[:_ATTR_TEXT_LIMIT],
|
||||||
ATTR_QUESTION: last_response.get("question", "")[:MAX_ATTRIBUTE_SIZE],
|
ATTR_QUESTION: last_response.get("question", "")[:_ATTR_TEXT_LIMIT],
|
||||||
"last_model": last_response.get("model", ""),
|
"last_model": last_response.get("model", ""),
|
||||||
"last_timestamp": last_response.get("timestamp", ""),
|
"last_timestamp": last_response.get("timestamp", ""),
|
||||||
"last_error": (last_response.get("error", "")[:MAX_ATTRIBUTE_SIZE]
|
"last_error": (last_response.get("error", "")[:_ATTR_TEXT_LIMIT]
|
||||||
if last_response.get("error") else None),
|
if last_response.get("error") else None),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user