Commit Graph
7 Commits
Author SHA1 Message Date
SMKRV 5af733b1b0 feat: v2.5.0 - disable_thinking, reasoning models, MIT license, security hardening
Features:
- disable_thinking toggle (issue #11) with per-provider semantics:
  OpenAI classic gets /no_think soft-switch, OpenAI reasoning gets
  reasoning_effort=low, DeepSeek gets both, Anthropic no-op (thinking
  opt-in), Gemini 2.5+ gets thinking_budget=0
- OpenAI reasoning model support (o1/o3/o4-mini/gpt-5 family):
  max_completion_tokens, developer role, reasoning_effort
- Per-request disable_thinking override in ask_question service
- Provider-specific temperature clip (Anthropic 0-1, others 0-2)

Security:
- Require API key re-entry on provider change (OptionsFlow)
- Validate Anthropic json_schema before system-prompt concatenation
- Symlink protection in history file operations
- Hardened secret redaction regexes (sk-*, AIza*, x-api-key)
- get_history service: hard cap on limit (default 10, max 100)

Reliability:
- Retry on 502/503/504 in addition to 429/timeout
- Honor Retry-After header on 429
- Exception chaining (raise ... from err)
- _strip_think_blocks handles nested/dangling tags
- normalize_name sha256 fallback for empty-collapse inputs

UI/housekeeping:
- api_key uses TextSelector(type=PASSWORD)
- DeviceInfo entry_type=SERVICE
- Services unregister on last entry unload
- Dependabot for GitHub Actions
- persist-credentials=false in checkout steps
- manifest requirements pinned with upper bounds
- Ignore docs/plans/ (working artifacts)

License: PolyForm Noncommercial 1.0.0 -> MIT

No breaking changes: service response shape, sensor attributes,
entity IDs and on-disk formats unchanged.
2026-04-17 01:30:57 +03:00
SMKRV 4e3b4cfdb7 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
2026-03-12 12:43:03 +03:00
SMKRV c45828953d chore: Change license from CC BY-NC-SA 4.0 to PolyForm Noncommercial 1.0.0
Replace Creative Commons Attribution-NonCommercial-ShareAlike 4.0
with PolyForm Noncommercial License 1.0.0 across all files:
LICENSE, README badge/footer, and all Python module headers.
2026-03-12 12:13:54 +03:00
SMKRV c8be545655 fix: Prevent shallow copy mutation in async_get_history with include_metadata
When include_metadata=True, the metadata dict was added directly to the
original history entry objects (shallow copy of list, same dict refs).
Now creates per-entry dict copies before enriching with metadata.
2026-03-12 02:24:52 +03:00
SMKRV a8a91972ba 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
2026-03-12 02:24:09 +03:00
SMKRV 31560a8835 fix: Round 2 review findings — async SSRF, error sanitization, constants
Security:
- Make validate_endpoint async with hass.async_add_executor_job for DNS resolution
- Use _RestrictedIPError instead of fragile string matching for IP check flow
- Add is_multicast/is_unspecified to SSRF IP restriction checks
- Remove resolved private IP from error messages (generic message)
- Remove raw endpoint from __init__.py error log
- Sanitize error messages in metrics: strip URLs, API keys, Gemini key patterns
- Truncate API error response bodies before logging (512 chars)
- Use generic error messages in Gemini exception handlers (no str(e) interpolation)
- Pass api_key as explicit APIClient constructor parameter (not from header)
- Add defensive validation: Gemini provider requires api_key at construction

Code quality:
- Add constants: DEFAULT_INSTANCE_NAME, MIN/MAX_CONTEXT_MESSAGES, MIN/MAX_HISTORY_SIZE
- Replace all hardcoded schema ranges with named constants
- Move datetime import to module level in history.py
- Remove unused full_history/full_history_available keys
- Chain socket.gaierror properly with raise...from
2026-03-12 01:57:49 +03:00
SMKRV c54bfcff3b fix: Coordinator split, Gemini chat context, review findings fixes
- Extract HistoryManager (history.py) and MetricsManager (metrics.py) from coordinator
- Fix Gemini chat: use client.chats.create(history=...) instead of sequential send_message
- Fix float("inf") in metrics breaking json.dump persistence
- Fix _get_current_state checking wrong error key ("error" vs "error_message")
- Fix API key re-entry requirement when endpoint/provider changes in options flow
- Make CONF_API_KEY optional in options schema (stored key used as fallback)
- Add DNS rebinding protection via socket.getaddrinfo in validate_endpoint
- Remove mass assignment vulnerability in config_flow._create_entry
- Add description_placeholders to all error re-show paths
- Fix history migration overwriting existing JSON data
- Return list copy from get_limited_history to prevent reference leaks
- Add history_info to _get_safe_initial_state for data shape consistency
- Add defensive None check in _get_sanitized_last_response
- Move dt_util import to module level in config_flow
- Remove dead fallback branches in coordinator.last_response property
- Fix sensor min_latency display after float("inf") removal
- Fix history directory permissions from 0o777 to 0o755
- Deduplicate schema definitions via _build_provider_schema()
- Use centralized build_auth_headers from providers.py
2026-03-12 01:50:17 +03:00