Helix is TeslaSync's optional AI layer. The brand mark (HelixMark) appears
anywhere AI is in play β sidebar nav, chatbot avatar, AI feature badges,
Settings β AI header.
This page is the user-facing reference. The implementation source of truth is:
internal/ai/features/registry.goβ every featureweb/src/ai/features.tsβ frontend mirror, generated bytools/aigeninternal/ai/provider/β provider adapter interface + 4 adaptersinternal/ai/{guard,redact,limit,audit,rag,tools,strategies,dispatch}/β runtime
There is no global "AI on" switch. Each Helix feature is enabled individually from Settings β AI. Disabled features are invisible:
| Surface | Off-mode behaviour |
|---|---|
| HTTP route | Returns 404 Not Found (asserted by tools/aivet) |
| React route | Mounts but renders no AI UI β the withAiFeature HOC short-circuits |
| Background job | The dispatcher gate trips before execution |
| Push notifications | The push fan-out worker filters by kind + recipient mode |
These invariants are enforced in CI by a final-gate test suite (Phase-50) that walks every feature in the registry and asserts each off-mode contract.
| Surface | Route | Description |
|---|---|---|
| Helix Chat | /chatbot |
Evidence-first fleet agent with cross-domain tool use, app knowledge retrieval, and visible provenance |
| AI Settings | /settings/ai |
Per-feature toggles, provider config, usage card, redaction controls, restore panel |
| Inline widgets | various pages | 55+ AI*.tsx widgets, each gated by withAiFeature |
Grouped by intent. Every feature has a stable kebab-case ID; toggle each in Settings β AI.
| Feature ID | What it does |
|---|---|
digest-narration |
LLM narration on top of the weekly digest |
yir-narration |
Year-in-review narration |
period-compare-narration |
"This month vs last month" prose |
tco-narration |
True cost of ownership narrative |
cost-forecast-narration |
Forward-looking charging cost narrative |
battery-health-forecast-narrative |
Battery degradation outlook |
cabin-temperature-impact-narrative |
Cabin-temp impact on range / comfort |
vampire-drain-explanation |
Why your car drank kWh while parked |
| Feature ID | What it does |
|---|---|
nl-alert-builder |
Type a sentence β draft an Alert Studio rule |
nl-automation-builder |
Type a sentence β draft an automation |
nl-dashboard-composer |
Compose a dashboard from prose |
nl-grafana-panel |
Compose a Grafana panel from prose |
nl-sql-playground |
Natural-language β SQL against the warehouse |
nl-drive-search-replay |
"Find the drive where I went over 90" |
nl-search |
Global NL search across fleet entities |
signal-explorer-nl-filter |
NL filter for the signal explorer |
| Feature ID | What it does |
|---|---|
range-prediction-model |
Range prediction under stated conditions |
predictive-maintenance |
Maintenance prediction from telemetry trends |
smart-charge-schedule-suggestion |
Schedule based on rates + departure |
preheat-precool-recommender |
When to pre-condition before a drive |
charging-curve-fingerprint-clustering |
Cluster sessions by curve shape |
ml-charging-curve-clustering |
ML variant with embedding similarity |
learned-per-vehicle-anomaly-baselines |
Per-VIN normal-range learning |
| Feature ID | What it does |
|---|---|
drive-coaching |
Per-drive efficiency coaching |
safety-setting-explainer |
"Why is this safety setting on?" |
anomaly-explanations |
Plain-language anomaly explanations |
mqtt-sse-inspector-explanations |
What does this MQTT / SSE event mean? |
state-machine-debugger-narrator |
Explain a state transition |
log-trace-summarization |
Summarise a log or trace span |
software-update-changelog-summarizer |
Concise summary of a Tesla changelog |
incident-timeline-summarizer |
Timeline summary of an incident |
charging-diagnosis |
Diagnose a slow / failed session |
speed-profile-insights |
Insights from the speed distribution |
route-efficiency-suggestions |
Suggest a more efficient route |
tire-pressure-trend-reasoning |
Reason over tyre pressure trends |
| Feature ID | What it does |
|---|---|
alert-tuning-suggestions |
Suggest threshold / cooldown tweaks |
cross-rule-conflict-detection |
Find rules that fight each other |
quiet-hours-suggestion |
Suggest quiet-hours windows |
inbox-auto-categorization |
Categorise inbox / notifications |
feedback-queue-triage |
Triage the feedback queue |
data-repair-suggestions |
Suggest data-repair actions |
geofence-aware-automation-suggestions |
Suggest automations from geofences |
suggest-new-geofences |
Suggest new geofences from clusters |
auto-name-unnamed-locations |
Name locations from context |
auto-trip-naming |
Name trips from route + endpoints |
| Feature ID | What it does |
|---|---|
voice-mode |
Voice-driven assistant mode |
watch-face-nl-response |
NL response surface for the watch face |
trip-planner-llm-agent |
LLM agent for trip planning |
trip-postcard-share-card-image-generation |
Generated share-card image for a trip |
vehicle-paint-preview |
Image-gen vehicle paint preview |
pii-redaction-shared-exports |
LLM-assisted PII redaction for shared exports |
rag-help |
RAG-backed in-app help |
lifetime-stats-qa |
Q&A over your lifetime stats |
chatbot-llm |
The Helix Chat backend |
| Feature ID | What it does |
|---|---|
__usage__ |
AI Usage Card β per-call audit log + spend |
__redaction_bypass__ |
Per-(feature, provider) redaction-bypass report |
ai-provider-health |
Diagnostic β which adapter is active and what can it do |
The __double_underscore__ IDs are not toggleable per feature; they gate on
ai_mode != 'off'.
Helix talks to LLMs through a small adapter interface
(internal/ai/provider/provider.go). Four production adapters ship in-tree
plus a mock adapter for tests:
| Adapter | Use cases |
|---|---|
openai |
OpenAI hosted models (gpt-4o, gpt-4o-mini, gpt-4.1, β¦) |
azure |
Azure OpenAI deployments (same protocol, different auth + URLs) |
anthropic |
Claude models (Sonnet, Opus, Haiku, β¦) |
ollama |
Self-hosted models via Ollama β fully local |
Provider choice resolves with this precedence (highest wins):
- Per-feature override β set the provider for a specific feature (e.g. use
Claude for
drive-coaching, GPT-4o-mini for everything else). - Mode default β the globally configured default for the current
ai_mode. - No provider β the feature stays off.
See ResolveProviderName in internal/ai/provider/config.go.
Every adapter call is wrapped by decorators in this order (outermost first):
- Trace β OpenTelemetry span with feature ID, provider, model
- Audit β write request / response metadata to the audit log
- Cost β compute spend from token counts Γ per-model price table
(
internal/ai/cost/cost.go) - Rate-limit β per-provider concurrency cap; tripped requests get back pressure, not silent failure
- Redact β outbound PII redaction; bypasses are logged for the bypass report
Result: nothing reaches the network without an audit row and a redaction pass.
The Ollama health prober (internal/ai/health/ollama_poll.go) polls the local
endpoint periodically. If Ollama goes unreachable, the prober suspends the
ollama provider in the rate-limiter so requests fail fast with a clear error
instead of hanging. The ai-provider-health feature exposes the current
adapter snapshot for ops debugging.
Features marked NeedsRAG=true in the registry retrieve relevant chunks from
the pgvector index before calling the provider. The chunk store and the
embedding model are configurable; see internal/ai/rag/.
Helix Chat uses an embedded corpus of maintained TeslaSync documentation. A
local BM25-style retriever ranks that corpus in process, so product questions
remain grounded without provider embeddings, a populated pgvector index, or
the separate rag-help feature toggle. Retrieved passages include source
paths that Chat can cite in its answer.
Every strategy runs under the shared Helix intelligence contract. It requires fleet-specific factual claims to come from tool results or context supplied in the current run, while preserving the output format requested by each feature. Helix calls out missing, stale, sparse, or conflicting evidence instead of filling gaps from model priors. It provides concise rationale, not hidden chain-of-thought.
The shared streaming UI retains a privacy-safe execution trail: tool name, running/succeeded/unavailable status, successful source count, and terminal token usage. Tool arguments and raw result payloads are deliberately excluded from this shared metadata because they can contain locations, VINs, or other fleet details.
Helix Chat can discover safe vehicle summaries and use all twelve core read-only fleet tools: vehicle state and location, battery status, drives and drive detail, charging sessions and charge detail, active and recent alerts, geofences, and period efficiency. It can chain these sources for cross-domain analysis. Questions about TeslaSync itself use the chatbot-scoped application knowledge retriever and cite only sources returned by retrieval.
Features marked NeedsTools=true can invoke functions on the server. The tool
registry lives at internal/ai/tools/:
- Each tool has a typed input schema (reflected from the Go DTO) and a typed output.
- The dispatcher (
internal/ai/dispatch/) validates the model's proposed arguments against the schema before running the tool β no schemaless calls reach state-mutating code. - Multiple tool calls per assistant turn are supported (OpenAI, Azure, and Anthropic all allow it). Every call is round-tripped through the conversation history so the next turn sees the result.
- Provider-specific streaming fragments are assembled into complete, schema-valid tool calls before execution. Partial JSON never reaches a tool.
Features marked NeedsStream=true deliver tokens through SSE via the
provider's streaming endpoint. Deltas are forwarded as they arrive rather than
materializing a complete response and replaying it as one chunk. A stream that
closes without a terminal frame is reported as incomplete. The shared
streaming layer lives at internal/ai/stream/.
The AI Usage Card surfaces:
- Today β token counts, requests, cost, top features
- By feature β per-feature breakdown over the selected window
- Recent β last N calls with feature, provider, model, latency, tokens, cost, and redaction status
Cost is computed locally from the per-model price table; no provider call is needed to price a request.
The redact decorator runs against every outbound payload, replacing well-known
PII surfaces (VINs, emails, GPS coordinates outside the relevant operation,
addresses) with stable token placeholders. Each (feature, provider) pair has a
configurable allow-list for fields that legitimately need the raw value.
Per-(feature, provider) bypass events are written for the
__redaction_bypass__ report.
The AI Restore Panel (Settings β AI) lets you replay a past AI response from the audit log without re-paying the provider. Useful when iterating on a prompt or recovering a lost narration.
The contract is:
- Add a
Featureentry tointernal/ai/features/registry.gowithDefaultOn: false, populatedRoutes, and the right capability flags. - Implement the backend strategy under
internal/ai/strategies/<feature-id>/strategy.gowith agoldens.yamlfixture set. - Wire the handler under
internal/api/ai_<feature_id>_handler.goand mount it insideinternal/api/ai_routes.gousingg.Wrap("<feature-id>", handler). - Add the React component under
web/src/components/ai/AI<FeatureName>.tsxwrapped withwithAiFeature('<feature-id>'). - Run
make generate(orgo run ./tools/aigen) to regenerateweb/src/ai/features.ts. - CI will fail unless:
tools/aivetfinds the route is wrapped byg.Wrap.tools/aigen --checkfinds the frontend mirror is in sync.- The off-mode invariant tests pass for the new feature.
See Configuration β AI for every environment variable. The short version: each provider needs an API key (or, for Ollama, a reachable base URL), and a default model. Per-feature overrides live in the database (Settings β AI writes them).
- Sidebar β the Helix entry (purple) deep-links to
/chatbot. - Settings β Settings β AI owns toggles, providers, audit, restore.
- Inline β wherever you see an
HelixMarkglyph or a "Generate with Helix" button. Each is governed by exactly one feature ID in the registry.
Helix builds on standard provider SDKs and the open Ollama project. The runtime contract (off-by-default, audited, redacted) is described in ADR-015.