- _PinnedResolver raises on unpinned hosts instead of falling back to
live DNS: nothing legitimate resolves other hosts on a pinned session
(redirects are off), so fail closed
- dedicated session is also closed on EVENT_HOMEASSISTANT_CLOSE: core
stop does not unload entries, and the raw ClientSession has no HA
auto-cleanup, which left 'Unclosed client session' logs at shutdown
- hassfest.yaml: remove the version-print step, hassfest runs inside
the action's docker image and is never on the runner PATH
- service registration extracted to idempotent _async_register_services,
called from both async_setup and async_setup_entry: unloading the last
entry unregisters services, and a reload (every options change) never
re-ran async_setup, leaving the integration without services
- get_history handler wraps the list in {"history": [...]}: HA rejects
non-dict action responses, so every return_response call failed with a
server error since the service gained SupportsResponse (v2.4.x) - the
path never worked, no consumer could depend on the old shape
- README: get_history example shows response_variable usage and the
actual limit clamp semantics
Both found by live smoke test in HA 2026.7 (Docker), not by static review
- create_pinned_session built directly on aiohttp: the HA helper injects
its own connector and raised TypeError on every setup and config flow
- session lifecycle: closed in APIClient.shutdown, on failed setup, and
in config flow validators; allow_redirects=False everywhere so 3xx
cannot route past the pinned resolver
- defaults: gemini-2.0-flash (shut down 2026-06-01) -> gemini-3.5-flash,
deepseek-chat (retires 2026-07-24) -> deepseek-v4-flash
- DeepSeek V4 disable_thinking via thinking request parameter
- Gemini 3.x disable_thinking via thinking_level (MINIMAL, LOW for Pro)
- get_history limit: no forced default/max in schema, storage layer clamps
- translations: 6 locales caught up with strings.json, 2 orphan keys dropped
- README: manual install path matches zip layout, model sections updated
Security:
- H1 DNS rebinding TOCTOU: validate_endpoint returns (endpoint, resolved_ips);
create_pinned_session builds an aiohttp session with a custom resolver that
returns only the pre-validated IPs, closing the re-resolve gap.
- H2/M3 Shared session cookie pollution: integration no longer uses HA shared
clientsession; isolated session with DummyCookieJar prevents cross-integration
cookie leaks.
- Cloud metadata / link-local block added to allow_local_network mode to
prevent IMDS exfiltration on cloud VMs.
- L3 hard cap extended to history.async_get_history (not only service schema).
ML/LLM correctness:
- _is_openai_reasoning_model uses regex with gpt-5-chat* blacklist and handles
OpenRouter-style openai/ prefix. Future o5/gpt-6 auto-recognized.
- reasoning_effort=minimal for gpt-5 family, low for o-series.
- Gemini 2.5 Pro gets thinking_budget=128 (Pro rejects 0, flash accepts 0).
- Anthropic extracts first type=text block instead of hardcoded content[0].
- /no_think dedup uses word-boundary regex instead of substring.
- DeepSeek-reasoner detected: skips /no_think; preserves reasoning_content.
Reliability:
- Exception chaining added to Gemini-block re-raises.
- Top-level imports for json/re/hashlib (no more lazy stdlib imports).
- allow_local_network logged at INFO, not WARNING on every setup.
Code style:
- PEP 604 type hints across all .py files (dict/list/| None).
No breaking changes for users. Internal API: validate_endpoint return type
changed from str to tuple[str, list[str]].
Add .claude/, .cursor/, .cursorrules, .windsurfrules, AGENTS.md, GEMINI.md
as defensive gitignore entries. None of these files currently exist in the
repo, but this prevents accidental leaks of AI-assistant local state if
such files appear in a future workspace.
Add per-instance boolean option to allow private IP endpoints and HTTP
scheme for self-hosted LLM proxies (LiteLLM, Ollama, vLLM, etc.).
- New CONF_ALLOW_LOCAL_NETWORK config option (default: false)
- When enabled: allows RFC1918 private IPs and HTTP endpoints
- When disabled: full SSRF protection preserved (HTTPS + public IPs only)
- Multicast and unspecified addresses blocked regardless of setting
- Warning logged when local network mode is active
- Checkbox added to ConfigFlow and OptionsFlow UI
- Translations for all 8 languages
Closes#9
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.
- Update recommended models to current versions (Claude 4.6, GPT-5, Gemini 3.1, DeepSeek-V3)
- Add Google Gemini to features list
- Remove YAML configuration section (integration is config_entry_only)
- Remove deleted Api status attribute from documentation
- Update conversation_history display count (1 → 5)
- Fix FAQ with current model names and token limits
- Remove internal spec file
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.
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
CRITICAL:
- Remove OptionsFlowHandler.__init__ (deprecated HA 2024.11+)
- Replace FlowResult with ConfigFlowResult (deprecated HA 2024.4+)
Compatibility:
- Reorder async_unload_entry: unload platforms before coordinator cleanup
- Clean up hass.data[DOMAIN] when last entry removed
- Remove aiohttp from manifest requirements (provided by HA core)
- Replace blocking file I/O in const.py with hardcoded VERSION
- Remove unused os, json, logging imports from const.py
- Fix f-string logger calls in api_client.py to use %s formatting
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
- 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
- Fix 404 accepted as valid API response in config_flow validation (both ConfigFlow and OptionsFlow)
- Sanitize catch-all exception in config_flow (str(e) → "unknown" error key)
- Add exception chaining (from err) to ConfigEntryNotReady raise
- Replace datetime.now() with dt_util.utcnow() for HA timezone convention
- Add defensive raise after retry loop in api_client._make_request
- Remove unused CONF_API_KEY/CONF_NAME imports from const.py
- Restore google-genai dependency in manifest (required for Gemini provider)
Security:
- Add SSRF protection via HTTPS-only endpoint validation with private IP blocking
- Mask API keys in all log output via safe_log_data()
- Sanitize error responses to prevent internal detail leakage
- Remove API key pre-population in config flow forms
- Harden service schemas with input length limits and type coercion
Bug fixes:
- Fix temperature=0 rejected due to Python falsy value bug (0 or default)
- Fix fire-and-forget race condition in coordinator init (5 async_create_task → awaited async_initialize)
- Fix rate limit state not resetting after successful API calls
- Fix ConnectionError incorrectly setting is_rate_limited=True
- Fix _rotate_history calling async method via sync executor
- Fix shutil.move blocking event loop in history migration
- Fix async_shutdown removing wrong key from hass.data
- Replace os.rename with shutil.move for cross-device safety
Improvements:
- Add asyncio.Lock for request serialization
- Replace async_timeout with stdlib asyncio.timeout (Python 3.12+)
- Use SupportsResponse.OPTIONAL for ask_question and get_history services
- Use Platform.SENSOR enum instead of string literal
- Add strings.json for HA translation framework
- Update DEFAULT_ANTHROPIC_MODEL to claude-sonnet-4-6
- Retry only transient errors (429, timeout) in API client
Cleanup:
- Remove dead code: unused schemas, imports, sync_write_history, check_memory, check_connection
- Remove icon copying code from async_setup
- Remove unused dependencies from manifest (anthropic, openai, certifi, async-timeout)
- Remove empty manifest arrays (bluetooth, mqtt, ssdp, usb, zeroconf)
- Fix duplicate JSON keys in 5 translation files
- Fix Serbian translation: "Прекључено" → "Искључено" for disconnected state
Bump version to 2.4.0
- Extended OptionsFlowHandler with two-step configuration flow
- Step 1: Select provider (OpenAI, Anthropic, DeepSeek, Gemini)
- Step 2: Configure API key, endpoint, model, and other settings
- Auto-reload integration on options change
- When switching providers, show appropriate default endpoint and model
- Updated translations for all 8 languages
- Remove __init__ method that was passing config_entry as argument
- OptionsFlow now automatically receives config_entry from base class
- Fixes '500 Internal Server Error' when editing existing integrations
- Introduced `structured_output` and `json_schema` parameters to enhance API responses.
- Updated service schemas and API client methods to handle structured output.
- Added translations for new parameters in multiple languages.
- Updated documentation to reflect changes in service capabilities.
Closes#9
- Add CONF_API_TIMEOUT configuration option (5-600 seconds, default 30)
- Update config_flow.py with api_timeout field in provider form and options flow
- Update api_client.py to use configurable timeout instead of hardcoded value
- Update coordinator.py to use api_timeout for async_process_message
- Update __init__.py to read and pass api_timeout from config
- Merge entry.data with entry.options for proper options flow support
- Add translations for api_timeout in all 8 language files (en, ru, de, es, it, hi, sr, zh)
- Bump version to 2.2.0
Closes#8
- Fixed async_get_history method to accept limit parameter and other filtering options
- Updated service schema to support all parameters from services.yaml
- Added support for start_date, include_metadata, and sort_order parameters
- Version bump to 2.1.9
- Update OpenAI models to GPT-5 and GPT-5 mini
- Update Anthropic Claude models to 4.1, 4.0 series
- Update DeepSeek models to V3.1 and R1
- Update Google Gemini models to 2.5 and 2.0 series
- Modernize model descriptions and capabilities
- Simplify HACS installation instructions
- Update recommended models section (remove year from title)
- Update Claude model names to current format (claude-3.5-sonnet, claude-3.5-haiku)
- Add missing parameters to get_history service documentation
- Remove non-configurable history_file_size parameter from table
- Add missing context_messages parameter to configuration table
- Update all model references in examples to use current naming
- Update default model from gpt-4o to gpt-4o-mini
- Update default temperature from 0.7 to 0.1
- Update default max_history_size from 100 to 50
- Add gemini-2.0-flash as latest recommended Gemini model
- Fix logo image link to use main branch instead of specific commit
- Update configuration parameters table with current defaults
Home Assistant's hassfest validation does not support 'response' section in services.yaml.
The response_variable functionality still works through supports_response=True flag in service registration.
Fixes hassfest validation error: extra keys not allowed @ data['ask_question']['response']
- Added response schema definition in services.yaml for ask_question service
- Set supports_response=True flag when registering the service
- Fixed JSON syntax error in English translation file
- Added comprehensive documentation with examples for response_variable usage
- Users can now capture AI responses directly in variables without sensor delays
Resolves issue where scripts failed with 'Script does not support response_variable' error
- Removed target blocks from all services in services.yaml
- Services now work as global services without requiring device/area/entity selection
- Users can call services directly with only required parameters
- Fixes issue #2 where services incorrectly required target selection after v2.1.8 update
- Remove invalid response schema from ask_question service
- Add required target configuration for all services
- Ensure compliance with Home Assistant service schema requirements
🚀 Major Features:
- Add response variables support to ask_question service
- Eliminate 255-character limitation for AI responses
- Enable direct data access in automations without sensors
- Prevent race conditions in parallel automations
🔧 Production Code Audit & Fixes:
- Enhanced resource management with context managers in api_client.py
- Fixed critical race conditions with asyncio.Semaphore implementation
- Improved file operations with atomic writes and corruption handling
- Enhanced error handling and logging security (removed sensitive data)
- Fixed _check_memory_available method placement in coordinator.py
🌐 Translation Updates (8 languages):
- Updated all translation files with response variables information
- Enhanced service descriptions in: en, ru, de, es, it, hi, sr, zh
- Added information about direct response capability
- Maintained consistency across all language files
📚 Documentation Enhancements:
- Added comprehensive Response Variables section to README
- Created advanced automation examples with response_variable usage
- Added migration guide from sensors to response variables
- Enhanced service documentation with response data structure
- Added practical examples for multi-step AI workflows
🔄 Service Improvements:
- Enhanced ask_question service to return structured response data
- Added comprehensive response schema in services.yaml
- Improved error handling with success/failure indicators
- Added metadata support (tokens, model, timestamp)
�� Version & Manifest:
- Bumped version to 2.1.8
- Maintained compatibility with existing integrations
- Updated service documentation
This release addresses GitHub issue #2 and significantly improves the integration's
production readiness while adding powerful new response variable functionality.
Completely rewrote the Google Gemini integration logic based on google-genai 1.16.0 to fix issue #6.
Key changes:
- Updated to the latest google-genai library
- Made API endpoint abstract while retaining option for custom endpoint configuration
- Refactored logic and classes exclusively within Google Gemini implementation
- All changes are limited to Google Gemini integration refactoring with no impact on other functionality.