@foresthubai/workflow-core 0.4.3 → 0.4.5

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 (298) hide show
  1. package/LICENSE +202 -202
  2. package/NOTICE +14 -14
  3. package/README.md +63 -63
  4. package/dist/api/deployment.d.ts +74 -0
  5. package/dist/api/deployment.d.ts.map +1 -0
  6. package/dist/api/deployment.js +6 -0
  7. package/dist/api/deployment.js.map +1 -0
  8. package/dist/api/engine.d.ts +744 -0
  9. package/dist/api/engine.d.ts.map +1 -0
  10. package/dist/api/engine.js +6 -0
  11. package/dist/api/engine.js.map +1 -0
  12. package/dist/api/index.d.ts +4 -0
  13. package/dist/api/index.d.ts.map +1 -1
  14. package/dist/api/index.js +2 -0
  15. package/dist/api/index.js.map +1 -1
  16. package/dist/api/workflow.d.ts +25 -9
  17. package/dist/api/workflow.d.ts.map +1 -1
  18. package/dist/channel/Channel.d.ts +1 -1
  19. package/dist/channel/Channel.d.ts.map +1 -1
  20. package/dist/channel/Channel.js +3 -1
  21. package/dist/channel/Channel.js.map +1 -1
  22. package/dist/channel/ChannelDefinition.d.ts.map +1 -1
  23. package/dist/channel/ChannelDefinition.js +24 -0
  24. package/dist/channel/ChannelDefinition.js.map +1 -1
  25. package/dist/channel/index.d.ts.map +1 -1
  26. package/dist/channel/index.js +2 -0
  27. package/dist/channel/index.js.map +1 -1
  28. package/dist/channel/serialization.d.ts.map +1 -1
  29. package/dist/channel/serialization.js +8 -0
  30. package/dist/channel/serialization.js.map +1 -1
  31. package/dist/deploy/index.d.ts +5 -1
  32. package/dist/deploy/index.d.ts.map +1 -1
  33. package/dist/deploy/index.js +4 -1
  34. package/dist/deploy/index.js.map +1 -1
  35. package/dist/deploy/inputs.d.ts +26 -0
  36. package/dist/deploy/inputs.d.ts.map +1 -0
  37. package/dist/deploy/inputs.js +4 -0
  38. package/dist/deploy/inputs.js.map +1 -0
  39. package/dist/deploy/requirements.d.ts +24 -0
  40. package/dist/deploy/requirements.d.ts.map +1 -1
  41. package/dist/deploy/requirements.js +63 -0
  42. package/dist/deploy/requirements.js.map +1 -1
  43. package/dist/deploy/spec.d.ts +27 -0
  44. package/dist/deploy/spec.d.ts.map +1 -0
  45. package/dist/deploy/spec.js +352 -0
  46. package/dist/deploy/spec.js.map +1 -0
  47. package/dist/diagnostics/__fixtures__/diagnosticFixtures.d.ts.map +1 -1
  48. package/dist/diagnostics/__fixtures__/diagnosticFixtures.js +2 -0
  49. package/dist/diagnostics/__fixtures__/diagnosticFixtures.js.map +1 -1
  50. package/dist/diagnostics/diagnostics.d.ts.map +1 -1
  51. package/dist/diagnostics/diagnostics.js +2 -0
  52. package/dist/diagnostics/diagnostics.js.map +1 -1
  53. package/dist/diagnostics/index.d.ts.map +1 -1
  54. package/dist/diagnostics/index.js +2 -0
  55. package/dist/diagnostics/index.js.map +1 -1
  56. package/dist/edge/Edge.d.ts.map +1 -1
  57. package/dist/edge/Edge.js +2 -0
  58. package/dist/edge/Edge.js.map +1 -1
  59. package/dist/edge/EdgeDefinition.d.ts.map +1 -1
  60. package/dist/edge/EdgeDefinition.js +2 -0
  61. package/dist/edge/EdgeDefinition.js.map +1 -1
  62. package/dist/edge/EdgeType.d.ts.map +1 -1
  63. package/dist/edge/EdgeType.js +2 -0
  64. package/dist/edge/EdgeType.js.map +1 -1
  65. package/dist/edge/index.d.ts.map +1 -1
  66. package/dist/edge/index.js +2 -2
  67. package/dist/edge/index.js.map +1 -1
  68. package/dist/edge/serialization.d.ts.map +1 -1
  69. package/dist/edge/serialization.js +2 -0
  70. package/dist/edge/serialization.js.map +1 -1
  71. package/dist/expression/index.d.ts.map +1 -1
  72. package/dist/expression/index.js +2 -0
  73. package/dist/expression/index.js.map +1 -1
  74. package/dist/expression/parser.d.ts.map +1 -1
  75. package/dist/expression/parser.js +2 -0
  76. package/dist/expression/parser.js.map +1 -1
  77. package/dist/expression/types.d.ts.map +1 -1
  78. package/dist/expression/types.js +2 -0
  79. package/dist/expression/types.js.map +1 -1
  80. package/dist/function/FunctionDeclaration.d.ts.map +1 -1
  81. package/dist/function/FunctionDeclaration.js +2 -0
  82. package/dist/function/FunctionDeclaration.js.map +1 -1
  83. package/dist/function/index.d.ts.map +1 -1
  84. package/dist/function/index.js +2 -0
  85. package/dist/function/index.js.map +1 -1
  86. package/dist/function/serialization.d.ts.map +1 -1
  87. package/dist/function/serialization.js +2 -0
  88. package/dist/function/serialization.js.map +1 -1
  89. package/dist/id/index.d.ts.map +1 -1
  90. package/dist/id/index.js +2 -0
  91. package/dist/id/index.js.map +1 -1
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +2 -0
  94. package/dist/index.js.map +1 -1
  95. package/dist/memory/Memory.d.ts.map +1 -1
  96. package/dist/memory/Memory.js +2 -0
  97. package/dist/memory/Memory.js.map +1 -1
  98. package/dist/memory/MemoryDefinition.d.ts.map +1 -1
  99. package/dist/memory/MemoryDefinition.js +2 -0
  100. package/dist/memory/MemoryDefinition.js.map +1 -1
  101. package/dist/memory/MemoryFileDefinition.d.ts.map +1 -1
  102. package/dist/memory/MemoryFileDefinition.js +2 -0
  103. package/dist/memory/MemoryFileDefinition.js.map +1 -1
  104. package/dist/memory/MemoryRegistry.d.ts.map +1 -1
  105. package/dist/memory/MemoryRegistry.js +2 -0
  106. package/dist/memory/MemoryRegistry.js.map +1 -1
  107. package/dist/memory/VectorDatabaseDefinition.d.ts.map +1 -1
  108. package/dist/memory/VectorDatabaseDefinition.js +2 -0
  109. package/dist/memory/VectorDatabaseDefinition.js.map +1 -1
  110. package/dist/memory/index.d.ts.map +1 -1
  111. package/dist/memory/index.js +2 -0
  112. package/dist/memory/index.js.map +1 -1
  113. package/dist/memory/serialization.d.ts.map +1 -1
  114. package/dist/memory/serialization.js +2 -0
  115. package/dist/memory/serialization.js.map +1 -1
  116. package/dist/migration/index.d.ts.map +1 -1
  117. package/dist/migration/index.js +2 -0
  118. package/dist/migration/index.js.map +1 -1
  119. package/dist/migration/migrate.d.ts.map +1 -1
  120. package/dist/migration/migrate.js +2 -0
  121. package/dist/migration/migrate.js.map +1 -1
  122. package/dist/migration/migrations.d.ts.map +1 -1
  123. package/dist/migration/migrations.js +2 -0
  124. package/dist/migration/migrations.js.map +1 -1
  125. package/dist/migration/version.d.ts.map +1 -1
  126. package/dist/migration/version.js +2 -0
  127. package/dist/migration/version.js.map +1 -1
  128. package/dist/model/LLMModelDefinition.d.ts.map +1 -1
  129. package/dist/model/LLMModelDefinition.js +2 -0
  130. package/dist/model/LLMModelDefinition.js.map +1 -1
  131. package/dist/model/Model.d.ts.map +1 -1
  132. package/dist/model/Model.js +2 -13
  133. package/dist/model/Model.js.map +1 -1
  134. package/dist/model/ModelDefinition.d.ts.map +1 -1
  135. package/dist/model/ModelDefinition.js +2 -0
  136. package/dist/model/ModelDefinition.js.map +1 -1
  137. package/dist/model/ModelRegistry.d.ts.map +1 -1
  138. package/dist/model/ModelRegistry.js +2 -0
  139. package/dist/model/ModelRegistry.js.map +1 -1
  140. package/dist/model/index.d.ts.map +1 -1
  141. package/dist/model/index.js +2 -0
  142. package/dist/model/index.js.map +1 -1
  143. package/dist/model/serialization.d.ts.map +1 -1
  144. package/dist/model/serialization.js +2 -0
  145. package/dist/model/serialization.js.map +1 -1
  146. package/dist/node/AgentNode.d.ts.map +1 -1
  147. package/dist/node/AgentNode.js +2 -0
  148. package/dist/node/AgentNode.js.map +1 -1
  149. package/dist/node/DataNode.d.ts.map +1 -1
  150. package/dist/node/DataNode.js +2 -0
  151. package/dist/node/DataNode.js.map +1 -1
  152. package/dist/node/FunctionNode.d.ts.map +1 -1
  153. package/dist/node/FunctionNode.js +2 -0
  154. package/dist/node/FunctionNode.js.map +1 -1
  155. package/dist/node/InputNode.d.ts.map +1 -1
  156. package/dist/node/InputNode.js +2 -0
  157. package/dist/node/InputNode.js.map +1 -1
  158. package/dist/node/LogicNode.d.ts.map +1 -1
  159. package/dist/node/LogicNode.js +2 -0
  160. package/dist/node/LogicNode.js.map +1 -1
  161. package/dist/node/MqttNode.d.ts.map +1 -1
  162. package/dist/node/MqttNode.js +2 -0
  163. package/dist/node/MqttNode.js.map +1 -1
  164. package/dist/node/Node.d.ts.map +1 -1
  165. package/dist/node/Node.js +2 -7
  166. package/dist/node/Node.js.map +1 -1
  167. package/dist/node/NodeDefinition.d.ts.map +1 -1
  168. package/dist/node/NodeDefinition.js +2 -0
  169. package/dist/node/NodeDefinition.js.map +1 -1
  170. package/dist/node/NodeRegistry.d.ts.map +1 -1
  171. package/dist/node/NodeRegistry.js +2 -0
  172. package/dist/node/NodeRegistry.js.map +1 -1
  173. package/dist/node/OutputNode.d.ts.map +1 -1
  174. package/dist/node/OutputNode.js +4 -2
  175. package/dist/node/OutputNode.js.map +1 -1
  176. package/dist/node/ToolNode.d.ts.map +1 -1
  177. package/dist/node/ToolNode.js +2 -0
  178. package/dist/node/ToolNode.js.map +1 -1
  179. package/dist/node/TriggerNode.d.ts.map +1 -1
  180. package/dist/node/TriggerNode.js +2 -0
  181. package/dist/node/TriggerNode.js.map +1 -1
  182. package/dist/node/constants.d.ts.map +1 -1
  183. package/dist/node/constants.js +2 -0
  184. package/dist/node/constants.js.map +1 -1
  185. package/dist/node/index.d.ts.map +1 -1
  186. package/dist/node/index.js +2 -0
  187. package/dist/node/index.js.map +1 -1
  188. package/dist/node/methods.d.ts.map +1 -1
  189. package/dist/node/methods.js +2 -0
  190. package/dist/node/methods.js.map +1 -1
  191. package/dist/node/serialization.d.ts.map +1 -1
  192. package/dist/node/serialization.js +33 -13
  193. package/dist/node/serialization.js.map +1 -1
  194. package/dist/parameter/OutputParameter.d.ts.map +1 -1
  195. package/dist/parameter/OutputParameter.js +2 -0
  196. package/dist/parameter/OutputParameter.js.map +1 -1
  197. package/dist/parameter/Parameter.d.ts.map +1 -1
  198. package/dist/parameter/Parameter.js +2 -0
  199. package/dist/parameter/Parameter.js.map +1 -1
  200. package/dist/parameter/index.d.ts.map +1 -1
  201. package/dist/parameter/index.js +2 -0
  202. package/dist/parameter/index.js.map +1 -1
  203. package/dist/variable/Variable.d.ts.map +1 -1
  204. package/dist/variable/Variable.js +2 -0
  205. package/dist/variable/Variable.js.map +1 -1
  206. package/dist/variable/index.d.ts.map +1 -1
  207. package/dist/variable/index.js +2 -3
  208. package/dist/variable/index.js.map +1 -1
  209. package/dist/variable/operations.d.ts.map +1 -1
  210. package/dist/variable/operations.js +2 -0
  211. package/dist/variable/operations.js.map +1 -1
  212. package/dist/workflow/Workflow.d.ts.map +1 -1
  213. package/dist/workflow/Workflow.js +2 -0
  214. package/dist/workflow/Workflow.js.map +1 -1
  215. package/dist/workflow/index.d.ts.map +1 -1
  216. package/dist/workflow/index.js +2 -0
  217. package/dist/workflow/index.js.map +1 -1
  218. package/dist/workflow/serialization.d.ts.map +1 -1
  219. package/dist/workflow/serialization.js +2 -4
  220. package/dist/workflow/serialization.js.map +1 -1
  221. package/package.json +2 -2
  222. package/src/api/deployment.ts +74 -0
  223. package/src/api/engine.ts +744 -0
  224. package/src/api/index.ts +29 -11
  225. package/src/api/workflow.ts +25 -9
  226. package/src/channel/Channel.ts +14 -11
  227. package/src/channel/ChannelDefinition.ts +101 -76
  228. package/src/channel/index.ts +9 -6
  229. package/src/channel/serialization.ts +77 -68
  230. package/src/deploy/index.ts +17 -1
  231. package/src/deploy/inputs.ts +44 -0
  232. package/src/deploy/requirements.test.ts +64 -61
  233. package/src/deploy/requirements.ts +159 -41
  234. package/src/deploy/spec.test.ts +227 -0
  235. package/src/deploy/spec.ts +397 -0
  236. package/src/diagnostics/__fixtures__/diagnosticFixtures.ts +161 -158
  237. package/src/diagnostics/diagnostics.test.ts +881 -878
  238. package/src/diagnostics/diagnostics.ts +939 -936
  239. package/src/diagnostics/index.ts +14 -11
  240. package/src/edge/Edge.ts +26 -23
  241. package/src/edge/EdgeDefinition.ts +48 -45
  242. package/src/edge/EdgeType.ts +22 -19
  243. package/src/edge/index.ts +11 -8
  244. package/src/edge/serialization.ts +86 -83
  245. package/src/expression/index.ts +7 -4
  246. package/src/expression/parser.ts +365 -362
  247. package/src/expression/types.ts +33 -30
  248. package/src/function/FunctionDeclaration.ts +57 -54
  249. package/src/function/index.ts +6 -3
  250. package/src/function/serialization.ts +43 -40
  251. package/src/globals.d.ts +12 -9
  252. package/src/id/index.ts +11 -8
  253. package/src/index.ts +25 -22
  254. package/src/memory/Memory.ts +18 -15
  255. package/src/memory/MemoryDefinition.ts +19 -16
  256. package/src/memory/MemoryFileDefinition.ts +40 -37
  257. package/src/memory/MemoryRegistry.ts +38 -35
  258. package/src/memory/VectorDatabaseDefinition.ts +24 -21
  259. package/src/memory/index.ts +11 -8
  260. package/src/memory/serialization.ts +50 -47
  261. package/src/migration/index.ts +7 -4
  262. package/src/migration/migrate.test.ts +47 -44
  263. package/src/migration/migrate.ts +61 -58
  264. package/src/migration/migrations.ts +27 -24
  265. package/src/migration/version.ts +12 -9
  266. package/src/model/LLMModelDefinition.ts +15 -12
  267. package/src/model/Model.ts +42 -39
  268. package/src/model/ModelDefinition.ts +18 -15
  269. package/src/model/ModelRegistry.ts +36 -33
  270. package/src/model/index.ts +10 -7
  271. package/src/model/serialization.ts +33 -30
  272. package/src/node/AgentNode.ts +85 -82
  273. package/src/node/DataNode.ts +44 -41
  274. package/src/node/FunctionNode.ts +79 -76
  275. package/src/node/InputNode.ts +188 -185
  276. package/src/node/LogicNode.ts +36 -33
  277. package/src/node/MqttNode.ts +130 -127
  278. package/src/node/Node.ts +64 -61
  279. package/src/node/NodeDefinition.ts +40 -37
  280. package/src/node/NodeRegistry.ts +88 -85
  281. package/src/node/OutputNode.ts +90 -87
  282. package/src/node/ToolNode.ts +35 -32
  283. package/src/node/TriggerNode.ts +275 -272
  284. package/src/node/constants.ts +19 -16
  285. package/src/node/index.ts +29 -26
  286. package/src/node/methods.ts +281 -278
  287. package/src/node/serialization.test.ts +51 -0
  288. package/src/node/serialization.ts +565 -544
  289. package/src/parameter/OutputParameter.ts +71 -68
  290. package/src/parameter/Parameter.ts +246 -243
  291. package/src/parameter/index.ts +36 -33
  292. package/src/variable/Variable.ts +13 -10
  293. package/src/variable/index.ts +19 -16
  294. package/src/variable/operations.ts +109 -106
  295. package/src/workflow/Workflow.ts +44 -41
  296. package/src/workflow/index.ts +6 -3
  297. package/src/workflow/serialization.test.ts +243 -240
  298. package/src/workflow/serialization.ts +245 -242
