@foresthubai/workflow-core 0.4.4 → 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.
- package/dist/api/deployment.d.ts +26 -19
- package/dist/api/deployment.d.ts.map +1 -1
- package/dist/api/engine.d.ts +26 -26
- package/dist/api/engine.d.ts.map +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +2 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/workflow.d.ts +10 -10
- package/dist/api/workflow.d.ts.map +1 -1
- package/dist/channel/Channel.d.ts.map +1 -1
- package/dist/channel/Channel.js +2 -0
- package/dist/channel/Channel.js.map +1 -1
- package/dist/channel/ChannelDefinition.d.ts.map +1 -1
- package/dist/channel/ChannelDefinition.js +2 -0
- package/dist/channel/ChannelDefinition.js.map +1 -1
- package/dist/channel/index.d.ts.map +1 -1
- package/dist/channel/index.js +2 -0
- package/dist/channel/index.js.map +1 -1
- package/dist/channel/serialization.d.ts.map +1 -1
- package/dist/channel/serialization.js +2 -0
- package/dist/channel/serialization.js.map +1 -1
- package/dist/deploy/index.d.ts +1 -1
- package/dist/deploy/index.d.ts.map +1 -1
- package/dist/deploy/index.js +2 -0
- package/dist/deploy/index.js.map +1 -1
- package/dist/deploy/inputs.d.ts.map +1 -1
- package/dist/deploy/inputs.js +2 -10
- package/dist/deploy/inputs.js.map +1 -1
- package/dist/deploy/requirements.d.ts.map +1 -1
- package/dist/deploy/requirements.js +2 -0
- package/dist/deploy/requirements.js.map +1 -1
- package/dist/deploy/spec.d.ts +2 -7
- package/dist/deploy/spec.d.ts.map +1 -1
- package/dist/deploy/spec.js +32 -23
- package/dist/deploy/spec.js.map +1 -1
- package/dist/diagnostics/__fixtures__/diagnosticFixtures.d.ts.map +1 -1
- package/dist/diagnostics/__fixtures__/diagnosticFixtures.js +2 -0
- package/dist/diagnostics/__fixtures__/diagnosticFixtures.js.map +1 -1
- package/dist/diagnostics/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics/diagnostics.js +2 -0
- package/dist/diagnostics/diagnostics.js.map +1 -1
- package/dist/diagnostics/index.d.ts.map +1 -1
- package/dist/diagnostics/index.js +2 -0
- package/dist/diagnostics/index.js.map +1 -1
- package/dist/edge/Edge.d.ts.map +1 -1
- package/dist/edge/Edge.js +2 -0
- package/dist/edge/Edge.js.map +1 -1
- package/dist/edge/EdgeDefinition.d.ts.map +1 -1
- package/dist/edge/EdgeDefinition.js +2 -0
- package/dist/edge/EdgeDefinition.js.map +1 -1
- package/dist/edge/EdgeType.d.ts.map +1 -1
- package/dist/edge/EdgeType.js +2 -0
- package/dist/edge/EdgeType.js.map +1 -1
- package/dist/edge/index.d.ts.map +1 -1
- package/dist/edge/index.js +2 -2
- package/dist/edge/index.js.map +1 -1
- package/dist/edge/serialization.d.ts.map +1 -1
- package/dist/edge/serialization.js +2 -0
- package/dist/edge/serialization.js.map +1 -1
- package/dist/expression/index.d.ts.map +1 -1
- package/dist/expression/index.js +2 -0
- package/dist/expression/index.js.map +1 -1
- package/dist/expression/parser.d.ts.map +1 -1
- package/dist/expression/parser.js +2 -0
- package/dist/expression/parser.js.map +1 -1
- package/dist/expression/types.d.ts.map +1 -1
- package/dist/expression/types.js +2 -0
- package/dist/expression/types.js.map +1 -1
- package/dist/function/FunctionDeclaration.d.ts.map +1 -1
- package/dist/function/FunctionDeclaration.js +2 -0
- package/dist/function/FunctionDeclaration.js.map +1 -1
- package/dist/function/index.d.ts.map +1 -1
- package/dist/function/index.js +2 -0
- package/dist/function/index.js.map +1 -1
- package/dist/function/serialization.d.ts.map +1 -1
- package/dist/function/serialization.js +2 -0
- package/dist/function/serialization.js.map +1 -1
- package/dist/id/index.d.ts.map +1 -1
- package/dist/id/index.js +2 -0
- package/dist/id/index.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/Memory.d.ts.map +1 -1
- package/dist/memory/Memory.js +2 -0
- package/dist/memory/Memory.js.map +1 -1
- package/dist/memory/MemoryDefinition.d.ts.map +1 -1
- package/dist/memory/MemoryDefinition.js +2 -0
- package/dist/memory/MemoryDefinition.js.map +1 -1
- package/dist/memory/MemoryFileDefinition.d.ts.map +1 -1
- package/dist/memory/MemoryFileDefinition.js +2 -0
- package/dist/memory/MemoryFileDefinition.js.map +1 -1
- package/dist/memory/MemoryRegistry.d.ts.map +1 -1
- package/dist/memory/MemoryRegistry.js +2 -0
- package/dist/memory/MemoryRegistry.js.map +1 -1
- package/dist/memory/VectorDatabaseDefinition.d.ts.map +1 -1
- package/dist/memory/VectorDatabaseDefinition.js +2 -0
- package/dist/memory/VectorDatabaseDefinition.js.map +1 -1
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +2 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/serialization.d.ts.map +1 -1
- package/dist/memory/serialization.js +2 -0
- package/dist/memory/serialization.js.map +1 -1
- package/dist/migration/index.d.ts.map +1 -1
- package/dist/migration/index.js +2 -0
- package/dist/migration/index.js.map +1 -1
- package/dist/migration/migrate.d.ts.map +1 -1
- package/dist/migration/migrate.js +2 -0
- package/dist/migration/migrate.js.map +1 -1
- package/dist/migration/migrations.d.ts.map +1 -1
- package/dist/migration/migrations.js +2 -0
- package/dist/migration/migrations.js.map +1 -1
- package/dist/migration/version.d.ts.map +1 -1
- package/dist/migration/version.js +2 -0
- package/dist/migration/version.js.map +1 -1
- package/dist/model/LLMModelDefinition.d.ts.map +1 -1
- package/dist/model/LLMModelDefinition.js +2 -0
- package/dist/model/LLMModelDefinition.js.map +1 -1
- package/dist/model/Model.d.ts.map +1 -1
- package/dist/model/Model.js +2 -13
- package/dist/model/Model.js.map +1 -1
- package/dist/model/ModelDefinition.d.ts.map +1 -1
- package/dist/model/ModelDefinition.js +2 -0
- package/dist/model/ModelDefinition.js.map +1 -1
- package/dist/model/ModelRegistry.d.ts.map +1 -1
- package/dist/model/ModelRegistry.js +2 -0
- package/dist/model/ModelRegistry.js.map +1 -1
- package/dist/model/index.d.ts.map +1 -1
- package/dist/model/index.js +2 -0
- package/dist/model/index.js.map +1 -1
- package/dist/model/serialization.d.ts.map +1 -1
- package/dist/model/serialization.js +2 -0
- package/dist/model/serialization.js.map +1 -1
- package/dist/node/AgentNode.d.ts.map +1 -1
- package/dist/node/AgentNode.js +2 -0
- package/dist/node/AgentNode.js.map +1 -1
- package/dist/node/DataNode.d.ts.map +1 -1
- package/dist/node/DataNode.js +2 -0
- package/dist/node/DataNode.js.map +1 -1
- package/dist/node/FunctionNode.d.ts.map +1 -1
- package/dist/node/FunctionNode.js +2 -0
- package/dist/node/FunctionNode.js.map +1 -1
- package/dist/node/InputNode.d.ts.map +1 -1
- package/dist/node/InputNode.js +2 -0
- package/dist/node/InputNode.js.map +1 -1
- package/dist/node/LogicNode.d.ts.map +1 -1
- package/dist/node/LogicNode.js +2 -0
- package/dist/node/LogicNode.js.map +1 -1
- package/dist/node/MqttNode.d.ts.map +1 -1
- package/dist/node/MqttNode.js +2 -0
- package/dist/node/MqttNode.js.map +1 -1
- package/dist/node/Node.d.ts.map +1 -1
- package/dist/node/Node.js +2 -7
- package/dist/node/Node.js.map +1 -1
- package/dist/node/NodeDefinition.d.ts.map +1 -1
- package/dist/node/NodeDefinition.js +2 -0
- package/dist/node/NodeDefinition.js.map +1 -1
- package/dist/node/NodeRegistry.d.ts.map +1 -1
- package/dist/node/NodeRegistry.js +2 -0
- package/dist/node/NodeRegistry.js.map +1 -1
- package/dist/node/OutputNode.d.ts.map +1 -1
- package/dist/node/OutputNode.js +2 -0
- package/dist/node/OutputNode.js.map +1 -1
- package/dist/node/ToolNode.d.ts.map +1 -1
- package/dist/node/ToolNode.js +2 -0
- package/dist/node/ToolNode.js.map +1 -1
- package/dist/node/TriggerNode.d.ts.map +1 -1
- package/dist/node/TriggerNode.js +2 -0
- package/dist/node/TriggerNode.js.map +1 -1
- package/dist/node/constants.d.ts.map +1 -1
- package/dist/node/constants.js +2 -0
- package/dist/node/constants.js.map +1 -1
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +2 -0
- package/dist/node/index.js.map +1 -1
- package/dist/node/methods.d.ts.map +1 -1
- package/dist/node/methods.js +2 -0
- package/dist/node/methods.js.map +1 -1
- package/dist/node/serialization.d.ts.map +1 -1
- package/dist/node/serialization.js +33 -13
- package/dist/node/serialization.js.map +1 -1
- package/dist/parameter/OutputParameter.d.ts.map +1 -1
- package/dist/parameter/OutputParameter.js +2 -0
- package/dist/parameter/OutputParameter.js.map +1 -1
- package/dist/parameter/Parameter.d.ts.map +1 -1
- package/dist/parameter/Parameter.js +2 -0
- package/dist/parameter/Parameter.js.map +1 -1
- package/dist/parameter/index.d.ts.map +1 -1
- package/dist/parameter/index.js +2 -0
- package/dist/parameter/index.js.map +1 -1
- package/dist/variable/Variable.d.ts.map +1 -1
- package/dist/variable/Variable.js +2 -0
- package/dist/variable/Variable.js.map +1 -1
- package/dist/variable/index.d.ts.map +1 -1
- package/dist/variable/index.js +2 -3
- package/dist/variable/index.js.map +1 -1
- package/dist/variable/operations.d.ts.map +1 -1
- package/dist/variable/operations.js +2 -0
- package/dist/variable/operations.js.map +1 -1
- package/dist/workflow/Workflow.d.ts.map +1 -1
- package/dist/workflow/Workflow.js +2 -0
- package/dist/workflow/Workflow.js.map +1 -1
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +2 -0
- package/dist/workflow/index.js.map +1 -1
- package/dist/workflow/serialization.d.ts.map +1 -1
- package/dist/workflow/serialization.js +2 -4
- package/dist/workflow/serialization.js.map +1 -1
- package/package.json +1 -1
- package/src/api/deployment.ts +26 -19
- package/src/api/engine.ts +26 -26
- package/src/api/index.ts +3 -0
- package/src/api/workflow.ts +10 -10
- package/src/channel/Channel.ts +3 -0
- package/src/channel/ChannelDefinition.ts +3 -0
- package/src/channel/index.ts +3 -0
- package/src/channel/serialization.ts +3 -0
- package/src/deploy/index.ts +4 -1
- package/src/deploy/inputs.ts +3 -0
- package/src/deploy/requirements.test.ts +3 -0
- package/src/deploy/requirements.ts +3 -0
- package/src/deploy/spec.test.ts +7 -6
- package/src/deploy/spec.ts +46 -28
- package/src/diagnostics/__fixtures__/diagnosticFixtures.ts +3 -0
- package/src/diagnostics/diagnostics.test.ts +3 -0
- package/src/diagnostics/diagnostics.ts +3 -0
- package/src/diagnostics/index.ts +3 -0
- package/src/edge/Edge.ts +3 -0
- package/src/edge/EdgeDefinition.ts +3 -0
- package/src/edge/EdgeType.ts +3 -0
- package/src/edge/index.ts +3 -0
- package/src/edge/serialization.ts +3 -0
- package/src/expression/index.ts +3 -0
- package/src/expression/parser.ts +3 -0
- package/src/expression/types.ts +3 -0
- package/src/function/FunctionDeclaration.ts +3 -0
- package/src/function/index.ts +3 -0
- package/src/function/serialization.ts +3 -0
- package/src/globals.d.ts +3 -0
- package/src/id/index.ts +3 -0
- package/src/index.ts +3 -0
- package/src/memory/Memory.ts +3 -0
- package/src/memory/MemoryDefinition.ts +3 -0
- package/src/memory/MemoryFileDefinition.ts +3 -0
- package/src/memory/MemoryRegistry.ts +3 -0
- package/src/memory/VectorDatabaseDefinition.ts +3 -0
- package/src/memory/index.ts +3 -0
- package/src/memory/serialization.ts +3 -0
- package/src/migration/index.ts +3 -0
- package/src/migration/migrate.test.ts +3 -0
- package/src/migration/migrate.ts +3 -0
- package/src/migration/migrations.ts +3 -0
- package/src/migration/version.ts +3 -0
- package/src/model/LLMModelDefinition.ts +3 -0
- package/src/model/Model.ts +3 -0
- package/src/model/ModelDefinition.ts +3 -0
- package/src/model/ModelRegistry.ts +3 -0
- package/src/model/index.ts +3 -0
- package/src/model/serialization.ts +3 -0
- package/src/node/AgentNode.ts +3 -0
- package/src/node/DataNode.ts +3 -0
- package/src/node/FunctionNode.ts +3 -0
- package/src/node/InputNode.ts +3 -0
- package/src/node/LogicNode.ts +3 -0
- package/src/node/MqttNode.ts +3 -0
- package/src/node/Node.ts +3 -0
- package/src/node/NodeDefinition.ts +3 -0
- package/src/node/NodeRegistry.ts +3 -0
- package/src/node/OutputNode.ts +3 -0
- package/src/node/ToolNode.ts +3 -0
- package/src/node/TriggerNode.ts +3 -0
- package/src/node/constants.ts +3 -0
- package/src/node/index.ts +3 -0
- package/src/node/methods.ts +3 -0
- package/src/node/serialization.test.ts +51 -0
- package/src/node/serialization.ts +34 -13
- package/src/parameter/OutputParameter.ts +3 -0
- package/src/parameter/Parameter.ts +3 -0
- package/src/parameter/index.ts +3 -0
- package/src/variable/Variable.ts +3 -0
- package/src/variable/index.ts +3 -0
- package/src/variable/operations.ts +3 -0
- package/src/workflow/Workflow.ts +3 -0
- package/src/workflow/index.ts +3 -0
- package/src/workflow/serialization.test.ts +3 -0
- package/src/workflow/serialization.ts +3 -0
package/src/api/engine.ts
CHANGED
|
@@ -7,31 +7,35 @@ export type paths = Record<string, never>;
|
|
|
7
7
|
export type webhooks = Record<string, never>;
|
|
8
8
|
export interface components {
|
|
9
9
|
schemas: {
|
|
10
|
-
/** @description The engine's complete boot input, loaded once at startup
|
|
10
|
+
/** @description The engine's complete boot input, loaded once at startup. */
|
|
11
11
|
EngineConfig: {
|
|
12
12
|
workflow: components["schemas"]["Workflow"];
|
|
13
|
-
mapping?: components["schemas"]["
|
|
13
|
+
mapping?: components["schemas"]["ResourceMapping"];
|
|
14
14
|
externalResources?: components["schemas"]["ExternalResources"];
|
|
15
15
|
manifest?: components["schemas"]["DeviceManifest"];
|
|
16
16
|
};
|
|
17
|
-
/** @description
|
|
18
|
-
|
|
17
|
+
/** @description The engine's secret store: a flat map of secret id -> opaque secret value. */
|
|
18
|
+
EngineSecrets: {
|
|
19
|
+
[key: string]: string;
|
|
20
|
+
};
|
|
21
|
+
/** @description Binds a binding-free workflow's logical resource ids to concrete platform resources, keyed by workflow resource id. */
|
|
22
|
+
ResourceMapping: {
|
|
19
23
|
[key: string]: components["schemas"]["ResourceBinding"];
|
|
20
24
|
};
|
|
21
|
-
/** @description How one workflow resource binds to the environment
|
|
25
|
+
/** @description How one workflow resource binds to the environment: a shared platform resource `ref` with an optional per-channel physical sub-address `index`. */
|
|
22
26
|
ResourceBinding: {
|
|
23
27
|
/** @description Shared platform resource id this binds to. */
|
|
24
28
|
ref: string;
|
|
25
29
|
/** @description Per-channel physical sub-address within the driver (GPIO line / ADC-PWM-DAC channel). Omitted when the resource has no sub-address. */
|
|
26
30
|
index?: number;
|
|
27
31
|
};
|
|
28
|
-
/** @description Deploy-time configs for a workflow's non-device external resources (MQTT transports, custom-model providers, ...), keyed by
|
|
32
|
+
/** @description Deploy-time configs for a workflow's non-device external resources (MQTT transports, custom-model providers, ...), keyed by platform resource id. */
|
|
29
33
|
ExternalResources: {
|
|
30
34
|
[key: string]: components["schemas"]["ExternalResourceConfig"];
|
|
31
35
|
};
|
|
32
36
|
/** @description Tagged union of deploy-time external-resource configs, discriminated by runtime kind (not by ownership — locality like on-device vs cloud lives inside an arm). New kinds extend this oneOf. */
|
|
33
37
|
ExternalResourceConfig: components["schemas"]["MQTTConnection"] | components["schemas"]["LLMProviderConfig"];
|
|
34
|
-
/** @description Resolved connection to a self-hosted/custom LLM endpoint the llmproxy doesn't ship.
|
|
38
|
+
/** @description Resolved connection to a self-hosted/custom LLM endpoint the llmproxy doesn't ship. */
|
|
35
39
|
LLMProviderConfig: {
|
|
36
40
|
/**
|
|
37
41
|
* @description discriminator enum property added by openapi-typescript
|
|
@@ -43,7 +47,7 @@ export interface components {
|
|
|
43
47
|
/** @description Upstream model name the endpoint serves; defaults to the workflow model id when empty. */
|
|
44
48
|
model?: string;
|
|
45
49
|
};
|
|
46
|
-
/** @description Resolved connection metadata for an MQTT broker.
|
|
50
|
+
/** @description Resolved connection metadata for an MQTT broker. */
|
|
47
51
|
MQTTConnection: {
|
|
48
52
|
/**
|
|
49
53
|
* @description discriminator enum property added by openapi-typescript
|
|
@@ -53,20 +57,20 @@ export interface components {
|
|
|
53
57
|
brokerUrl: string;
|
|
54
58
|
clientId?: string;
|
|
55
59
|
username?: string;
|
|
56
|
-
/** @description Topic prefix
|
|
60
|
+
/** @description Topic prefix for workflow-level publish topics ({networkId}/{agentId}/). */
|
|
57
61
|
publishPrefix?: string;
|
|
58
|
-
/** @description Topic prefix
|
|
62
|
+
/** @description Topic prefix for workflow-level subscribe filters ({networkId}/+/). */
|
|
59
63
|
subscribePrefix?: string;
|
|
60
64
|
will?: components["schemas"]["MQTTWill"];
|
|
61
65
|
};
|
|
62
66
|
MQTTWill: {
|
|
63
67
|
topic: string;
|
|
64
68
|
payload: string;
|
|
65
|
-
/** @description MQTT QoS (0,1,2).
|
|
69
|
+
/** @description MQTT QoS (0, 1, or 2). */
|
|
66
70
|
qos: number;
|
|
67
71
|
retain: boolean;
|
|
68
72
|
};
|
|
69
|
-
/** @description Hardware resources available on the device, keyed by driver instance ID.
|
|
73
|
+
/** @description Hardware resources available on the device, keyed by driver instance ID. */
|
|
70
74
|
DeviceManifest: {
|
|
71
75
|
gpios?: {
|
|
72
76
|
[key: string]: components["schemas"]["GPIOConfig"];
|
|
@@ -106,10 +110,6 @@ export interface components {
|
|
|
106
110
|
/** @description sysfs path to the pwmchip directory, e.g. "/sys/class/pwm/pwmchip0" */
|
|
107
111
|
chip: string;
|
|
108
112
|
};
|
|
109
|
-
/** @description Body of PUT /agents/memory/{name}. */
|
|
110
|
-
MemoryFileWrite: {
|
|
111
|
-
content: string;
|
|
112
|
-
};
|
|
113
113
|
RagQueryRequest: {
|
|
114
114
|
/** @description Collection to query */
|
|
115
115
|
collectionId: string;
|
|
@@ -162,7 +162,7 @@ export interface components {
|
|
|
162
162
|
pinReference?: string;
|
|
163
163
|
signalType: components["schemas"]["SignalType"];
|
|
164
164
|
output: components["schemas"]["OutputBinding"];
|
|
165
|
-
/** @description Description
|
|
165
|
+
/** @description Description used when this node is exposed as a tool; ignored in exec mode. */
|
|
166
166
|
toolDescription?: string;
|
|
167
167
|
};
|
|
168
168
|
};
|
|
@@ -232,7 +232,7 @@ export interface components {
|
|
|
232
232
|
outputDeclarations: components["schemas"]["OutputDeclaration"][];
|
|
233
233
|
/** @description Memory files this agent can access, each with an access mode. */
|
|
234
234
|
memoryRefs: components["schemas"]["MemoryRef"][];
|
|
235
|
-
/** @description Description
|
|
235
|
+
/** @description Description used when this node is exposed as a tool; ignored in exec mode. */
|
|
236
236
|
toolDescription?: string;
|
|
237
237
|
};
|
|
238
238
|
};
|
|
@@ -297,7 +297,7 @@ export interface components {
|
|
|
297
297
|
/** @description Search query expression */
|
|
298
298
|
query: components["schemas"]["Expression"];
|
|
299
299
|
output: components["schemas"]["OutputBinding"];
|
|
300
|
-
/** @description Description
|
|
300
|
+
/** @description Description used when this node is exposed as a tool; ignored in exec mode. */
|
|
301
301
|
toolDescription?: string;
|
|
302
302
|
};
|
|
303
303
|
};
|
|
@@ -336,7 +336,7 @@ export interface components {
|
|
|
336
336
|
outputBindings?: {
|
|
337
337
|
[key: string]: components["schemas"]["OutputBinding"];
|
|
338
338
|
};
|
|
339
|
-
/** @description Description
|
|
339
|
+
/** @description Description used when this function is exposed as a tool; ignored in exec mode. */
|
|
340
340
|
toolDescription?: string;
|
|
341
341
|
};
|
|
342
342
|
};
|
|
@@ -650,7 +650,7 @@ export interface components {
|
|
|
650
650
|
type: "MQTT";
|
|
651
651
|
id: string;
|
|
652
652
|
label: string;
|
|
653
|
-
/** @description Topic this channel publishes to / subscribes on.
|
|
653
|
+
/** @description Topic this channel publishes to / subscribes on. */
|
|
654
654
|
topic: string;
|
|
655
655
|
};
|
|
656
656
|
LOGChannel: {
|
|
@@ -662,11 +662,11 @@ export interface components {
|
|
|
662
662
|
id: string;
|
|
663
663
|
label: string;
|
|
664
664
|
/**
|
|
665
|
-
* @description Severity
|
|
665
|
+
* @description Severity for messages written to this channel.
|
|
666
666
|
* @enum {string}
|
|
667
667
|
*/
|
|
668
668
|
level: "debug" | "info" | "warn" | "error";
|
|
669
|
-
/** @description Optional category stamped on each line
|
|
669
|
+
/** @description Optional category label stamped on each line written to this channel. */
|
|
670
670
|
tag?: string;
|
|
671
671
|
};
|
|
672
672
|
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"];
|
|
@@ -679,7 +679,7 @@ export interface components {
|
|
|
679
679
|
type: "MemoryFile";
|
|
680
680
|
/** @description Stable identifier that survives renames; referenced from MemoryRef. */
|
|
681
681
|
id: string;
|
|
682
|
-
/** @description Display name. Unique per agent
|
|
682
|
+
/** @description Display name. Unique per agent. */
|
|
683
683
|
label: string;
|
|
684
684
|
description: string;
|
|
685
685
|
content: string;
|
|
@@ -713,11 +713,11 @@ export interface components {
|
|
|
713
713
|
id: string;
|
|
714
714
|
/** @description Display name. */
|
|
715
715
|
label: string;
|
|
716
|
-
/** @description Capabilities this model supports
|
|
716
|
+
/** @description Capabilities this model supports. */
|
|
717
717
|
capabilities: components["schemas"]["ModelCapability"][];
|
|
718
718
|
};
|
|
719
719
|
Model: components["schemas"]["LLMModel"];
|
|
720
|
-
/** @description
|
|
720
|
+
/** @description The deployment format of a workflow project. */
|
|
721
721
|
Workflow: {
|
|
722
722
|
/**
|
|
723
723
|
* Format: int32
|
package/src/api/index.ts
CHANGED
package/src/api/workflow.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface components {
|
|
|
17
17
|
x: number;
|
|
18
18
|
y: number;
|
|
19
19
|
};
|
|
20
|
-
/** @description
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
421
|
+
/** @description Description used when this node is exposed as a tool; ignored in exec mode. */
|
|
422
422
|
toolDescription?: string;
|
|
423
423
|
};
|
|
424
424
|
};
|
|
@@ -591,7 +591,7 @@ export interface components {
|
|
|
591
591
|
type: "MQTT";
|
|
592
592
|
id: string;
|
|
593
593
|
label: string;
|
|
594
|
-
/** @description Topic this channel publishes to / subscribes on.
|
|
594
|
+
/** @description Topic this channel publishes to / subscribes on. */
|
|
595
595
|
topic: string;
|
|
596
596
|
};
|
|
597
597
|
LOGChannel: {
|
|
@@ -603,11 +603,11 @@ export interface components {
|
|
|
603
603
|
id: string;
|
|
604
604
|
label: string;
|
|
605
605
|
/**
|
|
606
|
-
* @description Severity
|
|
606
|
+
* @description Severity for messages written to this channel.
|
|
607
607
|
* @enum {string}
|
|
608
608
|
*/
|
|
609
609
|
level: "debug" | "info" | "warn" | "error";
|
|
610
|
-
/** @description Optional category stamped on each line
|
|
610
|
+
/** @description Optional category label stamped on each line written to this channel. */
|
|
611
611
|
tag?: string;
|
|
612
612
|
};
|
|
613
613
|
/** @enum {string} */
|
package/src/channel/Channel.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 ForestHub.
|
|
3
|
+
|
|
1
4
|
export type ChannelType = "GPIOIN" | "GPIOOUT" | "ADC" | "PWM" | "DAC" | "UART" | "MQTT" | "LOG";
|
|
2
5
|
|
|
3
6
|
export const ALL_CHANNEL_TYPES: ChannelType[] = ["GPIOIN", "GPIOOUT", "ADC", "PWM", "DAC", "UART", "MQTT", "LOG"];
|
package/src/channel/index.ts
CHANGED
package/src/deploy/index.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 ForestHub.
|
|
3
|
+
|
|
1
4
|
export { getReferencedCatalogModelIds, deriveRequirements } from "./requirements";
|
|
2
5
|
export type { DeployRequirements, HardwareChannel, MqttChannel, CustomModel, HardwareFamily } from "./requirements";
|
|
3
6
|
export type { DeploymentInputs, HardwareBinding, MqttBinding, ModelBinding } from "./inputs";
|
|
@@ -11,4 +14,4 @@ export {
|
|
|
11
14
|
ggufNameError,
|
|
12
15
|
sidecarServiceName,
|
|
13
16
|
} from "./spec";
|
|
14
|
-
export type { DeploymentSpecMeta, DeploymentSpecResult,
|
|
17
|
+
export type { DeploymentSpecMeta, DeploymentSpecResult, EngineSecrets } from "./spec";
|
package/src/deploy/inputs.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 ForestHub.
|
|
3
|
+
|
|
1
4
|
// Operator-supplied bindings: the per-deploy values that bind a workflow's
|
|
2
5
|
// logical resource ids to a concrete environment. Shared by every spec
|
|
3
6
|
// producer (the CLI prompts/--values, the FE deploy forms) — how the values are
|
package/src/deploy/spec.test.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 ForestHub.
|
|
3
|
+
|
|
1
4
|
import { describe, it, expect } from "vitest";
|
|
2
5
|
import { buildDeploymentSpec, assertDeployable, sidecarServiceName } from "./spec";
|
|
3
6
|
import { deriveRequirements } from "./requirements";
|
|
@@ -57,7 +60,6 @@ const fullInputs: DeploymentInputs = {
|
|
|
57
60
|
|
|
58
61
|
const meta = {
|
|
59
62
|
id: "dep-1",
|
|
60
|
-
status: "active" as const,
|
|
61
63
|
engineImage: "fh-engine:0.4.2",
|
|
62
64
|
llamaServerImage: "ghcr.io/ggml-org/llama.cpp:server-b8589",
|
|
63
65
|
};
|
|
@@ -68,7 +70,6 @@ describe("buildDeploymentSpec", () => {
|
|
|
68
70
|
|
|
69
71
|
expect(spec.schemaVersion).toBe(1);
|
|
70
72
|
expect(spec.id).toBe("dep-1");
|
|
71
|
-
expect(spec.status).toBe("active");
|
|
72
73
|
|
|
73
74
|
const engine = engineOf(spec);
|
|
74
75
|
expect(engine.image).toBe("fh-engine:0.4.2");
|
|
@@ -102,8 +103,8 @@ describe("buildDeploymentSpec", () => {
|
|
|
102
103
|
expect(llamaOf(spec, "local-llm")).toMatchObject({
|
|
103
104
|
name: sidecarServiceName("local-llm"),
|
|
104
105
|
image: "ghcr.io/ggml-org/llama.cpp:server-b8589",
|
|
105
|
-
command: ["--model", "/
|
|
106
|
-
volumes: ["./
|
|
106
|
+
command: ["--model", "/var/lib/foresthub/workspace/model.gguf", "--host", "0.0.0.0", "--port", "8080", "--ctx-size", "4096"],
|
|
107
|
+
volumes: ["./workspaces/llama-local-llm:/var/lib/foresthub/workspace:ro"],
|
|
107
108
|
});
|
|
108
109
|
// The external-resource provider URL must point at the sidecar service name.
|
|
109
110
|
const ext = engineConfigOf(spec).externalResources!;
|
|
@@ -145,7 +146,7 @@ describe("buildDeploymentSpec", () => {
|
|
|
145
146
|
const ext = engineConfigOf(spec).externalResources!;
|
|
146
147
|
const [ref, provider] = Object.entries(ext).find(([, r]) => r.type === "selfhosted")!;
|
|
147
148
|
expect(provider).toEqual({ type: "selfhosted", url: "https://infer.example/v1" });
|
|
148
|
-
expect(resourceSecrets[ref]).toEqual(
|
|
149
|
+
expect(resourceSecrets[ref]).toEqual("k");
|
|
149
150
|
});
|
|
150
151
|
|
|
151
152
|
it("pulls MQTT/endpoint secrets out of the spec, keyed by resource ref", () => {
|
|
@@ -155,7 +156,7 @@ describe("buildDeploymentSpec", () => {
|
|
|
155
156
|
const [mqttRef, mqttConn] = Object.entries(ext).find(([, r]) => r.type === "mqtt")!;
|
|
156
157
|
expect(mqttConn).not.toHaveProperty("password");
|
|
157
158
|
expect(mqttConn).toMatchObject({ username: "u" });
|
|
158
|
-
expect(resourceSecrets[mqttRef]).toEqual(
|
|
159
|
+
expect(resourceSecrets[mqttRef]).toEqual("p");
|
|
159
160
|
// Whole spec serialized carries no secret value.
|
|
160
161
|
expect(JSON.stringify(spec)).not.toContain('"p"');
|
|
161
162
|
});
|
package/src/deploy/spec.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 ForestHub.
|
|
3
|
+
|
|
1
4
|
// The spec resolver: (workflow + bindings) -> DeploymentSpec. The shared
|
|
2
5
|
// "packaging library" the migration doc calls for — component-set derivation
|
|
3
6
|
// and device-grant resolution computed once here, frozen into the contract spec,
|
|
@@ -19,9 +22,22 @@ type DeployComponent = DeploymentSchemas["DeployComponent"];
|
|
|
19
22
|
// the spec carries it as an opaque blob in DeployComponent.config.
|
|
20
23
|
type EngineConfig = EngineSchemas["EngineConfig"];
|
|
21
24
|
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
+
// In-container mount path for a component's durable workspace. MUST equal the Go
|
|
26
|
+
// component.Workspace contract constant (go/component/paths.go) — the component
|
|
27
|
+
// reads/writes there, so we mount the host workspace dir there and wire no env var.
|
|
28
|
+
// A cross-repo contract: changing it requires changing the Go constant in lockstep.
|
|
29
|
+
const COMPONENT_WORKSPACE_PATH = "/var/lib/foresthub/workspace";
|
|
30
|
+
|
|
31
|
+
// The OSS renderer's state root (docs/device-filesystem.md §2). Bind-mount sources
|
|
32
|
+
// hang off it as `<root>/workspaces/<container>/`. "." makes Docker resolve them
|
|
33
|
+
// relative to the compose file, so the bundle stays drop-anywhere; Ranger is a
|
|
34
|
+
// separate renderer that sets root to the absolute `/var/lib/foresthub`.
|
|
35
|
+
const STATE_ROOT = ".";
|
|
36
|
+
|
|
37
|
+
// Host bind-mount source for a container's workspace under the state root.
|
|
38
|
+
function workspaceDir(container: string): string {
|
|
39
|
+
return `${STATE_ROOT}/workspaces/${container}`;
|
|
40
|
+
}
|
|
25
41
|
|
|
26
42
|
// Deploy-time metadata the resolver cannot derive from the workflow: identity,
|
|
27
43
|
// lifecycle, and the full image reference each component runs (frozen here so the
|
|
@@ -29,26 +45,24 @@ const ENGINE_MEMORY_PATH = "/var/lib/foresthub/memory";
|
|
|
29
45
|
// used only when the workflow has an on-device model.
|
|
30
46
|
export interface DeploymentSpecMeta {
|
|
31
47
|
id: string;
|
|
32
|
-
status: DeploymentSpec["status"];
|
|
33
48
|
createdAt?: string;
|
|
34
49
|
engineImage: string;
|
|
35
50
|
llamaServerImage: string;
|
|
36
51
|
}
|
|
37
52
|
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
export type ResourceSecrets = Record<string, ResourceSecret>;
|
|
53
|
+
// The engine's secret store: a flat map of secret id -> opaque secret value,
|
|
54
|
+
// keyed by the same resource ref the spec's externalResources use. Each value is
|
|
55
|
+
// the single credential that resource needs (MQTT password, self-hosted-LLM
|
|
56
|
+
// bearer token). Secrets are NEVER part of the spec (not rotation-safe, breach-
|
|
57
|
+
// exposed if stored): the resolver returns them separately, for the renderer to
|
|
58
|
+
// deliver out-of-band as a mounted secret document (secrets.json). Mirrors the
|
|
59
|
+
// wire EngineSecrets.
|
|
60
|
+
export type EngineSecrets = Record<string, string>;
|
|
47
61
|
|
|
48
62
|
// buildDeploymentSpec's output: the secret-free spec plus the pulled-out secrets.
|
|
49
63
|
export interface DeploymentSpecResult {
|
|
50
64
|
spec: DeploymentSpec;
|
|
51
|
-
resourceSecrets:
|
|
65
|
+
resourceSecrets: EngineSecrets;
|
|
52
66
|
}
|
|
53
67
|
|
|
54
68
|
// Hands out stable, collision-free ref names. Same dedup key -> same ref (the
|
|
@@ -104,7 +118,7 @@ export function ggufNameError(name: string | undefined): string | null {
|
|
|
104
118
|
const t = (name ?? "").trim();
|
|
105
119
|
if (!t) return "a model filename is required";
|
|
106
120
|
if (!t.toLowerCase().endsWith(".gguf")) return "must be a .gguf file (llama-server only loads GGUF)";
|
|
107
|
-
if (t.includes("/")) return "just the filename, not a path — the file goes in ./
|
|
121
|
+
if (t.includes("/")) return "just the filename, not a path — the file goes in the model's workspace dir (./workspaces/llama-…/)";
|
|
108
122
|
return null;
|
|
109
123
|
}
|
|
110
124
|
|
|
@@ -223,7 +237,7 @@ export function buildDeploymentSpec(
|
|
|
223
237
|
assertDeployable(req, inputs);
|
|
224
238
|
|
|
225
239
|
const refs = new RefAllocator();
|
|
226
|
-
const resourceSecrets:
|
|
240
|
+
const resourceSecrets: EngineSecrets = {};
|
|
227
241
|
|
|
228
242
|
// DeviceManifest is split per family; accumulate each separately, attach only
|
|
229
243
|
// the non-empty ones (all slots optional).
|
|
@@ -234,7 +248,7 @@ export function buildDeploymentSpec(
|
|
|
234
248
|
const serials: Record<string, EngineSchemas["SerialConfig"]> = {};
|
|
235
249
|
|
|
236
250
|
const externalResources: EngineSchemas["ExternalResources"] = {};
|
|
237
|
-
const mapping: EngineSchemas["
|
|
251
|
+
const mapping: EngineSchemas["ResourceMapping"] = {};
|
|
238
252
|
|
|
239
253
|
// Container-level hardware access, resolved once: cdev nodes (GPIO, UART) map
|
|
240
254
|
// one-to-one into the engine component's devices; sysfs families (ADC/DAC/PWM)
|
|
@@ -292,7 +306,7 @@ export function buildDeploymentSpec(
|
|
|
292
306
|
const ref = refs.alloc(`mqtt:${JSON.stringify(conn)}:${b.password ?? ""}`, `mqtt-${brokerHost(b.brokerUrl)}`);
|
|
293
307
|
externalResources[ref] = conn;
|
|
294
308
|
mapping[ch.id] = { ref };
|
|
295
|
-
if (b.password) resourceSecrets[ref] =
|
|
309
|
+
if (b.password) resourceSecrets[ref] = b.password;
|
|
296
310
|
}
|
|
297
311
|
|
|
298
312
|
// Custom models: one self-hosted provider per model id. A device model points
|
|
@@ -318,7 +332,7 @@ export function buildDeploymentSpec(
|
|
|
318
332
|
image: meta.llamaServerImage,
|
|
319
333
|
command: [
|
|
320
334
|
"--model",
|
|
321
|
-
|
|
335
|
+
`${COMPONENT_WORKSPACE_PATH}/${b.modelFile}`,
|
|
322
336
|
"--host",
|
|
323
337
|
"0.0.0.0",
|
|
324
338
|
"--port",
|
|
@@ -326,12 +340,14 @@ export function buildDeploymentSpec(
|
|
|
326
340
|
"--ctx-size",
|
|
327
341
|
String(b.ctxSize ?? 4096),
|
|
328
342
|
],
|
|
329
|
-
|
|
343
|
+
// The model lives in this sidecar's own workspace; read-only, so no chown
|
|
344
|
+
// is needed (docs §5). The operator drops the GGUF in workspaceDir(service).
|
|
345
|
+
volumes: [`${workspaceDir(service)}:${COMPONENT_WORKSPACE_PATH}:ro`],
|
|
330
346
|
});
|
|
331
347
|
} else {
|
|
332
348
|
externalResources[ref] = { type: "selfhosted", url: b.url };
|
|
333
349
|
// The endpoint bearer is a secret — out of the spec, returned separately.
|
|
334
|
-
if (b.apiKey) resourceSecrets[ref] =
|
|
350
|
+
if (b.apiKey) resourceSecrets[ref] = b.apiKey;
|
|
335
351
|
}
|
|
336
352
|
}
|
|
337
353
|
|
|
@@ -350,20 +366,23 @@ export function buildDeploymentSpec(
|
|
|
350
366
|
if (Object.keys(externalResources).length) config.externalResources = externalResources;
|
|
351
367
|
if (Object.keys(manifest).length) config.manifest = manifest;
|
|
352
368
|
|
|
353
|
-
// The engine component.
|
|
354
|
-
//
|
|
355
|
-
// nodes pass through as devices; sysfs families force privileged; either case
|
|
356
|
-
// needs root to open the root-owned nodes the nonroot image otherwise can't.
|
|
369
|
+
// The engine component. The config blob is mounted at the fixed convention path
|
|
370
|
+
// (component.ConfigFile) the engine image reads.
|
|
357
371
|
const engine: DeployComponent = {
|
|
358
372
|
name: "engine",
|
|
359
373
|
image: meta.engineImage,
|
|
360
374
|
pull: "never", // built locally before deploy, in no registry
|
|
361
375
|
config,
|
|
362
|
-
|
|
376
|
+
// Durable memory: a host bind mount under the state root, read-write, at the
|
|
377
|
+
// in-container workspace path (docs/device-filesystem.md §10).
|
|
378
|
+
volumes: [`${workspaceDir("engine")}:${COMPONENT_WORKSPACE_PATH}`],
|
|
379
|
+
// Run as root: writes the rw workspace bind mount without a host chown step
|
|
380
|
+
// (the OSS default, §5), and also opens root-owned device nodes when hardware
|
|
381
|
+
// (cdev passthrough / sysfs-privileged) is mapped in below.
|
|
382
|
+
user: "0:0",
|
|
363
383
|
};
|
|
364
384
|
if (cdev.size > 0) engine.devices = [...cdev];
|
|
365
385
|
if (privileged) engine.privileged = true;
|
|
366
|
-
if (cdev.size > 0 || privileged) engine.user = "0:0";
|
|
367
386
|
|
|
368
387
|
const components = [engine, ...llamaComponents, ...customComponents];
|
|
369
388
|
assertNoNameCollisions(components);
|
|
@@ -371,7 +390,6 @@ export function buildDeploymentSpec(
|
|
|
371
390
|
const spec: DeploymentSpec = {
|
|
372
391
|
schemaVersion: 1,
|
|
373
392
|
id: meta.id,
|
|
374
|
-
status: meta.status,
|
|
375
393
|
components,
|
|
376
394
|
};
|
|
377
395
|
if (meta.createdAt) spec.createdAt = meta.createdAt;
|
package/src/diagnostics/index.ts
CHANGED
package/src/edge/Edge.ts
CHANGED
package/src/edge/EdgeType.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 ForestHub.
|
|
3
|
+
|
|
1
4
|
// Edge taxonomy: a plain control/tool edge, or one of the three agent-specific
|
|
2
5
|
// control-flow refinements resolved at connection time from source/target context.
|
|
3
6
|
// Node port handles themselves only carry `control` or `tool`. Tool edges have no
|
package/src/edge/index.ts
CHANGED