flow: structured dtypes, and the widgets that read them
A series, record or list message declares its shape instead of riding DType.JSON, so a widget binds a shape rather than some JSON and a wrong binding is refused before anything runs. A list declares its item type, which is what keeps list[float] expressible for a pipeline. On top of that: an agenda over a list, a notification over a record, and a dashboard alert channel that publishes engine faults as one — so a panel can show what went wrong without a flow wiring it by hand. Also: only None means a node published nothing, a falsy value of the wrong shape is now the named error it always should have been; and the gauge's readout says its size is viewBox geometry rather than type scale. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -298,7 +298,7 @@ export const ChannelSchema = {
|
||||
},
|
||||
kind: {
|
||||
type: 'string',
|
||||
enum: ['ntfy', 'smtp', 'webhook'],
|
||||
enum: ['ntfy', 'smtp', 'webhook', 'dashboard'],
|
||||
title: 'Kind'
|
||||
},
|
||||
enabled: {
|
||||
@@ -320,10 +320,15 @@ export const ChannelSchema = {
|
||||
|
||||
export const DTypeSchema = {
|
||||
type: 'string',
|
||||
enum: ['float', 'int', 'str', 'bool', 'json'],
|
||||
enum: ['float', 'int', 'str', 'bool', 'json', 'series', 'record', 'list'],
|
||||
title: 'DType',
|
||||
description: `Serializable payload types.
|
||||
|
||||
The scalars carry what a single reading can say. The three structured ones
|
||||
are declared shapes rather than "some JSON": a widget or a downstream node
|
||||
knows what it is getting before anything runs, which is what lets the
|
||||
dashboard picker offer a message and refuse a wrong binding.
|
||||
|
||||
Binary payloads (tensors, images) will arrive later as explicitly declared
|
||||
codec fields; until then everything on the wire is JSON.`
|
||||
} as const;
|
||||
@@ -1151,6 +1156,16 @@ export const MessageSpecSchema = {
|
||||
'$ref': '#/components/schemas/DType',
|
||||
default: 'float'
|
||||
},
|
||||
item: {
|
||||
anyOf: [
|
||||
{
|
||||
'$ref': '#/components/schemas/DType'
|
||||
},
|
||||
{
|
||||
type: 'null'
|
||||
}
|
||||
]
|
||||
},
|
||||
interval: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
@@ -1172,6 +1187,10 @@ export const MessageSpecSchema = {
|
||||
:param port: The identifier the node function sees. Defaults to the last
|
||||
segment of \`\`name\`\`, so unqualified flows read naturally.
|
||||
:param dtype: Payload type, validated on every message that passes through.
|
||||
:param item: The type of each item of a \`\`list\`\` port, ignored otherwise.
|
||||
Unset means \`\`record\`\`, which is what the agenda and forecast widgets
|
||||
read; \`\`float\`\` is the numeric list a pipeline passes around. A list of
|
||||
lists, or of series, is refused — one declared level is the point.
|
||||
:param interval: Deliver at most every this many seconds; 0 is every time.
|
||||
On an output it holds back publishing, on an input it holds back waking
|
||||
the node. The value is never lost — state keeps the latest — only the
|
||||
@@ -2497,7 +2516,7 @@ export const WidgetDefSchema = {
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
enum: ['stat', 'gauge', 'chart', 'markdown', 'button', 'switch', 'slider', 'input', 'dropdown'],
|
||||
enum: ['stat', 'gauge', 'chart', 'markdown', 'agenda', 'notification', 'button', 'switch', 'slider', 'input', 'dropdown'],
|
||||
title: 'Type'
|
||||
},
|
||||
title: {
|
||||
@@ -2525,7 +2544,14 @@ export const WidgetDefSchema = {
|
||||
|
||||
\`\`config\`\` is per type — a chart names its series, a button names the
|
||||
message it publishes — and is validated against the type below rather than
|
||||
by a schema per class, because the whole set is small and closed.`
|
||||
by a schema per class, because the whole set is small and closed.
|
||||
|
||||
A chart comes in two kinds. The default reads what the engine kept for a
|
||||
message. One with \`\`source: "query"\`\` asks instead, and its config is
|
||||
\`\`{source, request, request_dtype: "record", message, dtype: "series",
|
||||
refresh_s, range_s}\`\`: it publishes \`\`{range_s, interval_s}\`\` to
|
||||
\`\`request\`\` exactly as a slider publishes a value, and draws the \`\`series\`\`
|
||||
a flow answers with on \`\`message\`\`.`
|
||||
} as const;
|
||||
|
||||
export const app__api__routes__dashboards__PublishRequestSchema = {
|
||||
|
||||
Reference in New Issue
Block a user