feat(value-sources): add sandboxed-Jinja template combinator
A new `template` value source evaluates a hardened, sandboxed Jinja expression over the live values of other value sources — the system's first float combinator. Backend: - Shared engine (utils/template_expr.py): ImmutableSandboxedEnvironment with filters/tests and auto-injected globals stripped; only min/max/abs/round/ clamp exposed; rejects **, string/collection-literal repetition, attribute access and non-global calls; NaN/inf-safe result coercion. - TemplateValueSource model + TemplateValueStream runtime: compile-once, primitives-only eval context, raw[name] exposure, eval_interval throttle, ref-counted input acquire/release, rename-safe hot-update. - Validation: unbound-variable + reserved-name rejection, reference cycle/depth guards (depth-only at create, full cycle at update), runtime acquire() depth backstop, and delete referential-integrity. - API: Create/Update/Response schemas + discriminated unions, _RESPONSE_MAP, and an advisory POST /value-sources/validate-template endpoint. - Demo seed: a static source plus a template combinator example. Frontend: - Editor modal section: repeatable inputs list (EntitySelect rows), a zero-dependency Jinja syntax highlighter, a hints/reference panel, and a debounced live validator that gates Save (stale-response-safe). - Graph editor: read-only template node with one edge per input. - i18n (en/ru/zh), icon, and card rendering. Tests: engine, stream, factory/cycle, validate endpoint, and demo seed.
This commit is contained in:
+7
-2
@@ -461,17 +461,22 @@ Reusable audio filter chains.
|
||||
|
||||
## Value sources
|
||||
|
||||
Dynamic data inputs (brightness and other parameters): static, animated, audio, adaptive, color, sensor, HTTP, and Home Assistant.
|
||||
Dynamic data inputs (brightness and other parameters): static, animated, audio, adaptive, color, sensor, HTTP, Home Assistant, and `template` — a sandboxed-Jinja **combinator** that evaluates an expression over the live values of other value sources.
|
||||
|
||||
| Method | Path | Description |
|
||||
| ------ | ---- | ----------- |
|
||||
| GET | `/api/v1/value-sources` | List all value sources (optional `source_type`). |
|
||||
| POST | `/api/v1/value-sources` | Create a value source (discriminated by `source_type`). |
|
||||
| POST | `/api/v1/value-sources/validate-template` | Validate a template expression + inputs (advisory; always `200` with `{valid, error, errors, warnings, variables}`). |
|
||||
| GET | `/api/v1/value-sources/{source_id}` | Get a value source by ID. |
|
||||
| PUT | `/api/v1/value-sources/{source_id}` | Update a value source; hot-reloads running streams. |
|
||||
| DELETE | `/api/v1/value-sources/{source_id}` | Delete a value source (`409` if referenced). |
|
||||
| DELETE | `/api/v1/value-sources/{source_id}` | Delete a value source (`400` if referenced by a target or another value source). |
|
||||
| WS | `/api/v1/value-sources/{source_id}/test/ws` | Real-time value output stream (~20 Hz). |
|
||||
|
||||
### Template value source (`source_type: "template"`)
|
||||
|
||||
A `float` combinator. Fields: `template` (a Jinja *expression*), `inputs` (`[{name, value_source_id}]` bindings to other value sources), `default_value` (fallback in `[0,1]` on any error), and `eval_interval` (optional re-eval throttle in seconds; `0`/null = every poll). At runtime each input is exposed by its `name` (the source's normalized `0..1` value) plus `raw[name]` (its un-normalized value, where available). Globals: `min`, `max`, `abs`, `round`, `clamp(x, lo=0, hi=1)`. The expression runs in a hardened `ImmutableSandboxedEnvironment` (no statements/blocks, filters, attribute access, `**`, or string repetition); results are coerced, NaN/inf-rejected, and clamped to `[0,1]`. Reference cycles and over-deep nesting are rejected at save time. For time-of-day logic, bind an `adaptive_time` or `daylight` source as an input.
|
||||
|
||||
## Weather sources
|
||||
|
||||
Weather data providers feeding weather-driven value sources.
|
||||
|
||||
Reference in New Issue
Block a user