@darkhorseprojects/circuitry 0.3.1 → 0.3.3

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/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 YAML from "yaml";
8
+ import YAML2 from "yaml";
9
9
 
10
10
  // src/graph.ts
11
- var CIRCUITRY_SPEC_VERSION = "0.3.1";
12
- var runtimeInputToText = (value) => {
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 executableKindsFromRules = (rules = []) => {
50
- const executableRule = rules.find(
51
- (entry) => typeof entry !== "string" && entry.rule === "require-executable-inputs"
52
- );
53
- return executableRule?.executableKinds;
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,12 +53,7 @@ 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") {
82
58
  const agent = resource;
83
59
  nodes.push({
@@ -87,7 +63,6 @@ var expandResources = (resources) => {
87
63
  agent: {
88
64
  identity: agent.identity || agent.label || id,
89
65
  model: agent.model,
90
- thinkingLevel: agent.thinkingLevel,
91
66
  tools: agent.tools,
92
67
  instructions: agent.instructions,
93
68
  personality: agent.personality,
@@ -96,286 +71,133 @@ var expandResources = (resources) => {
96
71
  skills: agent.skills,
97
72
  expect: agent.expect
98
73
  });
99
- for (const inputRef of agent.inputs || []) {
100
- edges.push({ from: inputRef, to: id, kind: "dependency" });
101
- }
74
+ for (const input of agent.inputs || []) edges.push({ from: input, to: id, kind: "dependency" });
102
75
  } else if (resource.type === "tool") {
103
76
  const tool = resource;
104
- nodes.push({
105
- id,
106
- kind: "tool",
107
- label: tool.label || id,
108
- agent: { instructions: tool.instructions }
109
- });
110
- for (const inputRef of tool.inputs || []) {
111
- edges.push({ from: inputRef, to: id, kind: "dependency" });
112
- }
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" });
113
79
  } else {
114
80
  const input = resource;
115
- nodes.push({
116
- id,
117
- kind: "input",
118
- label: input.label || id,
119
- input: {
120
- type: input.type,
121
- value: input.value,
122
- uri: input.uri || input.path,
123
- mimeType: input.mimeType,
124
- data: input.data
125
- }
126
- });
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 } });
127
82
  }
128
83
  }
129
84
  return { nodes, edges };
130
85
  };
131
86
  var normalizeCircuitryGraph = (graph) => {
132
- if (!graph.resources || Object.keys(graph.resources).length === 0) return { ...graph };
133
- const { nodes, edges } = expandResources(graph.resources);
134
- return { ...graph, nodes, edges };
87
+ if (!graph.resources) return { ...graph };
88
+ return { ...graph, ...expandResources(graph.resources) };
135
89
  };