package/src/api/index.ts CHANGED
@@ -1,11 +1,29 @@
1
- export type { components } from "./workflow";
2
-
3
- import type { components } from "./workflow";
4
- export type Schemas = components["schemas"];
5
-
6
- // Api-layer type aliases used across the domain. They live here (not in any
7
- // single domain module) so modules don't cross-import them; consumers pull
8
- // them from the package root (`@foresthubai/workflow-core`).
9
- export type DataType = Schemas["DataType"];
10
- export type Reference = Schemas["Reference"];
11
- export type Expression = Schemas["Expression"];
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
4
+ export type { components } from "./workflow";
5
+
6
+ import type { components } from "./workflow";
7
+ export type Schemas = components["schemas"];
8
+
9
+ // Deployment-spec api layer, generated from contract/deployment.yaml. Its
10
+ // DeployComponent.config is an opaque object — the spec transports rendered config
11
+ // as bytes and no longer $refs engine.yaml — so the engine's own config types live
12
+ // in EngineSchemas below, not here. Kept under a distinct name so it never collides
13
+ // with the workflow Schemas above.
14
+ import type { components as deploymentComponents } from "./deployment";
15
+ export type DeploymentSchemas = deploymentComponents["schemas"];
16
+
17
+ // Engine wire/config api layer, generated from contract/engine.yaml. The deploy
18
+ // resolver (src/deploy/) PRODUCES an EngineConfig (workflow + mapping + external
19
+ // resources + device manifest) and freezes it into a DeployComponent's opaque
20
+ // config, so it types that construction against these.
21
+ import type { components as engineComponents } from "./engine";
22
+ export type EngineSchemas = engineComponents["schemas"];
23
+
24
+ // Api-layer type aliases used across the domain. They live here (not in any
25
+ // single domain module) so modules don't cross-import them; consumers pull
26
+ // them from the package root (`@foresthubai/workflow-core`).
27
+ export type DataType = Schemas["DataType"];
28
+ export type Reference = Schemas["Reference"];
29
+ export type Expression = Schemas["Expression"];
@@ -17,7 +17,7 @@ export interface components {
17
17
  x: number;
18
18
  y: number;
19
19
  };
