@almadar/std 16.242.0 → 16.244.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/behaviors/behaviors-registry.json +4470 -513
  2. package/behaviors/lolo/agent/atoms/std-agent-context.lolo +24 -4
  3. package/behaviors/lolo/agent/atoms/std-agent-memory.lolo +20 -5
  4. package/behaviors/lolo/agent/atoms/std-agent-proposal.lolo +550 -0
  5. package/behaviors/lolo/agent/atoms/std-agent-session.lolo +284 -25
  6. package/behaviors/lolo/agent/atoms/std-agent-suggestions.lolo +841 -0
  7. package/behaviors/lolo/agent/atoms/std-agent-tool-loop.lolo +58 -8
  8. package/behaviors/lolo/agent/organisms/std-agent-assistant.lolo +1 -0
  9. package/behaviors/lolo/infra/atoms/std-page-search.lolo +3 -1
  10. package/behaviors/lolo/infra/atoms/std-page-treat.lolo +28 -1
  11. package/behaviors/lolo/infra/atoms/std-page-watch.lolo +3 -1
  12. package/behaviors/lolo/ui/avl/atoms/ui-avl-state-machine.lolo +22 -0
  13. package/behaviors/lolo/ui/avl/atoms/ui-avl-transition-explainer.lolo +175 -0
  14. package/behaviors/lolo/ui/avl/atoms/ui-module-card.lolo +22 -0
  15. package/behaviors/lolo/ui/core/atoms/std-app-layout.lolo +23 -4
  16. package/behaviors/lolo/ui/core/atoms/std-hero.lolo +72 -33
  17. package/behaviors/lolo/ui/core/molecules/ui-agent-chat-feed.lolo +1 -1
  18. package/behaviors/lolo/ui/core/molecules/ui-markdown-content.lolo +54 -0
  19. package/behaviors/lolo/ui/core/molecules/ui-upload-drop-zone.lolo +5 -0
  20. package/behaviors/lolo/ui/core/organisms/ui-segment-renderer.lolo +127 -3
  21. package/behaviors/lolo/ui/core/organisms/ui-state-machine-view.lolo +22 -0
  22. package/behaviors/lolo/ui/core/templates/ui-dashboard-layout.lolo +2 -2
  23. package/behaviors/lolo/ui/learning/atoms/std-learn-arrangement.lolo +87 -17
  24. package/behaviors/lolo/ui/learning/atoms/std-learn-classify.lolo +172 -37
  25. package/behaviors/lolo/ui/learning/atoms/std-learn-coupled-sim.lolo +183 -70
  26. package/behaviors/lolo/ui/learning/atoms/std-learn-derivation.lolo +78 -13
  27. package/behaviors/lolo/ui/learning/atoms/std-learn-diagram.lolo +58 -2
  28. package/behaviors/lolo/ui/learning/atoms/std-learn-doser.lolo +107 -12
  29. package/behaviors/lolo/ui/learning/atoms/std-learn-estimate.lolo +83 -10
  30. package/behaviors/lolo/ui/learning/atoms/std-learn-goal-seek.lolo +130 -9
  31. package/behaviors/lolo/ui/learning/atoms/std-learn-grid-sim.lolo +143 -59
  32. package/behaviors/lolo/ui/learning/atoms/std-learn-hotspot.lolo +96 -22
  33. package/behaviors/lolo/ui/learning/atoms/std-learn-live-sim.lolo +66 -5
  34. package/behaviors/lolo/ui/learning/atoms/std-learn-predict.lolo +84 -6
  35. package/behaviors/lolo/ui/learning/atoms/std-learn-sandbox.lolo +80 -14
  36. package/behaviors/lolo/ui/learning/atoms/std-learn-scatter-fit.lolo +99 -5
  37. package/behaviors/lolo/ui/learning/atoms/std-learn-scenario.lolo +81 -7
  38. package/behaviors/lolo/ui/learning/atoms/std-learn-speed-drill.lolo +83 -7
  39. package/behaviors/lolo/ui/learning/atoms/std-learn-stepper.lolo +224 -99
  40. package/behaviors/lolo/ui/learning/atoms/std-learn-tour-3d.lolo +63 -2
  41. package/behaviors/lolo/ui/learning/atoms/std-learn-trace-player.lolo +99 -38
  42. package/behaviors/lolo/ui/learning/atoms/std-learn-transport.lolo +7 -7
  43. package/behaviors/lolo/ui/learning/atoms/std-learn-tree.lolo +69 -4
  44. package/behaviors/lolo-behavior-contracts.json +1 -1
  45. package/behaviors/registry/agent/atoms/std-agent-context.orb +205 -6
  46. package/behaviors/registry/agent/atoms/std-agent-memory.orb +146 -4
  47. package/behaviors/registry/agent/atoms/std-agent-proposal.orb +1972 -0
  48. package/behaviors/registry/agent/atoms/std-agent-session.orb +2021 -597
  49. package/behaviors/registry/agent/atoms/std-agent-suggestions.orb +5079 -0
  50. package/behaviors/registry/agent/atoms/std-agent-tool-loop.orb +287 -5
  51. package/behaviors/registry/agent/organisms/std-agent-assistant.orb +7 -0
  52. package/behaviors/registry/factory-signatures.json +1 -1
  53. package/behaviors/registry/infra/atoms/std-page-search.orb +19 -1
  54. package/behaviors/registry/infra/atoms/std-page-treat.orb +327 -2
  55. package/behaviors/registry/infra/atoms/std-page-watch.orb +19 -1
  56. package/behaviors/registry/ui/avl/atoms/ui-avl-state-machine.orb +134 -0
  57. package/behaviors/registry/ui/avl/atoms/ui-avl-transition-explainer.orb +678 -0
  58. package/behaviors/registry/ui/avl/atoms/ui-module-card.orb +122 -0
  59. package/behaviors/registry/ui/core/atoms/std-app-layout.orb +73 -4
  60. package/behaviors/registry/ui/core/atoms/std-hero.orb +174 -97
  61. package/behaviors/registry/ui/core/molecules/ui-markdown-content.orb +204 -1
  62. package/behaviors/registry/ui/core/molecules/ui-upload-drop-zone.orb +12 -0
  63. package/behaviors/registry/ui/core/organisms/ui-segment-renderer.orb +683 -30
  64. package/behaviors/registry/ui/learning/atoms/std-learn-arrangement.orb +748 -21
  65. package/behaviors/registry/ui/learning/atoms/std-learn-classify.orb +1429 -41
  66. package/behaviors/registry/ui/learning/atoms/std-learn-coupled-sim.orb +1031 -185
  67. package/behaviors/registry/ui/learning/atoms/std-learn-derivation.orb +807 -132
  68. package/behaviors/registry/ui/learning/atoms/std-learn-diagram.orb +553 -6
  69. package/behaviors/registry/ui/learning/atoms/std-learn-doser.orb +987 -21
  70. package/behaviors/registry/ui/learning/atoms/std-learn-estimate.orb +582 -16
  71. package/behaviors/registry/ui/learning/atoms/std-learn-goal-seek.orb +954 -13
  72. package/behaviors/registry/ui/learning/atoms/std-learn-grid-sim.orb +828 -88
  73. package/behaviors/registry/ui/learning/atoms/std-learn-hotspot.orb +730 -28
  74. package/behaviors/registry/ui/learning/atoms/std-learn-live-sim.orb +479 -9
  75. package/behaviors/registry/ui/learning/atoms/std-learn-predict.orb +797 -46
  76. package/behaviors/registry/ui/learning/atoms/std-learn-sandbox.orb +757 -58
  77. package/behaviors/registry/ui/learning/atoms/std-learn-scatter-fit.orb +1176 -164
  78. package/behaviors/registry/ui/learning/atoms/std-learn-scenario.orb +599 -12
  79. package/behaviors/registry/ui/learning/atoms/std-learn-speed-drill.orb +832 -150
  80. package/behaviors/registry/ui/learning/atoms/std-learn-stepper.orb +1561 -127
  81. package/behaviors/registry/ui/learning/atoms/std-learn-tour-3d.orb +655 -6
  82. package/behaviors/registry/ui/learning/atoms/std-learn-trace-player.orb +634 -43
  83. package/behaviors/registry/ui/learning/atoms/std-learn-transport.orb +85 -31
  84. package/behaviors/registry/ui/learning/atoms/std-learn-tree.orb +425 -9
  85. package/canonical-operators.json +45 -2
  86. package/dist/behaviors/exports-reader.js +16667 -7868
  87. package/dist/behaviors/functions/index.d.ts +711 -32
  88. package/dist/behaviors/functions/index.js +16651 -7869
  89. package/dist/behaviors/index.d.ts +1 -1
  90. package/dist/behaviors/index.js +16668 -7869
  91. package/dist/behaviors/query.js +16667 -7868
  92. package/dist/behaviors-embeddings.hash.json +3 -3
  93. package/dist/behaviors-embeddings.json +77 -53
  94. package/dist/behaviors-registry.json +4470 -513
  95. package/dist/index.d.ts +3 -3
  96. package/dist/index.js +16101 -7275
  97. package/dist/knob-embeddings.hash.json +3 -3
  98. package/dist/knob-embeddings.json +1309 -685
  99. package/dist/modules/anim.d.ts +1 -1
  100. package/dist/modules/array.d.ts +1 -1
  101. package/dist/modules/async.d.ts +1 -1
  102. package/dist/modules/behavior.d.ts +1 -1
  103. package/dist/modules/browser.d.ts +1 -1
  104. package/dist/modules/composition.d.ts +1 -1
  105. package/dist/modules/contract.d.ts +1 -1
  106. package/dist/modules/core.d.ts +1 -1
  107. package/dist/modules/core.js +29 -2
  108. package/dist/modules/data.d.ts +1 -1
  109. package/dist/modules/ease.d.ts +1 -1
  110. package/dist/modules/format.d.ts +1 -1
  111. package/dist/modules/geo.d.ts +1 -1
  112. package/dist/modules/graph.d.ts +1 -1
  113. package/dist/modules/grid.d.ts +1 -1
  114. package/dist/modules/i18n.d.ts +1 -1
  115. package/dist/modules/index.d.ts +1 -1
  116. package/dist/modules/index.js +29 -2
  117. package/dist/modules/integration.d.ts +1 -1
  118. package/dist/modules/json.d.ts +1 -1
  119. package/dist/modules/llm.d.ts +1 -1
  120. package/dist/modules/math.d.ts +1 -1
  121. package/dist/modules/memory.d.ts +1 -1
  122. package/dist/modules/nn.d.ts +1 -1
  123. package/dist/modules/noise.d.ts +1 -1
  124. package/dist/modules/object.d.ts +1 -1
  125. package/dist/modules/os.d.ts +1 -1
  126. package/dist/modules/path.d.ts +1 -1
  127. package/dist/modules/prob.d.ts +1 -1
  128. package/dist/modules/session.d.ts +1 -1
  129. package/dist/modules/str.d.ts +1 -1
  130. package/dist/modules/tensor.d.ts +1 -1
  131. package/dist/modules/time.d.ts +1 -1
  132. package/dist/modules/trace.d.ts +1 -1
  133. package/dist/modules/train.d.ts +1 -1
  134. package/dist/modules/validate.d.ts +1 -1
  135. package/dist/modules/vector.d.ts +1 -1
  136. package/dist/modules/workspace.d.ts +1 -1
  137. package/dist/registry/factory-signatures.json +1 -1
  138. package/dist/registry.d.ts +2 -2
  139. package/dist/registry.js +29 -2
  140. package/dist/{types-Cdb321uM.d.ts → types-Y-yYWEOX.d.ts} +1 -1
  141. package/i18n/ar.json +3 -1
  142. package/i18n/en.json +2 -0
  143. package/i18n/sl.json +3 -1
  144. package/package.json +3 -3