136
- var VALID_SPEC_VERSIONS = /* @__PURE__ */ new Set([CIRCUITRY_SPEC_VERSION]);
137
- var validateCircuitryGraphInternal = (graph, standard = {}, options) => {
138
- const resolvedStandard = createCircuitryValidationStandard(
139
- standard,
140
- graph && typeof graph === "object" && !Array.isArray(graph) ? graph : void 0
141
- );
90
+ var validateCircuitryGraphInternal = (graph, standard = {}, source) => {
91
+ const resolved = createCircuitryValidationStandard(standard, graph && typeof graph === "object" && !Array.isArray(graph) ? graph : void 0);
142
92
  const errors = [];
143
- const addError = (code, message, path3) => errors.push({ code, message, ...path3 ? { path: path3 } : {} });
144
- if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
145
- addError("invalid_graph", "Circuitry graph must be an object");
146
- return { ok: false, errors, standard: resolvedStandard };
147
- }
148
- const graphObject = graph;
149
- const rules = resolvedStandard.rules;
150
- const hasRule = (name) => rules.some((entry) => (typeof entry === "string" ? entry : entry.rule) === name);
151
- if (resolvedStandard.requireSpecVersion && !VALID_SPEC_VERSIONS.has(String(graphObject.circuitry))) {
152
- addError(
153
- "invalid_spec_version",
154
- `Expected circuitry: "${CIRCUITRY_SPEC_VERSION}"`,
155
- ["circuitry"]
156
- );
157
- }
158
- if (options.sourceFormat) {
159
- if (!graphObject.resources || Object.keys(graphObject.resources).length === 0) {
160
- addError("missing_resources", "Circuitry graphs must use a resources: section", ["resources"]);
161
- }
162
- if (graphObject.agents && Object.keys(graphObject.agents).length > 0) {
163
- addError("forbidden_agents", "Circuitry graph files must not use top-level agents:; use resources:", ["agents"]);
164
- }
165
- if (graphObject.inputs && Object.keys(graphObject.inputs).length > 0) {
166
- addError("forbidden_inputs", "Circuitry graph files use args: for runtime arguments and resource inputs for edges", ["inputs"]);
167
- }
168
- if (graphObject.nodes && graphObject.nodes.length > 0) {
169
- addError("forbidden_nodes", "Circuitry graph files must not use top-level nodes:; use resources:", ["nodes"]);
170
- }
171
- if (graphObject.edges && graphObject.edges.length > 0) {
172
- addError("forbidden_edges", "Circuitry graph files must not use top-level edges:; use resource inputs:", ["edges"]);
173
- }
174
- if (graphObject.links && graphObject.links.length > 0) {
175
- addError("forbidden_links", "Circuitry graph files use imports: for multi-file graphs", ["links"]);
176
- }
177
- }
178
- 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);
179
108
  const ids = /* @__PURE__ */ new Set();
180
109
  for (const [index, node] of (normalized.nodes || []).entries()) {
181
110
  if (!node.id) {
182
- addError("missing_node_id", "Node is missing id", ["nodes", index, "id"]);
111
+ issue("missing_node_id", "missing node id", ["nodes", index, "id"]);
183
112
  continue;
184
113
  }
185
- if (ids.has(node.id)) {
186
- addError("duplicate_node_id", `Duplicate node id: ${node.id}`, ["nodes", index, "id"]);
187
- }
114
+ if (ids.has(node.id)) issue("duplicate_node_id", "duplicate node id", ["nodes", index, "id"]);
188
115
  ids.add(node.id);
189
- if (!node.kind) {
190
- addError("missing_node_kind", `Node ${node.id} is missing kind`, ["nodes", index, "kind"]);
191
- }
116
+ if (!node.kind) issue("missing_node_kind", "missing node kind", ["nodes", index, "kind"]);
192
117
  }
193
118
  const adjacency = /* @__PURE__ */ new Map();
194
- const incomingCount = /* @__PURE__ */ new Map();
119
+ const incoming = /* @__PURE__ */ new Map();
195
120
  for (const id of ids) {
196
121
  adjacency.set(id, []);
197
- incomingCount.set(id, 0);
122
+ incoming.set(id, 0);
198
123
  }
