@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/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.1";
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,12 +71,7 @@ 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") {
101
76
  const agent = resource;
102
77
  nodes.push({
@@ -106,7 +81,6 @@ var expandResources = (resources) => {
106
81
  agent: {
107
82
  identity: agent.identity || agent.label || id,
108
83
  model: agent.model,
109
- thinkingLevel: agent.thinkingLevel,
110
84
  tools: agent.tools,
111
85
  instructions: agent.instructions,
112
86
  personality: agent.personality,
@@ -115,288 +89,132 @@ var expandResources = (resources) => {
115
89
  skills: agent.skills,
116
90
  expect: agent.expect
117
91
  });
118
- for (const inputRef of agent.inputs || []) {
119
- edges.push({ from: inputRef, to: id, kind: "dependency" });
120
- }
92
+ for (const input of agent.inputs || []) edges.push({ from: input, to: id, kind: "dependency" });
121
93
  } else if (resource.type === "tool") {
122
94
  const tool = resource;
123
- nodes.push({
124
- id,
125
- kind: "tool",
126
- label: tool.label || id,
127
- agent: { instructions: tool.instructions }
128
- });
129
- for (const inputRef of tool.inputs || []) {
130
- edges.push({ from: inputRef, to: id, kind: "dependency" });
131
- }
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" });
132
97
  } else {
133
98
  const input = resource;
134
- nodes.push({
135
- id,
136
- kind: "input",
137
- label: input.label || id,
138
- input: {
139
- type: input.type,
140
- value: input.value,
141
- uri: input.uri || input.path,
142
- mimeType: input.mimeType,
143
- data: input.data
144
- }
145
- });
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 } });
146
100
  }
147
101
  }
148
102
  return { nodes, edges };
149
103
  };
150
104
  var normalizeCircuitryGraph = (graph) => {
151
- if (!graph.resources || Object.keys(graph.resources).length === 0) return { ...graph };
152
- const { nodes, edges } = expandResources(graph.resources);
153
- return { ...graph, nodes, edges };
105
+ if (!graph.resources) return { ...graph };
106
+ return { ...graph, ...expandResources(graph.resources) };
154
107
  };