@@ -29,6 +29,8 @@ orbital LearnDerivationOrbital {
29
29
  entity LearnDerivationScene [runtime] {
30
30
  id : string!
31
31
  active : boolean = false
32
+ premises : [LearnDerivationLine]
33
+ candidates : [LearnDerivationCandidate]
32
34
  title : string
33
35
  lines : [LearnDerivationLine]
34
36
  feedback : string
@@ -43,7 +45,9 @@ orbital LearnDerivationOrbital {
43
45
  initial: idle
44
46
 
45
47
  state idle {
46
- INIT -> idle when (== @config.matchMode "")
48
+ INIT -> idle when (and (== @config.matchMode "") (== @config.rosterSource "config"))
49
+ (set @entity.premises @config.premises)
50
+ (set @entity.candidates @config.candidates)
47
51
  (set @entity.active true)
48
52
  (set @entity.title @config.title)
49
53
  (set @entity.feedback "")
@@ -51,7 +55,7 @@ orbital LearnDerivationOrbital {
51
55
  (set @entity.goalReached false)
52
56
  (set @entity.running @config.autoRun)
53
57
  (set @entity.elapsedMs 0)
54
- (set @entity.lines @config.premises)
58
+ (set @entity.lines @entity.premises)
55
59
  (set @entity.renderChildren [
56
60
  { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
57
61
  { type: stack, direction: vertical, gap: xs, children: [
@@ -67,7 +71,7 @@ orbital LearnDerivationOrbital {
67
71
  { type: typography, variant: body, content: @line.label }
68
72
  ] }
69
73
  )) },
70
- { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @config.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
74
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @entity.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
71
75
  { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
72
76
  (if @entity.running { type: button, action: TOGGLE_RUN, label: "Pause", icon: "pause", variant: primary, aria-pressed: "true" } { type: button, action: TOGGLE_RUN, label: "Run", icon: "play", variant: primary, aria-pressed: "false", disabled: @entity.goalReached }),
73
77
  { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
@@ -89,7 +93,9 @@ orbital LearnDerivationOrbital {
89
93
  (set @entity.running false)
90
94
  (render-ui main null)
91
95
 
92
- MODE_SELECTED -> idle when (== ?mode @config.matchMode)
96
+ MODE_SELECTED -> idle when (and (== ?mode @config.matchMode) (== @config.rosterSource "config"))
97
+ (set @entity.premises @config.premises)
98
+ (set @entity.candidates @config.candidates)
93
99
  (set @entity.active true)
94
100
  (set @entity.title @config.title)
95
101
  (set @entity.feedback "")
@@ -97,7 +103,7 @@ orbital LearnDerivationOrbital {
97
103
  (set @entity.goalReached false)
98
104
  (set @entity.running @config.autoRun)
99
105
  (set @entity.elapsedMs 0)
100
- (set @entity.lines @config.premises)
106
+ (set @entity.lines @entity.premises)
101
107
  (set @entity.renderChildren [
102
108
  { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
103
109
  { type: stack, direction: vertical, gap: xs, children: [
@@ -113,7 +119,7 @@ orbital LearnDerivationOrbital {
113
119
  { type: typography, variant: body, content: @line.label }
114
120
  ] }
115
121
  )) },
116
- { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @config.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
122
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @entity.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
117
123
  { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
118
124
  (if @entity.running { type: button, action: TOGGLE_RUN, label: "Pause", icon: "pause", variant: primary, aria-pressed: "true" } { type: button, action: TOGGLE_RUN, label: "Run", icon: "play", variant: primary, aria-pressed: "false", disabled: @entity.goalReached }),
119
125
  { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
@@ -130,9 +136,57 @@ orbital LearnDerivationOrbital {
130
136
  ]
131
137
  })
132
138
 
139
+ ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (and (== ?mode @config.matchMode) (and (> (array/len ?premises) 0) (> (array/len ?candidates) 0))))
140
+ (set @entity.premises ?premises)
141
+ (set @entity.candidates ?candidates)
142
+ (set @entity.active true)
143
+ (set @entity.title @config.title)
144
+ (set @entity.feedback "")
145
+ (set @entity.narration "")
146
+ (set @entity.goalReached false)
147
+ (set @entity.running @config.autoRun)
148
+ (set @entity.elapsedMs 0)
149
+ (set @entity.lines @entity.premises)
150
+ (set @entity.renderChildren [
151
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
152
+ { type: stack, direction: vertical, gap: xs, children: [
153
+ { type: typography, variant: h4, content: @entity.title },
154
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
155
+ ] },
156
+ { type: badge, label: (if @entity.goalReached "Goal reached" (if @entity.running "Auto-stepping" "In progress")), variant: (if @entity.goalReached "success" (if @entity.running "primary" "neutral")) }
157
+ ] },
158
+ { type: typography, variant: body, content: (str/concat @config.goalPrefix @config.goalLabel) },
159
+ { type: stack, direction: vertical, gap: xs, style: { maxHeight: (str/concat @config.height "px"), overflowY: "auto" }, children: (array/map @entity.lines (fn line
160
+ { type: stack, direction: horizontal, align: center, gap: sm, children: [
161
+ { type: badge, label: @line.badgeLabel, variant: @line.badgeVariant },
162
+ { type: typography, variant: body, content: @line.label }
163
+ ] }
164
+ )) },
165
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @entity.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
166
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
167
+ (if @entity.running { type: button, action: TOGGLE_RUN, label: "Pause", icon: "pause", variant: primary, aria-pressed: "true" } { type: button, action: TOGGLE_RUN, label: "Run", icon: "play", variant: primary, aria-pressed: "false", disabled: @entity.goalReached }),
168
+ { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
169
+ { type: typography, variant: caption, color: muted, content: (str/concat (array/len @entity.lines) " lines") }
170
+ ] },
171
+ { type: typography, variant: body, content: (if @entity.goalReached @config.goalReachedMessage @entity.narration) }
172
+ ])
173
+ (render-ui main {
174
+ type: box
175
+ padding: md
176
+ maxWidth: (str/concat @config.width "px")
177
+ children: [
178
+ { type: stack, direction: vertical, gap: md, children: @entity.renderChildren }
179
+ ]
180
+ })
181
+
182
+ ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (not (== ?mode @config.matchMode)))
183
+ (set @entity.active false)
184
+ (set @entity.running false)
185
+ (render-ui main null)
186
+
133
187
  APPLY_STEP -> idle when (== @entity.active true)
134
188
  (let (
135
- (candidate (array/first (array/filter @config.candidates (fn c (== @c.key ?candidateKey)))))
189
+ (candidate (array/first (array/filter @entity.candidates (fn c (== @c.key ?candidateKey)))))
136
190
  (links (array/filter @entity.lines (fn l (== @l.kind "link"))))
137
191
  (facts (array/filter @entity.lines (fn l (== @l.kind "fact"))))
138
192
  (wantLeft (== @candidate.matchSide "left"))
@@ -181,7 +235,7 @@ orbital LearnDerivationOrbital {
181
235
  { type: typography, variant: body, content: @line.label }
182
236
  ] }
183
237
  )) },
184
- { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @config.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
238
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @entity.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
185
239
  { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
186
240
  (if @entity.running { type: button, action: TOGGLE_RUN, label: "Pause", icon: "pause", variant: primary, aria-pressed: "true" } { type: button, action: TOGGLE_RUN, label: "Run", icon: "play", variant: primary, aria-pressed: "false", disabled: @entity.goalReached }),
187
241
  { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
@@ -218,7 +272,7 @@ orbital LearnDerivationOrbital {
218
272
  { type: typography, variant: body, content: @line.label }
219
273
  ] }
220
274
  )) },
221
- { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @config.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
275
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @entity.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
222
276
  { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
223
277
  (if @entity.running { type: button, action: TOGGLE_RUN, label: "Pause", icon: "pause", variant: primary, aria-pressed: "true" } { type: button, action: TOGGLE_RUN, label: "Run", icon: "play", variant: primary, aria-pressed: "false", disabled: @entity.goalReached }),
224
278
  { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
@@ -237,7 +291,7 @@ orbital LearnDerivationOrbital {
237
291
  (emit DERIVATION_UPDATED { feedback: @entity.feedback, goalReached: @entity.goalReached, lineCount: (array/len @entity.lines), narration: @entity.narration })
238
292
 
239
293
  RESET -> idle when (== @entity.active true)
240
- (set @entity.lines @config.premises)
294
+ (set @entity.lines @entity.premises)
241
295
  (set @entity.feedback "")
242
296
  (set @entity.narration "")
243
297
  (set @entity.goalReached false)
@@ -258,7 +312,7 @@ orbital LearnDerivationOrbital {
258
312
  { type: typography, variant: body, content: @line.label }
259
313
  ] }
260
314
  )) },
261
- { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @config.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
315
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @entity.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
262
316
  { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
263
317
  (if @entity.running { type: button, action: TOGGLE_RUN, label: "Pause", icon: "pause", variant: primary, aria-pressed: "true" } { type: button, action: TOGGLE_RUN, label: "Run", icon: "play", variant: primary, aria-pressed: "false", disabled: @entity.goalReached }),
264
318
  { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
@@ -287,7 +341,7 @@ orbital LearnDerivationOrbital {
287
341
  (let (
288
342
  (links (array/filter @entity.lines (fn l (== @l.kind "link"))))
289
343
  (facts (array/filter @entity.lines (fn l (== @l.kind "fact"))))
290
- (evaluated (array/map @config.candidates (fn c (let (
344
+ (evaluated (array/map @entity.candidates (fn c (let (
291
345
  (wantLeft (== @c.matchSide "left"))
292
346
  (matchSense (== @c.matchNegationMode "same"))
293
347
  (activeLink (array/first (array/filter @links (fn l (let (
@@ -336,7 +390,7 @@ orbital LearnDerivationOrbital {
336
390
  { type: typography, variant: body, content: @line.label }
337
391
  ] }
338
392
  )) },
339
- { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @config.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
393
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: (array/map @entity.candidates (fn c { type: button, action: APPLY_STEP, actionPayload: { candidateKey: @c.key }, label: @c.label, variant: secondary, size: lg, disabled: @entity.goalReached })) },
340
394
  { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
341
395
  (if @entity.running { type: button, action: TOGGLE_RUN, label: "Pause", icon: "pause", variant: primary, aria-pressed: "true" } { type: button, action: TOGGLE_RUN, label: "Run", icon: "play", variant: primary, aria-pressed: "false", disabled: @entity.goalReached }),
342
396
  { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
@@ -362,6 +416,13 @@ orbital LearnDerivationOrbital {
362
416
  }
363
417
  @description "Lab router broadcast naming the active mode; this instrument renders when the mode equals matchMode, otherwise renders null."
364
418
  @tier "domain"
419
+ ROSTER_LOADED {
420
+ mode : string!
421
+ premises : [LearnDerivationLine]!
422
+ candidates : [LearnDerivationCandidate]!
423
+ }
424
+ @description "Runtime content feed, honoured only when rosterSource is event — mode names the instrument it is for (the matchMode it carries, blank when standalone), premises are the starting lines and candidates the offered derivation steps; a matching instrument re-initialises from them exactly as INIT does from config, any other instrument hides."
425
+ @tier "domain"
365
426
  APPLY_STEP {
366
427
  candidateKey : string
367
428
  }
@@ -417,6 +478,10 @@ orbital LearnDerivationOrbital {
417
478
  @label "Auto-Apply Interval (ms)"
418
479
  @description "Milliseconds of running clock per automatic candidate application — the 32ms base tick accumulates elapsed time and applies the first applicable candidate each time this interval elapses."
419
480
  @tier "domain"
481
+ rosterSource : "config" | "event" = "config"
482
+ @label "Roster Source"
483
+ @description "Where the roster comes from: config reads the premises/candidates knob(s) at INIT; event waits for ROSTER_LOADED and takes the roster from its payload."
484
+ @tier "domain"
420
485
  premises : [LearnDerivationLine] = [
421
486
  { id: "given-a", label: "A", kind: "fact", subject: "A", negated: false, badgeLabel: "GIVEN", badgeVariant: "neutral" },
422
487
  { id: "given-a-implies-b", label: "A → B", kind: "link", leftSubject: "A", leftNegated: false, rightSubject: "B", rightNegated: false, badgeLabel: "RULE", badgeVariant: "info" }
@@ -36,7 +36,7 @@ orbital LearnDiagramOrbital {
36
36
  initial: idle
37
37
 
38
38
  state idle {
39
- INIT -> idle when (== @config.matchMode "")
39
+ INIT -> idle when (and (== @config.matchMode "") (== @config.rosterSource "config"))
40
40
  (set @entity.active true)
41
41
  (set @entity.title @config.title)
42
42
  (set @entity.parts @config.parts)
@@ -81,7 +81,7 @@ orbital LearnDiagramOrbital {
81
81
  (set @entity.active false)
82
82
  (render-ui main null)
83
83
 
84
- MODE_SELECTED -> idle when (== ?mode @config.matchMode)
84
+ MODE_SELECTED -> idle when (and (== ?mode @config.matchMode) (== @config.rosterSource "config"))
85
85
  (set @entity.active true)
86
86
  (set @entity.title @config.title)
87
87
  (set @entity.parts @config.parts)
@@ -122,6 +122,51 @@ orbital LearnDiagramOrbital {
122
122
  ]
123
123
  })
124
124
 
125
+ ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (and (== ?mode @config.matchMode) (> (array/len ?parts) 0)))
126
+ (set @entity.active true)
127
+ (set @entity.title @config.title)
128
+ (set @entity.parts ?parts)
129
+ (set @entity.links ?links)
130
+ (set @entity.selectedId "")
131
+ (set @entity.selectedIndex -1)
132
+ (set @entity.captionText @config.overviewText)
133
+ (set @entity.readoutText "")
134
+ (let (
135
+ (buttons (array/map @entity.parts (fn p { type: button, action: SELECT_PART, actionPayload: { partId: (object/get @p id) }, label: (object/get @p label), variant: (if (== @entity.selectedId (object/get @p id)) "primary" "secondary"), size: sm })))
136
+ (clearButton { type: button, action: CLEAR_PART, label: @config.clearLabel, variant: ghost, size: sm })
137
+ )
138
+ (do
139
+ (set @entity.partButtons (array/append @buttons @clearButton))
140
+ (set @entity.captionChildren (if (!= @entity.readoutText "") [ { type: typography, variant: caption, color: muted, content: @entity.readoutText }, { type: typography, variant: body, content: @entity.captionText } ] [ { type: typography, variant: body, content: @entity.captionText } ]))
141
+ )
142
+ )
143
+ (render-ui main {
144
+ type: box
145
+ padding: md
146
+ children: [
147
+ { type: stack, direction: vertical, gap: md, children: [
148
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
149
+ { type: stack, direction: vertical, gap: xs, children: [
150
+ { type: typography, variant: h4, content: @entity.title },
151
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
152
+ ] },
153
+ { type: badge, label: (if (== @entity.selectedId "") "Overview" (str/concat "Part " (str/concat "" (+ @entity.selectedIndex 1)) " of " (str/concat "" (array/len @entity.parts)))), variant: (if (== @entity.selectedId "") "neutral" "primary") }
154
+ ] },
155
+ { type: stack, direction: horizontal, align: center, gap: xs, wrap: true, children: @entity.partButtons },
156
+ { type: biology-canvas, width: @config.width, height: @config.height, backgroundColor: @config.backgroundColor,
157
+ nodes: (array/map @entity.parts (fn p { id: (object/get @p id), x: (object/get @p x), y: (object/get @p y), radius: (if (== (object/get @p id) @entity.selectedId) (* (object/get @p radius) 1.4) (object/get @p radius)), color: (object/get @p color), label: (object/get @p label) })),
158
+ edges: @entity.links,
159
+ shapes: (if (== @entity.selectedId "") [] [ { type: circle, x: (object/get (array/nth @entity.parts @entity.selectedIndex) x), y: (object/get (array/nth @entity.parts @entity.selectedIndex) y), radius: (+ (object/get (array/nth @entity.parts @entity.selectedIndex) radius) 10), color: @config.highlightColor, stroke: bold } ])
160
+ },
161
+ { type: card, variant: bordered, padding: md, children: @entity.captionChildren }
162
+ ] }
163
+ ]
164
+ })
165
+
166
+ ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (not (== ?mode @config.matchMode)))
167
+ (set @entity.active false)
168
+ (render-ui main null)
169
+
125
170
  SELECT_PART -> idle when (== @entity.active true)
126
171
  (let (
127
172
  (idx (array/first (array/filter (array/range (array/len @entity.parts)) (fn i (== (object/get (array/nth @entity.parts @i) id) ?partId)))))
@@ -212,6 +257,13 @@ orbital LearnDiagramOrbital {
212
257
  }
213
258
  @description "Lab router broadcast naming the active mode; this instrument renders when the mode equals matchMode, otherwise renders null."
214
259
  @tier "domain"
260
+ ROSTER_LOADED {
261
+ mode : string!
262
+ parts : [LearnDiagramPart]!
263
+ links : [LearnDiagramLink]!
264
+ }
265
+ @description "Runtime content feed, honoured only when rosterSource is event — mode names the instrument it is for (the matchMode it carries, blank when standalone), parts is the labeled-part roster and links the connector list; a matching instrument re-initialises from it exactly as INIT does from config, any other instrument hides."
266
+ @tier "domain"
215
267
  SELECT_PART {
216
268
  partId : string
217
269
  }
@@ -242,6 +294,10 @@ orbital LearnDiagramOrbital {
242
294
  @label "Match Mode"
243
295
  @description "When composed behind a lab router, the MODE_SELECTED mode value this instrument responds to. Empty string means standalone — render immediately on INIT."
244
296
  @tier "presentation"
297
+ rosterSource : "config" | "event" = "config"
298
+ @label "Roster Source"
299
+ @description "Where the parts and links roster comes from: config reads the parts and links knobs at INIT; event waits for ROSTER_LOADED and takes the roster from its payload."
300
+ @tier "domain"
245
301
  title : string = "System Diagram"
246
302
  @label "Title"
247
303
  @description "Title shown above the diagram."
@@ -40,22 +40,24 @@ orbital LearnDoserOrbital {
40
40
  containers : [DoserContainer]
41
41
  readouts : [DoserReadout]
42
42
  doseSeries : [DoserTracePoint]
43
+ bands : [DoserBand]
43
44
  }
44
45
 
45
46
  trait LearnDoserSim -> @rebindable DoserScene [interaction, instance] {
46
47
  initial: idle
47
48
 
48
49
  state idle {
49
- INIT -> idle when (== @config.matchMode "")
50
+ INIT -> idle when (and (== @config.matchMode "") (== @config.rosterSource "config"))
50
51
  (set @entity.active true)
51
52
  (set @entity.title @config.title)
53
+ (set @entity.bands @config.bands)
52
54
  (set @entity.dose 0)
53
55
  (set @entity.done false)
54
56
  (set @entity.running @config.autoDrip)
55
57
  (set @entity.elapsedMs 0)
56
58
  (let (
57
- (matched (array/filter @config.bands (fn b (<= @entity.dose (object/get @b upperBound)))))
58
- (band (if (> (array/len @matched) 0) (array/first @matched) (array/nth @config.bands (- (array/len @config.bands) 1))))
59
+ (matched (array/filter @entity.bands (fn b (<= @entity.dose (object/get @b upperBound)))))
60
+ (band (if (> (array/len @matched) 0) (array/first @matched) (array/nth @entity.bands (- (array/len @entity.bands) 1))))
59
61
  )
60
62
  (do
61
63
  (set @entity.bandLabel (object/get @band label))
@@ -127,16 +129,17 @@ orbital LearnDoserOrbital {
127
129
  (set @entity.running false)
128
130
  (render-ui main null)
129
131
 
130
- MODE_SELECTED -> idle when (== ?mode @config.matchMode)
132
+ MODE_SELECTED -> idle when (and (== ?mode @config.matchMode) (== @config.rosterSource "config"))
131
133
  (set @entity.active true)
132
134
  (set @entity.title @config.title)
135
+ (set @entity.bands @config.bands)
133
136
  (set @entity.dose 0)
134
137
  (set @entity.done false)
135
138
  (set @entity.running @config.autoDrip)
136
139
  (set @entity.elapsedMs 0)
137
140
  (let (
138
- (matched (array/filter @config.bands (fn b (<= @entity.dose (object/get @b upperBound)))))
139
- (band (if (> (array/len @matched) 0) (array/first @matched) (array/nth @config.bands (- (array/len @config.bands) 1))))
141
+ (matched (array/filter @entity.bands (fn b (<= @entity.dose (object/get @b upperBound)))))
142
+ (band (if (> (array/len @matched) 0) (array/first @matched) (array/nth @entity.bands (- (array/len @entity.bands) 1))))
140
143
  )
141
144
  (do
142
145
  (set @entity.bandLabel (object/get @band label))
@@ -203,11 +206,93 @@ orbital LearnDoserOrbital {
203
206
  }))
204
207
  (emit DOSER_UPDATED { running: @entity.running, dose: @entity.dose, bandLabel: @entity.bandLabel, done: @entity.done })
205
208
 
209
+ ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (and (== ?mode @config.matchMode) (> (array/len ?bands) 0)))
210
+ (set @entity.active true)
211
+ (set @entity.title @config.title)
212
+ (set @entity.bands ?bands)
213
+ (set @entity.dose 0)
214
+ (set @entity.done false)
215
+ (set @entity.running @config.autoDrip)
216
+ (set @entity.elapsedMs 0)
217
+ (let (
218
+ (matched (array/filter @entity.bands (fn b (<= @entity.dose (object/get @b upperBound)))))
219
+ (band (if (> (array/len @matched) 0) (array/first @matched) (array/nth @entity.bands (- (array/len @entity.bands) 1))))
220
+ )
221
+ (do
222
+ (set @entity.bandLabel (object/get @band label))
223
+ (set @entity.bandColor (object/get @band color))
224
+ (set @entity.done (if (object/get @band terminal false) true @entity.done))
225
+ )
226
+ )
227
+ (set @entity.containers [
228
+ { x: (* @config.width 0.12), y: (* @config.height 0.3), width: (* @config.width 0.28), height: (* @config.height 0.6), divider: "none", level: (math/clamp (/ @entity.dose @config.capacity) 0 1), levelColor: @entity.bandColor, label: @config.reservoirLabel },
229
+ { x: (* @config.width 0.58), y: (* @config.height 0.05), width: (* @config.width 0.06), height: (* @config.height 0.55), divider: "none", level: (math/clamp (/ (- @config.capacity @entity.dose) @config.capacity) 0 1), levelColor: @config.sourceColor, label: @config.sourceLabel }
230
+ ])
231
+ (set @entity.readouts [
232
+ { label: @config.quantityLabel, value: (str/concat "" (math/round @entity.dose 2)) },
233
+ { label: @config.zoneReadoutLabel, value: @entity.bandLabel }
234
+ ])
235
+ (set @entity.doseSeries [{ x: 0, y: @entity.dose }])
236
+ (set @entity.narration (str/concat @config.quantityLabel (str/concat " at " (str/concat (str/concat "" (math/round @entity.dose 2)) (str/concat " — " @entity.bandLabel)))))
237
+ (if @config.showCanvas
238
+ (render-ui main {
239
+ type: box
240
+ padding: md
241
+ children: [
242
+ { type: stack, direction: vertical, gap: md, children: [
243
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
244
+ { type: stack, direction: vertical, gap: xs, children: [
245
+ { type: typography, variant: h4, content: @entity.title },
246
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
247
+ ] },
248
+ { type: badge, label: (if @entity.done "Locked" (if @entity.running "Auto-dosing" "Ready")), variant: (if @entity.done "warning" (if @entity.running "primary" "neutral")) }
249
+ ] },
250
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
251
+ { type: button, action: ADD_SMALL, label: (str/concat "Add " (str/concat (str/concat "" @config.stepSmall) (if (== @config.unit "") "" (str/concat " " @config.unit)))), icon: "plus", variant: primary, disabled: @entity.done },
252
+ { type: button, action: ADD_LARGE, label: (str/concat "Add " (str/concat (str/concat "" @config.stepLarge) (if (== @config.unit "") "" (str/concat " " @config.unit)))), icon: "plus", variant: secondary, disabled: @entity.done },
253
+ (if @entity.running { type: button, action: TOGGLE_DRIP, label: "Pause", icon: "pause", variant: secondary, aria-pressed: "true" } { type: button, action: TOGGLE_DRIP, label: "Auto-dose", icon: "play", variant: secondary, aria-pressed: "false", disabled: @entity.done }),
254
+ { type: button, action: RESET, label: "Reset", icon: "rotate-ccw", variant: ghost },
255
+ { type: typography, variant: caption, color: muted, content: (str/concat @config.quantityLabel (str/concat " " (str/concat (str/concat "" (math/round @entity.dose 2)) (str/concat " of " (str/concat (str/concat "" @config.capacity) (if (== @config.unit "") "" (str/concat " " @config.unit))))))) }
256
+ ] },
257
+ { type: chemistry-canvas, series: @config.series, keyMap: { Space: TOGGLE_DRIP, KeyR: RESET }, width: @config.width, height: @config.height, backgroundColor: @config.backgroundColor, containers: @entity.containers, readouts: @entity.readouts, traces: [ { series: [ { samples: @entity.doseSeries, label: @config.quantityLabel } ], xLabel: "step", yLabel: @config.quantityLabel } ] },
258
+ { type: typography, variant: body, content: @entity.narration }
259
+ ] }
260
+ ]
261
+ })
262
+ (render-ui main {
263
+ type: box
264
+ padding: md
265
+ children: [
266
+ { type: stack, direction: vertical, gap: md, children: [
267
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
268
+ { type: stack, direction: vertical, gap: xs, children: [
269
+ { type: typography, variant: h4, content: @entity.title },
270
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
271
+ ] },
272
+ { type: badge, label: (if @entity.done "Locked" (if @entity.running "Auto-dosing" "Ready")), variant: (if @entity.done "warning" (if @entity.running "primary" "neutral")) }
273
+ ] },
274
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
275
+ { type: button, action: ADD_SMALL, label: (str/concat "Add " (str/concat (str/concat "" @config.stepSmall) (if (== @config.unit "") "" (str/concat " " @config.unit)))), icon: "plus", variant: primary, disabled: @entity.done },
276
+ { type: button, action: ADD_LARGE, label: (str/concat "Add " (str/concat (str/concat "" @config.stepLarge) (if (== @config.unit "") "" (str/concat " " @config.unit)))), icon: "plus", variant: secondary, disabled: @entity.done },
277
+ (if @entity.running { type: button, action: TOGGLE_DRIP, label: "Pause", icon: "pause", variant: secondary, aria-pressed: "true" } { type: button, action: TOGGLE_DRIP, label: "Auto-dose", icon: "play", variant: secondary, aria-pressed: "false", disabled: @entity.done }),
278
+ { type: button, action: RESET, label: "Reset", icon: "rotate-ccw", variant: ghost },
279
+ { type: typography, variant: caption, color: muted, content: (str/concat @config.quantityLabel (str/concat " " (str/concat (str/concat "" (math/round @entity.dose 2)) (str/concat " of " (str/concat (str/concat "" @config.capacity) (if (== @config.unit "") "" (str/concat " " @config.unit))))))) }
280
+ ] }
281
+ ] }
282
+ ]
283
+ }))
284
+ (emit DOSER_UPDATED { running: @entity.running, dose: @entity.dose, bandLabel: @entity.bandLabel, done: @entity.done })
285
+
286
+ ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (not (== ?mode @config.matchMode)))
287
+ (set @entity.active false)
288
+ (set @entity.running false)
289
+ (render-ui main null)
290
+
206
291
  ADD_SMALL -> idle when (and (== @entity.active true) (== @entity.done false))
207
292
  (set @entity.dose (math/min (+ @entity.dose @config.stepSmall) @config.capacity))
208
293
  (let (
209
- (matched (array/filter @config.bands (fn b (<= @entity.dose (object/get @b upperBound)))))
210
- (band (if (> (array/len @matched) 0) (array/first @matched) (array/nth @config.bands (- (array/len @config.bands) 1))))
294
+ (matched (array/filter @entity.bands (fn b (<= @entity.dose (object/get @b upperBound)))))
295
+ (band (if (> (array/len @matched) 0) (array/first @matched) (array/nth @entity.bands (- (array/len @entity.bands) 1))))
211
296
  )
212
297
  (do
213
298
  (set @entity.bandLabel (object/get @band label))
@@ -278,8 +363,8 @@ orbital LearnDoserOrbital {
278
363
  ADD_LARGE -> idle when (and (== @entity.active true) (== @entity.done false))
279
364
  (set @entity.dose (math/min (+ @entity.dose @config.stepLarge) @config.capacity))
280
365
  (let (
281
- (matched (array/filter @config.bands (fn b (<= @entity.dose (object/get @b upperBound)))))
282
- (band (if (> (array/len @matched) 0) (array/first @matched) (array/nth @config.bands (- (array/len @config.bands) 1))))
366
+ (matched (array/filter @entity.bands (fn b (<= @entity.dose (object/get @b upperBound)))))
367
+ (band (if (> (array/len @matched) 0) (array/first @matched) (array/nth @entity.bands (- (array/len @entity.bands) 1))))
283
368
  )
284
369
  (do
285
370
  (set @entity.bandLabel (object/get @band label))
@@ -406,8 +491,8 @@ orbital LearnDoserOrbital {
406
491
  (set @entity.running @config.autoDrip)
407
492
  (set @entity.elapsedMs 0)
408
493
  (let (
409
- (matched (array/filter @config.bands (fn b (<= @entity.dose (object/get @b upperBound)))))
410
- (band (if (> (array/len @matched) 0) (array/first @matched) (array/nth @config.bands (- (array/len @config.bands) 1))))
494
+ (matched (array/filter @entity.bands (fn b (<= @entity.dose (object/get @b upperBound)))))
495
+ (band (if (> (array/len @matched) 0) (array/first @matched) (array/nth @entity.bands (- (array/len @entity.bands) 1))))
411
496
  )
412
497
  (do
413
498
  (set @entity.bandLabel (object/get @band label))
@@ -492,6 +577,12 @@ orbital LearnDoserOrbital {
492
577
  }
493
578
  @description "Lab router broadcast naming the active mode; this instrument renders when the mode equals matchMode, otherwise renders null."
494
579
  @tier "domain"
580
+ ROSTER_LOADED {
581
+ mode : string!
582
+ bands : [DoserBand]!
583
+ }
584
+ @description "Runtime content feed, honoured only when rosterSource is event — mode names the instrument it is for (the matchMode it carries, blank when standalone) and bands is the band roster; a matching instrument re-initialises from it exactly as INIT does from config, any other instrument hides."
585
+ @tier "domain"
495
586
  }
496
587
 
497
588
  emits {
@@ -597,6 +688,10 @@ orbital LearnDoserOrbital {
597
688
  @label "Dose History"
598
689
  @description "Maximum points kept in the dose-history trace; older points drop off once exceeded."
599
690
  @tier "domain"
691
+ rosterSource : "config" | "event" = "config"
692
+ @label "Roster Source"
693
+ @description "Where the band roster comes from: config reads the bands knob at INIT; event waits for ROSTER_LOADED and takes the roster from its payload."
694
+ @tier "domain"
600
695
  bands : [DoserBand] = [
601
696
  { upperBound: 50, label: "Low", color: "muted", terminal: false },
602
697
  { upperBound: 999999999, label: "High", color: "success", terminal: true }