@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/index.js CHANGED
@@ -7,9 +7,8 @@ var createDefaultNodeData = (label) => {
7
7
  kind: CIRCUITRY_NODE_KIND,
8
8
  identity,
9
9
  label: identity,
10
- model: "github-copilot/claude-haiku-4.5",
10
+ model: "inherit",
11
11
  tools: [],
12
- thinkingLevel: "off",
13
12
  personality: "",
14
13
  instructions: "Define this agent's behavior and objective.",
15
14
  context: "",
@@ -27,32 +26,8 @@ var isNodeElement = (element) => {
27
26
  };
28
27
 
29
28
  // src/graph.ts
30
- var CIRCUITRY_SPEC_VERSION = "0.3.0";
31
- var runtimeInputToText = (value) => {
32
- if (typeof value === "string") return value;
33
- if (value === void 0) return "";
34
- return JSON.stringify(value, null, 2);
35
- };
36
- var applyCircuitryRuntimeInputs = (graph, inputs = {}) => {
37
- const entries = Object.entries(inputs);
38
- if (entries.length === 0) return graph;
39
- const next = {
40
- ...graph,
41
- resources: graph.resources ? { ...graph.resources } : graph.resources
42
- };
43
- for (const [id, value] of entries) {
44
- const text = runtimeInputToText(value);
45
- const resource = next.resources?.[id];
46
- if (resource) {
47
- if (resource.type !== "text")
48
- throw new Error(`Runtime input ${id} targets non-text resource: ${resource.type}`);
49
- next.resources[id] = { ...resource, value: text };
50
- continue;
51
- }
52
- throw new Error(`Runtime input does not match a graph text resource: ${id}`);
53
- }
54
- return next;
55
- };
29
+ import YAML from "yaml";
30
+ var CIRCUITRY_SPEC_VERSION = "0.3.2";
56
31
  var DEFAULT_CIRCUITRY_VALIDATION_RULES = [
57
32
  "no-self-loops",
58
33
  "no-unknown-edge-endpoints",
@@ -65,25 +40,30 @@ var DEFAULT_CIRCUITRY_VALIDATION_STANDARD = {
65
40
  rules: DEFAULT_CIRCUITRY_VALIDATION_RULES,
66
41
  executableKinds: ["agent", "tool", "output"]
67
42
  };
68
- var executableKindsFromRules = (rules = []) => {
69
- const executableRule = rules.find(
70
- (entry) => typeof entry !== "string" && entry.rule === "require-executable-inputs"
71
- );
72
- return executableRule?.executableKinds;
43
+ var runtimeInputToText = (value) => {
44
+ if (typeof value === "string") return value;
45
+ if (value === void 0) return "";
46
+ return YAML.stringify(value).trimEnd();
73
47
  };
48
+ var applyCircuitryRuntimeInputs = (graph, inputs = {}) => {
49
+ const next = { ...graph, resources: graph.resources ? { ...graph.resources } : graph.resources };
50
+ for (const [id, value] of Object.entries(inputs)) {
51
+ const resource = next.resources?.[id];
52
+ if (!resource) throw new Error(`unknown arg: ${id}`);
53
+ if (resource.type !== "text") throw new Error(`arg is not text: ${id}`);
54
+ next.resources[id] = { ...resource, value: runtimeInputToText(value) };
55
+ }
56
+ return next;
57
+ };
58
+ var ruleName = (rule) => typeof rule === "string" ? rule : rule.rule;
59
+ var executableKindsFromRules = (rules) => rules.find((rule) => typeof rule !== "string" && rule.rule === "require-executable-inputs")?.executableKinds;
74
60
  var createCircuitryValidationStandard = (standard = {}, graph) => {
75
- const rules = [
76
- ...DEFAULT_CIRCUITRY_VALIDATION_RULES,
77
- ...graph?.validation?.rules || [],
78
- ...standard.rules || []
79
- ];
61
+ const rules = [...DEFAULT_CIRCUITRY_VALIDATION_RULES, ...graph?.validation?.rules || [], ...standard.rules || []];
80
62
  return {
81
63
  version: standard.version || DEFAULT_CIRCUITRY_VALIDATION_STANDARD.version,
82
64
  requireSpecVersion: standard.requireSpecVersion ?? DEFAULT_CIRCUITRY_VALIDATION_STANDARD.requireSpecVersion,
83
65
  rules,
84
- executableKinds: standard.executableKinds || executableKindsFromRules(rules) || [
85
- ...DEFAULT_CIRCUITRY_VALIDATION_STANDARD.executableKinds
86
- ]
66
+ executableKinds: standard.executableKinds || executableKindsFromRules(rules) || [...DEFAULT_CIRCUITRY_VALIDATION_STANDARD.executableKinds]
87
67
  };
88
68
  };
89
69
  var expandResources = (resources) => {
@@ -91,296 +71,150 @@ var expandResources = (resources) => {
91
71
  const edges = [];
92
72
  for (const [id, resource] of Object.entries(resources)) {
93
73
  if (resource.type === "text") {
94
- nodes.push({
95
- id,
96
- kind: "input",
97
- label: resource.label || id,
98
- input: { type: "text", value: resource.value }
99
- });
74
+ nodes.push({ id, kind: "input", label: resource.label || id, input: { type: "text", value: resource.value } });
100
75
  } else if (resource.type === "agent") {
76
+ const agent = resource;
101
77
  nodes.push({
102
78
  id,
103
79
  kind: "agent",
104
- label: resource.label || resource.identity || id,
80
+ label: agent.label || agent.identity || id,
105
81
  agent: {
106
- identity: resource.identity || resource.label || id,
107
- model: resource.model,
108
- thinkingLevel: resource.thinkingLevel,
109
- tools: resource.tools,
110
- instructions: resource.instructions,
111
- personality: resource.personality,
112
- context: resource.context
82
+ identity: agent.identity || agent.label || id,
83
+ model: agent.model,
84
+ tools: agent.tools,
85
+ instructions: agent.instructions,
86
+ personality: agent.personality,
87
+ context: agent.context
113
88
  },
114
- skills: resource.skills,
115
- expect: resource.expect
89
+ skills: agent.skills,
90
+ expect: agent.expect
116
91
  });
117
- for (const inputRef of resource.inputs || []) {
118
- edges.push({ from: inputRef, to: id, kind: "dependency" });
119
- }
92
+ for (const input of agent.inputs || []) edges.push({ from: input, to: id, kind: "dependency" });
120
93
  } else if (resource.type === "tool") {
121
- nodes.push({
122
- id,
123
- kind: "tool",
124
- label: resource.label || id,
125
- agent: { instructions: resource.instructions }
126
- });
127
- for (const inputRef of resource.inputs || []) {
128
- edges.push({ from: inputRef, to: id, kind: "dependency" });
129
- }
94
+ const tool = resource;
95
+ nodes.push({ id, kind: "tool", label: tool.label || id, agent: { instructions: tool.instructions } });
96
+ for (const input of tool.inputs || []) edges.push({ from: input, to: id, kind: "dependency" });
97
+ } else {
98
+ const input = resource;
99
+ 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 } });
130
100
  }
131
101
  }
132
102
  return { nodes, edges };
133
103
  };
134
104
  var normalizeCircuitryGraph = (graph) => {
135
- if (!graph.resources || Object.keys(graph.resources).length === 0) return { ...graph };
136
- const { nodes, edges } = expandResources(graph.resources);
137
- return { ...graph, nodes, edges };
105
+ if (!graph.resources) return { ...graph };
106
+ return { ...graph, ...expandResources(graph.resources) };
138
107
  };
139
- var VALID_SPEC_VERSIONS = /* @__PURE__ */ new Set(["0.3"]);
140
- var validateCircuitryGraphInternal = (graph, standard = {}, options) => {
141
- const resolvedStandard = createCircuitryValidationStandard(
142
- standard,
143
- graph && typeof graph === "object" && !Array.isArray(graph) ? graph : void 0
144
- );
108
+ var validateCircuitryGraphInternal = (graph, standard = {}, source) => {
109
+ const resolved = createCircuitryValidationStandard(standard, graph && typeof graph === "object" && !Array.isArray(graph) ? graph : void 0);
145
110
  const errors = [];
146
- const addError = (code, message, path2) => errors.push({ code, message, ...path2 ? { path: path2 } : {} });
147
- if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
148
- addError("invalid_graph", "Circuitry graph must be an object");
149
- return { ok: false, errors, standard: resolvedStandard };
111
+ const issue = (code, message = code, path) => errors.push({ code, message, ...path ? { path } : {} });
112
+ if (!graph || typeof graph !== "object" || Array.isArray(graph)) return { ok: false, errors: [{ code: "invalid_graph", message: "invalid graph" }], standard: resolved };
113
+ const g = graph;
114
+ if (resolved.requireSpecVersion && g.circuitry !== resolved.version) issue("invalid_version", "invalid version", ["circuitry"]);
115
+ if (source) {
116
+ const raw = g;
117
+ if (!g.resources || Object.keys(g.resources).length === 0) issue("missing_resources", "missing resources", ["resources"]);
118
+ if (raw.agents) issue("forbidden_agents", "forbidden agents", ["agents"]);
119
+ if (raw.inputs) issue("forbidden_inputs", "forbidden inputs", ["inputs"]);
120
+ if (g.nodes?.length) issue("forbidden_nodes", "forbidden nodes", ["nodes"]);
121
+ if (g.edges?.length) issue("forbidden_edges", "forbidden edges", ["edges"]);
122
+ if (raw.links) issue("forbidden_links", "forbidden links", ["links"]);
150
123
  }
151
- const graphObject = graph;
152
- const rules = resolvedStandard.rules;
153
- const hasRule = (name) => rules.some((entry) => (typeof entry === "string" ? entry : entry.rule) === name);
154
- if (resolvedStandard.requireSpecVersion && !VALID_SPEC_VERSIONS.has(String(graphObject.circuitry))) {
155
- addError(
156
- "invalid_spec_version",
157
- `Expected circuitry: "${CIRCUITRY_SPEC_VERSION}"`,
158
- ["circuitry"]
159
- );
160
- }
161
- if (options.sourceFormat) {
162
- if (!graphObject.resources || Object.keys(graphObject.resources).length === 0) {
163
- addError("missing_resources", "Circuitry v0.3 graphs must use a resources: section", ["resources"]);
164
- }
165
- if (graphObject.agents && Object.keys(graphObject.agents).length > 0) {
166
- addError("forbidden_agents", "Circuitry v0.3 graph files must not use top-level agents:; use resources:", ["agents"]);
167
- }
168
- if (graphObject.inputs && Object.keys(graphObject.inputs).length > 0) {
169
- addError("forbidden_inputs", "Circuitry v0.3 graph files must not use top-level inputs:; use resources:", ["inputs"]);
170
- }
171
- if (graphObject.nodes && graphObject.nodes.length > 0) {
172
- addError("forbidden_nodes", "Circuitry v0.3 graph files must not use top-level nodes:; use resources:", ["nodes"]);
173
- }
174
- if (graphObject.edges && graphObject.edges.length > 0) {
175
- addError("forbidden_edges", "Circuitry v0.3 graph files must not use top-level edges:; use resource inputs:", ["edges"]);
176
- }
177
- if (graphObject.links && graphObject.links.length > 0) {
178
- addError("forbidden_links", "Circuitry v0.3 graph files must use imports: instead of links:", ["links"]);
179
- }
180
- }
181
- const normalized = normalizeCircuitryGraph(graphObject);
124
+ const rules = new Set(resolved.rules.map(ruleName));
125
+ const normalized = normalizeCircuitryGraph(g);
182
126
  const ids = /* @__PURE__ */ new Set();
183
127
  for (const [index, node] of (normalized.nodes || []).entries()) {
184
128
  if (!node.id) {
185
- addError("missing_node_id", "Node is missing id", ["nodes", index, "id"]);
129
+ issue("missing_node_id", "missing node id", ["nodes", index, "id"]);
186
130
  continue;
187
131
  }
188
- if (ids.has(node.id)) {
189
- addError("duplicate_node_id", `Duplicate node id: ${node.id}`, ["nodes", index, "id"]);
190
- }
132
+ if (ids.has(node.id)) issue("duplicate_node_id", "duplicate node id", ["nodes", index, "id"]);
191
133
  ids.add(node.id);
192
- if (!node.kind) {
193
- addError("missing_node_kind", `Node ${node.id} is missing kind`, ["nodes", index, "kind"]);
194
- }
134
+ if (!node.kind) issue("missing_node_kind", "missing node kind", ["nodes", index, "kind"]);
195
135
  }
196
136
  const adjacency = /* @__PURE__ */ new Map();
197
- const incomingCount = /* @__PURE__ */ new Map();
137
+ const incoming = /* @__PURE__ */ new Map();
198
138
  for (const id of ids) {
199
139
  adjacency.set(id, []);
200
- incomingCount.set(id, 0);
140
+ incoming.set(id, 0);
201
141
  }
202
142
  for (const [index, edge] of (normalized.edges || []).entries()) {
203
143
  if (!edge.from || !edge.to) {
204
- addError("missing_edge_endpoint", "Edge is missing from/to", ["edges", index]);
144
+ issue("missing_edge_endpoint", "missing edge endpoint", ["edges", index]);
205
145
  continue;
206
146
  }
207
- if (hasRule("no-self-loops") && edge.from === edge.to) {
208
- addError("self_loop", `Edge creates self loop: ${edge.from} -> ${edge.to}`, ["edges", index]);
147
+ if (rules.has("no-self-loops") && edge.from === edge.to) {
148
+ issue("self_loop", "self loop", ["edges", index]);
209
149
  continue;
210
150
  }
211
- if (hasRule("no-unknown-edge-endpoints") && !ids.has(edge.from)) {
212
- addError("unknown_edge_source", `Edge references unknown source: ${edge.from}`, ["edges", index, "from"]);
151
+ const ok = ids.has(edge.from) && ids.has(edge.to);
152
+ if (rules.has("no-unknown-edge-endpoints")) {
153
+ if (!ids.has(edge.from)) issue("unknown_edge_source", "unknown edge source", ["edges", index, "from"]);
154
+ if (!ids.has(edge.to)) issue("unknown_edge_target", "unknown edge target", ["edges", index, "to"]);
213
155
  }
214
- if (hasRule("no-unknown-edge-endpoints") && !ids.has(edge.to)) {
215
- addError("unknown_edge_target", `Edge references unknown target: ${edge.to}`, ["edges", index, "to"]);
216
- }
217
- if (ids.has(edge.from) && ids.has(edge.to)) {
156
+ if (ok) {
218
157
  adjacency.get(edge.from).push(edge.to);
219
- incomingCount.set(edge.to, (incomingCount.get(edge.to) || 0) + 1);
158
+ incoming.set(edge.to, (incoming.get(edge.to) || 0) + 1);
220
159
  }
221
160
  }
222
- const executableKinds = new Set(resolvedStandard.executableKinds);
223
- if (hasRule("require-executable-inputs")) {
161
+ if (rules.has("require-executable-inputs")) {
162
+ const executable = new Set(resolved.executableKinds);
224
163
  for (const [index, node] of (normalized.nodes || []).entries()) {
225
- if (executableKinds.has(node.kind) && (incomingCount.get(node.id) || 0) === 0) {
226
- addError("executable_without_inputs", `Executable node has no inputs: ${node.id}`, ["nodes", index]);
227
- }
164
+ if (executable.has(node.kind) && (incoming.get(node.id) || 0) === 0) issue("missing_executable_input", "missing executable input", ["nodes", index]);
228
165
  }
229
166
  }
230
- const visiting = /* @__PURE__ */ new Set();
231
- const visited = /* @__PURE__ */ new Set();
232
- const path = [];
233
- let cycleMessage = "";
234
- const visit = (id) => {
235
- if (cycleMessage) return;
236
- if (visiting.has(id)) {
237
- cycleMessage = [...path.slice(path.indexOf(id)), id].join(" -> ");
238
- return;
239
- }
240
- if (visited.has(id)) return;
241
- visiting.add(id);
242
- path.push(id);
243
- for (const next of adjacency.get(id) || []) visit(next);
244
- path.pop();
245
- visiting.delete(id);
246
- visited.add(id);
247
- };
248
- if (hasRule("no-cycles")) {
249
- for (const id of ids) {
250
- visit(id);
251
- if (cycleMessage) {
252
- addError("cycle", `Graph contains cycle: ${cycleMessage}`);
253
- break;
254
- }
255
- }
256
- }
257
- const additionalRules = rules.filter((rule) => {
258
- if (typeof rule === "string") return false;
259
- return rule.rule === "require-graph-field" || rule.rule === "require-node-field" || rule.rule === "require-edge-field" || rule.rule === "require-string" || rule.rule === "reject-string";
260
- });
261
- const fieldPath = (field) => field.split(".").filter(Boolean);
262
- const getField = (value, field) => fieldPath(field).reduce((current, key) => {
263
- if (!current || typeof current !== "object") return void 0;
264
- return current[key];
265
- }, value);
266
- const isPresent = (value) => value !== void 0 && value !== null && value !== "";
267
- for (const rule of additionalRules) {
268
- if (rule.rule === "require-graph-field") {
269
- if (!isPresent(getField(normalized, rule.field))) {
270
- addError("missing_required_graph_field", `Graph is missing required field: ${rule.field}`, fieldPath(rule.field));
271
- }
272
- continue;
273
- }
274
- if (rule.rule === "require-node-field") {
275
- const nodeKinds = new Set(rule.nodeKinds || []);
276
- for (const [index, node] of (normalized.nodes || []).entries()) {
277
- if (nodeKinds.size > 0 && !nodeKinds.has(node.kind)) continue;
278
- if (!isPresent(getField(node, rule.field))) {
279
- addError("missing_required_node_field", `Node ${node.id || "<missing id>"} is missing required field: ${rule.field}`, ["nodes", index, ...fieldPath(rule.field)]);
280
- }
281
- }
282
- continue;
283
- }
284
- if (rule.rule === "require-edge-field") {
285
- const edgeKinds = new Set(rule.edgeKinds || []);
286
- for (const [index, edge] of (normalized.edges || []).entries()) {
287
- if (edgeKinds.size > 0 && (!edge.kind || !edgeKinds.has(edge.kind))) continue;
288
- if (!isPresent(getField(edge, rule.field))) {
289
- addError("missing_required_edge_field", `Edge ${edge.id || index} is missing required field: ${rule.field}`, ["edges", index, ...fieldPath(rule.field)]);
290
- }
291
- }
292
- continue;
293
- }
294
- const checkString = (target, subject, id, match, path2) => {
295
- const value = getField(subject, match.field);
296
- const text = typeof value === "string" ? value : "";
297
- const includes = text.includes(match.value);
298
- if (rule.rule === "require-string" && !includes) {
299
- addError("missing_required_string", `${target} ${id} field ${match.field} must include string: ${match.value}`, path2);
300
- }
301
- if (rule.rule === "reject-string" && includes) {
302
- addError("rejected_string", `${target} ${id} field ${match.field} must not include string: ${match.value}`, path2);
303
- }
167
+ if (rules.has("no-cycles")) {
168
+ const visiting = /* @__PURE__ */ new Set();
169
+ const visited = /* @__PURE__ */ new Set();
170
+ const visit = (id) => {
171
+ if (visiting.has(id)) return true;
172
+ if (visited.has(id)) return false;
173
+ visiting.add(id);
174
+ for (const next of adjacency.get(id) || []) if (visit(next)) return true;
175
+ visiting.delete(id);
176
+ visited.add(id);
177
+ return false;
304
178
  };
305
- for (const match of rule.graph || []) checkString("graph", normalized, "<root>", match, fieldPath(match.field));
306
- for (const match of rule.nodes || []) {
307
- const nodeKinds = new Set(match.nodeKinds || []);
308
- for (const [index, node] of (normalized.nodes || []).entries()) {
309
- if (nodeKinds.size > 0 && !nodeKinds.has(node.kind)) continue;
310
- checkString("node", node, node.id || "<missing id>", match, ["nodes", index, ...fieldPath(match.field)]);
311
- }
179
+ for (const id of ids) if (visit(id)) {
180
+ issue("cycle", "cycle");
181
+ break;
312
182
  }
313
- for (const match of rule.edges || []) {
314
- const edgeKinds = new Set(match.edgeKinds || []);
315
- for (const [index, edge] of (normalized.edges || []).entries()) {
316
- if (edgeKinds.size > 0 && (!edge.kind || !edgeKinds.has(edge.kind))) continue;
317
- checkString("edge", edge, edge.id || String(index), match, ["edges", index, ...fieldPath(match.field)]);
318
- }
319
- }
320
- }
321
- return { ok: errors.length === 0, errors, standard: resolvedStandard };
322
- };
323
- var validateCircuitryGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, { sourceFormat: true });
324
- var validateCircuitryExecutionGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, { sourceFormat: false });
325
- var validateCircuitryGraph = (graph, standard = {}) => validateCircuitryGraphWithStandard(graph, standard).errors.map(
326
- (error) => error.message
327
- );
328
- var parseCircuitryJson = (text, standard = {}, options = {}) => {
329
- let graph;
330
- try {
331
- graph = JSON.parse(text);
332
- } catch (error) {
333
- const message = error instanceof Error ? error.message : String(error);
334
- throw new Error(`Could not parse Circuitry JSON. Check commas, quotes, and braces.
335
- ${message}`);
336
- }
337
- if (options.validate === false) return graph;
338
- const errors = validateCircuitryGraph(graph, standard);
339
- if (errors.length) {
340
- throw new Error(`Invalid Circuitry graph:
341
- ${errors.join("\n")}`);
342
183
  }
343
- return normalizeCircuitryGraph(graph);
344
- };
345
- var stringifyCircuitryJson = (graph) => {
346
- return `${JSON.stringify(normalizeCircuitryGraph(graph), null, 2)}
347
- `;
348
- };
349
- var isUriInput = (input) => {
350
- return Boolean(input.uri || ["file", "url", "uri", "image", "mcp"].includes(input.type));
184
+ return { ok: errors.length === 0, errors, standard: resolved };
351
185
  };
186
+ var validateCircuitryGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, true);
187
+ var validateCircuitryExecutionGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, false);
188
+ var validateCircuitryGraph = (graph, standard = {}) => validateCircuitryGraphWithStandard(graph, standard).errors.map((error) => error.message);
189
+ var isUriInput = (input) => Boolean(input.uri || ["file", "url", "uri", "image", "mcp"].includes(input.type));
352
190
 
353
191
  // src/yaml.ts
354
- import YAML from "yaml";
355
- var parseCircuitryYaml = (text, standard = {}, options = {}) => {
356
- let graph;
192
+ import YAML2 from "yaml";
193
+ var parseYamlData = (text) => {
357
194
  try {
358
- graph = YAML.parse(text);
195
+ return YAML2.parse(text);
359
196
  } catch (error) {
360
197
  const message = error instanceof Error ? error.message : String(error);
361
- throw new Error(`Could not parse Circuitry YAML. Check indentation and quotes.
198
+ throw new Error(`Could not parse YAML.
362
199
  ${message}`);
363
200
  }
201
+ };
202
+ var stringifyYamlData = (value) => YAML2.stringify(value);
203
+ var parseCircuitryYaml = (text, standard = {}, options = {}) => {
204
+ const graph = parseYamlData(text);
364
205
  if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
365
- throw new Error("Could not parse Circuitry YAML. Expected a graph object.");
206
+ throw new Error("Circuitry YAML must be a graph object.");
366
207
  }
367
- if (options.validate === false) return graph;
368
- const errors = validateCircuitryGraph(graph, standard);
369
- if (errors.length) {
370
- throw new Error(`Invalid Circuitry graph:
208
+ if (options.validate !== false) {
209
+ const errors = validateCircuitryGraph(graph, standard);
210
+ if (errors.length) throw new Error(`Invalid Circuitry graph:
371
211
  ${errors.join("\n")}`);
372
212
  }
373
- return normalizeCircuitryGraph(graph);
374
- };
375
- var stringifyCircuitryYaml = (graph) => {
376
- return YAML.stringify(normalizeCircuitryGraph(graph));
377
- };
378
- var parseCircuitryText = (text, filename = "graph.circuitry.yaml", standard = {}, options = {}) => {
379
- return filename.endsWith(".json") ? parseCircuitryJson(text, standard, options) : parseCircuitryYaml(text, standard, options);
380
- };
381
- var stringifyCircuitryText = (graph, filename = "graph.circuitry.yaml") => {
382
- return filename.endsWith(".json") ? stringifyCircuitryJson(graph) : stringifyCircuitryYaml(graph);
213
+ return graph;
383
214
  };
215
+ var stringifyCircuitryYaml = (graph) => YAML2.stringify(graph);
216
+ var parseCircuitryText = (text, standard = {}, options = {}) => parseCircuitryYaml(text, standard, options);
217
+ var stringifyCircuitryText = (graph) => stringifyCircuitryYaml(graph);
384
218
 
385
219
  // src/presets.ts
386
220
  var CIRCUITRY_AGENT_PRESET_DIRS = [
@@ -389,11 +223,11 @@ var CIRCUITRY_AGENT_PRESET_DIRS = [
389
223
  "~/.agents/agents",
390
224
  "~/.circuitry/agents"
391
225
  ];
392
- var parseAgentPresetMarkdown = (text, fallbackName) => {
226
+ var parseAgentPresetMarkdown = (text, defaultName) => {
393
227
  const frontmatter = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/m.exec(text);
394
228
  if (!frontmatter) {
395
229
  return {
396
- name: fallbackName,
230
+ name: defaultName,
397
231
  instructions: text.trim()
398
232
  };
399
233
  }
@@ -405,7 +239,7 @@ var parseAgentPresetMarkdown = (text, fallbackName) => {
405
239
  }
406
240
  }
407
241
  return {
408
- name: metadata.name || fallbackName,
242
+ name: metadata.name || defaultName,
409
243
  description: metadata.description,
410
244
  model: metadata.model,
411
245
  personality: metadata.personality,
@@ -438,6 +272,7 @@ var applyAgentPresets = (graph, presets) => {
438
272
  };
439
273
 
440
274
  // src/scheduler.ts
275
+ import YAML3 from "yaml";
441
276
  var buildCircuitryExecutionGraph = (graph) => {
442
277
  const normalized = normalizeCircuitryGraph(graph);
443
278
  const nodes = /* @__PURE__ */ new Map();
@@ -477,7 +312,7 @@ var formatEdgeData = (data) => {
477
312
  if (!data || Object.keys(data).length === 0) {
478
313
  return "";
479
314
  }
480
- return ` data=${JSON.stringify(data)}`;
315
+ return ` data=${YAML3.stringify(data).trimEnd()}`;
481
316
  };
482
317
  var describeEdge = (edge, direction) => {
483
318
  const otherId = direction === "incoming" ? edge.from : edge.to;
@@ -522,17 +357,17 @@ ${contextSection}`
522
357
  ].filter(Boolean).join("\n\n");
523
358
  };
524
359
  var collectImages = (contextInputs) => contextInputs.filter((item) => item.kind === "image" && item.image).map((item) => item.image);
525
- var stripJsonFence = (output) => {
360
+ var stripYamlFence = (output) => {
526
361
  const trimmed = output.trim();
527
- const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
362
+ const fenced = trimmed.match(/^```(?:ya?ml)?\s*([\s\S]*?)\s*```$/i);
528
363
  return fenced ? fenced[1].trim() : trimmed;
529
364
  };
530
365
  var parseExpectedOutput = (nodeId, output) => {
531
366
  try {
532
- return JSON.parse(stripJsonFence(output));
367
+ return YAML3.parse(stripYamlFence(output));
533
368
  } catch (error) {
534
369
  const detail = error instanceof Error ? error.message : String(error);
535
- throw new Error(`Node ${nodeId} output does not match expect: output is not valid JSON (${detail})`);
370
+ throw new Error(`Node ${nodeId} output does not match expect: output is not valid YAML (${detail})`);
536
371
  }
537
372
  };
538
373
  var isFieldObject = (schema) => !!schema && typeof schema === "object" && !Array.isArray(schema) && typeof schema.type === "string";
@@ -615,7 +450,7 @@ ${errors.join("\n")}`);
615
450
  var executeCircuitryNode = async ({
616
451
  graph,
617
452
  item,
618
- fallbackCycle,
453
+ cycle,
619
454
  inputPayload,
620
455
  contextInputs,
621
456
  defaultModel,
@@ -623,13 +458,13 @@ var executeCircuitryNode = async ({
623
458
  onNodeStart,
624
459
  onNodeComplete
625
460
  }) => {
626
- onNodeStart?.(item.id, fallbackCycle);
461
+ onNodeStart?.(item.id, cycle);
627
462
  if (item.node.kind === "output") {
628
463
  const output = inputPayload.map((input) => input.output).join("\n\n");
629
464
  onNodeComplete?.(item.id, { output });
630
465
  return {
631
466
  nodeId: item.id,
632
- fallbackCycle,
467
+ cycle,
633
468
  inputNodeIds: inputPayload.map((input) => input.nodeId),
634
469
  output
635
470
  };
@@ -641,7 +476,6 @@ var executeCircuitryNode = async ({
641
476
  nodeId: item.id,
642
477
  model: (agent.model === "inherit" ? void 0 : agent.model) || (defaultModel === "inherit" ? void 0 : defaultModel) || "inherit",
643
478
  tools: agent.tools || [],
644
- thinkingLevel: agent.thinkingLevel || "off",
645
479
  personality: agent.personality || "",
646
480
  instructions: agent.instructions || "",
647
481
  context: agent.context || "",
@@ -655,7 +489,7 @@ var executeCircuitryNode = async ({
655
489
  onNodeComplete?.(item.id, { error: message });
656
490
  return {
657
491
  nodeId: item.id,
658
- fallbackCycle,
492
+ cycle,
659
493
  inputNodeIds: inputPayload.map((input) => input.nodeId),
660
494
  output: "",
661
495
  error: message
@@ -665,7 +499,7 @@ var executeCircuitryNode = async ({
665
499
  onNodeComplete?.(item.id, { output: result.output });
666
500
  return {
667
501
  nodeId: item.id,
668
- fallbackCycle,
502
+ cycle,
669
503
  inputNodeIds: inputPayload.map((input) => input.nodeId),
670
504
  output: result.output
671
505
  };
@@ -684,7 +518,7 @@ var runCircuitryGraphExecution = async ({
684
518
  const parallelism = Math.max(1, Math.floor(maxParallelRuns));
685
519
  const defaultModel = graph.runtime?.model;
686
520
  const runOne = async (nodeId, outputs2) => {
687
- const fallbackCycle = false;
521
+ const cycle = false;
688
522
  const item = executionGraph.nodes.get(nodeId);
689
523
  const inputPayload = item.inputNodeIds.filter((sourceId) => outputs2.has(sourceId)).map((sourceId) => ({
690
524
  nodeId: sourceId,
@@ -698,7 +532,7 @@ var runCircuitryGraphExecution = async ({
698
532
  return executeCircuitryNode({
699
533
  graph,
700
534
  item,
701
- fallbackCycle,
535
+ cycle,
702
536
  inputPayload,
703
537
  contextInputs,
704
538
  defaultModel,
@@ -853,20 +687,19 @@ var collectImages2 = (contextInputs) => {
853
687
  };
854
688
  var executeSimulationNode = async ({
855
689
  node,
856
- fallbackCycle,
690
+ cycle,
857
691
  inputPayload,
858
692
  contextInputs,
859
693
  executeNode,
860
694
  onNodeStart,
861
695
  onNodeComplete
862
696
  }) => {
863
- onNodeStart?.(node.id, fallbackCycle);
697
+ onNodeStart?.(node.id, cycle);
864
698
  try {
865
699
  const result = await executeNode({
866
700
  nodeId: node.id,
867
701
  model: node.data.model === "inherit" ? "inherit" : node.data.model || "inherit",
868
702
  tools: node.data.tools || [],
869
- thinkingLevel: node.data.thinkingLevel || "off",
870
703
  personality: node.data.personality,
871
704
  instructions: node.data.instructions,
872
705
  context: node.data.context,
@@ -877,7 +710,7 @@ var executeSimulationNode = async ({
877
710
  });
878
711
  const item = {
879
712
  nodeId: node.id,
880
- fallbackCycle,
713
+ cycle,
881
714
  inputNodeIds: inputPayload.map((input) => input.nodeId),
882
715
  output: result.output
883
716
  };
@@ -887,7 +720,7 @@ var executeSimulationNode = async ({
887
720
  const message = error instanceof Error ? error.message : String(error);
888
721
  const item = {
889
722
  nodeId: node.id,
890
- fallbackCycle,
723
+ cycle,
891
724
  inputNodeIds: inputPayload.map((input) => input.nodeId),
892
725
  output: "",
893
726
  error: message
@@ -927,7 +760,7 @@ var runGraphExecution = async ({
927
760
  runs.push(
928
761
  await executeSimulationNode({
929
762
  node,
930
- fallbackCycle: false,
763
+ cycle: false,
931
764
  inputPayload,
932
765
  contextInputs,
933
766
  executeNode,
@@ -949,7 +782,7 @@ var runGraphExecution = async ({
949
782
  if (ready.length === 0) {
950
783
  throw new Error(`Circuitry execution stalled; unresolved dependencies: ${pending.join(", ")}`);
951
784
  }
952
- const fallbackCycle = false;
785
+ const cycle = false;
953
786
  const currentBatch = ready;
954
787
  for (let index = 0; index < currentBatch.length; index += parallelism) {
955
788
  const chunk = currentBatch.slice(index, index + parallelism);
@@ -968,7 +801,7 @@ var runGraphExecution = async ({
968
801
  }) || [];
969
802
  const result = await executeSimulationNode({
970
803
  node,
971
- fallbackCycle,
804
+ cycle,
972
805
  inputPayload,
973
806
  contextInputs,
974
807
  executeNode,
@@ -1005,8 +838,9 @@ var runDependencySimulation = async ({
1005
838
  };
1006
839
 
1007
840
  // src/bundle.ts
1008
- var BUNDLE_MIME = "application/vnd.circuitry.bundle+json";
1009
- var deepClone = (value) => JSON.parse(JSON.stringify(value));
841
+ import YAML4 from "yaml";
842
+ var BUNDLE_MIME = "application/vnd.circuitry.bundle+yaml";
843
+ var deepClone = (value) => structuredClone(value);
1010
844
  var createBundleFromSelection = (elements, selectedIds) => {
1011
845
  const selected = elements.filter((el) => selectedIds[el.id]);
1012
846
  if (!selected.length) {
@@ -1030,8 +864,9 @@ var createBundleFromSelection = (elements, selectedIds) => {
1030
864
  elements: [...dedup.values()]
1031
865
  };
1032
866
  };
867
+ var stringifyBundle = (bundle) => YAML4.stringify(bundle);
1033
868
  var parseBundleText = (text) => {
1034
- const parsed = JSON.parse(text);
869
+ const parsed = YAML4.parse(text);
1035
870
  if (parsed.version !== 1 || !Array.isArray(parsed.elements)) {
1036
871
  throw new Error("Invalid Circuitry bundle format");
1037
872
  }
@@ -1143,9 +978,9 @@ var createCircuitryRunGraphTool = (host) => ({
1143
978
  });
1144
979
  var createCircuitryValidateGraphTool = (host) => ({
1145
980
  name: "circuitry_validate_graph",
1146
- description: "Validate Circuitry YAML or JSON graph text. Returns structured validation issues.",
981
+ description: "Validate Circuitry YAML graph text. Returns structured validation issues.",
1147
982
  parameters: z.object({
1148
- text: z.string().describe("YAML or JSON graph text to validate."),
983
+ text: z.string().describe("YAML graph text to validate."),
1149
984
  filename: z.string().optional().describe("Optional filename context."),
1150
985
  standard: standardSchema
1151
986
  }),
@@ -1186,16 +1021,17 @@ export {
1186
1021
  normalizeCircuitryGraph,
1187
1022
  parseAgentPresetMarkdown,
1188
1023
  parseBundleText,
1189
- parseCircuitryJson,
1190
1024
  parseCircuitryText,
1191
1025
  parseCircuitryYaml,
1026
+ parseYamlData,
1192
1027
  runCircuitryGraphExecution,
1193
1028
  runDependencySimulation,
1194
1029
  runGraphExecution,
1195
1030
  standardSchema,
1196
- stringifyCircuitryJson,
1031
+ stringifyBundle,
1197
1032
  stringifyCircuitryText,
1198
1033
  stringifyCircuitryYaml,
1034
+ stringifyYamlData,
1199
1035
  validateCircuitryExecutionGraphWithStandard,
1200
1036
  validateCircuitryGraph,
1201
1037
  validateCircuitryGraphWithStandard