Skip to content

v1.1.0 - Spectra

Choose a tag to compare

@seiggy seiggy released this 06 Mar 22:29
· 485 commits to master since this release
9a1185d

Release Notes - 1.1.0

Release Date: March 6, 2026
Code Name: "Spectra"


🔮 Overview

"Spectra" delivers Lucia's largest entity-intelligence upgrade to date and folds in post-cut stabilization work across Home Assistant conversation flow, model-provider support, setup/plugins UX, and CI reliability. This release unifies entity modeling, introduces multi-signal matching, fixes semantic prompt-cache persistence and thresholding, and hardens the platform for day-to-day operation.

🚀 Highlights

  • Unified Entity Model — All Home Assistant entity types now share a common HomeAssistantEntity base with domain-specific subtypes.
  • HybridEntityMatcher — Multi-weighted search combines Levenshtein, Jaro-Winkler, phonetic matching, aliases, and token overlap.
  • Prompt Cache Overhaul — Embeddings now persist correctly, routing/chat thresholds are split, and cache settings hot-reload without restart.
  • Embedding Resiliency + Live Progress — Entity-location embeddings now generate in throttled background batches, expose SSE progress, and support per-item evict/regenerate controls.
  • Home Assistant Multi-turn Continuity — Follow-up conversation flow restored and HA commit validation tightened.
  • OpenRouter + Discovery — OpenRouter added as a first-class provider with model discovery support.
  • Plugin/Setup/Dashboard Stabilization — Headless setup and HA setup-step UX improvements, plugin installation reliability fixes, and dashboard/tooling cleanup.
  • Brave Search API Plugin — New privacy-respecting web search plugin using the Brave Search API, with full plugin config GUI for managing API keys from the dashboard.
  • CI Hardening — HACS validation workflow corrected, deployment docs lint cleanup, and release pipeline reliability improvements.

✨ What's New

🔍 HybridEntityMatcher

  • Multi-signal scoring — Combines normalized Levenshtein, Jaro-Winkler, token overlap, phonetic matching, and exact/prefix bonuses into a weighted composite score.
  • Configurable via HybridMatchOptions — Tune weights, minimum thresholds, and phonetic algorithm (Soundex vs Double Metaphone) per search context.
  • IMatchableEntity interface — Any entity type can participate in hybrid search by implementing this lightweight interface.
  • EntityMatchResult — Rich result type carrying the matched entity, composite score, individual signal scores, and match metadata.

🏠 Unified Entity Architecture

  • HomeAssistantEntity base class — Shared properties (entity ID, friendly name, area, floor, aliases, state, supported features as SupportedFeatures bitflag enum) for all HA entity types.
  • Domain subtypesLightEntity, ClimateEntity, FanEntity, MusicPlayerEntity extend the base with domain-specific attributes (color modes, HVAC modes, fan speeds, media metadata).
  • EntityLocationService refactor — Centralized entity resolution service replaces per-skill FindLightsByAreaAsync/FindLightAsync methods. Skills now delegate entity lookup to the location service.
  • AreaInfo caching — Areas now pre-build and cache entity collections, floor associations, and phonetic data for fast hierarchical search.
  • FloorInfo model — First-class floor representation with area containment for multi-level home topologies.

👁️ Entity Visibility

  • EntityVisibilityConfig — Per-entity visibility settings stored in MongoDB, letting users hide entities from Lucia without removing them from Home Assistant.
  • EntityVisibilityApi — REST endpoints for bulk visibility management with area/domain filtering.
  • HA Exposed Entity List — Support for pulling the pre-filtered exposed entity list from Home Assistant via WebSocket (homeassistant/expose_entity/list).

📡 Entity Embedding Resiliency + Live Progress

  • Name fallback for embedding safety — When an entity/floor/area has no name or alias, matchable names now fall back to IDs (entity IDs strip domain and replace _ with spaces) to avoid invalid empty embedding inputs.
  • Non-blocking embedding generationEntityLocationService now loads/cache location data first, then generates embeddings asynchronously in throttled batches with retry/backoff.
  • Batch embedding pipeline — Uses provider batch generation (GenerateAsync(IEnumerable<string>)) to reduce request pressure and better handle provider-side limits.
  • Progress API + SSE stream — Added /api/entity-location/embedding-progress and /api/entity-location/embedding-progress/live for real-time generation status.
  • Per-item cache controls — Added embedding eviction/regeneration endpoints for floors, areas, and entities.
  • Dashboard live status — Entity Location page now shows a live generation progress bar, missing-embedding count, and updates without manual refresh.

