@darkhorseprojects/circuitry 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle.d.ts +2 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +277 -0
- package/dist/graph.d.ts +33 -68
- package/dist/index.js +142 -306
- package/dist/node.d.ts +11 -6
- package/dist/node.js +204 -369
- package/dist/presets.d.ts +1 -1
- package/dist/scheduler.d.ts +1 -1
- package/dist/simulation.d.ts +3 -4
- package/dist/types.d.ts +0 -1
- package/dist/yaml.d.ts +4 -2
- package/package.json +4 -1
package/dist/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: "
|
|
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
|
-
|
|
31
|
-
var
|
|
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
|
|
69
|
-
|
|
70
|
-
|
|
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:
|
|
80
|
+
label: agent.label || agent.identity || id,
|
|
105
81
|
agent: {
|
|
106
|
-
identity:
|
|
107
|
-
model:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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:
|
|
115
|
-
expect:
|
|
89
|
+
skills: agent.skills,
|
|
90
|
+
expect: agent.expect
|
|
116
91
|
});
|
|
117
|
-
for (const
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
|
136
|
-
|
|
137
|
-
return { ...graph, nodes, edges };
|
|
105
|
+
if (!graph.resources) return { ...graph };
|
|
106
|
+
return { ...graph, ...expandResources(graph.resources) };
|
|
138
107
|
};
|
|
139
|
-
var
|
|
140
|
-
|
|
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
|
|
147
|
-
if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
|
|
148
|
-
|
|
149
|
-
|
|
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
|
|
152
|
-
const
|
|
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
|
-
|
|
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
|
|
137
|
+
const incoming = /* @__PURE__ */ new Map();
|
|
198
138
|
for (const id of ids) {
|
|
199
139
|
adjacency.set(id, []);
|
|
200
|
-
|
|
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
|
-
|
|
144
|
+
issue("missing_edge_endpoint", "missing edge endpoint", ["edges", index]);
|
|
205
145
|
continue;
|
|
206
146
|
}
|
|
207
|
-
if (
|
|
208
|
-
|
|
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
|
-
|
|
212
|
-
|
|
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 (
|
|
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
|
-
|
|
158
|
+
incoming.set(edge.to, (incoming.get(edge.to) || 0) + 1);
|
|
220
159
|
}
|
|
221
160
|
}
|
|
222
|
-
|
|
223
|
-
|
|
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 (
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
|
306
|
-
|
|
307
|
-
|
|
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
|
|
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
|
|
355
|
-
var
|
|
356
|
-
let graph;
|
|
192
|
+
import YAML2 from "yaml";
|
|
193
|
+
var parseYamlData = (text) => {
|
|
357
194
|
try {
|
|
358
|
-
|
|
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
|
|
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("
|
|
206
|
+
throw new Error("Circuitry YAML must be a graph object.");
|
|
366
207
|
}
|
|
367
|
-
if (options.validate
|
|
368
|
-
|
|
369
|
-
|
|
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
|
|
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,
|
|
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:
|
|
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 ||
|
|
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=${
|
|
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
|
|
360
|
+
var stripYamlFence = (output) => {
|
|
526
361
|
const trimmed = output.trim();
|
|
527
|
-
const fenced = trimmed.match(/^```(?:
|
|
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
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
690
|
+
cycle,
|
|
857
691
|
inputPayload,
|
|
858
692
|
contextInputs,
|
|
859
693
|
executeNode,
|
|
860
694
|
onNodeStart,
|
|
861
695
|
onNodeComplete
|
|
862
696
|
}) => {
|
|
863
|
-
onNodeStart?.(node.id,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1009
|
-
var
|
|
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 =
|
|
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
|
|
981
|
+
description: "Validate Circuitry YAML graph text. Returns structured validation issues.",
|
|
1147
982
|
parameters: z.object({
|
|
1148
|
-
text: z.string().describe("YAML
|
|
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
|
-
|
|
1031
|
+
stringifyBundle,
|
|
1197
1032
|
stringifyCircuitryText,
|
|
1198
1033
|
stringifyCircuitryYaml,
|
|
1034
|
+
stringifyYamlData,
|
|
1199
1035
|
validateCircuitryExecutionGraphWithStandard,
|
|
1200
1036
|
validateCircuitryGraph,
|
|
1201
1037
|
validateCircuitryGraphWithStandard
|