wren node: untrained targets left out of the prompt, a read beside a held-back set goes on whole

This commit is contained in:
Melvin Strobl
2026-10-25 12:09:37 +01:00
parent e9941b770d
commit 96ba512d40
3 changed files with 31 additions and 4 deletions
+7 -1
View File
@@ -445,11 +445,14 @@ class WrenNode(Node):
threshold = 1.0
if self.pack is not None:
wren = _wren()
# A target the model never learnt is left out: shown, it is a line
# unlike any in training, which shifts the answers on the others.
targets = [
wren.Target(
**t, value=_unset(t) if current.get(p) is None else current[p]
)
for p, t in self.targets.items()
if p not in self.untrained
]
# One BLAS thread answers in about half the time for a model
# this small. Scoped to the call, so numpy elsewhere in the
@@ -470,6 +473,9 @@ class WrenNode(Node):
and (call.value is not None or current.get(call.target) is not None)
for call in calls
)
# A reading answered beside a set that is not written would drop the
# set unsaid, so the whole command goes on instead.
held = not self.cfg.apply and any(call.value is not None for call in calls)
specs = {spec.port: spec for spec in [*self.input_ports, *self.output_ports]}
writes: dict[str, Any] = {}
actions: list[dict[str, Any]] = []
@@ -477,7 +483,7 @@ class WrenNode(Node):
answers: list[str] = []
for call in calls:
spec, unit = specs[call.target], self.targets[call.target]["unit"]
applied = sure if call.value is None else sure and self.cfg.apply
applied = sure and (not held if call.value is None else self.cfg.apply)
if call.value is None:
value = current.get(call.target)
if applied:
+20
View File
@@ -295,6 +295,8 @@ def test_a_target_the_model_was_not_trained_on_is_never_applied(fake_wren):
fake_wren.answer = [fake_wren.Call("canopy", "DOWN")]
out = node.execute({"house.command": "close the awning"})
# The model is not shown the targets it never learnt.
assert [t.name for t in fake_wren.targets[0]] == ["living_room_heating"]
assert out is not None
assert [a["applied"] for a in out["house.actions"]] == [False]
assert out["house.unhandled"] == "close the awning"
@@ -325,6 +327,24 @@ def test_a_read_is_answered_from_the_target_value(fake_wren):
assert out["house.unhandled"] == command
def test_a_read_beside_a_set_not_written_goes_on_whole(fake_wren):
node = _node(
fake_wren, ("kitchen_light", DType.BOOL), inputs=[OUTDOOR], saying=True
)
fake_wren.answer = [
fake_wren.Call("outdoor_temperature"),
fake_wren.Call("kitchen_light", True),
]
command = "how warm is it outside and turn on the kitchen light"
out = node.execute({"house.command": command, "house.outdoor": 6.2})
assert out is not None
assert [a["applied"] for a in out["house.actions"]] == [False, False]
assert out["house.unhandled"] == command
assert "house.reply" not in out or out["house.reply"] == CANT
def test_a_delayed_call_is_held_by_the_work_queue(fake_wren, monkeypatch):
node = _node(fake_wren, ("kitchen_light", DType.BOOL), saying=True, apply=True)
deferred: list[tuple[dict[str, Any], float]] = []