155
- var VALID_SPEC_VERSIONS = /* @__PURE__ */ new Set([CIRCUITRY_SPEC_VERSION]);
156
- var validateCircuitryGraphInternal = (graph, standard = {}, options) => {
157
- const resolvedStandard = createCircuitryValidationStandard(
158
- standard,
159
- graph && typeof graph === "object" && !Array.isArray(graph) ? graph : void 0
160
- );
108
+ var validateCircuitryGraphInternal = (graph, standard = {}, source) => {
109
+ const resolved = createCircuitryValidationStandard(standard, graph && typeof graph === "object" && !Array.isArray(graph) ? graph : void 0);
161
110
  const errors = [];
162
- const addError = (code, message, path2) => errors.push({ code, message, ...path2 ? { path: path2 } : {} });
163
- if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
164
- addError("invalid_graph", "Circuitry graph must be an object");
165
- 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"]);
166
123
  }
167
- const graphObject = graph;
168
- const rules = resolvedStandard.rules;
169
- const hasRule = (name) => rules.some((entry) => (typeof entry === "string" ? entry : entry.rule) === name);
170
- if (resolvedStandard.requireSpecVersion && !VALID_SPEC_VERSIONS.has(String(graphObject.circuitry))) {
171
- addError(
172
- "invalid_spec_version",
173
- `Expected circuitry: "${CIRCUITRY_SPEC_VERSION}"`,
174
- ["circuitry"]
175
- );
176
- }
177
- if (options.sourceFormat) {
178
- if (!graphObject.resources || Object.keys(graphObject.resources).length === 0) {
179
- addError("missing_resources", "Circuitry graphs must use a resources: section", ["resources"]);
180
- }
181
- if (graphObject.agents && Object.keys(graphObject.agents).length > 0) {
182
- addError("forbidden_agents", "Circuitry graph files must not use top-level agents:; use resources:", ["agents"]);
183
- }
184
- if (graphObject.inputs && Object.keys(graphObject.inputs).length > 0) {
185
- addError("forbidden_inputs", "Circuitry graph files use args: for runtime arguments and resource inputs for edges", ["inputs"]);
186
- }
187
- if (graphObject.nodes && graphObject.nodes.length > 0) {
188
- addError("forbidden_nodes", "Circuitry graph files must not use top-level nodes:; use resources:", ["nodes"]);
189
- }
190
- if (graphObject.edges && graphObject.edges.length > 0) {
191
- addError("forbidden_edges", "Circuitry graph files must not use top-level edges:; use resource inputs:", ["edges"]);
192
- }
193
- if (graphObject.links && graphObject.links.length > 0) {
194
- addError("forbidden_links", "Circuitry graph files use imports: for multi-file graphs", ["links"]);
195
- }
196
- }
197
- const normalized = normalizeCircuitryGraph(graphObject);
124
+ const rules = new Set(resolved.rules.map(ruleName));
125
+ const normalized = normalizeCircuitryGraph(g);
198
126
  const ids = /* @__PURE__ */ new Set();
199
127
  for (const [index, node] of (normalized.nodes || []).entries()) {
200
128
  if (!node.id) {
201
- addError("missing_node_id", "Node is missing id", ["nodes", index, "id"]);
129
+ issue("missing_node_id", "missing node id", ["nodes", index, "id"]);
202
130
  continue;
203
131
  }
204
- if (ids.has(node.id)) {
205
- addError("duplicate_node_id", `Duplicate node id: ${node.id}`, ["nodes", index, "id"]);
206
- }
132
+ if (ids.has(node.id)) issue("duplicate_node_id", "duplicate node id", ["nodes", index, "id"]);
207
133
  ids.add(node.id);
208
- if (!node.kind) {
209
- addError("missing_node_kind", `Node ${node.id} is missing kind`, ["nodes", index, "kind"]);
210
- }
134
+ if (!node.kind) issue("missing_node_kind", "missing node kind", ["nodes", index, "kind"]);
211
135
  }
212
136
  const adjacency = /* @__PURE__ */ new Map();
213
- const incomingCount = /* @__PURE__ */ new Map();
137
+ const incoming = /* @__PURE__ */ new Map();
214
138
  for (const id of ids) {
215
139
  adjacency.set(id, []);
216
- incomingCount.set(id, 0);
140
+ incoming.set(id, 0);
217
141
  }
218
142
  for (const [index, edge] of (normalized.edges || []).entries()) {
219
143
  if (!edge.from || !edge.to) {
220
- addError("missing_edge_endpoint", "Edge is missing from/to", ["edges", index]);
144
+ issue("missing_edge_endpoint", "missing edge endpoint", ["edges", index]);
221
145
  continue;
222
146
  }
223
- if (hasRule("no-self-loops") && edge.from === edge.to) {
224
- 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]);
225
149
  continue;
226
150
  }
227
- if (hasRule("no-unknown-edge-endpoints") && !ids.has(edge.from)) {
228
- 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"]);
229
155
  }
230
- if (hasRule("no-unknown-edge-endpoints") && !ids.has(edge.to)) {
231
- addError("unknown_edge_target", `Edge references unknown target: ${edge.to}`, ["edges", index, "to"]);
232
- }
233
- if (ids.has(edge.from) && ids.has(edge.to)) {
156
+ if (ok) {
234
157
  adjacency.get(edge.from).push(edge.to);
235
- incomingCount.set(edge.to, (incomingCount.get(edge.to) || 0) + 1);
158
+ incoming.set(edge.to, (incoming.get(edge.to) || 0) + 1);
236
159
  }
237
160
  }