199
124
  for (const [index, edge] of (normalized.edges || []).entries()) {
200
125
  if (!edge.from || !edge.to) {
201
- addError("missing_edge_endpoint", "Edge is missing from/to", ["edges", index]);
126
+ issue("missing_edge_endpoint", "missing edge endpoint", ["edges", index]);
202
127
  continue;
203
128
  }
204
- if (hasRule("no-self-loops") && edge.from === edge.to) {
205
- addError("self_loop", `Edge creates self loop: ${edge.from} -> ${edge.to}`, ["edges", index]);
129
+ if (rules.has("no-self-loops") && edge.from === edge.to) {
130
+ issue("self_loop", "self loop", ["edges", index]);
206
131
  continue;
207
132
  }
208
- if (hasRule("no-unknown-edge-endpoints") && !ids.has(edge.from)) {
209
- addError("unknown_edge_source", `Edge references unknown source: ${edge.from}`, ["edges", index, "from"]);
210
- }
211
- if (hasRule("no-unknown-edge-endpoints") && !ids.has(edge.to)) {
212
- addError("unknown_edge_target", `Edge references unknown target: ${edge.to}`, ["edges", index, "to"]);
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"]);
213
137
  }
214
- if (ids.has(edge.from) && ids.has(edge.to)) {
138
+ if (ok) {
215
139
  adjacency.get(edge.from).push(edge.to);
216
- incomingCount.set(edge.to, (incomingCount.get(edge.to) || 0) + 1);
140
+ incoming.set(edge.to, (incoming.get(edge.to) || 0) + 1);
217
141
  }
218
142
  }
219
- const executableKinds = new Set(resolvedStandard.executableKinds);
220
- if (hasRule("require-executable-inputs")) {
143
+ if (rules.has("require-executable-inputs")) {
144
+ const executable = new Set(resolved.executableKinds);
221
145
  for (const [index, node] of (normalized.nodes || []).entries()) {
222
- if (executableKinds.has(node.kind) && (incomingCount.get(node.id) || 0) === 0) {
223
- addError("executable_without_inputs", `Executable node has no inputs: ${node.id}`, ["nodes", index]);
224
- }
225
- }
226
- }
227
- const visiting = /* @__PURE__ */ new Set();
228
- const visited = /* @__PURE__ */ new Set();
229
- const path2 = [];
230
- let cycleMessage = "";
231
- const visit = (id) => {
232
- if (cycleMessage) return;
233
- if (visiting.has(id)) {
234
- cycleMessage = [...path2.slice(path2.indexOf(id)), id].join(" -> ");
235
- return;
236
- }
237
- if (visited.has(id)) return;
238
- visiting.add(id);
239
- path2.push(id);
240
- for (const next of adjacency.get(id) || []) visit(next);
241
- path2.pop();
242
- visiting.delete(id);
243
- visited.add(id);
244
- };
245
- if (hasRule("no-cycles")) {
246
- for (const id of ids) {
247
- visit(id);
248
- if (cycleMessage) {
249
- addError("cycle", `Graph contains cycle: ${cycleMessage}`);
250
- break;
251
- }
252
- }
253
- }
254
- const additionalRules = rules.filter((rule) => {
255
- if (typeof rule === "string") return false;
256
- return rule.rule === "require-graph-field" || rule.rule === "require-node-field" || rule.rule === "require-edge-field" || rule.rule === "require-string" || rule.rule === "reject-string";
257
- });
258
- const fieldPath = (field) => field.split(".").filter(Boolean);
259
- const getField = (value, field) => fieldPath(field).reduce((current, key) => {
260
- if (!current || typeof current !== "object") return void 0;
261
- return current[key];
262
- }, value);
263
- const isPresent = (value) => value !== void 0 && value !== null && value !== "";
264
- for (const rule of additionalRules) {
265
- if (rule.rule === "require-graph-field") {
266
- if (!isPresent(getField(normalized, rule.field))) {
267
- addError("missing_required_graph_field", `Graph is missing required field: ${rule.field}`, fieldPath(rule.field));
268
- }
269
- continue;
270
- }
271
- if (rule.rule === "require-node-field") {
272
- const nodeKinds = new Set(rule.nodeKinds || []);
273
- for (const [index, node] of (normalized.nodes || []).entries()) {
274
- if (nodeKinds.size > 0 && !nodeKinds.has(node.kind)) continue;
275
- if (!isPresent(getField(node, rule.field))) {
276
- addError("missing_required_node_field", `Node ${node.id || "<missing id>"} is missing required field: ${rule.field}`, ["nodes", index, ...fieldPath(rule.field)]);
277
- }
278
- }
279
- continue;
280
- }
281
- if (rule.rule === "require-edge-field") {
282
- const edgeKinds = new Set(rule.edgeKinds || []);
283
- for (const [index, edge] of (normalized.edges || []).entries()) {
284
- if (edgeKinds.size > 0 && (!edge.kind || !edgeKinds.has(edge.kind))) continue;
285
- if (!isPresent(getField(edge, rule.field))) {
286
- addError("missing_required_edge_field", `Edge ${edge.id || index} is missing required field: ${rule.field}`, ["edges", index, ...fieldPath(rule.field)]);
287
- }
288
- }
289
- continue;
290
- }
291
- const checkString = (target, subject, id, match, path3) => {
292
- const value = getField(subject, match.field);
293
- const text = typeof value === "string" ? value : "";
294
- const includes = text.includes(match.value);
295
- if (rule.rule === "require-string" && !includes) {
296
- addError("missing_required_string", `${target} ${id} field ${match.field} must include string: ${match.value}`, path3);
297
- }
298
- if (rule.rule === "reject-string" && includes) {
299
- addError("rejected_string", `${target} ${id} field ${match.field} must not include string: ${match.value}`, path3);
300
- }
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;
301
160
  };
302
- for (const match of rule.graph || []) checkString("graph", normalized, "<root>", match, fieldPath(match.field));
303
- for (const match of rule.nodes || []) {
304
- const nodeKinds = new Set(match.nodeKinds || []);
305
- for (const [index, node] of (normalized.nodes || []).entries()) {
306
- if (nodeKinds.size > 0 && !nodeKinds.has(node.kind)) continue;
307
- checkString("node", node, node.id || "<missing id>", match, ["nodes", index, ...fieldPath(match.field)]);
308
- }
309
- }
310
- for (const match of rule.edges || []) {
311
- const edgeKinds = new Set(match.edgeKinds || []);
312
- for (const [index, edge] of (normalized.edges || []).entries()) {
313
- if (edgeKinds.size > 0 && (!edge.kind || !edgeKinds.has(edge.kind))) continue;
314
- checkString("edge", edge, edge.id || String(index), match, ["edges", index, ...fieldPath(match.field)]);
315
- }
161
+ for (const id of ids) if (visit(id)) {
162
+ issue("cycle", "cycle");
163
+ break;
316
164
  }
317
165
  }
318
- return { ok: errors.length === 0, errors, standard: resolvedStandard };
319
- };
320
- var validateCircuitryGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, { sourceFormat: true });
321
- var validateCircuitryExecutionGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, { sourceFormat: false });
322
- var validateCircuitryGraph = (graph, standard = {}) => validateCircuitryGraphWithStandard(graph, standard).errors.map(
323
- (error) => error.message
324
- );
325
- var parseCircuitryJson = (text, standard = {}, options = {}) => {
326
- let graph;
327
- try {
328
- graph = JSON.parse(text);
329
- } catch (error) {
330
- const message = error instanceof Error ? error.message : String(error);
331
- throw new Error(`Could not parse Circuitry JSON. Check commas, quotes, and braces.
332
- ${message}`);
333
- }
334
- if (options.validate === false) return graph;
335
- const errors = validateCircuitryGraph(graph, standard);
336
- if (errors.length) {
337
- throw new Error(`Invalid Circuitry graph:
338
- ${errors.join("\n")}`);
339
- }
340
- return normalizeCircuitryGraph(graph);
341
- };
342
- var stringifyCircuitryJson = (graph) => {
343
- return `${JSON.stringify(normalizeCircuitryGraph(graph), null, 2)}
344
- `;
166
+ return { ok: errors.length === 0, errors, standard: resolved };
345
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);
346
171
 
347
172
  // src/yaml.ts
348
- var parseCircuitryYaml = (text, standard = {}, options = {}) => {
349
- let graph;
173
+ var parseYamlData = (text) => {
350
174
  try {
351
- graph = YAML.parse(text);
175
+ return YAML2.parse(text);
352
176
  } catch (error) {
353
177
  const message = error instanceof Error ? error.message : String(error);
354
- throw new Error(`Could not parse Circuitry YAML. Check indentation and quotes.
178
+ throw new Error(`Could not parse YAML.
355
179
  ${message}`);
356
180
  }
181
+ };
182
+ var stringifyYamlData = (value) => YAML2.stringify(value);
183
+ var parseCircuitryYaml = (text, standard = {}, options = {}) => {
184
+ const graph = parseYamlData(text);
357
185
  if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
358
- throw new Error("Could not parse Circuitry YAML. Expected a graph object.");
186
+ throw new Error("Circuitry YAML must be a graph object.");
359
187
  }
360
- if (options.validate === false) return graph;
361
- const errors = validateCircuitryGraph(graph, standard);
362
- if (errors.length) {
363
- 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:
364
191
  ${errors.join("\n")}`);
365
192
  }
366
- return normalizeCircuitryGraph(graph);
367
- };
368
- var stringifyCircuitryYaml = (graph) => {
369
- return YAML.stringify(normalizeCircuitryGraph(graph));
370
- };
371
- var parseCircuitryText = (text, filename = "graph.circuitry.yaml", standard = {}, options = {}) => {
372
- return filename.endsWith(".json") ? parseCircuitryJson(text, standard, options) : parseCircuitryYaml(text, standard, options);
373
- };
374
- var stringifyCircuitryText = (graph, filename = "graph.circuitry.yaml") => {
375
- return filename.endsWith(".json") ? stringifyCircuitryJson(graph) : stringifyCircuitryYaml(graph);
193
+ return graph;
376
194
  };
195
+ var stringifyCircuitryYaml = (graph) => YAML2.stringify(graph);
196
+ var parseCircuitryText = (text, standard = {}, options = {}) => parseCircuitryYaml(text, standard, options);
197
+ var stringifyCircuitryText = (graph) => stringifyCircuitryYaml(graph);
377
198
 
378
199
  // src/scheduler.ts
200
+ import YAML3 from "yaml";
379
201
  var buildCircuitryExecutionGraph = (graph) => {
380
202
  const normalized = normalizeCircuitryGraph(graph);
381
203
  const nodes = /* @__PURE__ */ new Map();
@@ -415,7 +237,7 @@ var formatEdgeData = (data) => {
415
237
  if (!data || Object.keys(data).length === 0) {
416
238
  return "";
417
239
  }
418
- return ` data=${JSON.stringify(data)}`;
240
+ return ` data=${YAML3.stringify(data).trimEnd()}`;
419
241
  };
420
242
  var describeEdge = (edge, direction) => {
421
243
  const otherId = direction === "incoming" ? edge.from : edge.to;
@@ -460,17 +282,17 @@ ${contextSection}`
460
282
  ].filter(Boolean).join("\n\n");
461
283
  };
462
284
  var collectImages = (contextInputs) => contextInputs.filter((item) => item.kind === "image" && item.image).map((item) => item.image);
463
- var stripJsonFence = (output) => {
285
+ var stripYamlFence = (output) => {
464
286
  const trimmed = output.trim();
465
- const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
287
+ const fenced = trimmed.match(/^```(?:ya?ml)?\s*([\s\S]*?)\s*```$/i);
466
288
  return fenced ? fenced[1].trim() : trimmed;
467
289
  };
468
290
  var parseExpectedOutput = (nodeId, output) => {
469
291
  try {
470
- return JSON.parse(stripJsonFence(output));
292
+ return YAML3.parse(stripYamlFence(output));
471
293
  } catch (error) {
472
294
  const detail = error instanceof Error ? error.message : String(error);
473
- throw new Error(`Node ${nodeId} output does not match expect: output is not valid JSON (${detail})`);
295
+ throw new Error(`Node ${nodeId} output does not match expect: output is not valid YAML (${detail})`);
474
296
  }
475
297
  };
476
298
  var isFieldObject = (schema) => !!schema && typeof schema === "object" && !Array.isArray(schema) && typeof schema.type === "string";
@@ -553,7 +375,7 @@ ${errors.join("\n")}`);
553
375
  var executeCircuitryNode = async ({
554
376
  graph,
555
377
  item,
556
- fallbackCycle,
378
+ cycle,
557
379
  inputPayload,
558
380
  contextInputs,
559
381
  defaultModel,
@@ -561,13 +383,13 @@ var executeCircuitryNode = async ({
561
383
  onNodeStart,
562
384
  onNodeComplete
563
385
  }) => {
564
- onNodeStart?.(item.id, fallbackCycle);
386
+ onNodeStart?.(item.id, cycle);
565
387
  if (item.node.kind === "output") {
566
388
  const output = inputPayload.map((input) => input.output).join("\n\n");
567
389
  onNodeComplete?.(item.id, { output });
568
390
  return {
569
391
  nodeId: item.id,
570
- fallbackCycle,
392
+ cycle,
571
393
  inputNodeIds: inputPayload.map((input) => input.nodeId),
572
394
  output
573
395
  };
@@ -579,7 +401,6 @@ var executeCircuitryNode = async ({
579
401
  nodeId: item.id,
580
402
  model: (agent.model === "inherit" ? void 0 : agent.model) || (defaultModel === "inherit" ? void 0 : defaultModel) || "inherit",
581
403
  tools: agent.tools || [],
582
- thinkingLevel: agent.thinkingLevel || "off",
583
404
  personality: agent.personality || "",
584
405
  instructions: agent.instructions || "",
585
406
  context: agent.context || "",
@@ -593,7 +414,7 @@ var executeCircuitryNode = async ({
593
414
  onNodeComplete?.(item.id, { error: message });
594
415
  return {
595
416
  nodeId: item.id,
596
- fallbackCycle,
417
+ cycle,
597
418
  inputNodeIds: inputPayload.map((input) => input.nodeId),
598
419
  output: "",
599
420
  error: message
@@ -603,7 +424,7 @@ var executeCircuitryNode = async ({
603
424
  onNodeComplete?.(item.id, { output: result.output });
604
425
  return {
605
426
  nodeId: item.id,
606
- fallbackCycle,
427
+ cycle,
607
428
  inputNodeIds: inputPayload.map((input) => input.nodeId),
608
429
  output: result.output
609
430
  };
@@ -622,7 +443,7 @@ var runCircuitryGraphExecution = async ({
622
443
  const parallelism = Math.max(1, Math.floor(maxParallelRuns));
623
444
  const defaultModel = graph.runtime?.model;
624
445
  const runOne = async (nodeId, outputs2) => {
625
- const fallbackCycle = false;
446
+ const cycle = false;
626
447
  const item = executionGraph.nodes.get(nodeId);
627
448
  const inputPayload = item.inputNodeIds.filter((sourceId) => outputs2.has(sourceId)).map((sourceId) => ({
628
449
  nodeId: sourceId,
@@ -636,7 +457,7 @@ var runCircuitryGraphExecution = async ({
636
457
  return executeCircuitryNode({
637
458
  graph,
638
459
  item,
639
- fallbackCycle,
460
+ cycle,
640
461
  inputPayload,
641
462
  contextInputs,
642
463
  defaultModel,
@@ -722,7 +543,8 @@ var loadPiSDK = async () => {
722
543
  return await import(modulePath);
723
544
  }
724
545
  }
725
- return await import("@earendil-works/pi-coding-agent");
546
+ const packageName = "@earendil-works/pi-coding-agent";
547
+ return await import(packageName);
726
548
  };
727
549
  var extractAssistantText = (message) => {
728
550
  if (!message || message.role !== "assistant") return "";
@@ -761,8 +583,7 @@ var runNodeWithPiSDK = async ({
761
583
  model,
762
584
  prompt,
763
585
  images = [],
764
- tools = [],
765
- thinkingLevel = "off"
586
+ tools = []
766
587
  }) => {
767
588
  let sdk;
768
589
  try {
@@ -786,7 +607,6 @@ var runNodeWithPiSDK = async ({
786
607
  const selectedModel = requestedModel && requestedModel !== "inherit" ? findRequestedModel(modelRegistry, await modelRegistry.getAvailable(), requestedModel) : void 0;
787
608
  const { session } = await createAgentSession({
788
609
  ...selectedModel ? { model: selectedModel } : {},
789
- thinkingLevel,
790
610
  sessionManager: SessionManager.inMemory(),
791
611
  authStorage,
792
612
  modelRegistry,
@@ -874,7 +694,7 @@ ${validation.errors.map((e) => e.message).join("\n")}`);
874
694
  var loadCircuitryGraphFile = async (filename = defaultFilename, standard, stack = []) => {
875
695
  const graphFile = path.resolve(process.cwd(), filename);
876
696
  const text = await readFile(graphFile, "utf8");
877
- const parsed = parseCircuitryText(text, graphFile, standard, { validate: false });
697
+ const parsed = parseCircuitryText(text, standard, { validate: false });
878
698
  return resolveCircuitryGraph(parsed, graphFile, text, standard, stack);
879
699
  };
880
700
  var NodeCircuitryHost = class {
@@ -885,7 +705,7 @@ var NodeCircuitryHost = class {
885
705
  );
886
706
  }
887
707
  runFileFor(filename) {
888
- return `${filename}.run.json`;
708
+ return `${filename}.run.yaml`;
889
709
  }
890
710
  async exists(filename) {
891
711
  try {
@@ -902,13 +722,9 @@ var NodeCircuitryHost = class {
902
722
  path: [filename]
903
723
  };
904
724
  }
905
- parseGraphForValidation(text, filename, standard) {
725
+ parseSourceGraph(text, filename, standard) {
906
726
  try {
907
- return {
908
- graph: parseCircuitryText(text || "", filename, standard, {
909
- validate: false
910
- })
911
- };
727
+ return { graph: parseCircuitryText(text || "", standard, { validate: false }) };
912
728
  } catch (error) {
913
729
  return { error: this.parseIssue(error, filename) };
914
730
  }
@@ -917,7 +733,7 @@ var NodeCircuitryHost = class {
917
733
  try {
918
734
  const graphFile = path.resolve(process.cwd(), filename);
919
735
  const source = text || "";
920
- const parsed = parseCircuitryText(source, graphFile, standard, { validate: false });
736
+ const parsed = parseCircuitryText(source, standard, { validate: false });
921
737
  return { graph: (await resolveCircuitryGraph(parsed, graphFile, source, standard)).graph };
922
738
  } catch (error) {
923
739
  return { error: this.parseIssue(error, filename) };
@@ -930,14 +746,14 @@ var NodeCircuitryHost = class {
930
746
  async readGraph(input = {}) {
931
747
  const { graphFile, text, graph } = await this.readGraphFile(input.filename);
932
748
  const lastRunFile = this.runFileFor(graphFile);
933
- const lastRun = await this.exists(lastRunFile) ? JSON.parse(await readFile(lastRunFile, "utf8")) : void 0;
749
+ const lastRun = await this.exists(lastRunFile) ? parseYamlData(await readFile(lastRunFile, "utf8")) : void 0;
934
750
  return { filename: graphFile, graph, text, lastRun };
935
751
  }
936
752
  async validateGraph(input) {
937
753
  if (input.graph)
938
754
  return validateCircuitryGraphWithStandard(input.graph, input.standard);
939
755
  const filename = input.filename || defaultFilename;
940
- const parsed = await this.parseAndResolveGraph(input.text, filename, input.standard);
756
+ const parsed = this.parseSourceGraph(input.text, filename, input.standard);
941
757
  if (!("graph" in parsed)) {
942
758
  return {
943
759
  ok: false,
@@ -949,11 +765,7 @@ var NodeCircuitryHost = class {
949
765
  }
950
766
  async writeGraph(input) {
951
767
  const graphFile = this.resolveGraphFile(input.filename);
952
- const parsed = input.graph ? { graph: input.graph } : await this.parseAndResolveGraph(
953
- input.text,
954
- input.filename || graphFile,
955
- input.standard
956
- );
768
+ const parsed = input.graph ? { graph: input.graph } : this.parseSourceGraph(input.text, input.filename || graphFile, input.standard);
957
769
  if (!("graph" in parsed))
958
770
  throw new Error(`Invalid Circuitry graph:
959
771
  ${parsed.error?.message}`);
@@ -969,7 +781,7 @@ ${validation.errors.map((e) => e.message).join("\n")}`
969
781
  );
970
782
  await writeFile(
971
783
  graphFile,
972
- stringifyCircuitryText(graph, graphFile),
784
+ stringifyCircuitryText(graph),
973
785
  "utf8"
974
786
  );
975
787
  return {
@@ -1008,7 +820,7 @@ ${validation.errors.map((e) => e.message).join("\n")}`
1008
820
  if (source !== "text")
1009
821
  await writeFile(
1010
822
  this.runFileFor(graphFile),
1011
- JSON.stringify(result, null, 2),
823
+ stringifyYamlData(result),
1012
824
  "utf8"
1013
825
  );
1014
826
  return result;