Node settings arrive as keyword arguments, not a params dict

A python node's settings are constants of its own function, so they are passed
the way its ports are: by name. The controller binds them to the compiled
function, the `params` field is gone from the worker and remote protocols, and
a setting sharing a port's name is reported as a node error rather than
shadowing it. The panel's scaffold follows suit and keeps the header in step
with both ports and settings.

The demo's `pace` moves from a flow input to a setting of the training node,
which is what it always was.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NUb8YpL2s3gmN9WTACTt4q
This commit is contained in:
2026-08-20 17:47:45 +02:00
co-authored by Claude Opus 5
parent 2385e3cf8e
commit 4355c917f8
24 changed files with 225 additions and 126 deletions
+11 -10
View File
@@ -110,7 +110,7 @@ def _peak(hour, at, width):
return math.exp(-((hour - at) ** 2) / (2 * width * width))
def process(tick, mode="comfort", away=False, setpoint=21.0, params=None):
def process(tick, mode="comfort", away=False, setpoint=21.0):
clock = time.localtime()
hour = clock.tm_hour + clock.tm_min / 60.0 + clock.tm_sec / 3600.0
seconds = time.time()
@@ -161,7 +161,7 @@ other and have the picture mean something.
"""
def process(pv_kw, load_kw, grid_kw, tariff=32.0, params=None):
def process(pv_kw, load_kw, grid_kw, tariff=32.0):
return {
"cost_now": round(max(0.0, grid_kw) * float(tariff) / 100.0, 2),
"self_use_kw": round(min(pv_kw, load_kw), 2),
@@ -206,7 +206,7 @@ DIARY = [
]
def process(day_start, climate=None, params=None):
def process(day_start, climate=None):
now = time.time()
# Anchored on what it is doing outside, once the flow has got that far; the
# first plan after a cold start has nothing to anchor to yet.
@@ -410,7 +410,7 @@ def _outdoor(when):
)
def process(chart_request, setpoint=21.0, params=None):
def process(chart_request, setpoint=21.0):
span = int(chart_request["range_s"])
every = max(1, int(chart_request["interval_s"]))
now = int(time.time())
@@ -494,7 +494,7 @@ KW_PER_UNIT = 3.0
KW_AT_MEAN_LIGHT = 2.0
def process(seed, noise, samples, params):
def process(seed, noise, samples):
rng = random.Random(int(seed))
rows = [
[x, KW_PER_UNIT * x + KW_AT_MEAN_LIGHT + rng.gauss(0.0, float(noise))]
@@ -539,7 +539,7 @@ except ImportError: # The engine's own venv has no numpy; a GPU box will.
np = None
def process(dataset, learning_rate, epochs, pace, params):
def process(dataset, learning_rate, epochs, pace):
with open(fluksio.load_artifact(dataset)) as handle:
data = json.load(handle)
@@ -600,7 +600,7 @@ import json
import fluksio
def process(weights, dataset, params):
def process(weights, dataset):
with open(fluksio.load_artifact(weights)) as handle:
fit = json.load(handle)
with open(fluksio.load_artifact(dataset)) as handle:
@@ -655,11 +655,14 @@ MODEL_NODES = [
# Generous, and an *idle* timeout: a node that keeps publishing keeps
# its deadline reset, so this is how long it may go quiet.
"timeout": 300,
# A setting: a constant of this node's own code, reaching `process` as
# an argument like the ports beside it. Only so a human can watch the
# curve arrive — set it to 0 in the node panel for a sweep.
"params": {"pace": 0.15},
"requires": [
{"name": "dataset", "dtype": "artifact"},
{"name": "learning_rate", "dtype": "float"},
{"name": "epochs", "dtype": "int"},
{"name": "pace", "dtype": "float"},
],
"provides": [
# The curve. `stream` says this port publishes repeatedly while the
@@ -693,8 +696,6 @@ MODEL_INPUTS = [
{"spec": {"name": "samples", "dtype": "int"}, "initial": 200},
{"spec": {"name": "learning_rate", "dtype": "float"}, "initial": 0.2},
{"spec": {"name": "epochs", "dtype": "int"}, "initial": 40},
# Only so a human can watch the curve arrive; set it to 0 for a sweep.
{"spec": {"name": "pace", "dtype": "float"}, "initial": 0.15},
]
#: What a run reports as its result. Everything else the flow computed stays in