🧠 Prompt Cache Overhaul

  • Embedding persistence fixed — Removed [JsonIgnore] from CachedPromptEntry.Embedding and CachedChatResponseData.Embedding that prevented embeddings from ever being serialized to Redis.
  • Split thresholdsSemanticSimilarityThreshold (routing, default 0.95) and ChatCacheSemanticThreshold (chat, default 0.98) are independently configurable.
  • Hot-reload via IOptionsMonitor — Cache thresholds update within seconds of dashboard config changes, no restart required.
  • Hit count tracking fix — Routing cache exact-match hits now correctly persist the incremented HitCount back to Redis.
  • Normalized prompt keysNormalizePrompt applies Trim().ToLowerInvariant() for stable, case-insensitive cache keys.
  • User-text-only embedding — Chat cache embeddings are computed from the user's request text only.

🏠 Home Assistant Conversation Flow

  • Restored multi-turn continuity behavior for follow-up requests.
  • Enforced stricter HA-side commit validation in automation and tool flows.
  • Addressed follow-up review feedback for the multi-turn flow fix set.

🤖 Model Providers

  • Added OpenRouter as a provider option in model-provider interactions.
  • Expanded model discovery flow and post-review provider hardening.

🔌 Setup, Plugins, and Dashboard

  • Improved headless setup and Home Assistant setup-step UX.
  • Fixed plugin tooling/integration issues that blocked reliable plugin installation.
  • Resolved setup/plugin/dashboard review and lint issues.

🌐 Brave Search API Plugin

  • New web search providerplugins/brave-search/plugin.cs implements IWebSearchSkill using the Brave Search API as an alternative to SearXNG.
  • API key authentication — Configurable via BraveSearch:ApiKey, BRAVE_SEARCH_API_KEY env var, or the new plugin config GUI.
  • Full telemetry — OpenTelemetry ActivitySource and Meter instrumentation for request counts, failure counts, and search duration.
  • Provider-agnostic agent — General Agent skill description no longer references SearXNG; works with whichever search plugin is active.

⚙️ Plugin Configuration GUI

  • Schema-driven config — Plugins can now declare configurable properties via ConfigSection, ConfigDescription, and ConfigProperties on the ILuciaPlugin interface (default interface members — non-breaking).
  • PluginConfigProperty record — Defines name, type, description, default value, and sensitivity for each config field.
  • GET /api/plugins/config/schemas — New endpoint aggregates config schemas from all loaded plugins.
  • Dashboard Configuration tab — New tab on the Plugins page renders dynamic forms from plugin schemas, with sensitive-field masking, save/discard, and toast notifications.
  • SearXNG retrofitted — SearXNG plugin now declares its BaseUrl in the config schema so it can also be configured from the UI.

🐛 Matcher Debug API

  • /api/matcher/debug — Interactive endpoint for testing HybridEntityMatcher queries against live entity data with per-signal score breakdowns.
  • Dashboard pageMatcherDebugPage.tsx provides a UI for experimenting with matcher queries and score distributions.

🔧 Skill Optimizer Migration

  • GetCachedEntitiesAsync removed from IOptimizableSkill — Entity resolution now flows through EntityLocationService.
  • Legacy skill methods retiredLightControlSkill.FindLightsByAreaAsync, FindLightAsync, GetLightStateAsync, and SetLightStateAsync now throw NotSupportedException.
  • Device cache dependencies removedLightAgent no longer depends directly on embedding provider or device cache.

🎯 Skill Optimizer Enhancements

  • Import from Traces — Fixed and operational. Extracts search terms from traced tool calls for the skill's owning agent, using skill-declared SearchToolNames and AgentId instead of hardcoded values.
  • Multi-entity expected results — Test cases now support multiple expected entities (e.g., "kitchen lights" → 2 light entities). New EntityMultiSelect component with chip display, searchable dropdown, and keyboard navigation (↑/↓/Enter/Tab/Escape/Backspace).
  • Partial scoring — Recall (3.0 max) goes negative when expected entities are missed or when results exceed the max count. Precision (1.0 max) rewards exact count matches with partial credit for extras within limits.
  • Export test dataset — New "Export Dataset" button downloads a JSON file containing test cases + entity location data for offline replay and issue reporting.

