@darkhorseprojects/circuitry 0.3.0 → 0.3.2
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/bundle.d.ts +2 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +277 -0
- package/dist/graph.d.ts +33 -68
- package/dist/index.js +142 -306
- package/dist/node.d.ts +11 -6
- package/dist/node.js +204 -369
- package/dist/presets.d.ts +1 -1
- package/dist/scheduler.d.ts +1 -1
- package/dist/simulation.d.ts +3 -4
- package/dist/types.d.ts +0 -1
- package/dist/yaml.d.ts +4 -2
- package/package.json +4 -1
package/dist/node.js
CHANGED
|
@@ -5,35 +5,11 @@ import path from "node:path";
|
|
|
5
5
|
import os from "node:os";
|
|
6
6
|
|
|
7
7
|
// src/yaml.ts
|
|
8
|
-
import
|
|
8
|
+
import YAML2 from "yaml";
|
|
9
9
|
|
|
10
10
|
// src/graph.ts
|
|
11
|
-
|
|
12
|
-
var
|
|
13
|
-
if (typeof value === "string") return value;
|
|
14
|
-
if (value === void 0) return "";
|
|
15
|
-
return JSON.stringify(value, null, 2);
|
|
16
|
-
};
|
|
17
|
-
var applyCircuitryRuntimeInputs = (graph, inputs = {}) => {
|
|
18
|
-
const entries = Object.entries(inputs);
|
|
19
|
-
if (entries.length === 0) return graph;
|
|
20
|
-
const next = {
|
|
21
|
-
...graph,
|
|
22
|
-
resources: graph.resources ? { ...graph.resources } : graph.resources
|
|
23
|
-
};
|
|
24
|
-
for (const [id, value] of entries) {
|
|
25
|
-
const text = runtimeInputToText(value);
|
|
26
|
-
const resource = next.resources?.[id];
|
|
27
|
-
if (resource) {
|
|
28
|
-
if (resource.type !== "text")
|
|
29
|
-
throw new Error(`Runtime input ${id} targets non-text resource: ${resource.type}`);
|
|
30
|
-
next.resources[id] = { ...resource, value: text };
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
throw new Error(`Runtime input does not match a graph text resource: ${id}`);
|
|
34
|
-
}
|
|
35
|
-
return next;
|
|
36
|
-
};
|
|
11
|
+
import YAML from "yaml";
|
|
12
|
+
var CIRCUITRY_SPEC_VERSION = "0.3.2";
|
|
37
13
|
var DEFAULT_CIRCUITRY_VALIDATION_RULES = [
|
|
38
14
|
"no-self-loops",
|
|
39
15
|
"no-unknown-edge-endpoints",
|
|
@@ -46,25 +22,30 @@ var DEFAULT_CIRCUITRY_VALIDATION_STANDARD = {
|
|
|
46
22
|
rules: DEFAULT_CIRCUITRY_VALIDATION_RULES,
|
|
47
23
|
executableKinds: ["agent", "tool", "output"]
|
|
48
24
|
};
|
|
49
|
-
var
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
);
|
|
53
|
-
|
|
25
|
+
var runtimeInputToText = (value) => {
|
|
26
|
+
if (typeof value === "string") return value;
|
|
27
|
+
if (value === void 0) return "";
|
|
28
|
+
return YAML.stringify(value).trimEnd();
|
|
29
|
+
};
|
|
30
|
+
var applyCircuitryRuntimeInputs = (graph, inputs = {}) => {
|
|
31
|
+
const next = { ...graph, resources: graph.resources ? { ...graph.resources } : graph.resources };
|
|
32
|
+
for (const [id, value] of Object.entries(inputs)) {
|
|
33
|
+
const resource = next.resources?.[id];
|
|
34
|
+
if (!resource) throw new Error(`unknown arg: ${id}`);
|
|
35
|
+
if (resource.type !== "text") throw new Error(`arg is not text: ${id}`);
|
|
36
|
+
next.resources[id] = { ...resource, value: runtimeInputToText(value) };
|
|
37
|
+
}
|
|
38
|
+
return next;
|
|
54
39
|
};
|
|
40
|
+
var ruleName = (rule) => typeof rule === "string" ? rule : rule.rule;
|
|
41
|
+
var executableKindsFromRules = (rules) => rules.find((rule) => typeof rule !== "string" && rule.rule === "require-executable-inputs")?.executableKinds;
|
|
55
42
|
var createCircuitryValidationStandard = (standard = {}, graph) => {
|
|
56
|
-
const rules = [
|
|
57
|
-
...DEFAULT_CIRCUITRY_VALIDATION_RULES,
|
|
58
|
-
...graph?.validation?.rules || [],
|
|
59
|
-
...standard.rules || []
|
|
60
|
-
];
|
|
43
|
+
const rules = [...DEFAULT_CIRCUITRY_VALIDATION_RULES, ...graph?.validation?.rules || [], ...standard.rules || []];
|
|
61
44
|
return {
|
|
62
45
|
version: standard.version || DEFAULT_CIRCUITRY_VALIDATION_STANDARD.version,
|
|
63
46
|
requireSpecVersion: standard.requireSpecVersion ?? DEFAULT_CIRCUITRY_VALIDATION_STANDARD.requireSpecVersion,
|
|
64
47
|
rules,
|
|
65
|
-
executableKinds: standard.executableKinds || executableKindsFromRules(rules) || [
|
|
66
|
-
...DEFAULT_CIRCUITRY_VALIDATION_STANDARD.executableKinds
|
|
67
|
-
]
|
|
48
|
+
executableKinds: standard.executableKinds || executableKindsFromRules(rules) || [...DEFAULT_CIRCUITRY_VALIDATION_STANDARD.executableKinds]
|
|
68
49
|
};
|
|
69
50
|
};
|
|
70
51
|
var expandResources = (resources) => {
|
|
@@ -72,294 +53,151 @@ var expandResources = (resources) => {
|
|
|
72
53
|
const edges = [];
|
|
73
54
|
for (const [id, resource] of Object.entries(resources)) {
|
|
74
55
|
if (resource.type === "text") {
|
|
75
|
-
nodes.push({
|
|
76
|
-
id,
|
|
77
|
-
kind: "input",
|
|
78
|
-
label: resource.label || id,
|
|
79
|
-
input: { type: "text", value: resource.value }
|
|
80
|
-
});
|
|
56
|
+
nodes.push({ id, kind: "input", label: resource.label || id, input: { type: "text", value: resource.value } });
|
|
81
57
|
} else if (resource.type === "agent") {
|
|
58
|
+
const agent = resource;
|
|
82
59
|
nodes.push({
|
|
83
60
|
id,
|
|
84
61
|
kind: "agent",
|
|
85
|
-
label:
|
|
62
|
+
label: agent.label || agent.identity || id,
|
|
86
63
|
agent: {
|
|
87
|
-
identity:
|
|
88
|
-
model:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
context: resource.context
|
|
64
|
+
identity: agent.identity || agent.label || id,
|
|
65
|
+
model: agent.model,
|
|
66
|
+
tools: agent.tools,
|
|
67
|
+
instructions: agent.instructions,
|
|
68
|
+
personality: agent.personality,
|
|
69
|
+
context: agent.context
|
|
94
70
|
},
|
|
95
|
-
skills:
|
|
96
|
-
expect:
|
|
71
|
+
skills: agent.skills,
|
|
72
|
+
expect: agent.expect
|
|
97
73
|
});
|
|
98
|
-
for (const
|
|
99
|
-
edges.push({ from: inputRef, to: id, kind: "dependency" });
|
|
100
|
-
}
|
|
74
|
+
for (const input of agent.inputs || []) edges.push({ from: input, to: id, kind: "dependency" });
|
|
101
75
|
} else if (resource.type === "tool") {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
});
|
|
108
|
-
for (const inputRef of resource.inputs || []) {
|
|
109
|
-
edges.push({ from: inputRef, to: id, kind: "dependency" });
|
|
110
|
-
}
|
|
76
|
+
const tool = resource;
|
|
77
|
+
nodes.push({ id, kind: "tool", label: tool.label || id, agent: { instructions: tool.instructions } });
|
|
78
|
+
for (const input of tool.inputs || []) edges.push({ from: input, to: id, kind: "dependency" });
|
|
79
|
+
} else {
|
|
80
|
+
const input = resource;
|
|
81
|
+
nodes.push({ id, kind: "input", label: input.label || id, input: { type: input.type, value: input.value, uri: input.uri || input.path, mimeType: input.mimeType, data: input.data } });
|
|
111
82
|
}
|
|
112
83
|
}
|
|
113
84
|
return { nodes, edges };
|
|
114
85
|
};
|
|
115
86
|
var normalizeCircuitryGraph = (graph) => {
|
|
116
|
-
if (!graph.resources
|
|
117
|
-
|
|
118
|
-
return { ...graph, nodes, edges };
|
|
87
|
+
if (!graph.resources) return { ...graph };
|
|
88
|
+
return { ...graph, ...expandResources(graph.resources) };
|
|
119
89
|
};
|
|
120
|
-
var
|
|
121
|
-
|
|
122
|
-
const resolvedStandard = createCircuitryValidationStandard(
|
|
123
|
-
standard,
|
|
124
|
-
graph && typeof graph === "object" && !Array.isArray(graph) ? graph : void 0
|
|
125
|
-
);
|
|
90
|
+
var validateCircuitryGraphInternal = (graph, standard = {}, source) => {
|
|
91
|
+
const resolved = createCircuitryValidationStandard(standard, graph && typeof graph === "object" && !Array.isArray(graph) ? graph : void 0);
|
|
126
92
|
const errors = [];
|
|
127
|
-
const
|
|
128
|
-
if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (options.sourceFormat) {
|
|
143
|
-
if (!graphObject.resources || Object.keys(graphObject.resources).length === 0) {
|
|
144
|
-
addError("missing_resources", "Circuitry v0.3 graphs must use a resources: section", ["resources"]);
|
|
145
|
-
}
|
|
146
|
-
if (graphObject.agents && Object.keys(graphObject.agents).length > 0) {
|
|
147
|
-
addError("forbidden_agents", "Circuitry v0.3 graph files must not use top-level agents:; use resources:", ["agents"]);
|
|
148
|
-
}
|
|
149
|
-
if (graphObject.inputs && Object.keys(graphObject.inputs).length > 0) {
|
|
150
|
-
addError("forbidden_inputs", "Circuitry v0.3 graph files must not use top-level inputs:; use resources:", ["inputs"]);
|
|
151
|
-
}
|
|
152
|
-
if (graphObject.nodes && graphObject.nodes.length > 0) {
|
|
153
|
-
addError("forbidden_nodes", "Circuitry v0.3 graph files must not use top-level nodes:; use resources:", ["nodes"]);
|
|
154
|
-
}
|
|
155
|
-
if (graphObject.edges && graphObject.edges.length > 0) {
|
|
156
|
-
addError("forbidden_edges", "Circuitry v0.3 graph files must not use top-level edges:; use resource inputs:", ["edges"]);
|
|
157
|
-
}
|
|
158
|
-
if (graphObject.links && graphObject.links.length > 0) {
|
|
159
|
-
addError("forbidden_links", "Circuitry v0.3 graph files must use imports: instead of links:", ["links"]);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
const normalized = normalizeCircuitryGraph(graphObject);
|
|
93
|
+
const issue = (code, message = code, path2) => errors.push({ code, message, ...path2 ? { path: path2 } : {} });
|
|
94
|
+
if (!graph || typeof graph !== "object" || Array.isArray(graph)) return { ok: false, errors: [{ code: "invalid_graph", message: "invalid graph" }], standard: resolved };
|
|
95
|
+
const g = graph;
|
|
96
|
+
if (resolved.requireSpecVersion && g.circuitry !== resolved.version) issue("invalid_version", "invalid version", ["circuitry"]);
|
|
97
|
+
if (source) {
|
|
98
|
+
const raw = g;
|
|
99
|
+
if (!g.resources || Object.keys(g.resources).length === 0) issue("missing_resources", "missing resources", ["resources"]);
|
|
100
|
+
if (raw.agents) issue("forbidden_agents", "forbidden agents", ["agents"]);
|
|
101
|
+
if (raw.inputs) issue("forbidden_inputs", "forbidden inputs", ["inputs"]);
|
|
102
|
+
if (g.nodes?.length) issue("forbidden_nodes", "forbidden nodes", ["nodes"]);
|
|
103
|
+
if (g.edges?.length) issue("forbidden_edges", "forbidden edges", ["edges"]);
|
|
104
|
+
if (raw.links) issue("forbidden_links", "forbidden links", ["links"]);
|
|
105
|
+
}
|
|
106
|
+
const rules = new Set(resolved.rules.map(ruleName));
|
|
107
|
+
const normalized = normalizeCircuitryGraph(g);
|
|
163
108
|
const ids = /* @__PURE__ */ new Set();
|
|
164
109
|
for (const [index, node] of (normalized.nodes || []).entries()) {
|
|
165
110
|
if (!node.id) {
|
|
166
|
-
|
|
111
|
+
issue("missing_node_id", "missing node id", ["nodes", index, "id"]);
|
|
167
112
|
continue;
|
|
168
113
|
}
|
|
169
|
-
if (ids.has(node.id))
|
|
170
|
-
addError("duplicate_node_id", `Duplicate node id: ${node.id}`, ["nodes", index, "id"]);
|
|
171
|
-
}
|
|
114
|
+
if (ids.has(node.id)) issue("duplicate_node_id", "duplicate node id", ["nodes", index, "id"]);
|
|
172
115
|
ids.add(node.id);
|
|
173
|
-
if (!node.kind)
|
|
174
|
-
addError("missing_node_kind", `Node ${node.id} is missing kind`, ["nodes", index, "kind"]);
|
|
175
|
-
}
|
|
116
|
+
if (!node.kind) issue("missing_node_kind", "missing node kind", ["nodes", index, "kind"]);
|
|
176
117
|
}
|
|
177
118
|
const adjacency = /* @__PURE__ */ new Map();
|
|
178
|
-
const
|
|
119
|
+
const incoming = /* @__PURE__ */ new Map();
|
|
179
120
|
for (const id of ids) {
|
|
180
121
|
adjacency.set(id, []);
|
|
181
|
-
|
|
122
|
+
incoming.set(id, 0);
|
|
182
123
|
}
|
|
183
124
|
for (const [index, edge] of (normalized.edges || []).entries()) {
|
|
184
125
|
if (!edge.from || !edge.to) {
|
|
185
|
-
|
|
126
|
+
issue("missing_edge_endpoint", "missing edge endpoint", ["edges", index]);
|
|
186
127
|
continue;
|
|
187
128
|
}
|
|
188
|
-
if (
|
|
189
|
-
|
|
129
|
+
if (rules.has("no-self-loops") && edge.from === edge.to) {
|
|
130
|
+
issue("self_loop", "self loop", ["edges", index]);
|
|
190
131
|
continue;
|
|
191
132
|
}
|
|
192
|
-
|
|
193
|
-
|
|
133
|
+
const ok = ids.has(edge.from) && ids.has(edge.to);
|
|
134
|
+
if (rules.has("no-unknown-edge-endpoints")) {
|
|
135
|
+
if (!ids.has(edge.from)) issue("unknown_edge_source", "unknown edge source", ["edges", index, "from"]);
|
|
136
|
+
if (!ids.has(edge.to)) issue("unknown_edge_target", "unknown edge target", ["edges", index, "to"]);
|
|
194
137
|
}
|
|
195
|
-
if (
|
|
196
|
-
addError("unknown_edge_target", `Edge references unknown target: ${edge.to}`, ["edges", index, "to"]);
|
|
197
|
-
}
|
|
198
|
-
if (ids.has(edge.from) && ids.has(edge.to)) {
|
|
138
|
+
if (ok) {
|
|
199
139
|
adjacency.get(edge.from).push(edge.to);
|
|
200
|
-
|
|
140
|
+
incoming.set(edge.to, (incoming.get(edge.to) || 0) + 1);
|
|
201
141
|
}
|
|
202
142
|
}
|
|
203
|
-
|
|
204
|
-
|
|
143
|
+
if (rules.has("require-executable-inputs")) {
|
|
144
|
+
const executable = new Set(resolved.executableKinds);
|
|
205
145
|
for (const [index, node] of (normalized.nodes || []).entries()) {
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
if (visited.has(id)) return;
|
|
222
|
-
visiting.add(id);
|
|
223
|
-
path2.push(id);
|
|
224
|
-
for (const next of adjacency.get(id) || []) visit(next);
|
|
225
|
-
path2.pop();
|
|
226
|
-
visiting.delete(id);
|
|
227
|
-
visited.add(id);
|
|
228
|
-
};
|
|
229
|
-
if (hasRule("no-cycles")) {
|
|
230
|
-
for (const id of ids) {
|
|
231
|
-
visit(id);
|
|
232
|
-
if (cycleMessage) {
|
|
233
|
-
addError("cycle", `Graph contains cycle: ${cycleMessage}`);
|
|
234
|
-
break;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
const additionalRules = rules.filter((rule) => {
|
|
239
|
-
if (typeof rule === "string") return false;
|
|
240
|
-
return rule.rule === "require-graph-field" || rule.rule === "require-node-field" || rule.rule === "require-edge-field" || rule.rule === "require-string" || rule.rule === "reject-string";
|
|
241
|
-
});
|
|
242
|
-
const fieldPath = (field) => field.split(".").filter(Boolean);
|
|
243
|
-
const getField = (value, field) => fieldPath(field).reduce((current, key) => {
|
|
244
|
-
if (!current || typeof current !== "object") return void 0;
|
|
245
|
-
return current[key];
|
|
246
|
-
}, value);
|
|
247
|
-
const isPresent = (value) => value !== void 0 && value !== null && value !== "";
|
|
248
|
-
for (const rule of additionalRules) {
|
|
249
|
-
if (rule.rule === "require-graph-field") {
|
|
250
|
-
if (!isPresent(getField(normalized, rule.field))) {
|
|
251
|
-
addError("missing_required_graph_field", `Graph is missing required field: ${rule.field}`, fieldPath(rule.field));
|
|
252
|
-
}
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
|
-
if (rule.rule === "require-node-field") {
|
|
256
|
-
const nodeKinds = new Set(rule.nodeKinds || []);
|
|
257
|
-
for (const [index, node] of (normalized.nodes || []).entries()) {
|
|
258
|
-
if (nodeKinds.size > 0 && !nodeKinds.has(node.kind)) continue;
|
|
259
|
-
if (!isPresent(getField(node, rule.field))) {
|
|
260
|
-
addError("missing_required_node_field", `Node ${node.id || "<missing id>"} is missing required field: ${rule.field}`, ["nodes", index, ...fieldPath(rule.field)]);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
continue;
|
|
264
|
-
}
|
|
265
|
-
if (rule.rule === "require-edge-field") {
|
|
266
|
-
const edgeKinds = new Set(rule.edgeKinds || []);
|
|
267
|
-
for (const [index, edge] of (normalized.edges || []).entries()) {
|
|
268
|
-
if (edgeKinds.size > 0 && (!edge.kind || !edgeKinds.has(edge.kind))) continue;
|
|
269
|
-
if (!isPresent(getField(edge, rule.field))) {
|
|
270
|
-
addError("missing_required_edge_field", `Edge ${edge.id || index} is missing required field: ${rule.field}`, ["edges", index, ...fieldPath(rule.field)]);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
continue;
|
|
274
|
-
}
|
|
275
|
-
const checkString = (target, subject, id, match, path3) => {
|
|
276
|
-
const value = getField(subject, match.field);
|
|
277
|
-
const text = typeof value === "string" ? value : "";
|
|
278
|
-
const includes = text.includes(match.value);
|
|
279
|
-
if (rule.rule === "require-string" && !includes) {
|
|
280
|
-
addError("missing_required_string", `${target} ${id} field ${match.field} must include string: ${match.value}`, path3);
|
|
281
|
-
}
|
|
282
|
-
if (rule.rule === "reject-string" && includes) {
|
|
283
|
-
addError("rejected_string", `${target} ${id} field ${match.field} must not include string: ${match.value}`, path3);
|
|
284
|
-
}
|
|
146
|
+
if (executable.has(node.kind) && (incoming.get(node.id) || 0) === 0) issue("missing_executable_input", "missing executable input", ["nodes", index]);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (rules.has("no-cycles")) {
|
|
150
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
151
|
+
const visited = /* @__PURE__ */ new Set();
|
|
152
|
+
const visit = (id) => {
|
|
153
|
+
if (visiting.has(id)) return true;
|
|
154
|
+
if (visited.has(id)) return false;
|
|
155
|
+
visiting.add(id);
|
|
156
|
+
for (const next of adjacency.get(id) || []) if (visit(next)) return true;
|
|
157
|
+
visiting.delete(id);
|
|
158
|
+
visited.add(id);
|
|
159
|
+
return false;
|
|
285
160
|
};
|
|
286
|
-
for (const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
for (const [index, node] of (normalized.nodes || []).entries()) {
|
|
290
|
-
if (nodeKinds.size > 0 && !nodeKinds.has(node.kind)) continue;
|
|
291
|
-
checkString("node", node, node.id || "<missing id>", match, ["nodes", index, ...fieldPath(match.field)]);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
for (const match of rule.edges || []) {
|
|
295
|
-
const edgeKinds = new Set(match.edgeKinds || []);
|
|
296
|
-
for (const [index, edge] of (normalized.edges || []).entries()) {
|
|
297
|
-
if (edgeKinds.size > 0 && (!edge.kind || !edgeKinds.has(edge.kind))) continue;
|
|
298
|
-
checkString("edge", edge, edge.id || String(index), match, ["edges", index, ...fieldPath(match.field)]);
|
|
299
|
-
}
|
|
161
|
+
for (const id of ids) if (visit(id)) {
|
|
162
|
+
issue("cycle", "cycle");
|
|
163
|
+
break;
|
|
300
164
|
}
|
|
301
165
|
}
|
|
302
|
-
return { ok: errors.length === 0, errors, standard:
|
|
303
|
-
};
|
|
304
|
-
var validateCircuitryGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, { sourceFormat: true });
|
|
305
|
-
var validateCircuitryExecutionGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, { sourceFormat: false });
|
|
306
|
-
var validateCircuitryGraph = (graph, standard = {}) => validateCircuitryGraphWithStandard(graph, standard).errors.map(
|
|
307
|
-
(error) => error.message
|
|
308
|
-
);
|
|
309
|
-
var parseCircuitryJson = (text, standard = {}, options = {}) => {
|
|
310
|
-
let graph;
|
|
311
|
-
try {
|
|
312
|
-
graph = JSON.parse(text);
|
|
313
|
-
} catch (error) {
|
|
314
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
315
|
-
throw new Error(`Could not parse Circuitry JSON. Check commas, quotes, and braces.
|
|
316
|
-
${message}`);
|
|
317
|
-
}
|
|
318
|
-
if (options.validate === false) return graph;
|
|
319
|
-
const errors = validateCircuitryGraph(graph, standard);
|
|
320
|
-
if (errors.length) {
|
|
321
|
-
throw new Error(`Invalid Circuitry graph:
|
|
322
|
-
${errors.join("\n")}`);
|
|
323
|
-
}
|
|
324
|
-
return normalizeCircuitryGraph(graph);
|
|
325
|
-
};
|
|
326
|
-
var stringifyCircuitryJson = (graph) => {
|
|
327
|
-
return `${JSON.stringify(normalizeCircuitryGraph(graph), null, 2)}
|
|
328
|
-
`;
|
|
166
|
+
return { ok: errors.length === 0, errors, standard: resolved };
|
|
329
167
|
};
|
|
168
|
+
var validateCircuitryGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, true);
|
|
169
|
+
var validateCircuitryExecutionGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, false);
|
|
170
|
+
var validateCircuitryGraph = (graph, standard = {}) => validateCircuitryGraphWithStandard(graph, standard).errors.map((error) => error.message);
|
|
330
171
|
|
|
331
172
|
// src/yaml.ts
|
|
332
|
-
var
|
|
333
|
-
let graph;
|
|
173
|
+
var parseYamlData = (text) => {
|
|
334
174
|
try {
|
|
335
|
-
|
|
175
|
+
return YAML2.parse(text);
|
|
336
176
|
} catch (error) {
|
|
337
177
|
const message = error instanceof Error ? error.message : String(error);
|
|
338
|
-
throw new Error(`Could not parse
|
|
178
|
+
throw new Error(`Could not parse YAML.
|
|
339
179
|
${message}`);
|
|
340
180
|
}
|
|
181
|
+
};
|
|
182
|
+
var stringifyYamlData = (value) => YAML2.stringify(value);
|
|
183
|
+
var parseCircuitryYaml = (text, standard = {}, options = {}) => {
|
|
184
|
+
const graph = parseYamlData(text);
|
|
341
185
|
if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
|
|
342
|
-
throw new Error("
|
|
186
|
+
throw new Error("Circuitry YAML must be a graph object.");
|
|
343
187
|
}
|
|
344
|
-
if (options.validate
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
throw new Error(`Invalid Circuitry graph:
|
|
188
|
+
if (options.validate !== false) {
|
|
189
|
+
const errors = validateCircuitryGraph(graph, standard);
|
|
190
|
+
if (errors.length) throw new Error(`Invalid Circuitry graph:
|
|
348
191
|
${errors.join("\n")}`);
|
|
349
192
|
}
|
|
350
|
-
return
|
|
351
|
-
};
|
|
352
|
-
var stringifyCircuitryYaml = (graph) => {
|
|
353
|
-
return YAML.stringify(normalizeCircuitryGraph(graph));
|
|
354
|
-
};
|
|
355
|
-
var parseCircuitryText = (text, filename = "graph.circuitry.yaml", standard = {}, options = {}) => {
|
|
356
|
-
return filename.endsWith(".json") ? parseCircuitryJson(text, standard, options) : parseCircuitryYaml(text, standard, options);
|
|
357
|
-
};
|
|
358
|
-
var stringifyCircuitryText = (graph, filename = "graph.circuitry.yaml") => {
|
|
359
|
-
return filename.endsWith(".json") ? stringifyCircuitryJson(graph) : stringifyCircuitryYaml(graph);
|
|
193
|
+
return graph;
|
|
360
194
|
};
|
|
195
|
+
var stringifyCircuitryYaml = (graph) => YAML2.stringify(graph);
|
|
196
|
+
var parseCircuitryText = (text, standard = {}, options = {}) => parseCircuitryYaml(text, standard, options);
|
|
197
|
+
var stringifyCircuitryText = (graph) => stringifyCircuitryYaml(graph);
|
|
361
198
|
|
|
362
199
|
// src/scheduler.ts
|
|
200
|
+
import YAML3 from "yaml";
|
|
363
201
|
var buildCircuitryExecutionGraph = (graph) => {
|
|
364
202
|
const normalized = normalizeCircuitryGraph(graph);
|
|
365
203
|
const nodes = /* @__PURE__ */ new Map();
|
|
@@ -399,7 +237,7 @@ var formatEdgeData = (data) => {
|
|
|
399
237
|
if (!data || Object.keys(data).length === 0) {
|
|
400
238
|
return "";
|
|
401
239
|
}
|
|
402
|
-
return ` data=${
|
|
240
|
+
return ` data=${YAML3.stringify(data).trimEnd()}`;
|
|
403
241
|
};
|
|
404
242
|
var describeEdge = (edge, direction) => {
|
|
405
243
|
const otherId = direction === "incoming" ? edge.from : edge.to;
|
|
@@ -444,17 +282,17 @@ ${contextSection}`
|
|
|
444
282
|
].filter(Boolean).join("\n\n");
|
|
445
283
|
};
|
|
446
284
|
var collectImages = (contextInputs) => contextInputs.filter((item) => item.kind === "image" && item.image).map((item) => item.image);
|
|
447
|
-
var
|
|
285
|
+
var stripYamlFence = (output) => {
|
|
448
286
|
const trimmed = output.trim();
|
|
449
|
-
const fenced = trimmed.match(/^```(?:
|
|
287
|
+
const fenced = trimmed.match(/^```(?:ya?ml)?\s*([\s\S]*?)\s*```$/i);
|
|
450
288
|
return fenced ? fenced[1].trim() : trimmed;
|
|
451
289
|
};
|
|
452
290
|
var parseExpectedOutput = (nodeId, output) => {
|
|
453
291
|
try {
|
|
454
|
-
return
|
|
292
|
+
return YAML3.parse(stripYamlFence(output));
|
|
455
293
|
} catch (error) {
|
|
456
294
|
const detail = error instanceof Error ? error.message : String(error);
|
|
457
|
-
throw new Error(`Node ${nodeId} output does not match expect: output is not valid
|
|
295
|
+
throw new Error(`Node ${nodeId} output does not match expect: output is not valid YAML (${detail})`);
|
|
458
296
|
}
|
|
459
297
|
};
|
|
460
298
|
var isFieldObject = (schema) => !!schema && typeof schema === "object" && !Array.isArray(schema) && typeof schema.type === "string";
|
|
@@ -537,7 +375,7 @@ ${errors.join("\n")}`);
|
|
|
537
375
|
var executeCircuitryNode = async ({
|
|
538
376
|
graph,
|
|
539
377
|
item,
|
|
540
|
-
|
|
378
|
+
cycle,
|
|
541
379
|
inputPayload,
|
|
542
380
|
contextInputs,
|
|
543
381
|
defaultModel,
|
|
@@ -545,13 +383,13 @@ var executeCircuitryNode = async ({
|
|
|
545
383
|
onNodeStart,
|
|
546
384
|
onNodeComplete
|
|
547
385
|
}) => {
|
|
548
|
-
onNodeStart?.(item.id,
|
|
386
|
+
onNodeStart?.(item.id, cycle);
|
|
549
387
|
if (item.node.kind === "output") {
|
|
550
388
|
const output = inputPayload.map((input) => input.output).join("\n\n");
|
|
551
389
|
onNodeComplete?.(item.id, { output });
|
|
552
390
|
return {
|
|
553
391
|
nodeId: item.id,
|
|
554
|
-
|
|
392
|
+
cycle,
|
|
555
393
|
inputNodeIds: inputPayload.map((input) => input.nodeId),
|
|
556
394
|
output
|
|
557
395
|
};
|
|
@@ -563,7 +401,6 @@ var executeCircuitryNode = async ({
|
|
|
563
401
|
nodeId: item.id,
|
|
564
402
|
model: (agent.model === "inherit" ? void 0 : agent.model) || (defaultModel === "inherit" ? void 0 : defaultModel) || "inherit",
|
|
565
403
|
tools: agent.tools || [],
|
|
566
|
-
thinkingLevel: agent.thinkingLevel || "off",
|
|
567
404
|
personality: agent.personality || "",
|
|
568
405
|
instructions: agent.instructions || "",
|
|
569
406
|
context: agent.context || "",
|
|
@@ -577,7 +414,7 @@ var executeCircuitryNode = async ({
|
|
|
577
414
|
onNodeComplete?.(item.id, { error: message });
|
|
578
415
|
return {
|
|
579
416
|
nodeId: item.id,
|
|
580
|
-
|
|
417
|
+
cycle,
|
|
581
418
|
inputNodeIds: inputPayload.map((input) => input.nodeId),
|
|
582
419
|
output: "",
|
|
583
420
|
error: message
|
|
@@ -587,7 +424,7 @@ var executeCircuitryNode = async ({
|
|
|
587
424
|
onNodeComplete?.(item.id, { output: result.output });
|
|
588
425
|
return {
|
|
589
426
|
nodeId: item.id,
|
|
590
|
-
|
|
427
|
+
cycle,
|
|
591
428
|
inputNodeIds: inputPayload.map((input) => input.nodeId),
|
|
592
429
|
output: result.output
|
|
593
430
|
};
|
|
@@ -606,7 +443,7 @@ var runCircuitryGraphExecution = async ({
|
|
|
606
443
|
const parallelism = Math.max(1, Math.floor(maxParallelRuns));
|
|
607
444
|
const defaultModel = graph.runtime?.model;
|
|
608
445
|
const runOne = async (nodeId, outputs2) => {
|
|
609
|
-
const
|
|
446
|
+
const cycle = false;
|
|
610
447
|
const item = executionGraph.nodes.get(nodeId);
|
|
611
448
|
const inputPayload = item.inputNodeIds.filter((sourceId) => outputs2.has(sourceId)).map((sourceId) => ({
|
|
612
449
|
nodeId: sourceId,
|
|
@@ -620,7 +457,7 @@ var runCircuitryGraphExecution = async ({
|
|
|
620
457
|
return executeCircuitryNode({
|
|
621
458
|
graph,
|
|
622
459
|
item,
|
|
623
|
-
|
|
460
|
+
cycle,
|
|
624
461
|
inputPayload,
|
|
625
462
|
contextInputs,
|
|
626
463
|
defaultModel,
|
|
@@ -706,7 +543,8 @@ var loadPiSDK = async () => {
|
|
|
706
543
|
return await import(modulePath);
|
|
707
544
|
}
|
|
708
545
|
}
|
|
709
|
-
|
|
546
|
+
const packageName = "@earendil-works/pi-coding-agent";
|
|
547
|
+
return await import(packageName);
|
|
710
548
|
};
|
|
711
549
|
var extractAssistantText = (message) => {
|
|
712
550
|
if (!message || message.role !== "assistant") return "";
|
|
@@ -745,8 +583,7 @@ var runNodeWithPiSDK = async ({
|
|
|
745
583
|
model,
|
|
746
584
|
prompt,
|
|
747
585
|
images = [],
|
|
748
|
-
tools = []
|
|
749
|
-
thinkingLevel = "off"
|
|
586
|
+
tools = []
|
|
750
587
|
}) => {
|
|
751
588
|
let sdk;
|
|
752
589
|
try {
|
|
@@ -770,7 +607,6 @@ var runNodeWithPiSDK = async ({
|
|
|
770
607
|
const selectedModel = requestedModel && requestedModel !== "inherit" ? findRequestedModel(modelRegistry, await modelRegistry.getAvailable(), requestedModel) : void 0;
|
|
771
608
|
const { session } = await createAgentSession({
|
|
772
609
|
...selectedModel ? { model: selectedModel } : {},
|
|
773
|
-
thinkingLevel,
|
|
774
610
|
sessionManager: SessionManager.inMemory(),
|
|
775
611
|
authStorage,
|
|
776
612
|
modelRegistry,
|
|
@@ -804,6 +640,63 @@ var runNodeWithPiSDK = async ({
|
|
|
804
640
|
}
|
|
805
641
|
};
|
|
806
642
|
var defaultFilename = "graph.circuitry.yaml";
|
|
643
|
+
var resourceInputs = (resource) => "inputs" in resource && Array.isArray(resource.inputs) ? resource.inputs : [];
|
|
644
|
+
var withResourceInputs = (resource, inputs) => "inputs" in resource ? { ...resource, inputs } : resource;
|
|
645
|
+
var selectedImportResources = (imp, resources) => {
|
|
646
|
+
if (imp.resources === "*") return Object.fromEntries(Object.keys(resources).map((id) => [id, id]));
|
|
647
|
+
if (Array.isArray(imp.resources)) return Object.fromEntries(imp.resources.map((id) => [id, id]));
|
|
648
|
+
return imp.resources;
|
|
649
|
+
};
|
|
650
|
+
var importedId = (localId, prefix) => `${prefix || ""}${localId}`;
|
|
651
|
+
var rewriteResourceInputs = (resource, aliasMap) => {
|
|
652
|
+
const inputs = resourceInputs(resource);
|
|
653
|
+
if (inputs.length === 0) return resource;
|
|
654
|
+
return withResourceInputs(resource, inputs.map((input) => aliasMap[input] || input));
|
|
655
|
+
};
|
|
656
|
+
var resolveCircuitryGraph = async (parsed, graphFile, text, standard, stack = []) => {
|
|
657
|
+
if (stack.includes(graphFile)) {
|
|
658
|
+
throw new Error(`Circuitry graph import cycle: ${[...stack, graphFile].join(" -> ")}`);
|
|
659
|
+
}
|
|
660
|
+
const nextStack = [...stack, graphFile];
|
|
661
|
+
const resources = {};
|
|
662
|
+
const origins = {};
|
|
663
|
+
for (const imp of parsed.imports || []) {
|
|
664
|
+
const linkedFile = path.resolve(path.dirname(graphFile), imp.path);
|
|
665
|
+
const loaded = await loadCircuitryGraphFile(linkedFile, standard, nextStack);
|
|
666
|
+
const available = loaded.graph.resources || {};
|
|
667
|
+
const aliases = selectedImportResources(imp, available);
|
|
668
|
+
const aliasMap = {};
|
|
669
|
+
for (const [sourceId, localId] of Object.entries(aliases)) aliasMap[sourceId] = importedId(localId, imp.prefix);
|
|
670
|
+
for (const [sourceId, localId] of Object.entries(aliases)) {
|
|
671
|
+
const resource = available[sourceId];
|
|
672
|
+
if (!resource) throw new Error(`Imported resource not found: ${sourceId} in ${imp.path}`);
|
|
673
|
+
const nextId = importedId(localId, imp.prefix);
|
|
674
|
+
if (resources[nextId]) throw new Error(`Imported Circuitry resource id collision: ${nextId} from ${imp.path}`);
|
|
675
|
+
resources[nextId] = rewriteResourceInputs(resource, aliasMap);
|
|
676
|
+
origins[nextId] = loaded.origins[sourceId] || linkedFile;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
for (const [id, resource] of Object.entries(parsed.resources || {})) {
|
|
680
|
+
if (resources[id]) throw new Error(`Circuitry resource id collision: ${id} in ${graphFile}`);
|
|
681
|
+
resources[id] = resource;
|
|
682
|
+
origins[id] = graphFile;
|
|
683
|
+
}
|
|
684
|
+
const graph = normalizeCircuitryGraph({ ...parsed, imports: [], resources });
|
|
685
|
+
if (stack.length === 0) {
|
|
686
|
+
const validation = validateCircuitryExecutionGraphWithStandard(graph, standard);
|
|
687
|
+
if (validation.errors.length) {
|
|
688
|
+
throw new Error(`Invalid Circuitry graph:
|
|
689
|
+
${validation.errors.map((e) => e.message).join("\n")}`);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return { filename: graphFile, text, graph, origins };
|
|
693
|
+
};
|
|
694
|
+
var loadCircuitryGraphFile = async (filename = defaultFilename, standard, stack = []) => {
|
|
695
|
+
const graphFile = path.resolve(process.cwd(), filename);
|
|
696
|
+
const text = await readFile(graphFile, "utf8");
|
|
697
|
+
const parsed = parseCircuitryText(text, standard, { validate: false });
|
|
698
|
+
return resolveCircuitryGraph(parsed, graphFile, text, standard, stack);
|
|
699
|
+
};
|
|
807
700
|
var NodeCircuitryHost = class {
|
|
808
701
|
resolveGraphFile(filename) {
|
|
809
702
|
return path.resolve(
|
|
@@ -812,7 +705,7 @@ var NodeCircuitryHost = class {
|
|
|
812
705
|
);
|
|
813
706
|
}
|
|
814
707
|
runFileFor(filename) {
|
|
815
|
-
return `${filename}.run.
|
|
708
|
+
return `${filename}.run.yaml`;
|
|
816
709
|
}
|
|
817
710
|
async exists(filename) {
|
|
818
711
|
try {
|
|
@@ -829,98 +722,42 @@ var NodeCircuitryHost = class {
|
|
|
829
722
|
path: [filename]
|
|
830
723
|
};
|
|
831
724
|
}
|
|
832
|
-
|
|
725
|
+
parseSourceGraph(text, filename, standard) {
|
|
833
726
|
try {
|
|
834
|
-
return {
|
|
835
|
-
graph: parseCircuitryText(text || "", filename, standard, {
|
|
836
|
-
validate: false
|
|
837
|
-
})
|
|
838
|
-
};
|
|
727
|
+
return { graph: parseCircuitryText(text || "", standard, { validate: false }) };
|
|
839
728
|
} catch (error) {
|
|
840
729
|
return { error: this.parseIssue(error, filename) };
|
|
841
730
|
}
|
|
842
731
|
}
|
|
843
|
-
async resolveGraphImports(graph, filename, standard, stack = []) {
|
|
844
|
-
const graphFile = path.resolve(filename);
|
|
845
|
-
if (stack.includes(graphFile)) {
|
|
846
|
-
throw new Error(`Circuitry graph import cycle: ${[...stack, graphFile].join(" -> ")}`);
|
|
847
|
-
}
|
|
848
|
-
const importedResources = {};
|
|
849
|
-
const aliasMap = {};
|
|
850
|
-
const nextStack = [...stack, graphFile];
|
|
851
|
-
for (const imp of graph.imports || []) {
|
|
852
|
-
const linkedFile = path.resolve(path.dirname(graphFile), imp.path);
|
|
853
|
-
const linkedText = await readFile(linkedFile, "utf8");
|
|
854
|
-
const parsed = parseCircuitryText(linkedText, linkedFile, standard, { validate: false });
|
|
855
|
-
const resolved = await this.resolveGraphImports(parsed, linkedFile, standard, nextStack);
|
|
856
|
-
const resourceId = imp.resource;
|
|
857
|
-
const resource = resolved.resources?.[resourceId];
|
|
858
|
-
if (!resource) {
|
|
859
|
-
throw new Error(`Imported resource not found: ${resourceId} in ${imp.path}`);
|
|
860
|
-
}
|
|
861
|
-
const localId = imp.as || resourceId;
|
|
862
|
-
if (importedResources[localId]) {
|
|
863
|
-
throw new Error(`Imported Circuitry resource id collision: ${localId} from ${imp.path}`);
|
|
864
|
-
}
|
|
865
|
-
if (imp.as) aliasMap[resourceId] = localId;
|
|
866
|
-
const resourceWithRewrittenInputs = this.rewriteImportInputs(resource, aliasMap);
|
|
867
|
-
importedResources[localId] = resourceWithRewrittenInputs;
|
|
868
|
-
}
|
|
869
|
-
return {
|
|
870
|
-
...graph,
|
|
871
|
-
resources: {
|
|
872
|
-
...importedResources,
|
|
873
|
-
...graph.resources || {}
|
|
874
|
-
}
|
|
875
|
-
};
|
|
876
|
-
}
|
|
877
|
-
/** Rewrite inputs in imported resource to use aliased resource ids. */
|
|
878
|
-
rewriteImportInputs(resource, aliasMap) {
|
|
879
|
-
if (resource.type === "agent" || resource.type === "tool") {
|
|
880
|
-
const newInputs = (resource.inputs || []).map((input) => aliasMap[input] || input);
|
|
881
|
-
return { ...resource, inputs: newInputs };
|
|
882
|
-
}
|
|
883
|
-
return resource;
|
|
884
|
-
}
|
|
885
732
|
async parseAndResolveGraph(text, filename, standard) {
|
|
886
|
-
const parsed = this.parseGraphForValidation(text, filename, standard);
|
|
887
|
-
if (!parsed.graph) return parsed;
|
|
888
733
|
try {
|
|
889
|
-
|
|
734
|
+
const graphFile = path.resolve(process.cwd(), filename);
|
|
735
|
+
const source = text || "";
|
|
736
|
+
const parsed = parseCircuitryText(source, standard, { validate: false });
|
|
737
|
+
return { graph: (await resolveCircuitryGraph(parsed, graphFile, source, standard)).graph };
|
|
890
738
|
} catch (error) {
|
|
891
739
|
return { error: this.parseIssue(error, filename) };
|
|
892
740
|
}
|
|
893
741
|
}
|
|
894
742
|
async readGraphFile(filename) {
|
|
895
|
-
const
|
|
896
|
-
|
|
897
|
-
const parsed = await this.parseAndResolveGraph(text, graphFile);
|
|
898
|
-
if (!parsed.graph) throw new Error(`Invalid Circuitry graph:
|
|
899
|
-
${parsed.error?.message}`);
|
|
900
|
-
const validation = validateCircuitryGraphWithStandard(parsed.graph);
|
|
901
|
-
if (validation.errors.length) {
|
|
902
|
-
throw new Error(
|
|
903
|
-
`Invalid Circuitry graph:
|
|
904
|
-
${validation.errors.map((e) => e.message).join("\n")}`
|
|
905
|
-
);
|
|
906
|
-
}
|
|
907
|
-
return { graphFile, text, graph: normalizeCircuitryGraph(parsed.graph) };
|
|
743
|
+
const loaded = await loadCircuitryGraphFile(this.resolveGraphFile(filename));
|
|
744
|
+
return { graphFile: loaded.filename, text: loaded.text, graph: loaded.graph, origins: loaded.origins };
|
|
908
745
|
}
|
|
909
746
|
async readGraph(input = {}) {
|
|
910
747
|
const { graphFile, text, graph } = await this.readGraphFile(input.filename);
|
|
911
748
|
const lastRunFile = this.runFileFor(graphFile);
|
|
912
|
-
const lastRun = await this.exists(lastRunFile) ?
|
|
749
|
+
const lastRun = await this.exists(lastRunFile) ? parseYamlData(await readFile(lastRunFile, "utf8")) : void 0;
|
|
913
750
|
return { filename: graphFile, graph, text, lastRun };
|
|
914
751
|
}
|
|
915
752
|
async validateGraph(input) {
|
|
916
753
|
if (input.graph)
|
|
917
754
|
return validateCircuitryGraphWithStandard(input.graph, input.standard);
|
|
918
755
|
const filename = input.filename || defaultFilename;
|
|
919
|
-
const parsed =
|
|
920
|
-
if ("
|
|
756
|
+
const parsed = this.parseSourceGraph(input.text, filename, input.standard);
|
|
757
|
+
if (!("graph" in parsed)) {
|
|
921
758
|
return {
|
|
922
759
|
ok: false,
|
|
923
|
-
errors: [parsed.error],
|
|
760
|
+
errors: parsed.error ? [parsed.error] : [],
|
|
924
761
|
standard: validateCircuitryGraphWithStandard({}, input.standard).standard
|
|
925
762
|
};
|
|
926
763
|
}
|
|
@@ -928,16 +765,13 @@ ${validation.errors.map((e) => e.message).join("\n")}`
|
|
|
928
765
|
}
|
|
929
766
|
async writeGraph(input) {
|
|
930
767
|
const graphFile = this.resolveGraphFile(input.filename);
|
|
931
|
-
const parsed = input.graph ? { graph: input.graph } :
|
|
932
|
-
|
|
933
|
-
input.filename || graphFile,
|
|
934
|
-
input.standard
|
|
935
|
-
);
|
|
936
|
-
if (!parsed.graph)
|
|
768
|
+
const parsed = input.graph ? { graph: input.graph } : this.parseSourceGraph(input.text, input.filename || graphFile, input.standard);
|
|
769
|
+
if (!("graph" in parsed))
|
|
937
770
|
throw new Error(`Invalid Circuitry graph:
|
|
938
771
|
${parsed.error?.message}`);
|
|
772
|
+
const graph = parsed.graph;
|
|
939
773
|
const validation = await this.validateGraph({
|
|
940
|
-
graph
|
|
774
|
+
graph,
|
|
941
775
|
standard: input.standard
|
|
942
776
|
});
|
|
943
777
|
if (validation.errors.length)
|
|
@@ -947,12 +781,12 @@ ${validation.errors.map((e) => e.message).join("\n")}`
|
|
|
947
781
|
);
|
|
948
782
|
await writeFile(
|
|
949
783
|
graphFile,
|
|
950
|
-
stringifyCircuitryText(
|
|
784
|
+
stringifyCircuitryText(graph),
|
|
951
785
|
"utf8"
|
|
952
786
|
);
|
|
953
787
|
return {
|
|
954
788
|
filename: graphFile,
|
|
955
|
-
graph
|
|
789
|
+
graph,
|
|
956
790
|
mode: "replace"
|
|
957
791
|
};
|
|
958
792
|
}
|
|
@@ -986,7 +820,7 @@ ${validation.errors.map((e) => e.message).join("\n")}`
|
|
|
986
820
|
if (source !== "text")
|
|
987
821
|
await writeFile(
|
|
988
822
|
this.runFileFor(graphFile),
|
|
989
|
-
|
|
823
|
+
stringifyYamlData(result),
|
|
990
824
|
"utf8"
|
|
991
825
|
);
|
|
992
826
|
return result;
|
|
@@ -994,5 +828,6 @@ ${validation.errors.map((e) => e.message).join("\n")}`
|
|
|
994
828
|
};
|
|
995
829
|
export {
|
|
996
830
|
NodeCircuitryHost,
|
|
831
|
+
loadCircuitryGraphFile,
|
|
997
832
|
runNodeWithPiSDK
|
|
998
833
|
};
|