20
- /** @description Workflow represents the deployment format of a project, passed to agents. */
20
+ /** @description The deployment format of a workflow project. */
21
21
  Workflow: {
22
22
  /**
23
23
  * Format: int32
@@ -115,7 +115,7 @@ export interface components {
115
115
  type: "MemoryFile";
116
116
  /** @description Stable identifier that survives renames; referenced from MemoryRef. */
117
117
  id: string;
118
- /** @description Display name. Unique per agent (LLM tool enums use it). */
118
+ /** @description Display name. Unique per agent. */
119
119
  label: string;
120
120
  description: string;
121
121
  content: string;
@@ -157,7 +157,7 @@ export interface components {
157
157
  id: string;
158
158
  /** @description Display name. */
159
159
  label: string;
160
- /** @description Capabilities this model supports (used to filter model pickers). */
160
+ /** @description Capabilities this model supports. */
161
161
  capabilities: components["schemas"]["ModelCapability"][];
162
162
  };
163
163
  Node: components["schemas"]["ReadPinNode"] | components["schemas"]["WritePinNode"] | components["schemas"]["AgentNode"] | components["schemas"]["IfNode"] | components["schemas"]["SerialReadNode"] | components["schemas"]["SerialWriteNode"] | components["schemas"]["RetrieverNode"] | components["schemas"]["WebFetchNode"] | components["schemas"]["FunctionCallNode"] | components["schemas"]["OnFunctionCallNode"] | components["schemas"]["DelayNode"] | components["schemas"]["TickerNode"] | components["schemas"]["AlarmNode"] | components["schemas"]["WebSearchToolNode"] | components["schemas"]["OnStartupNode"] | components["schemas"]["OnPinEdgeNode"] | components["schemas"]["OnSerialReceiveNode"] | components["schemas"]["OnThresholdNode"] | components["schemas"]["SetVariableNode"] | components["schemas"]["MqttPublishNode"] | components["schemas"]["OnMqttMessageNode"];
@@ -242,7 +242,7 @@ export interface components {
242
242
  outputBindings?: {
243
243
  [key: string]: components["schemas"]["OutputBinding"];
244
244
  };
245
- /** @description Description exposed to the LLM when this function is wired as a tool. Ignored in exec mode. */
245
+ /** @description Description used when this function is exposed as a tool; ignored in exec mode. */
246
246
  toolDescription?: string;
247
247
  };
248
248
  };
