@darkhorseprojects/circuitry 0.3.10 → 0.4.0

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
@@ -27,166 +27,161 @@ var isNodeElement = (element) => {
27
27
 
28
28
  // src/graph.ts
29
29
  import YAML from "yaml";
30
- var CIRCUITRY_SPEC_VERSION = "0.3.10";
31
- var DEFAULT_CIRCUITRY_VALIDATION_RULES = [
32
- "no-self-loops",
33
- "no-unknown-edge-endpoints",
34
- "require-executable-inputs",
35
- "no-cycles"
36
- ];
30
+ var CIRCUITRY_SPEC_VERSION = "0.4";
37
31
  var DEFAULT_CIRCUITRY_VALIDATION_STANDARD = {
38
32
  version: CIRCUITRY_SPEC_VERSION,
39
- requireSpecVersion: true,
40
- rules: DEFAULT_CIRCUITRY_VALIDATION_RULES,
41
- executableKinds: ["agent", "tool", "output"]
33
+ requireSpecVersion: true
42
34
  };
43
- var runtimeInputToText = (value) => {
44
- if (typeof value === "string") return value;
45
- if (value === void 0) return "";
46
- return YAML.stringify(value).trimEnd();
35
+ var createCircuitryValidationStandard = (standard = {}) => ({
36
+ version: standard.version || DEFAULT_CIRCUITRY_VALIDATION_STANDARD.version,
37
+ requireSpecVersion: standard.requireSpecVersion ?? DEFAULT_CIRCUITRY_VALIDATION_STANDARD.requireSpecVersion
38
+ });
39
+ var getResourceInputs = (resource) => {
40
+ const inputs = resource.inputs;
41
+ if (!inputs) return [];
42
+ if (Array.isArray(inputs)) return inputs.map((from) => ({ from, to: "" }));
43
+ return Object.entries(inputs).map(([name, from]) => ({ from, to: "", name }));
47
44
  };
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) };
45
+ var resourceInputIds = (resource) => getResourceInputs(resource).map((dependency) => dependency.from);
46
+ var getCircuitryDependencies = (graph) => {
47
+ const dependencies = [];
48
+ for (const [to, resource] of Object.entries(graph.resources || {})) {
49
+ for (const dependency of getResourceInputs(resource)) dependencies.push({ ...dependency, to });
55
50
  }
56
- return next;
51
+ return dependencies;
57
52
  };
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;
60
- var createCircuitryValidationStandard = (standard = {}, graph) => {
61
- const rules = [...DEFAULT_CIRCUITRY_VALIDATION_RULES, ...graph?.validation?.rules || [], ...standard.rules || []];
62
- return {
63
- version: standard.version || DEFAULT_CIRCUITRY_VALIDATION_STANDARD.version,
64
- requireSpecVersion: standard.requireSpecVersion ?? DEFAULT_CIRCUITRY_VALIDATION_STANDARD.requireSpecVersion,
65
- rules,
66
- executableKinds: standard.executableKinds || executableKindsFromRules(rules) || [...DEFAULT_CIRCUITRY_VALIDATION_STANDARD.executableKinds]
53
+ var getCircuitryDependents = (graph, resourceId) => getCircuitryDependencies(graph).filter((dependency) => dependency.from === resourceId).map((dependency) => dependency.to);
54
+ var getCircuitryRunSet = (graph, entry = graph.entry) => {
55
+ if (!entry) return [];
56
+ const visited = /* @__PURE__ */ new Set();
57
+ const visit = (id) => {
58
+ if (visited.has(id)) return;
59
+ const resource = graph.resources?.[id];
60
+ if (!resource) return;
61
+ for (const input of resourceInputIds(resource)) visit(input);
62
+ visited.add(id);
67
63
  };
64
+ visit(entry);
65
+ return [...visited];
68
66
  };
69
- var expandResources = (resources) => {
70
- const nodes = [];
71
- const edges = [];
72
- for (const [id, resource] of Object.entries(resources)) {
73
- if (resource.type === "text") {
74
- nodes.push({ id, kind: "input", label: resource.label || id, input: { type: "text", value: resource.value } });
75
- } else if (resource.type === "agent") {
76
- const agent = resource;
77
- nodes.push({
78
- id,
79
- kind: "agent",
80
- label: agent.label || agent.identity || id,
81
- agent: {
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
88
- },
89
- skills: agent.skills,
90
- expect: agent.expect
91
- });
92
- for (const input of agent.inputs || []) edges.push({ from: input, to: id, kind: "dependency" });
93
- } else if (resource.type === "tool") {
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 } });
67
+ var toposortCircuitryResources = (graph, entry) => {
68
+ const ids = entry ? new Set(getCircuitryRunSet(graph, entry)) : new Set(Object.keys(graph.resources || {}));
69
+ const visiting = /* @__PURE__ */ new Set();
70
+ const visited = /* @__PURE__ */ new Set();
71
+ const ordered = [];
72
+ const visit = (id) => {
73
+ if (!ids.has(id) || visited.has(id)) return;
74
+ if (visiting.has(id)) throw new Error(`Circuitry resource dependency cycle at ${id}`);
75
+ visiting.add(id);
76
+ const resource = graph.resources?.[id];
77
+ if (resource) for (const input of resourceInputIds(resource)) visit(input);
78
+ visiting.delete(id);
79
+ visited.add(id);
80
+ ordered.push(id);
81
+ };
82
+ for (const id of ids) visit(id);
83
+ return ordered;
84
+ };
85
+ var runtimeInputToText = (value) => {
86
+ if (typeof value === "string") return value;
87
+ if (value === void 0) return "";
88
+ return YAML.stringify(value).trimEnd();
89
+ };
90
+ var resolveCircuitrySource = (graph) => {
91
+ const inputs = graph.inputs || graph.args || {};
92
+ const resources = { ...graph.resources || {} };
93
+ for (const [id, input] of Object.entries(inputs)) {
94
+ if (!resources[id]) {
95
+ resources[id] = {
96
+ type: "input",
97
+ from: id,
98
+ label: input.label,
99
+ description: input.description,
100
+ mime: input.mime || input.mimeType
101
+ };
100
102
  }
101
103
  }
102
- return { nodes, edges };
104
+ return { ...graph, circuitry: CIRCUITRY_SPEC_VERSION, imports: graph.imports || [], inputs, resources };
103
105
  };
104
- var normalizeCircuitryGraph = (graph) => {
105
- if (!graph.resources) return { ...graph };
106
- return { ...graph, ...expandResources(graph.resources) };
106
+ var applyCircuitryRuntimeInputs = (graph, inputs = {}) => {
107
+ const next = resolveCircuitrySource(graph);
108
+ const resources = { ...next.resources || {} };
109
+ for (const [id, value] of Object.entries(inputs)) {
110
+ const resource = resources[id];
111
+ if (!resource) throw new Error(`unknown input: ${id}`);
112
+ if (resource.type === "input") resources[id] = { ...resource, value, from: resource.from || id };
113
+ else resources[id] = { ...resource, value: runtimeInputToText(value) };
114
+ }
115
+ return { ...next, resources };
107
116
  };
108
- var validateCircuitryGraphInternal = (graph, standard = {}, source) => {
109
- const resolved = createCircuitryValidationStandard(standard, graph && typeof graph === "object" && !Array.isArray(graph) ? graph : void 0);
117
+ var validateCircuitrySource = (graph, standard = {}) => {
118
+ const resolvedStandard = createCircuitryValidationStandard(standard);
110
119
  const errors = [];
111
120
  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 };
121
+ if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
122
+ return { ok: false, errors: [{ code: "invalid_graph", message: "invalid graph" }], standard: resolvedStandard };
123
+ }
113
124
  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"]);
125
+ if (resolvedStandard.requireSpecVersion && g.circuitry !== resolvedStandard.version) issue("invalid_version", "invalid version", ["circuitry"]);
126
+ if (!g.resources || Object.keys(g.resources).length === 0) issue("missing_resources", "missing resources", ["resources"]);
127
+ if (g.nodes) issue("forbidden_nodes", "forbidden nodes", ["nodes"]);
128
+ if (g.edges) issue("forbidden_edges", "forbidden edges", ["edges"]);
129
+ if (g.agents) issue("forbidden_agents", "forbidden agents", ["agents"]);
130
+ const resolved = resolveCircuitrySource(g);
131
+ const ids = new Set(Object.keys(resolved.resources || {}));
132
+ if (resolved.entry && !ids.has(resolved.entry)) issue("unknown_entry", "unknown entry", ["entry"]);
133
+ for (const [name, target] of Object.entries(resolved.entries || {})) {
134
+ if (!ids.has(target)) issue("unknown_entry", `unknown entry: ${name}`, ["entries", name]);
123
135
  }
124
- const rules = new Set(resolved.rules.map(ruleName));
125
- const normalized = normalizeCircuitryGraph(g);
126
- const ids = /* @__PURE__ */ new Set();
127
- for (const [index, node] of (normalized.nodes || []).entries()) {
128
- if (!node.id) {
129
- issue("missing_node_id", "missing node id", ["nodes", index, "id"]);
130
- continue;
136
+ for (const [id, resource] of Object.entries(resolved.resources || {})) {
137
+ if (!resource.type) issue("missing_resource_type", "missing resource type", ["resources", id, "type"]);
138
+ for (const input of resourceInputIds(resource)) {
139
+ if (!ids.has(input)) issue("unknown_resource_input", `unknown resource input: ${input}`, ["resources", id, "inputs"]);
140
+ if (input === id) issue("self_input", "self input", ["resources", id, "inputs"]);
131
141
  }
132
- if (ids.has(node.id)) issue("duplicate_node_id", "duplicate node id", ["nodes", index, "id"]);
133
- ids.add(node.id);
134
- if (!node.kind) issue("missing_node_kind", "missing node kind", ["nodes", index, "kind"]);
135
142
  }
136
- const adjacency = /* @__PURE__ */ new Map();
137
- const incoming = /* @__PURE__ */ new Map();
138
- for (const id of ids) {
139
- adjacency.set(id, []);
140
- incoming.set(id, 0);
143
+ for (const [name, output] of Object.entries(resolved.outputs || {})) {
144
+ const root = output.from.split(".")[0];
145
+ if (!ids.has(root)) issue("unknown_output_source", `unknown output source: ${output.from}`, ["outputs", name, "from"]);
141
146
  }
142
- for (const [index, edge] of (normalized.edges || []).entries()) {
143
- if (!edge.from || !edge.to) {
144
- issue("missing_edge_endpoint", "missing edge endpoint", ["edges", index]);
145
- continue;
146
- }
147
- if (rules.has("no-self-loops") && edge.from === edge.to) {
148
- issue("self_loop", "self loop", ["edges", index]);
149
- continue;
150
- }
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"]);
155
- }
156
- if (ok) {
157
- adjacency.get(edge.from).push(edge.to);
158
- incoming.set(edge.to, (incoming.get(edge.to) || 0) + 1);
159
- }
160
- }
161
- if (rules.has("require-executable-inputs")) {
162
- const executable = new Set(resolved.executableKinds);
163
- for (const [index, node] of (normalized.nodes || []).entries()) {
164
- if (executable.has(node.kind) && (incoming.get(node.id) || 0) === 0) issue("missing_executable_input", "missing executable input", ["nodes", index]);
165
- }
147
+ try {
148
+ toposortCircuitryResources(resolved);
149
+ } catch {
150
+ issue("cycle", "cycle");
166
151
  }
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;
178
- };
179
- for (const id of ids) if (visit(id)) {
180
- issue("cycle", "cycle");
181
- break;
182
- }
152
+ return { ok: errors.length === 0, errors, standard: resolvedStandard };
153
+ };
154
+ var validateCircuitryGraphWithStandard = validateCircuitrySource;
155
+ var validateCircuitryExecutionGraphWithStandard = validateCircuitrySource;
156
+ var validateCircuitryGraph = (graph, standard = {}) => validateCircuitrySource(graph, standard).errors.map((error) => error.message);
157
+ var inspectCircuitrySource = (graph) => {
158
+ const resolved = resolveCircuitrySource(graph);
159
+ return {
160
+ version: String(resolved.circuitry),
161
+ title: resolved.title,
162
+ entry: resolved.entry,
163
+ entries: resolved.entries || {},
164
+ inputs: Object.keys(resolved.inputs || {}),
165
+ resources: Object.keys(resolved.resources || {}),
166
+ outputs: Object.keys(resolved.outputs || {}),
167
+ dependencies: getCircuitryDependencies(resolved)
168
+ };
169
+ };
170
+ var parseCircuitrySource = (value) => {
171
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Circuitry source must be an object.");
172
+ return value;
173
+ };
174
+ var isUriInput = (input) => Boolean(input.uri || ["file", "url", "uri", "image", "mcp"].includes(String(input.type)));
175
+ var normalizeCircuitryGraph = (graph) => {
176
+ const resolved = resolveCircuitrySource(graph);
177
+ const nodes = [];
178
+ for (const [id, resource] of Object.entries(resolved.resources || {})) {
179
+ if (resource.type === "agent") nodes.push({ id, kind: "agent", label: resource.label || resource.identity || id, agent: { identity: resource.identity, model: resource.model, tools: resource.tools, instructions: resource.instructions, personality: resource.personality, context: resource.context }, skills: resource.skills, expect: resource.expect });
180
+ else nodes.push({ id, kind: resource.type === "tool" ? "tool" : "input", label: resource.label || id, input: { type: resource.type, value: typeof resource.value === "string" ? resource.value : void 0, uri: resource.uri || resource.path, mimeType: resource.mime || resource.mimeType, data: resource.data } });
183
181
  }
184
- return { ok: errors.length === 0, errors, standard: resolved };
182
+ const edges = getCircuitryDependencies(resolved).map(({ from, to }) => ({ from, to, kind: "dependency" }));
183
+ return { ...resolved, nodes, edges };
185
184
  };
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));
190
185
 
191
186
  // src/yaml.ts
192
187
  import YAML2 from "yaml";
@@ -521,7 +516,7 @@ var runCircuitryGraphExecution = async ({
521
516
  const executionGraph = buildCircuitryExecutionGraph(graph);
522
517
  const runs = [];
523
518
  const parallelism = Math.max(1, Math.floor(maxParallelRuns));
524
- const defaultModel = graph.runtime?.model;
519
+ const defaultModel = typeof graph.runtime?.model === "string" ? graph.runtime.model : void 0;
525
520
  const runOne = async (nodeId, outputs2) => {
526
521
  const cycle = false;
527
522
  const item = executionGraph.nodes.get(nodeId);
@@ -1003,7 +998,6 @@ export {
1003
998
  CIRCUITRY_NODE_CUSTOM_TYPE,
1004
999
  CIRCUITRY_NODE_KIND,
1005
1000
  CIRCUITRY_SPEC_VERSION,
1006
- DEFAULT_CIRCUITRY_VALIDATION_RULES,
1007
1001
  DEFAULT_CIRCUITRY_VALIDATION_STANDARD,
1008
1002
  DEFAULT_MAX_PARALLEL_RUNS,
1009
1003
  applyAgentPresets,
@@ -1019,16 +1013,23 @@ export {
1019
1013
  createCircuitryWriteGraphTool,
1020
1014
  createDefaultNodeData,
1021
1015
  createUnsupportedRuntimeAdapter,
1016
+ getCircuitryDependencies,
1017
+ getCircuitryDependents,
1018
+ getCircuitryRunSet,
1019
+ getResourceInputs,
1022
1020
  hasCircuitryNodeData,
1023
1021
  importBundleElements,
1022
+ inspectCircuitrySource,
1024
1023
  isNodeElement,
1025
1024
  isUriInput,
1026
1025
  normalizeCircuitryGraph,
1027
1026
  parseAgentPresetMarkdown,
1028
1027
  parseBundleText,
1028
+ parseCircuitrySource,
1029
1029
  parseCircuitryText,
1030
1030
  parseCircuitryYaml,
1031
1031
  parseYamlData,
1032
+ resolveCircuitrySource,
1032
1033
  runCircuitryGraphExecution,
1033
1034
  runDependencySimulation,
1034
1035
  runGraphExecution,
@@ -1037,7 +1038,9 @@ export {
1037
1038
  stringifyCircuitryText,
1038
1039
  stringifyCircuitryYaml,
1039
1040
  stringifyYamlData,
1041
+ toposortCircuitryResources,
1040
1042
  validateCircuitryExecutionGraphWithStandard,
1041
1043
  validateCircuitryGraph,
1042
- validateCircuitryGraphWithStandard
1044
+ validateCircuitryGraphWithStandard,
1045
+ validateCircuitrySource
1043
1046
  };