238
- const executableKinds = new Set(resolvedStandard.executableKinds);
239
- if (hasRule("require-executable-inputs")) {
161
+ if (rules.has("require-executable-inputs")) {
162
+ const executable = new Set(resolved.executableKinds);
240
163
  for (const [index, node] of (normalized.nodes || []).entries()) {
241
- if (executableKinds.has(node.kind) && (incomingCount.get(node.id) || 0) === 0) {
242
- addError("executable_without_inputs", `Executable node has no inputs: ${node.id}`, ["nodes", index]);
243
- }
244
- }
245
- }
246
- const visiting = /* @__PURE__ */ new Set();
247
- const visited = /* @__PURE__ */ new Set();
248
- const path = [];
249
- let cycleMessage = "";
250
- const visit = (id) => {
251
- if (cycleMessage) return;
252
- if (visiting.has(id)) {
253
- cycleMessage = [...path.slice(path.indexOf(id)), id].join(" -> ");
254
- return;
255
- }
256
- if (visited.has(id)) return;
257
- visiting.add(id);
258
- path.push(id);
259
- for (const next of adjacency.get(id) || []) visit(next);
260
- path.pop();
261
- visiting.delete(id);
262
- visited.add(id);
263
- };
264
- if (hasRule("no-cycles")) {
265
- for (const id of ids) {
266
- visit(id);
267
- if (cycleMessage) {
268
- addError("cycle", `Graph contains cycle: ${cycleMessage}`);
269
- break;
270
- }
164
+ if (executable.has(node.kind) && (incoming.get(node.id) || 0) === 0) issue("missing_executable_input", "missing executable input", ["nodes", index]);
271
165
  }
272
166
  }
273
- const additionalRules = rules.filter((rule) => {
274
- if (typeof rule === "string") return false;
275
- return rule.rule === "require-graph-field" || rule.rule === "require-node-field" || rule.rule === "require-edge-field" || rule.rule === "require-string" || rule.rule === "reject-string";
276
- });
277
- const fieldPath = (field) => field.split(".").filter(Boolean);
278
- const getField = (value, field) => fieldPath(field).reduce((current, key) => {
279
- if (!current || typeof current !== "object") return void 0;
280
- return current[key];
281
- }, value);
282
- const isPresent = (value) => value !== void 0 && value !== null && value !== "";
283
- for (const rule of additionalRules) {
284
- if (rule.rule === "require-graph-field") {
285
- if (!isPresent(getField(normalized, rule.field))) {
286
- addError("missing_required_graph_field", `Graph is missing required field: ${rule.field}`, fieldPath(rule.field));
287
- }
288
- continue;
289
- }
290
- if (rule.rule === "require-node-field") {
291
- const nodeKinds = new Set(rule.nodeKinds || []);
292
- for (const [index, node] of (normalized.nodes || []).entries()) {
293
- if (nodeKinds.size > 0 && !nodeKinds.has(node.kind)) continue;
294
- if (!isPresent(getField(node, rule.field))) {
295
- addError("missing_required_node_field", `Node ${node.id || "<missing id>"} is missing required field: ${rule.field}`, ["nodes", index, ...fieldPath(rule.field)]);
296
- }
297
- }
298
- continue;
299
- }
300
- if (rule.rule === "require-edge-field") {
301
- const edgeKinds = new Set(rule.edgeKinds || []);
302
- for (const [index, edge] of (normalized.edges || []).entries()) {
303
- if (edgeKinds.size > 0 && (!edge.kind || !edgeKinds.has(edge.kind))) continue;
304
- if (!isPresent(getField(edge, rule.field))) {
305
- addError("missing_required_edge_field", `Edge ${edge.id || index} is missing required field: ${rule.field}`, ["edges", index, ...fieldPath(rule.field)]);
306
- }
307
- }
308
- continue;
309
- }
310
- const checkString = (target, subject, id, match, path2) => {
311
- const value = getField(subject, match.field);
312
- const text = typeof value === "string" ? value : "";
313
- const includes = text.includes(match.value);
314
- if (rule.rule === "require-string" && !includes) {
315
- addError("missing_required_string", `${target} ${id} field ${match.field} must include string: ${match.value}`, path2);
316
- }
317
- if (rule.rule === "reject-string" && includes) {
318
- addError("rejected_string", `${target} ${id} field ${match.field} must not include string: ${match.value}`, path2);
319
- }
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;
320
178
  };
321
- for (const match of rule.graph || []) checkString("graph", normalized, "<root>", match, fieldPath(match.field));
322
- for (const match of rule.nodes || []) {
323
- const nodeKinds = new Set(match.nodeKinds || []);
324
- for (const [index, node] of (normalized.nodes || []).entries()) {
325
- if (nodeKinds.size > 0 && !nodeKinds.has(node.kind)) continue;
326
- checkString("node", node, node.id || "<missing id>", match, ["nodes", index, ...fieldPath(match.field)]);
327
- }
328
- }
329
- for (const match of rule.edges || []) {
330
- const edgeKinds = new Set(match.edgeKinds || []);
331
- for (const [index, edge] of (normalized.edges || []).entries()) {
332
- if (edgeKinds.size > 0 && (!edge.kind || !edgeKinds.has(edge.kind))) continue;
333
- checkString("edge", edge, edge.id || String(index), match, ["edges", index, ...fieldPath(match.field)]);
334
- }
179
+ for (const id of ids) if (visit(id)) {
180
+ issue("cycle", "cycle");
181
+ break;
335
182
  }
336
183
  }
337
- return { ok: errors.length === 0, errors, standard: resolvedStandard };
338
- };
339
- var validateCircuitryGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, { sourceFormat: true });
340
- var validateCircuitryExecutionGraphWithStandard = (graph, standard = {}) => validateCircuitryGraphInternal(graph, standard, { sourceFormat: false });
341
- var validateCircuitryGraph = (graph, standard = {}) => validateCircuitryGraphWithStandard(graph, standard).errors.map(
342
- (error) => error.message
343
- );
344
- var parseCircuitryJson = (text, standard = {}, options = {}) => {
345
- let graph;
346
- try {
347
- graph = JSON.parse(text);
348
- } catch (error) {
349
- const message = error instanceof Error ? error.message : String(error);
350
- throw new Error(`Could not parse Circuitry JSON. Check commas, quotes, and braces.
351
- ${message}`);
352
- }
353
- if (options.validate === false) return graph;
354
- const errors = validateCircuitryGraph(graph, standard);
355
- if (errors.length) {
356
- throw new Error(`Invalid Circuitry graph:
357
- ${errors.join("\n")}`);
358
- }
359
- return normalizeCircuitryGraph(graph);
360
- };
361
- var stringifyCircuitryJson = (graph) => {
362
- return `${JSON.stringify(normalizeCircuitryGraph(graph), null, 2)}
363
- `;
364
- };
365
- var isUriInput = (input) => {
366
- return Boolean(input.uri || ["file", "url", "uri", "image", "mcp"].includes(input.type));
184
+ return { ok: errors.length === 0, errors, standard: resolved };
367
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));
368
190
 