@@ -342,7 +342,7 @@ export interface components {
342
342
  /** @description Search query expression */
343
343
  query: components["schemas"]["Expression"];
344
344
  output: components["schemas"]["OutputBinding"];
345
- /** @description Description exposed to the LLM when this node is wired as a tool. Ignored in exec mode. */
345
+ /** @description Description used when this node is exposed as a tool; ignored in exec mode. */
346
346
  toolDescription?: string;
347
347
  };
348
348
  };
@@ -377,7 +377,7 @@ export interface components {
377
377
  pinReference?: string;
378
378
  signalType: components["schemas"]["SignalType"];
379
379
  output: components["schemas"]["OutputBinding"];
380
- /** @description Description exposed to the LLM when this node is wired as a tool. Ignored in exec mode. */
380
+ /** @description Description used when this node is exposed as a tool; ignored in exec mode. */
381
381
  toolDescription?: string;
382
382
  };
383
383
  };
@@ -418,7 +418,7 @@ export interface components {
418
418
  outputDeclarations: components["schemas"]["OutputDeclaration"][];
419
419
  /** @description Memory files this agent can access, each with an access mode. */
420
420
  memoryRefs: components["schemas"]["MemoryRef"][];
421
- /** @description Description exposed to the LLM when this node is wired as a tool. Ignored in exec mode. */
421
+ /** @description Description used when this node is exposed as a tool; ignored in exec mode. */
422
422
  toolDescription?: string;
423
423
  };
