wren node: targets from the wiring, on wren 2
Every output is a target and every input besides prompt a reading. A targets setting gives descriptions, values, ranges and per-target guards, model takes a trained pack's artifact digest, min_confidence defaults to the model's threshold. A command is applied whole or not at all, and targets the model was not trained on read degraded. The home path (area/kind ports, groups, brightness, temperature answers) is gone.
This commit is contained in:
@@ -340,113 +340,97 @@ use a [batch flow](../concepts/runs.md) and a Function node.
|
||||
|
||||
### Wren
|
||||
|
||||
**`wren`** — turn a typed command into values for the devices wired to it.
|
||||
**`wren`** — turn a typed command into values for the targets wired to it.
|
||||
|
||||
[Wren](https://github.com/stroblme/wren) is an optional local language model
|
||||
for device commands. Install it in the engine's environment with
|
||||
`pip install git+https://github.com/stroblme/wren@eae4d6ff9ded68e36624972fd3f4a8f8d210b0c2`.
|
||||
The `wren` package on PyPI is an unrelated one. Without the model the node
|
||||
reports a missing dependency.
|
||||
that turns short commands into calls on a fixed list of targets. Install it in
|
||||
the engine's environment with
|
||||
`pip install git+https://github.com/stroblme/wren`. The `wren` package on PyPI
|
||||
is an unrelated one. Without the model the node reports a missing dependency.
|
||||
[Wren's own docs](https://stroblme.github.io/wren/) explain how to describe
|
||||
targets, train a model for them, and what a model can and cannot do.
|
||||
|
||||
| Input | Type | Notes |
|
||||
|---|---|---|
|
||||
| `prompt` | `str` | the command, and the only input that runs the node |
|
||||
| `presence` | `str` | the area the user is in; anything else reads as away |
|
||||
| `outdoor` | `float` or `int` | °C; 20 without it, clamped to −5…30 |
|
||||
| `dark` | `bool` | without it, dark before 07:00 and from 18:00 |
|
||||
| `<area>_temperature` | `float` or `int` | °C, read when the command asks how warm the area is |
|
||||
| any other | `bool`, `int`, `float` or `str` | a **reading**: a target a command may ask about but not set |
|
||||
|
||||
The outputs are `actions`, a list of records, `reply`, `unhandled`,
|
||||
`brightness`, and any number of **targets**. A
|
||||
target is an output named `<area>_<kind>` and bound to the message its device
|
||||
listens on: `living_room_setpoint` bound to `home.setpoint` is the living
|
||||
room's heating. The wiring is the allowlist, so the model can write nothing
|
||||
that is not wired to the node.
|
||||
| Output | Type | Notes |
|
||||
|---|---|---|
|
||||
| `actions` | `list` | one record per call |
|
||||
| `reply` | `str` | what was set or read, as "Kitchen light on." |
|
||||
| `unhandled` | `str` | the prompt, when the node did nothing with it |
|
||||
| any other | `bool`, `int`, `float` or `str` | a **target** a command may set |
|
||||
|
||||
- **area**: `living_room`, `kitchen`, `bathroom`, `bedroom`, `office`,
|
||||
`garden`, `patio`, `garage`, `driveway`, `balcony`
|
||||
- **kind**: `light`, `lamp`, `brightness` for a light; `setpoint`, `heating`,
|
||||
`heat`, `boost` for heating; `media`, `music`, `tv`; `shutter`, `blind`,
|
||||
`cover`; `water`, `watering`, `sprinkler`; `switch`, `plug`, `socket`,
|
||||
`appliances` for a switch, which only wren's s10 model knows
|
||||
|
||||
A port naming anything else, or a kind the installed model lacks, is refused
|
||||
when the flow is built. A port is
|
||||
named after its message unless it is given a name of its own, in the node
|
||||
panel's port name field or as `{"name": "setpoint", "port":
|
||||
"living_room_setpoint"}` through the flow API.
|
||||
|
||||
Targets of one area and kind are one device to the model, and each takes what
|
||||
a call means for its type. A target's current value is the state the model
|
||||
reads.
|
||||
|
||||
| Call | `bool` | number | `str` |
|
||||
|---|---|---|---|
|
||||
| `lights.on` / `off` | `true` / `false` | `100` / `0` | `on` / `off` |
|
||||
| `media.play` / `stop` | `true` / `false` | — | `play` / `stop` |
|
||||
| `heating.set` | — | the temperature | — |
|
||||
| `heating.boost` / `off` | `true` / `false` | — | `boost` / `off` |
|
||||
| `shutters.up` / `down` | `true` / `false` | `100` / `0` | `up` / `down` |
|
||||
| `shutters.stop` | — | — | `stop` |
|
||||
| `watering.start` / `stop` | `true` / `false` | — | `on` / `off` |
|
||||
| `switches.on` / `off` | `true` / `false` | `1` / `0` | `on` / `off` |
|
||||
| `lights.set` / `dim` / `brighten` | — | the level, on `brightness` only | — |
|
||||
A target is named by its port and bound to the message it stands for:
|
||||
`living_room_heating` bound to `home.setpoint` is the living room's heating.
|
||||
Its name, type and current value are what the model is shown, so the wiring
|
||||
is the allowlist and the model can reach nothing that is not wired to the
|
||||
node. A target nothing has set yet is shown as off, as 0 within its range, or
|
||||
as its first value. A port is named after its message unless it is given a
|
||||
name of its own, in the node panel's port name field or as
|
||||
`{"name": "setpoint", "port": "living_room_heating"}` through the flow API.
|
||||
|
||||
| Setting | Default | Notes |
|
||||
|---|---|---|
|
||||
| `apply` | `false` | write to the targets; off, the node only reports |
|
||||
| `min_confidence` | `0.93` | below this nothing is written. wren's s10 model is less sure of itself, use `0.8` with it |
|
||||
| `aliases` | empty | the house's own words, or words the recogniser hears wrong, in the model's: `{"traverse": "living room light", "page too": "patio"}` |
|
||||
| `model` | empty | the trained model, an artifact digest; empty runs wren's demo model |
|
||||
| `min_confidence` | empty | the confidence a call needs; empty takes the model's own threshold |
|
||||
| `targets` | empty | by target port, what the model is told of it and how far it is trusted (below) |
|
||||
| `aliases` | empty | your own words, or words the recogniser hears wrong, in the model's: `{"traverse": "living room light", "page too": "patio"}` |
|
||||
|
||||
Each record in `actions` contains `message`, `value`, `applied`, `delay_s`,
|
||||
`call`, and `confidence`. Unwired calls have an empty `message` and are not
|
||||
applied. Keep `apply=false` while checking how the model interprets commands.
|
||||
Every field of a `targets` entry is optional:
|
||||
|
||||
`reply` is one sentence saying what was applied, such as "Kitchen light on."
|
||||
or "Garage light on in 5 minutes.". When nothing was applied, `unhandled`
|
||||
carries the prompt instead, for something else to answer, such as an
|
||||
[Assistant](#assistant). When no node reads `unhandled`, `reply` says "Sorry,
|
||||
I can't do that yet." instead, so a spoken command never goes unanswered.
|
||||
| Field | Notes |
|
||||
|---|---|
|
||||
| `description` | more words for the target, which help pick it: `"awning over the patio"` |
|
||||
| `values` | the only values a `str` target takes: `["UP", "DOWN", "STOP"]` |
|
||||
| `range` | the lowest and highest value of a number: `[5, 30]` |
|
||||
| `unit` | said after a number in the reply, such as `"°C"`; the model never sees it |
|
||||
| `min_confidence` | this target's own bar, used over the node's, such as a higher one for a lock |
|
||||
| `pass_on` | wren never sets it, and a command on it goes on to `unhandled` |
|
||||
|
||||
`brightness` is the house's, a `float` or `int` from 0 to 100. No wren model
|
||||
makes brightness calls yet. For one that does, the node writes them to
|
||||
`brightness` whatever area they name: "set the brightness in the kitchen to 30%" sets the
|
||||
house to 30. "Dim" and "brighter" move it 30 from its current value (70
|
||||
when nothing has set it), and a dim stops at 10. The reply is "Brightness at
|
||||
40 percent.". Without the output these calls go on to `unhandled`.
|
||||
A target that is not a `bool`, `int`, `float` or `str`, a `targets` entry
|
||||
naming no target, `values` on a target that is not a `str` and a `range` on
|
||||
one that is not a number are refused when the flow is built.
|
||||
|
||||
A call with a delay ("in 10m") is held by the engine's work queue, like the
|
||||
Debounce node's second value: it survives a restart where the queue is in
|
||||
A command is applied whole or not at all. Its calls are written only when
|
||||
`apply` is on, every call reaches its target's bar, and none is on a
|
||||
`pass_on` target or on one the model was not trained on. Applying part of a
|
||||
command would leave half of a duration ("off for 7 minutes" is off now and on
|
||||
again later), or let the assistant do again what was already done. Otherwise
|
||||
nothing is written and `unhandled` carries the prompt, for something else to
|
||||
answer, such as an [Assistant](#assistant). When no node reads `unhandled`,
|
||||
`reply` says "Sorry, I can't do that yet." instead, so a spoken command never
|
||||
goes unanswered.
|
||||
|
||||
`reply` says what was set, as "Kitchen light on, living room heating to 21 °C
|
||||
in 5 minutes.", and answers a read from the target's current value, as
|
||||
"Outdoor temperature is 6.2 °C.", with `apply` off too, since a read writes
|
||||
nothing. A read of a target nothing has written yet goes on to `unhandled`. Each record in `actions` contains `message`, `value`,
|
||||
`applied`, `delay_s`, `call` as wren writes it, such as
|
||||
`set(kitchen_light, true)`, and that call's `confidence`. Keep `apply=false`
|
||||
while checking how the model reads commands.
|
||||
|
||||
A call with a delay ("in 10 minutes") is held by the engine's work queue, like
|
||||
the Debounce node's second value: it survives a restart where the queue is in
|
||||
Redis, and not otherwise.
|
||||
|
||||
The model sees every area, wired or not, each with at least a light, so "the
|
||||
bathroom light" is not taken for a light that is wired elsewhere. Such a call
|
||||
is reported but not applied, and goes on to `unhandled`. So is a call on an
|
||||
area the command does not name, unless it is the user's area or, with no area
|
||||
named, the living room: "switch on the appliances" is a word the pinned model
|
||||
never learned, and it lands on whichever light it was shown. The command is read
|
||||
in lower case without sentence marks and with number words as digits ("in
|
||||
five minutes" as "in 5 minutes"), as the model was trained. `aliases` are
|
||||
applied before, whole words in any case, and `unhandled` carries the prompt
|
||||
with them.
|
||||
A model knows the targets it was trained on: their names, types, `values`,
|
||||
`range`, descriptions and which are readings. A target wired since, or
|
||||
described otherwise since, is one it never learnt. The node then reads
|
||||
degraded, naming such targets and asking for the model to be retrained, and a
|
||||
call on one is never applied. wren's demo model knows the 20 targets of its
|
||||
[demo home](https://github.com/stroblme/wren/blob/main/wren/home.json), so
|
||||
it runs without that warning only on ports named and described as there. A
|
||||
`model` the artifact store does not have or cannot read also reads degraded,
|
||||
and every command goes on to `unhandled`. A model trained with wren goes into
|
||||
the store with `PUT /artifacts` (see the [API](../code/api.md#artifacts)).
|
||||
|
||||
A command for all of a kind, such as "turn off all lights", "switch every
|
||||
light on in 5 minutes" or "everything off in the office", is not the
|
||||
model's. The node applies it to every wired target of that kind, within the
|
||||
areas it names, and replies "All lights off." or "Lights off in the
|
||||
office.". A question ("are all lights off") or an exception ("all but the
|
||||
kitchen") goes to the model as any other command.
|
||||
|
||||
A question for an area's temperature ("how warm is it in the kitchen") is
|
||||
answered from its `<area>_temperature` input, or from `outdoor` for an area
|
||||
outside, as "It's 8 degrees outside.". Without a reading it goes on to
|
||||
`unhandled`.
|
||||
|
||||
!!! note "What the current model cannot do"
|
||||
|
||||
Commands are English, such as "turn on the lights in the kitchen".
|
||||
The model uses the areas above, one device per kind and area, on/off
|
||||
actions, and whole-minute delays. It does not dim lights or set colors.
|
||||
The command is read in lower case without sentence marks and with number words
|
||||
as digits ("in five minutes" as "in 5 minutes"), as the model was trained.
|
||||
`aliases` are applied before, whole words in any case, and `unhandled` carries
|
||||
the prompt with them.
|
||||
|
||||
The chat's [Control tab](../code/agents.md#control) sends commands by hand.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user