- crypto.go: Add runtime validation to Encrypt() that verifies the key file
still exists on disk before encrypting. If the key was deleted while Pulse
is running, encryption now fails with a clear error instead of creating
orphaned data that can never be decrypted.
- hot-dev.sh: Auto-generate encryption key for production data directory
(/etc/pulse) when HOT_DEV_USE_PROD_DATA=true and key is missing. This
prevents startup failures and ensures encrypted data can be created.
- Added test TestEncryptRefusesAfterKeyDeleted to verify the protection works.
The unified agent now handles temperature monitoring in v5+, making
pulse-sensor-proxy unnecessary. This commit:
1. Adds INSTALLER_MAJOR_VERSION constant to declare bundled version
2. Skips 'Temperature Monitoring Setup' prompts for v5+ installs
3. Skips sensor proxy installation entirely for v5+
4. Updates help text to mark --proxy as deprecated for v5+
5. Removes outdated sensor proxy instructions from completion message
Fixes the 'pct pull TASK ERROR: failed to open /opt/pulse/bin/pulse-sensor-proxy-linux-amd64'
error reported by users installing v5.0.0-rc.3.
Reported-by: RLSinRFV (GitHub Discussion #845)
Fixes issue where Ollama users get 'I'm a large language model, I can't do XYZ'
responses when trying to use the AI assistant. The problem was that the
Ollama provider was not passing tool definitions to the API.
Changes:
- Add Tools field to ollamaRequest struct
- Add ollamaTool, ollamaToolFunction, ollamaToolCall structs
- Convert tools from ChatRequest to Ollama format in Chat()
- Parse tool_calls from Ollama response
- Set StopReason to 'tool_use' when model requests tool execution
- Handle tool results in multi-turn conversations
Requires Ollama v0.3.0+ and a tool-capable model (llama3.1+, mistral-nemo, etc.)
Closes: Discussion #845 comment by misterlegend
Release improvements:
- Add standalone Linux agent archives (amd64, arm64, armv7, armv6, 386) to releases
- Previously only Darwin/Windows had standalone agent downloads
Agent version mismatch detection:
- New agentVersion.ts utility compares agent versions against server version
- DockerHostSummaryTable now shows accurate 'outdated' warnings when
agent version is older than the connected Pulse server
- Better tooltips explain version status and upgrade instructions
Previously, SyncGuestBackupTimes matched backups to guests using only VMID.
This caused newly created containers to incorrectly show old backup times
from different containers on other Proxmox instances that happened to have
the same VMID.
Now uses composite key (instance+VMID) for PVE storage backups to ensure
proper isolation. PBS backups still use VMID matching (since they aggregate
from multiple sources) but only as a fallback.
Fixes issue where ollama LXC showed 'last backup 3 months ago' despite
being created yesterday.
- Add sanitizeEndpointError() to transform raw Go errors into user-friendly messages
- Transform 'context deadline exceeded' into helpful messages mentioning possible causes
- Storage timeout errors now suggest checking PBS/NFS/Ceph backend connectivity
- Connection refused, certificate errors, and auth errors get actionable hints
- Apply sanitization everywhere cluster endpoint lastError is stored
- Add comprehensive tests for all error transformations
Adds TestOIDCEnvVarsWithNilConfig to catch the case where OIDC_* env
vars were silently ignored when no oidc.enc file existed. This documents
the proper pattern of initializing OIDCConfig before calling MergeFromEnv.
Add max-height and overflow-y-auto to the model selector dropdown in
the AI chat panel to prevent it from extending past the screen when
there are many models available (e.g., with Ollama).
Fixes feedback from discussion #845
When OIDC_* environment variables were set but no oidc.enc config file
existed, cfg.OIDC was nil and MergeFromEnv would silently return without
applying the env vars (due to nil receiver check).
Fix: Initialize cfg.OIDC to default values before merging env vars if
it's nil. This ensures OIDC can be configured purely through environment
variables without requiring a pre-existing config file.
Related to #853
Reverts overly strict alert ID validation that was rejecting valid
alert IDs containing special characters. Docker host IDs can contain
user-supplied data like hostnames which may include parentheses,
brackets, or other printable ASCII characters.
The previous validation only allowed alphanumeric + limited punctuation,
which caused 400 errors when acknowledging alerts from Docker hosts
with special characters in their identifiers.
Related to #852
Adds FreshHours and StaleHours settings to control when the dashboard
backup indicator shows green (fresh), amber (stale), or red (critical).
- Backend: Added FreshHours/StaleHours to BackupAlertConfig (default 24/72 hours)
- Frontend: getBackupInfo() now accepts optional thresholds parameter
- Dashboard/GuestRow components use thresholds from alert config
- Settings saved/loaded with alert configuration
Closes#839
- Add integration tests for Ollama provider (17 tests against real API)
- Add unit tests for baseline, correlation, patterns, memory, knowledge, cost packages
- Add context formatter and builder tests
- Add factory tests for provider initialization
- Add Makefile targets: test-integration, test-all
- Clean up test theatre (removed struct field tests)
Integration tests require Ollama at OLLAMA_URL (default: 192.168.0.124:11434)
Run with: make test-integration
Previously the Retry-After header was hardcoded to "60" seconds
regardless of the rate limiter's actual window duration. Now uses
the limiter's configured window (e.g., 600 seconds for recovery
endpoints, 300 for exports).
Related to #579
- Replace verbose info banner with streamlined layout
- Add collapsible 'Advanced Model Selection' accordion for Chat/Patrol models
- Make AI Patrol Settings section collapsible with inline summary badges
- Compact Cost Controls into single-row inline layout
- Reduce form spacing for tighter presentation
- Remove unused formHelpText import
Also includes:
- OpenAI provider fixes for max_tokens parameters
- Security setup CSRF and 401 fixes
- Minor UI tweaks
The installer had a fallback that tried to copy the sensor-proxy binary from
inside the Pulse container using `pct pull`. However, the paths it tried
(/opt/pulse/bin/pulse-sensor-proxy-linux-amd64) don't exist in Pulse containers.
When pct pull fails, Proxmox logs a task error visible in the UI, even though
the error is harmless and expected. This caused recurring "TASK ERROR: failed
to open /opt/pulse/bin/pulse-sensor-proxy-linux-amd64: No such file or directory"
messages every time the selfheal timer ran and couldn't download from GitHub.
The pct pull approach was never going to succeed for LXC-installed Pulse instances
since the binary doesn't exist at those paths inside the container. Removing it
eliminates the spurious error messages.
Related to #817
The frontend was incorrectly assuming any 401/403 response from the
quick-setup endpoint meant the legacy DISABLE_AUTH flag was present.
This was wrong - the real causes are typically:
- Missing bootstrap token (for first-run setup)
- Invalid bootstrap token
- Authentication required for existing setups
Now the frontend properly displays the actual error message from the
backend, which includes helpful instructions for retrieving the
bootstrap token.
Backend fixes:
- Strip provider prefix (anthropic:, openai:, deepseek:, ollama:) in all
provider Chat methods and constructors for robust handling
- Models are now correctly parsed regardless of caller format
Frontend fixes:
- Tool cards now persist in AI chat after approval execution by adding
to streamEvents array
- Dashboard now listens for pulse:metadata-changed custom event
- AI Chat emits this event when set_resource_url tool completes
- Guest URL icons now update instantly when AI sets them
- Add setup modal that appears when enabling AI without configured provider
- Modal allows selecting provider (Anthropic, OpenAI, DeepSeek, Ollama)
- Enter API key/URL and enable AI in one smooth flow
- Reorder backend to apply API keys before enabled check
- Fix Ollama to strip 'ollama:' prefix from model names
- Simplify backend error message for unconfigured providers
Previously the workflow ran install.sh without --version, which caused it
to download the latest stable release instead of the target release tag.
This was causing the demo server to downgrade from RC versions to stable
when triggered via workflow_dispatch.
Skip arm64 QEMU emulation in preflight tests - staging images are only
used for integration tests which run on amd64. This cuts ~20-30 minutes
off the release pipeline.
Multi-arch Docker images are still built in the final release job via
publish-docker.yml.
The PULSE_SENSOR_PROXY_SELFHEAL env var is set to "1", but the check
was only looking for "true", causing selfheal to regenerate itself on
every run. This meant the cached installer would overwrite the selfheal
script with its (potentially older) version, defeating any fixes in
the selfheal script.
Now correctly checks for both "true" and "1".
Related to #849
The selfheal timer was running the full installer every 5 minutes even when
the service was already running and healthy. This caused unnecessary:
- Pulse service restarts
- Config migrations
- Socket setup
- 172MB memory spikes and 15s CPU usage per run
Now the selfheal exits early after checking service health, only proceeding
to reinstall logic if the service is actually failing.
Fixes#849
When a user configures only Ollama (or any single provider) via the
multi-provider UI without explicitly selecting a model, GetModel() now
returns that provider's default model instead of falling back to the
legacy Provider field which defaults to "anthropic".
This fixes "API key is required for anthropic" errors when enabling AI
with only Ollama configured.
Related to #847
The selfheal timer was downloading prerelease versions (e.g., v5.0.0-rc.1)
even when users had the stable channel selected. This happened because
fetch_latest_release_tag() didn't filter out prereleases from the GitHub
releases API response.
Now both the Python-based parser and the grep fallback skip prereleases:
- Python: checks `release.get("prerelease")` field
- Grep fallback: filters out -rc, -alpha, -beta patterns
Related to #849
The form pre-fills the Ollama URL field with http://localhost:11434 but
compared it against that same default value to detect changes. This meant
users configuring Ollama with the default URL never actually saved it.
Also shows actual backend error messages instead of generic "Failed to update"
when toggling the AI enable switch.
Related to #847
The enable validation was using the legacy single-provider model which
checked settings.Provider and settings.APIKey. Users configuring Ollama
via the new multi-provider UI (setting ollama_base_url) couldn't enable
AI because settings.Provider defaulted to "anthropic" which required an
API key.
Now checks GetConfiguredProviders() first - if any provider is configured
(Anthropic, OpenAI, DeepSeek, or Ollama), AI can be enabled.
Related to #847
Fixes#819
The installer was hanging at 'Pending control-plane sync detected' because
systemctl start ran synchronously, waiting for the selfheal service to complete.
If the control-plane sync failed or took a long time (e.g., Proxmox node not
configured in Pulse yet), the installer would hang indefinitely.
Changed to use 'systemctl start --no-block' to run the selfheal service
asynchronously in the background. The sync will still be attempted, but the
installer will complete immediately and show the success message.
The container config backup and pct commands could hang indefinitely
when the Proxmox cluster filesystem (pmxcfs) is slow or unresponsive.
This caused the installer to appear to hang after printing
"Configuring socket bind mount..." with no further output.
Added timeout protection to:
- Container config backup cp operation
- pct status check
- pct config verification
- Config rollback cp operation
Related to #738
On TrueNAS, the runtime binary may be in /root/bin or /var/tmp while
the install script only checked INSTALL_DIR (/data/pulse-agent).
This left the running process using the binary when the script tried
to copy a new version, causing "Text file busy" errors.
Now explicitly stop the service and kill any pulse-agent processes
before modifying binaries on TrueNAS systems.
Related to #846
The standalone installer creates the socket at /mnt/pulse-proxy on the host,
not /run/pulse-sensor-proxy. Updated documentation to show the correct mount:
/mnt/pulse-proxy:/run/pulse-sensor-proxy:ro
Related to #822
LXC containers share the host's /sys/class/dmi/id/product_uuid, which
causes gopsutil to return identical HostIDs for all LXC containers on
the same physical host. This results in agent ID collisions where
multiple LXC containers appear as a single host in Pulse.
The fix detects LXC containers and prefers /etc/machine-id (which is
unique per container) over gopsutil's HostID.
Related to #773