424
424
  };
@@ -519,7 +519,7 @@ export interface components {
519
519
  output: components["schemas"]["OutputBinding"];
520
520
  };
521
521
  };
522
- Channel: components["schemas"]["GPIOINChannel"] | components["schemas"]["GPIOOUTChannel"] | components["schemas"]["ADCChannel"] | components["schemas"]["PWMChannel"] | components["schemas"]["DACChannel"] | components["schemas"]["UARTChannel"] | components["schemas"]["MQTTChannel"];
522
+ Channel: components["schemas"]["GPIOINChannel"] | components["schemas"]["GPIOOUTChannel"] | components["schemas"]["ADCChannel"] | components["schemas"]["PWMChannel"] | components["schemas"]["DACChannel"] | components["schemas"]["UARTChannel"] | components["schemas"]["MQTTChannel"] | components["schemas"]["LOGChannel"];
523
523
  GPIOINChannel: {
524
524
  /**
525
525
  * @description discriminator enum property added by openapi-typescript
@@ -591,9 +591,25 @@ export interface components {
591
591
  type: "MQTT";
592
592
  id: string;
593
593
  label: string;
594
- /** @description Topic this channel publishes to / subscribes on. The engine wraps it with the bound broker's prefix at runtime. */
594
+ /** @description Topic this channel publishes to / subscribes on. */
595
595
  topic: string;
596
596
  };
597
+ LOGChannel: {
598
+ /**
599
+ * @description discriminator enum property added by openapi-typescript
600
+ * @enum {string}
601
+ */
602
+ type: "LOG";
603
+ id: string;
604
+ label: string;
605
+ /**
606
+ * @description Severity for messages written to this channel.
607
+ * @enum {string}
608
+ */
609
+ level: "debug" | "info" | "warn" | "error";
610
+ /** @description Optional category label stamped on each line written to this channel. */
611
+ tag?: string;
612
+ };
597
613
  /** @enum {string} */
598
614
  ModelCapability: "chat" | "embedding" | "function_call" | "vision" | "fine_tuning" | "reasoning" | "classification" | "code";
599
615
  };