🕵️ Agent Impersonation & Entity Debugging

  • Impersonate Agent filter — New dropdown on Entity Locations page (Entities + Search tabs) filters the entity view to what a specific agent can see. Auto-applies the agent's configured entity domains and visibility restrictions.
  • Agent domain metadataavailable-agents API returns {name, domains} objects by aggregating EntityDomains from IOptimizableSkill registrations. Domainless agents are filtered out.
  • Server-side domain+agent filtering — Entity and search endpoints accept comma-separated domain and agent query parameters for combined filtering.
  • Entity removal — Delete button on Entity Locations page now fully removes entities from the cache (not just embeddings), fixing issues with stale/duplicate entity IDs.

⚙️ Configurable Skill Domains & Agent Definitions

  • ISkillConfigProvider interface — Agents expose their skill config sections with OptionsType for schema generation. Implemented by LightAgent, ClimateAgent, SceneAgent, and MusicAgent.
  • Dynamic skill config editor — Agent Definitions page renders a schema-driven form for each agent's skill options (EntityDomains, matcher thresholds, etc.). Controls: tag picker for string arrays (backed by available HA domains), range sliders for numbers, integer inputs.
  • EntityDomains via IOptionsMonitor — All skill options classes (LightControlSkillOptions, ClimateControlSkillOptions, FanControlSkillOptions, SceneControlSkillOptions, MusicPlaybackSkillOptions) now include EntityDomains with hot-reload from MongoDB config.
  • IAgentSkill.EntityDomains — All agent skills declare their operating domains. SearchHierarchyAsync calls use the options-backed value instead of hardcoded arrays.
  • Config seeder upgrade — Seeds missing config sections on restart (not just when collection is empty), handling upgrades gracefully.
  • Skill sections hidden from raw Config page — Skill config is managed exclusively through the Agent Definitions page.

🎵 Music Agent Consolidation

  • In-process execution — Music Agent moved from a separate A2A container to always running in-process with AgentHost. Enables IOptimizableSkill and ISkillConfigProvider visibility in the AgentHost DI container.
  • IEntityLocationService migration — Replaced ~300 lines of custom entity resolution (Redis cache, embeddings, Music Assistant-specific filtering, cosine similarity) with the shared SearchHierarchyAsync pipeline.
  • MusicPlaybackSkillOptions — New options class with EntityDomains defaulting to ["media_player"] plus standard matcher params, hot-reloaded via IOptionsMonitor.
  • Kubernetes cleanup — Removed music-agent Service, Deployment, and image overrides from helm chart and raw manifests. Only timer-agent remains as an external A2A pod.

🐳 CI/CD and Delivery

  • Added support for pre-release Docker tags without moving latest.
  • Fixed CI workflow ordering to check out repository contents before HACS validation.
  • Fixed deployment markdownlint issues and removed defunct documentation.