369
191
  // src/yaml.ts
370
- import YAML from "yaml";
371
- var parseCircuitryYaml = (text, standard = {}, options = {}) => {
372
- let graph;
192
+ import YAML2 from "yaml";
193
+ var parseYamlData = (text) => {
373
194
  try {
374
- graph = YAML.parse(text);
195
+ return YAML2.parse(text);
375
196
  } catch (error) {
376
197
  const message = error instanceof Error ? error.message : String(error);
377
- throw new Error(`Could not parse Circuitry YAML. Check indentation and quotes.
198
+ throw new Error(`Could not parse YAML.
378
199
  ${message}`);
379
200
  }
201
+ };
202
+ var stringifyYamlData = (value) => YAML2.stringify(value);
203
+ var parseCircuitryYaml = (text, standard = {}, options = {}) => {
204
+ const graph = parseYamlData(text);
380
205
  if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
381
- throw new Error("Could not parse Circuitry YAML. Expected a graph object.");
206
+ throw new Error("Circuitry YAML must be a graph object.");
382
207
  }
383
- if (options.validate === false) return graph;
384
- const errors = validateCircuitryGraph(graph, standard);
385
- if (errors.length) {
386
- 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:
387
211
  ${errors.join("\n")}`);
388
212
  }
389
- return normalizeCircuitryGraph(graph);
390
- };
391
- var stringifyCircuitryYaml = (graph) => {
392
- return YAML.stringify(normalizeCircuitryGraph(graph));
393
- };
394
- var parseCircuitryText = (text, filename = "graph.circuitry.yaml", standard = {}, options = {}) => {
395
- return filename.endsWith(".json") ? parseCircuitryJson(text, standard, options) : parseCircuitryYaml(text, standard, options);
396
- };
397
- var stringifyCircuitryText = (graph, filename = "graph.circuitry.yaml") => {
398
- return filename.endsWith(".json") ? stringifyCircuitryJson(graph) : stringifyCircuitryYaml(graph);
213
+ return graph;
399
214
  };
215
+ var stringifyCircuitryYaml = (graph) => YAML2.stringify(graph);
216
+ var parseCircuitryText = (text, standard = {}, options = {}) => parseCircuitryYaml(text, standard, options);
217
+ var stringifyCircuitryText = (graph) => stringifyCircuitryYaml(graph);
400
218
 
401
219
  // src/presets.ts
402
220
  var CIRCUITRY_AGENT_PRESET_DIRS = [
@@ -405,11 +223,11 @@ var CIRCUITRY_AGENT_PRESET_DIRS = [
405
223
  "~/.agents/agents",
406
224
  "~/.circuitry/agents"
407
225
  ];
408
- var parseAgentPresetMarkdown = (text, fallbackName) => {
226
+ var parseAgentPresetMarkdown = (text, defaultName) => {
409
227
  const frontmatter = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/m.exec(text);
410
228
  if (!frontmatter) {
411
229
  return {
412
- name: fallbackName,
230
+ name: defaultName,
413
231
  instructions: text.trim()
414
232
  };
415
233
  }
@@ -421,7 +239,7 @@ var parseAgentPresetMarkdown = (text, fallbackName) => {
421
239
  }
422
240
  }
423
241
  return {
424
- name: metadata.name || fallbackName,
242
+ name: metadata.name || defaultName,
425
243
  description: metadata.description,
426
244
  model: metadata.model,
427
245
  personality: metadata.personality,
@@ -454,6 +272,7 @@ var applyAgentPresets = (graph, presets) => {
454
272
  };
455
273
 
456
274
  // src/scheduler.ts
275
+ import YAML3 from "yaml";
457
276
  var buildCircuitryExecutionGraph = (graph) => {
458
277
  const normalized = normalizeCircuitryGraph(graph);
459
278
  const nodes = /* @__PURE__ */ new Map();
@@ -493,7 +312,7 @@ var formatEdgeData = (data) => {
493
312
  if (!data || Object.keys(data).length === 0) {
494
313
  return "";
495
314
  }
496
- return ` data=${JSON.stringify(data)}`;
315
+ return ` data=${YAML3.stringify(data).trimEnd()}`;
497
316
  };
498
317
  var describeEdge = (edge, direction) => {
499
318
  const otherId = direction === "incoming" ? edge.from : edge.to;
@@ -538,17 +357,17 @@ ${contextSection}`
538
357
  ].filter(Boolean).join("\n\n");
539
358
  };
540
359
  var collectImages = (contextInputs) => contextInputs.filter((item) => item.kind === "image" && item.image).map((item) => item.image);
541
- var stripJsonFence = (output) => {
360
+ var stripYamlFence = (output) => {
542
361
  const trimmed = output.trim();
543
- const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
362
+ const fenced = trimmed.match(/^```(?:ya?ml)?\s*([\s\S]*?)\s*```$/i);
544
363
  return fenced ? fenced[1].trim() : trimmed;
545
364
  };
546
365
  var parseExpectedOutput = (nodeId, output) => {
547
366
  try {
548
- return JSON.parse(stripJsonFence(output));
367
+ return YAML3.parse(stripYamlFence(output));
549
368
  } catch (error) {
550
369
  const detail = error instanceof Error ? error.message : String(error);
551
- 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})`);
552
371
  }
553
372
  };
554
373
  var isFieldObject = (schema) => !!schema && typeof schema === "object" && !Array.isArray(schema) && typeof schema.type === "string";
@@ -631,7 +450,7 @@ ${errors.join("\n")}`);
631
450
  var executeCircuitryNode = async ({
632
451
  graph,
633
452
  item,
634
- fallbackCycle,
453
+ cycle,
635
454
  inputPayload,
636
455
  contextInputs,
637
456
  defaultModel,
@@ -639,13 +458,13 @@ var executeCircuitryNode = async ({
639
458
  onNodeStart,
640
459
  onNodeComplete
641
460
  }) => {
642
- onNodeStart?.(item.id, fallbackCycle);
461
+ onNodeStart?.(item.id, cycle);
643
462
  if (item.node.kind === "output") {
644
463
  const output = inputPayload.map((input) => input.output).join("\n\n");
645
464
  onNodeComplete?.(item.id, { output });
646
465
  return {
647
466
  nodeId: item.id,
648
- fallbackCycle,
467
+ cycle,
649
468
  inputNodeIds: inputPayload.map((input) => input.nodeId),
650
469
  output
651
470
  };
@@ -657,7 +476,6 @@ var executeCircuitryNode = async ({
657
476
  nodeId: item.id,
658
477
  model: (agent.model === "inherit" ? void 0 : agent.model) || (defaultModel === "inherit" ? void 0 : defaultModel) || "inherit",
659
478
  tools: agent.tools || [],
660
- thinkingLevel: agent.thinkingLevel || "off",
661
479
  personality: agent.personality || "",
662
480
  instructions: agent.instructions || "",
663
481
  context: agent.context || "",
@@ -671,7 +489,7 @@ var executeCircuitryNode = async ({
671
489
  onNodeComplete?.(item.id, { error: message });
672
490
  return {
673
491
  nodeId: item.id,
674
- fallbackCycle,
492
+ cycle,
675
493
  inputNodeIds: inputPayload.map((input) => input.nodeId),
676
494
  output: "",
677
495
  error: message
@@ -681,7 +499,7 @@ var executeCircuitryNode = async ({
681
499
  onNodeComplete?.(item.id, { output: result.output });
682
500
  return {
683
501
  nodeId: item.id,
684
- fallbackCycle,
502
+ cycle,
685
503
  inputNodeIds: inputPayload.map((input) => input.nodeId),
686
504
  output: result.output
687
505
  };
@@ -700,7 +518,7 @@ var runCircuitryGraphExecution = async ({
700
518
  const parallelism = Math.max(1, Math.floor(maxParallelRuns));
701
519
  const defaultModel = graph.runtime?.model;
702
520
  const runOne = async (nodeId, outputs2) => {
703
- const fallbackCycle = false;
521
+ const cycle = false;
704
522
  const item = executionGraph.nodes.get(nodeId);
705
523
  const inputPayload = item.inputNodeIds.filter((sourceId) => outputs2.has(sourceId)).map((sourceId) => ({
706
524
  nodeId: sourceId,
@@ -714,7 +532,7 @@ var runCircuitryGraphExecution = async ({
714
532
  return executeCircuitryNode({
715
533
  graph,
716
534
  item,
717
- fallbackCycle,
535
+ cycle,
718
536
  inputPayload,
719
537
  contextInputs,
720
538
  defaultModel,
@@ -869,20 +687,19 @@ var collectImages2 = (contextInputs) => {
869
687
  };
870
688
  var executeSimulationNode = async ({
871
689
  node,
872
- fallbackCycle,
690
+ cycle,
873
691
  inputPayload,
874
692
  contextInputs,
875
693
  executeNode,
876
694
  onNodeStart,
877
695
  onNodeComplete
878
696
  }) => {
879
- onNodeStart?.(node.id, fallbackCycle);
697
+ onNodeStart?.(node.id, cycle);
880
698
  try {
881
699
  const result = await executeNode({
882
700
  nodeId: node.id,
883
701
  model: node.data.model === "inherit" ? "inherit" : node.data.model || "inherit",
884
702
  tools: node.data.tools || [],
885
- thinkingLevel: node.data.thinkingLevel || "off",
886
703
  personality: node.data.personality,
887
704
  instructions: node.data.instructions,
888
705
  context: node.data.context,
@@ -893,7 +710,7 @@ var executeSimulationNode = async ({
893
710
  });
894
711
  const item = {
895
712
  nodeId: node.id,
896
- fallbackCycle,
713
+ cycle,
897
714
  inputNodeIds: inputPayload.map((input) => input.nodeId),
898
715
  output: result.output
899
716
  };
@@ -903,7 +720,7 @@ var executeSimulationNode = async ({
903
720
  const message = error instanceof Error ? error.message : String(error);
904
721
  const item = {
905
722
  nodeId: node.id,
906
- fallbackCycle,
723
+ cycle,
907
724
  inputNodeIds: inputPayload.map((input) => input.nodeId),
908
725
  output: "",
909
726
  error: message
@@ -943,7 +760,7 @@ var runGraphExecution = async ({
943
760
  runs.push(
944
761
  await executeSimulationNode({
945
762
  node,
946
- fallbackCycle: false,
763
+ cycle: false,
947
764
  inputPayload,
948
765
  contextInputs,
949
766
  executeNode,
@@ -965,7 +782,7 @@ var runGraphExecution = async ({
965
782
  if (ready.length === 0) {
966
783
  throw new Error(`Circuitry execution stalled; unresolved dependencies: ${pending.join(", ")}`);
967
784
  }
968
- const fallbackCycle = false;
785
+ const cycle = false;
969
786
  const currentBatch = ready;
970
787
  for (let index = 0; index < currentBatch.length; index += parallelism) {
971
788
  const chunk = currentBatch.slice(index, index + parallelism);
@@ -984,7 +801,7 @@ var runGraphExecution = async ({
984
801
  }) || [];
985
802
  const result = await executeSimulationNode({
986
803
  node,
987
- fallbackCycle,
804
+ cycle,
988
805
  inputPayload,
989
806
  contextInputs,
990
807
  executeNode,
@@ -1021,8 +838,9 @@ var runDependencySimulation = async ({
1021
838
  };
1022
839
 
1023
840
  // src/bundle.ts
1024
- var BUNDLE_MIME = "application/vnd.circuitry.bundle+json";
1025
- 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);
1026
844
  var createBundleFromSelection = (elements, selectedIds) => {
1027
845
  const selected = elements.filter((el) => selectedIds[el.id]);
1028
846
  if (!selected.length) {
@@ -1046,8 +864,9 @@ var createBundleFromSelection = (elements, selectedIds) => {
1046
864
  elements: [...dedup.values()]
1047
865
  };
1048
866
  };
867
+ var stringifyBundle = (bundle) => YAML4.stringify(bundle);
1049
868
  var parseBundleText = (text) => {
1050
- const parsed = JSON.parse(text);
869
+ const parsed = YAML4.parse(text);
1051
870
  if (parsed.version !== 1 || !Array.isArray(parsed.elements)) {
1052
871
  throw new Error("Invalid Circuitry bundle format");
1053
872
  }
@@ -1159,9 +978,9 @@ var createCircuitryRunGraphTool = (host) => ({
1159
978
  });
1160
979
  var createCircuitryValidateGraphTool = (host) => ({
1161
980
  name: "circuitry_validate_graph",
1162
- description: "Validate Circuitry YAML or JSON graph text. Returns structured validation issues.",
981
+ description: "Validate Circuitry YAML graph text. Returns structured validation issues.",
1163
982
  parameters: z.object({
1164
- text: z.string().describe("YAML or JSON graph text to validate."),
983
+ text: z.string().describe("YAML graph text to validate."),
1165
984
  filename: z.string().optional().describe("Optional filename context."),
1166
985
  standard: standardSchema
1167
986
  }),
@@ -1202,16 +1021,17 @@ export {
1202
1021
  normalizeCircuitryGraph,
1203
1022
  parseAgentPresetMarkdown,
1204
1023
  parseBundleText,
1205
- parseCircuitryJson,
1206
1024
  parseCircuitryText,
1207
1025
  parseCircuitryYaml,
1026
+ parseYamlData,
1208
1027
  runCircuitryGraphExecution,
1209
1028
  runDependencySimulation,
1210
1029
  runGraphExecution,
1211
1030
  standardSchema,
1212
- stringifyCircuitryJson,
1031
+ stringifyBundle,
1213
1032
  stringifyCircuitryText,
1214
1033
  stringifyCircuitryYaml,
1034
+ stringifyYamlData,
1215
1035
  validateCircuitryExecutionGraphWithStandard,
1216
1036
  validateCircuitryGraph,
1217
1037
  validateCircuitryGraphWithStandard