@@ -1,11 +1,14 @@
1
- export type ChannelType = "GPIOIN" | "GPIOOUT" | "ADC" | "PWM" | "DAC" | "UART" | "MQTT";
2
-
3
- export const ALL_CHANNEL_TYPES: ChannelType[] = ["GPIOIN", "GPIOOUT", "ADC", "PWM", "DAC", "UART", "MQTT"];
4
-
5
- /** Interface for a channel instance in the workflow */
6
- export interface Channel {
7
- id: string;
8
- label: string;
9
- type: ChannelType;
10
- arguments: Record<string, unknown>;
11
- }
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
4
+ export type ChannelType = "GPIOIN" | "GPIOOUT" | "ADC" | "PWM" | "DAC" | "UART" | "MQTT" | "LOG";
5
+
6
+ export const ALL_CHANNEL_TYPES: ChannelType[] = ["GPIOIN", "GPIOOUT", "ADC", "PWM", "DAC", "UART", "MQTT", "LOG"];
7
+
8
+ /** Interface for a channel instance in the workflow */
9
+ export interface Channel {
10
+ id: string;
11
+ label: string;
12
+ type: ChannelType;
13
+ arguments: Record<string, unknown>;
14
+ }
@@ -1,76 +1,101 @@
1
- import type { Parameter } from "../parameter";
2
- import { ALL_CHANNEL_TYPES } from "./Channel";
3
-
4
- /**
5
- * Single union definition for all Channel variants — deliberately NOT the
6
- * per-type registry pattern used by Node/Memory/Model (`*Definition` +
7
- * `*Registry`, one definition object per type).
8
- *
9
- * The reason is in-place `type` switching that preserves shared parameter state.
10
- * Because `type` is a parameter and all variants share one `arguments` bag,
11
- * changing a channel's type keeps the same instance (id, label) and retains any
12
- * entered values that are still valid for the new type: the parameter +
13
- * `activationRules` machinery just re-gates which fields show, and `serialize`
14
- * (via `pruneArguments`) drops the now-inactive ones. A per-type registry
15
- * would make each variant its own definition, so switching type would mean
16
- * delete-and-recreate losing id/label and every shared value the user entered.
17
- * (It also lets channels add from one "Add Channel" button with type as a field,
18
- * rather than an add-button per type. Node/Memory/Model instead treat `type` as
19
- * an immutable registry key chosen at creation.)
20
- *
21
- * The same could be achieved with a UI-layer "type selector" over a
22
- * ChannelRegistry; this union trades cross-family consistency for that
23
- * shared-state-preserving switch.
24
- */
25
- export interface ChannelDefinition {
26
- parameters: Parameter[];
27
- }
28
-
29
- export const CHANNEL_DEFINITION: ChannelDefinition = {
30
- parameters: [
31
- {
32
- id: "type",
33
- label: "Type",
34
- description: "Channel type",
35
- type: "selection",
36
- default: "GPIOIN",
37
- options: ALL_CHANNEL_TYPES.map((t) => ({ value: t, label: t })),
38
- },
39
- {
40
- id: "bias",
41
- label: "Bias",
42
- description: "Pin bias configuration",
43
- type: "selection",
44
- default: "none",
45
- options: [
46
- { value: "none", label: "None" },
47
- { value: "pullup", label: "Pull-up" },
48
- { value: "pulldown", label: "Pull-down" },
49
- ],
50
- activationRules: [{ type: "parameterIn", parameterId: "type", values: ["GPIOIN"] }],
51
- },
52
- {
53
- id: "debounceMs",
54
- label: "Debounce (ms)",
55
- description: "Debounce window in milliseconds",
56
- type: "int",
57
- default: 50,
58
- activationRules: [{ type: "parameterIn", parameterId: "type", values: ["GPIOIN"] }],
59
- },
60
- {
61
- id: "frequency",
62
- label: "Frequency (Hz)",
63
- description: "PWM frequency in Hz",
64
- type: "int",
65
- default: 1000,
66
- activationRules: [{ type: "parameterIn", parameterId: "type", values: ["PWM"] }],
67
- },
68
- {
69
- id: "topic",
70
- label: "Topic",
71
- description: "MQTT topic this channel publishes to / subscribes on (e.g. sensors/temperature)",
72
- type: "string",
73
- activationRules: [{ type: "parameterIn", parameterId: "type", values: ["MQTT"] }],
74
- },
75
- ],
76
- };
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
4
+ import type { Parameter } from "../parameter";
5
+ import { ALL_CHANNEL_TYPES } from "./Channel";
6
+
7
+ /**
8
+ * Single union definition for all Channel variants — deliberately NOT the
9
+ * per-type registry pattern used by Node/Memory/Model (`*Definition` +
10
+ * `*Registry`, one definition object per type).
11
+ *
12
+ * The reason is in-place `type` switching that preserves shared parameter state.
13
+ * Because `type` is a parameter and all variants share one `arguments` bag,
14
+ * changing a channel's type keeps the same instance (id, label) and retains any
15
+ * entered values that are still valid for the new type: the parameter +
16
+ * `activationRules` machinery just re-gates which fields show, and `serialize`
17
+ * (via `pruneArguments`) drops the now-inactive ones. A per-type registry
18
+ * would make each variant its own definition, so switching type would mean
19
+ * delete-and-recreate losing id/label and every shared value the user entered.
20
+ * (It also lets channels add from one "Add Channel" button with type as a field,
21
+ * rather than an add-button per type. Node/Memory/Model instead treat `type` as
22
+ * an immutable registry key chosen at creation.)
23
+ *
24
+ * The same could be achieved with a UI-layer "type selector" over a
25
+ * ChannelRegistry; this union trades cross-family consistency for that
26
+ * shared-state-preserving switch.
27
+ */
28
+ export interface ChannelDefinition {
29
+ parameters: Parameter[];
30
+ }
31
+
32
+ export const CHANNEL_DEFINITION: ChannelDefinition = {
33
+ parameters: [
34
+ {
35
+ id: "type",
36
+ label: "Type",
37
+ description: "Channel type",
38
+ type: "selection",
39
+ default: "GPIOIN",
40
+ options: ALL_CHANNEL_TYPES.map((t) => ({ value: t, label: t })),
41
+ },
42
+ {
43
+ id: "bias",
44
+ label: "Bias",
45
+ description: "Pin bias configuration",
46
+ type: "selection",
47
+ default: "none",
48
+ options: [
49
+ { value: "none", label: "None" },
50
+ { value: "pullup", label: "Pull-up" },
51
+ { value: "pulldown", label: "Pull-down" },
52
+ ],
53
+ activationRules: [{ type: "parameterIn", parameterId: "type", values: ["GPIOIN"] }],
54
+ },
55
+ {
56
+ id: "debounceMs",
57
+ label: "Debounce (ms)",
58
+ description: "Debounce window in milliseconds",
59
+ type: "int",
60
+ default: 50,
61
+ activationRules: [{ type: "parameterIn", parameterId: "type", values: ["GPIOIN"] }],
62
+ },
63
+ {
64
+ id: "frequency",
65
+ label: "Frequency (Hz)",
66
+ description: "PWM frequency in Hz",
67
+ type: "int",
68
+ default: 1000,
69
+ activationRules: [{ type: "parameterIn", parameterId: "type", values: ["PWM"] }],
70
+ },
71
+ {
72
+ id: "topic",
73
+ label: "Topic",
74
+ description: "MQTT topic this channel publishes to / subscribes on (e.g. sensors/temperature)",
75
+ type: "string",
76
+ activationRules: [{ type: "parameterIn", parameterId: "type", values: ["MQTT"] }],
77
+ },
78
+ {
79
+ id: "level",
80
+ label: "Level",
81
+ description: "Severity the engine records messages written to this channel at",
82
+ type: "selection",
83
+ default: "info",
84
+ options: [
85
+ { value: "debug", label: "Debug" },
86
+ { value: "info", label: "Info" },
87
+ { value: "warn", label: "Warn" },
88
+ { value: "error", label: "Error" },
89
+ ],
90
+ activationRules: [{ type: "parameterIn", parameterId: "type", values: ["LOG"] }],
91
+ },
92
+ {
93
+ id: "tag",
94
+ label: "Tag",
95
+ description: "Optional category stamped on each line so the backend can group workflow-emitted logs",
96
+ type: "string",
97
+ optional: true,
98
+ activationRules: [{ type: "parameterIn", parameterId: "type", values: ["LOG"] }],
99
+ },
100
+ ],
101
+ };
@@ -1,6 +1,9 @@
1
- export type { ChannelType, Channel } from "./Channel";
2
- export { ALL_CHANNEL_TYPES } from "./Channel";
3
- export type { ChannelDefinition } from "./ChannelDefinition";
4
- export { CHANNEL_DEFINITION } from "./ChannelDefinition";
5
- export { serialize, deserialize } from "./serialization";
6
- export type { ApiChannel } from "./serialization";
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
4
+ export type { ChannelType, Channel } from "./Channel";
5
+ export { ALL_CHANNEL_TYPES } from "./Channel";
6
+ export type { ChannelDefinition } from "./ChannelDefinition";
7
+ export { CHANNEL_DEFINITION } from "./ChannelDefinition";
8
+ export { serialize, deserialize } from "./serialization";
9
+ export type { ApiChannel } from "./serialization";
@@ -1,68 +1,77 @@
1
- import type { Schemas } from "../api";
2
- import { pruneArguments } from "../parameter";
3
- import { CHANNEL_DEFINITION } from "./ChannelDefinition";
4
- import type { Channel } from "./Channel";
5
-
6
- export type ApiChannel = Schemas["Channel"];
7
-
8
- /**
9
- * Serialize a domain Channel to the API discriminated-union shape.
10
- *
11
- * The domain store retains inactive parameters (non-destructive type switching),
12
- * so this is the boundary that drops them. The `type` discriminator must be in
13
- * the args record so `parameterIn` rules can evaluate — otherwise every gated
14
- * field (bias/debounceMs/frequency) is stripped as "inactive". Physical
15
- * addressing (GPIO line, ADC/PWM/DAC channel) is not here it's a deploy
16
- * binding, not workflow state.
17
- */
18
- export function serialize(ch: Channel): ApiChannel {
19
- const { id, label, type } = ch;
20
- const args: Record<string, unknown> = { ...ch.arguments, type };
21
- pruneArguments(args, CHANNEL_DEFINITION.parameters);
22
- switch (type) {
23
- case "GPIOIN":
24
- return {
25
- type,
26
- id,
27
- label,
28
- bias: args.bias as Schemas["GPIOINChannel"]["bias"],
29
- debounceMs: args.debounceMs as number,
30
- };
31
- case "GPIOOUT":
32
- return { type, id, label };
33
- case "ADC":
34
- return { type, id, label };
35
- case "PWM":
36
- return { type, id, label, frequency: args.frequency as number };
37
- case "DAC":
38
- return { type, id, label };
39
- case "UART":
40
- return { type, id, label };
41
- case "MQTT":
42
- return { type, id, label, topic: args.topic as string };
43
- }
44
- }
45
-
46
- /** Convert an API Channel into a domain Channel. */
47
- export function deserialize(api: ApiChannel): Channel {
48
- const { id, label, type } = api;
49
- const args: Record<string, unknown> = {};
50
- switch (type) {
51
- case "GPIOIN":
52
- args.bias = api.bias;
53
- args.debounceMs = api.debounceMs;
54
- break;
55
- case "PWM":
56
- args.frequency = api.frequency;
57
- break;
58
- case "MQTT":
59
- args.topic = api.topic;
60
- break;
61
- case "GPIOOUT":
62
- case "ADC":
63
- case "DAC":
64
- case "UART":
65
- break;
66
- }
67
- return { id, label, type, arguments: args };
68
- }
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
4
+ import type { Schemas } from "../api";
5
+ import { pruneArguments } from "../parameter";
6
+ import { CHANNEL_DEFINITION } from "./ChannelDefinition";
7
+ import type { Channel } from "./Channel";
8
+
9
+ export type ApiChannel = Schemas["Channel"];
10
+
11
+ /**
12
+ * Serialize a domain Channel to the API discriminated-union shape.
13
+ *
14
+ * The domain store retains inactive parameters (non-destructive type switching),
15
+ * so this is the boundary that drops them. The `type` discriminator must be in
16
+ * the args record so `parameterIn` rules can evaluate — otherwise every gated
17
+ * field (bias/debounceMs/frequency) is stripped as "inactive". Physical
18
+ * addressing (GPIO line, ADC/PWM/DAC channel) is not here — it's a deploy
19
+ * binding, not workflow state.
20
+ */
21
+ export function serialize(ch: Channel): ApiChannel {
22
+ const { id, label, type } = ch;
23
+ const args: Record<string, unknown> = { ...ch.arguments, type };
24
+ pruneArguments(args, CHANNEL_DEFINITION.parameters);
25
+ switch (type) {
26
+ case "GPIOIN":
27
+ return {
28
+ type,
29
+ id,
30
+ label,
31
+ bias: args.bias as Schemas["GPIOINChannel"]["bias"],
32
+ debounceMs: args.debounceMs as number,
33
+ };
34
+ case "GPIOOUT":
35
+ return { type, id, label };
36
+ case "ADC":
37
+ return { type, id, label };
38
+ case "PWM":
39
+ return { type, id, label, frequency: args.frequency as number };
40
+ case "DAC":
41
+ return { type, id, label };
42
+ case "UART":
43
+ return { type, id, label };
44
+ case "MQTT":
45
+ return { type, id, label, topic: args.topic as string };
46
+ case "LOG":
47
+ return { type, id, label, level: args.level as Schemas["LOGChannel"]["level"], tag: args.tag as string | undefined };
48
+ }
49
+ }
50
+
51
+ /** Convert an API Channel into a domain Channel. */
52
+ export function deserialize(api: ApiChannel): Channel {
53
+ const { id, label, type } = api;
54
+ const args: Record<string, unknown> = {};
55
+ switch (type) {
56
+ case "GPIOIN":
57
+ args.bias = api.bias;
58
+ args.debounceMs = api.debounceMs;
59
+ break;
60
+ case "PWM":
61
+ args.frequency = api.frequency;
62
+ break;
63
+ case "MQTT":
64
+ args.topic = api.topic;
65
+ break;
66
+ case "LOG":
67
+ args.level = api.level;
68
+ args.tag = api.tag;
69
+ break;
70
+ case "GPIOOUT":
71
+ case "ADC":
72
+ case "DAC":
73
+ case "UART":
74
+ break;
75
+ }
76
+ return { id, label, type, arguments: args };
77
+ }
@@ -1 +1,17 @@
1
- export { getReferencedCatalogModelIds } from "./requirements";
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
4
+ export { getReferencedCatalogModelIds, deriveRequirements } from "./requirements";
5
+ export type { DeployRequirements, HardwareChannel, MqttChannel, CustomModel, HardwareFamily } from "./requirements";
6
+ export type { DeploymentInputs, HardwareBinding, MqttBinding, ModelBinding } from "./inputs";
7
+ export {
8
+ buildDeploymentSpec,
9
+ assertDeployable,
10
+ hardwareConflicts,
11
+ familyMismatches,
12
+ hardwareAddressKey,
13
+ hardwareAddressLabel,
14
+ ggufNameError,
15
+ sidecarServiceName,
16
+ } from "./spec";
17
+ export type { DeploymentSpecMeta, DeploymentSpecResult, EngineSecrets } from "./spec";
@@ -0,0 +1,44 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
4
+ // Operator-supplied bindings: the per-deploy values that bind a workflow's
5
+ // logical resource ids to a concrete environment. Shared by every spec
6
+ // producer (the CLI prompts/--values, the FE deploy forms) — how the values are
7
+ // collected differs per renderer, but the shape they resolve to is one thing.
8
+ //
9
+ // Secrets policy: provider API keys and the web-search key are NOT here — they
10
+ // are device/operator-scoped engine env, injected at render time, never frozen
11
+ // into a versioned spec. Only deployment-scoped resource creds (broker, custom
12
+ // endpoint) live in these bindings, because EngineConfig.externalResources needs
13
+ // them resolved inline.
14
+
15
+ // One hardware channel's physical address. `index` = sub-address (addressable
16
+ // families: GPIO line, ADC/DAC/PWM channel); `baud` = serial only.
17
+ export interface HardwareBinding {
18
+ chipOrDevice: string;
19
+ index?: number;
20
+ baud?: number;
21
+ }
22
+
23
+ // One MQTT channel's broker connection.
24
+ export interface MqttBinding {
25
+ brokerUrl: string;
26
+ username?: string;
27
+ password?: string;
28
+ }
29
+
30
+ // One custom model's runtime location. `device` = a llama-server sidecar on this
31
+ // controller (the engine reaches it over the container network by service name);
32
+ // `network` = an inference endpoint the operator runs elsewhere. The endpoint
33
+ // serves the model under its workflow id — no upstream-name aliasing yet.
34
+ export type ModelBinding =
35
+ | { location: "device"; modelFile: string; port?: number; ctxSize?: number }
36
+ | { location: "network"; url: string; apiKey?: string };
37
+
38
+ // The complete set of bindings a deploy supplies, keyed by workflow logical id
39
+ // (channel id / model id). Empty for any resource kind the workflow doesn't use.
40
+ export interface DeploymentInputs {
41
+ hardware: Record<string, HardwareBinding>;
42
+ mqtt: Record<string, MqttBinding>;
43
+ models: Record<string, ModelBinding>;
44
+ }