🐛 Bug Fixes

  • Prompt cache embeddings never persisted — Fixed serialization of embedding fields.
  • Chat cache replayed incorrect actions — Prevented cross-action semantic collisions by splitting routing/chat thresholds.
  • Routing cache hit count not persisted — Exact-hit HitCount now writes back to Redis.
  • Cache config changes required restart — Migrated to IOptionsMonitor<T> for hot-reload.
  • Embedding provider concurrency issue — Replaced unsafe dictionary usage with concurrency-safe coordination.
  • Tracing duration always reported 0ms — Routing completion timing now measures elapsed request duration correctly.
  • Unsupported tool-chain config caused provider errors — Removed invalid configuration path.
  • Dashboard dependency vulnerabilities — Patched minimatch (CVE-2026-27903) and rollup (CVE-2026-27606).
  • Home Assistant follow-up flow regression — Fixed continuity and follow-up behavior for multi-turn requests.
  • Plugin install regressions — Fixed install path/tooling issues affecting plugin usability.
  • HACS validation workflow failure — Corrected CI step order to ensure repository content is present.
  • Startup embedding failures from blank input — Prevented invalid embedding calls caused by empty match names.
  • Embedding request bursts during cache reloads — Moved generation to throttled background batching to reduce provider rate-limit pressure.
  • Presence sensor refresh duplicate-key crashes — Fixed MongoDB duplicate key failures on re-scan by deduplicating auto-detected sensor IDs and skipping IDs already reserved by user overrides (issue #41).
  • Skill Optimizer "Import from Traces" broken — Fixed hardcoded tool names (used deprecated FindLightAsync instead of GetLightsState), missing agent filter on trace queries, and parameter name mismatch (searchTerm vs searchTerms array). Trace import now uses skill-declared SearchToolNames and AgentId.
  • Music Agent playback regression — Removed unnecessary ?return_response query parameter from play_media service calls. Migrated Music Agent from custom entity resolution (Redis cache, embeddings, MA-specific filtering) to shared IEntityLocationService.
  • Stale entities in location cache — Added full entity removal (not just embedding eviction) so duplicate/orphaned entities can be deleted from the cache.
  • Kubernetes HPA for single-instance app — Removed HorizontalPodAutoscaler from helm chart and raw manifests since Lucia doesn't support multi-instance yet.

🧪 Testing

  • Playwright e2e testPromptCacheRoutingTests validates prompt-cache embedding round-trip and semantic route matching behavior.
  • Embedding diagnosticsEmbeddingMatchingTests measure similarity behavior across synonym/opposite/cross-domain prompt variants.
  • Plugin/install regression coverage — Added and updated tests around plugin installability and related dashboard/setup flows.
  • Name fallback testsEntityMatchNameFormatterTests validates alias sanitization and ID-based fallback behavior used by embedding inputs.
  • Brave Search contract testsBraveSearchWebSearchSkillTests validates HTTP request format, auth headers, JSON deserialization, empty results, and error handling.
  • Plugin config schema testsPluginConfigSchemaTests validates default interface members, schema declaration, property equality, and filtering logic.
  • Skill Optimizer trace import e2e03-skill-optimizer-traces.spec.ts validates traces API returns Light Agent data, skill traces API extracts search terms, and UI "Import from Traces" populates test cases.
  • Agent impersonation e2e04-entity-location-impersonate.spec.ts validates agent domain metadata, entity filtering by domain+agent (22 light/switch entities for light-agent), and search scoping ("zack's light" returns 1 result as light-agent).
  • Dashboard port pinned — Vite dashboard pinned to port 7233 via Aspire WithEndpoint for stable Playwright test URLs.

📋 New Files

Path Purpose
lucia.Agents/Abstractions/IEntityLocationService.cs Centralized entity resolution interface
lucia.Agents/Abstractions/IHybridEntityMatcher.cs Multi-signal entity search interface
lucia.Agents/Abstractions/IMatchableEntity.cs Entity search participation contract
lucia.Agents/Models/HomeAssistant/HomeAssistantEntity.cs Unified HA entity base class
lucia.Agents/Models/HomeAssistant/SupportedColorModes.cs Light color mode bitflag enum
lucia.Agents/Models/HomeAssistant/FloorInfo.cs Floor model with area containment
lucia.Agents/Models/HomeAssistant/OccupiedArea.cs Area occupancy tracking
lucia.Agents/Models/HomeAssistant/EntityVisibilityConfig.cs Per-entity visibility settings
lucia.Agents/Models/HybridEntityMatcher.cs Multi-weighted entity matching engine
lucia.Agents/Models/HybridMatchOptions.cs Matcher configuration (weights, thresholds)
lucia.Agents/Models/MatchableEntityInfo.cs Searchable entity wrapper
lucia.Agents/Models/EntityMatchResult.cs Scored match result with signal breakdown
lucia.Agents/Models/HierarchicalSearchResult.cs Floor→Area→Entity search result
lucia.Agents/Models/ResolutionStrategy.cs Entity resolution strategy enum
lucia.Agents/Integration/SearchTermCache.cs Cached search term normalization
lucia.Agents/Integration/SearchTermNormalizer.cs Query normalization pipeline
lucia.HomeAssistant/Models/ExposedEntityListResponse.cs HA WebSocket exposed entity response
lucia.AgentHost/Apis/EntityVisibilityApi.cs Entity visibility REST endpoints
lucia.AgentHost/Apis/MatcherDebugApi.cs Matcher debug/testing REST endpoints
lucia.Agents/Models/HomeAssistant/EntityLocationEmbeddingProgress.cs Embedding coverage/progress snapshot model
lucia.Agents/Services/EntityMatchNameFormatter.cs Safe name/alias formatter with ID fallback
lucia-dashboard/src/pages/MatcherDebugPage.tsx Matcher debug dashboard page
lucia-dashboard/src/pages/EntityLocationPage.tsx Live embedding progress UI + embedding actions
lucia.PlaywrightTests/Agents/PromptCacheRoutingTests.cs Cache embedding e2e test
plugins/brave-search/plugin.cs Brave Search API web search plugin
lucia.Agents/Abstractions/PluginConfigProperty.cs Plugin config property record type
lucia.AgentHost/PluginFramework/Models/PluginConfigSchemaDto.cs Plugin config schema API DTO
lucia.AgentHost/PluginFramework/Models/PluginConfigPropertyDto.cs Plugin config property API DTO
lucia-dashboard/src/components/PluginConfigTab.tsx Plugin configuration tab component
lucia.Tests/BraveSearchWebSearchSkillTests.cs Brave Search HTTP contract tests
lucia.Tests/PluginConfigSchemaTests.cs Plugin config schema infrastructure tests
lucia.Agents/Abstractions/ISkillConfigProvider.cs Agent skill config section exposure interface
lucia.Agents/Abstractions/SkillConfigSection.cs Skill config section descriptor with OptionsType
lucia.Agents/Configuration/SceneControlSkillOptions.cs Scene skill configurable options
lucia.MusicAgent/MusicPlaybackSkillOptions.cs Music skill configurable options
lucia.AgentHost/Apis/AgentInfo.cs Agent info DTO with domain metadata
lucia-dashboard/src/components/EntityMultiSelect.tsx Multi-select with chips, search, keyboard nav
lucia-dashboard/src/components/SkillConfigEditor.tsx Schema-driven skill config form editor
lucia-playwright/e2e/03-skill-optimizer-traces.spec.ts Skill optimizer trace import e2e tests
lucia-playwright/e2e/04-entity-location-impersonate.spec.ts Agent impersonation filter e2e tests

🗑️ Removed / Deprecated

Path Reason
lucia.Agents/Services/IEntityLocationService.cs Moved to Abstractions/ namespace
lucia.Agents/Models/FloorInfo.cs Moved to Models/HomeAssistant/
lucia.Agents/Models/OccupiedArea.cs Moved to Models/HomeAssistant/
lucia.Agents/Agents/DiagnosticChatClientWrapper.cs Replaced by TracingChatClientFactory
lucia.Agents/Configuration/AgentConfiguration.cs Replaced by AgentDefinition
LightControlSkill.FindLightsByAreaAsync Throws NotSupportedException — use entity tools
LightControlSkill.FindLightAsync Throws NotSupportedException — use entity tools
IOptimizableSkill.GetCachedEntitiesAsync Removed — optimizer uses location service
infra/kubernetes/manifests/07-hpa.yaml Removed — single-instance constraint, no HPA needed
MusicPlaybackSkill custom resolution Replaced by IEntityLocationService.SearchHierarchyAsync
Music Agent A2A container Moved in-process with AgentHost

⬆️ Upgrade Notes

  1. Cache eviction recommended — Evict routing and chat caches via dashboard (or DELETE /api/prompt-cache and DELETE /api/chat-cache) to clear stale entries.
  2. New cache config propertiesRouterExecutor:SemanticSimilarityThreshold (0.95) and RouterExecutor:ChatCacheSemanticThreshold (0.98) can be tuned in dashboard settings.
  3. Skill API breaking changes — Skills calling FindLightsByAreaAsync, FindLightAsync, or GetCachedEntitiesAsync must migrate to unified entity tools via EntityLocationService.
  4. Music Agent now in-process — The music-agent container is no longer deployed separately. Remove the music-agent Deployment/Service from your Kubernetes cluster if upgrading from mesh mode.
  5. HPA removed — If you had a HorizontalPodAutoscaler for the lucia deployment, remove it. Lucia requires a single replica until HA support is implemented.
  6. Skill config auto-seeded — New skill option sections (LightControlSkill, ClimateControlSkill, FanControlSkill, SceneControlSkill, MusicPlaybackSkill) are auto-seeded to MongoDB on first startup. Edit via Agent Definitions page, not the raw Configuration page.
  7. Entity cleanup — Use the new delete button on Entity Locations to remove stale/duplicate entities that may cause service call failures.