@darkhorseprojects/circuitry 0.2.33 → 0.3.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/graph.d.ts +15 -4
- package/dist/index.js +10 -7
- package/dist/node.d.ts +4 -0
- package/dist/node.js +76 -13
- package/package.json +1 -1
package/dist/graph.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export declare const CIRCUITRY_SPEC_VERSION: "0.
|
|
2
|
-
export type CircuitrySpecVersion = typeof CIRCUITRY_SPEC_VERSION;
|
|
1
|
+
export declare const CIRCUITRY_SPEC_VERSION: "0.3.0";
|
|
2
|
+
export type CircuitrySpecVersion = typeof CIRCUITRY_SPEC_VERSION | "0.2";
|
|
3
3
|
export type CircuitryNodeKind = "agent" | "input" | "tool" | "output" | string;
|
|
4
4
|
export type CircuitryEdgeKind = "context" | "dependency" | "message" | "control" | string;
|
|
5
5
|
export type CircuitryInputKind = "text" | "file" | "url" | "image" | "uri" | "canvas" | "mcp" | string;
|
|
@@ -170,12 +170,23 @@ export type CircuitryRuntimeInputs = Record<string, unknown>;
|
|
|
170
170
|
* graph source stable and catches misspelled input names before execution.
|
|
171
171
|
*/
|
|
172
172
|
export declare const applyCircuitryRuntimeInputs: (graph: CircuitryGraph, inputs?: CircuitryRuntimeInputs) => CircuitryGraph;
|
|
173
|
+
/** Import declaration for bringing resources from another graph file. */
|
|
174
|
+
export type CircuitryImport = {
|
|
175
|
+
/** Path to another .circuitry.yaml/.json file, resolved relative to this file. */
|
|
176
|
+
path: string;
|
|
177
|
+
/** Resource id to import from the source file. */
|
|
178
|
+
resource: string;
|
|
179
|
+
/** Optional local name (alias) for the imported resource. */
|
|
180
|
+
as?: string;
|
|
181
|
+
};
|
|
173
182
|
export type CircuitryGraph = {
|
|
174
|
-
/** Spec version. Use "0.
|
|
183
|
+
/** Spec version. Use "0.3.0" for import-based graph files. */
|
|
175
184
|
circuitry: CircuitrySpecVersion | string;
|
|
176
185
|
id?: string;
|
|
177
186
|
title?: string;
|
|
178
187
|
description?: string;
|
|
188
|
+
/** Explicit imports of specific resources from other graph files. */
|
|
189
|
+
imports?: CircuitryImport[];
|
|
179
190
|
resources?: Record<string, CircuitryResourceEntry>;
|
|
180
191
|
/** Internal normalized execution nodes. Authored graph files must not set this. */
|
|
181
192
|
nodes?: CircuitryNode[];
|
|
@@ -215,7 +226,7 @@ export type CircuitryValidationResult = {
|
|
|
215
226
|
};
|
|
216
227
|
export declare const DEFAULT_CIRCUITRY_VALIDATION_RULES: CircuitryValidationRuleEntry[];
|
|
217
228
|
export declare const DEFAULT_CIRCUITRY_VALIDATION_STANDARD: {
|
|
218
|
-
readonly version: "0.
|
|
229
|
+
readonly version: "0.3.0";
|
|
219
230
|
readonly requireSpecVersion: true;
|
|
220
231
|
readonly rules: CircuitryValidationRuleEntry[];
|
|
221
232
|
readonly executableKinds: ["agent", "tool", "output"];
|
package/dist/index.js
CHANGED
|
@@ -27,7 +27,7 @@ var isNodeElement = (element) => {
|
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
// src/graph.ts
|
|
30
|
-
var CIRCUITRY_SPEC_VERSION = "0.
|
|
30
|
+
var CIRCUITRY_SPEC_VERSION = "0.3.0";
|
|
31
31
|
var runtimeInputToText = (value) => {
|
|
32
32
|
if (typeof value === "string") return value;
|
|
33
33
|
if (value === void 0) return "";
|
|
@@ -136,7 +136,7 @@ var normalizeCircuitryGraph = (graph) => {
|
|
|
136
136
|
const { nodes, edges } = expandResources(graph.resources);
|
|
137
137
|
return { ...graph, nodes, edges };
|
|
138
138
|
};
|
|
139
|
-
var VALID_SPEC_VERSIONS = /* @__PURE__ */ new Set([
|
|
139
|
+
var VALID_SPEC_VERSIONS = /* @__PURE__ */ new Set(["0.3"]);
|
|
140
140
|
var validateCircuitryGraphInternal = (graph, standard = {}, options) => {
|
|
141
141
|
const resolvedStandard = createCircuitryValidationStandard(
|
|
142
142
|
standard,
|
|
@@ -160,19 +160,22 @@ var validateCircuitryGraphInternal = (graph, standard = {}, options) => {
|
|
|
160
160
|
}
|
|
161
161
|
if (options.sourceFormat) {
|
|
162
162
|
if (!graphObject.resources || Object.keys(graphObject.resources).length === 0) {
|
|
163
|
-
addError("missing_resources", "Circuitry v0.
|
|
163
|
+
addError("missing_resources", "Circuitry v0.3 graphs must use a resources: section", ["resources"]);
|
|
164
164
|
}
|
|
165
165
|
if (graphObject.agents && Object.keys(graphObject.agents).length > 0) {
|
|
166
|
-
addError("forbidden_agents", "Circuitry v0.
|
|
166
|
+
addError("forbidden_agents", "Circuitry v0.3 graph files must not use top-level agents:; use resources:", ["agents"]);
|
|
167
167
|
}
|
|
168
168
|
if (graphObject.inputs && Object.keys(graphObject.inputs).length > 0) {
|
|
169
|
-
addError("forbidden_inputs", "Circuitry v0.
|
|
169
|
+
addError("forbidden_inputs", "Circuitry v0.3 graph files must not use top-level inputs:; use resources:", ["inputs"]);
|
|
170
170
|
}
|
|
171
171
|
if (graphObject.nodes && graphObject.nodes.length > 0) {
|
|
172
|
-
addError("forbidden_nodes", "Circuitry v0.
|
|
172
|
+
addError("forbidden_nodes", "Circuitry v0.3 graph files must not use top-level nodes:; use resources:", ["nodes"]);
|
|
173
173
|
}
|
|
174
174
|
if (graphObject.edges && graphObject.edges.length > 0) {
|
|
175
|
-
addError("forbidden_edges", "Circuitry v0.
|
|
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"]);
|
|
176
179
|
}
|
|
177
180
|
}
|
|
178
181
|
const normalized = normalizeCircuitryGraph(graphObject);
|
package/dist/node.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ export declare class NodeCircuitryHost implements CircuitryHost {
|
|
|
8
8
|
private exists;
|
|
9
9
|
private parseIssue;
|
|
10
10
|
private parseGraphForValidation;
|
|
11
|
+
private resolveGraphImports;
|
|
12
|
+
/** Rewrite inputs in imported resource to use aliased resource ids. */
|
|
13
|
+
private rewriteImportInputs;
|
|
14
|
+
private parseAndResolveGraph;
|
|
11
15
|
private readGraphFile;
|
|
12
16
|
readGraph(input?: {
|
|
13
17
|
filename?: string;
|
package/dist/node.js
CHANGED
|
@@ -8,7 +8,7 @@ import os from "node:os";
|
|
|
8
8
|
import YAML from "yaml";
|
|
9
9
|
|
|
10
10
|
// src/graph.ts
|
|
11
|
-
var CIRCUITRY_SPEC_VERSION = "0.
|
|
11
|
+
var CIRCUITRY_SPEC_VERSION = "0.3.0";
|
|
12
12
|
var runtimeInputToText = (value) => {
|
|
13
13
|
if (typeof value === "string") return value;
|
|
14
14
|
if (value === void 0) return "";
|
|
@@ -117,7 +117,7 @@ var normalizeCircuitryGraph = (graph) => {
|
|
|
117
117
|
const { nodes, edges } = expandResources(graph.resources);
|
|
118
118
|
return { ...graph, nodes, edges };
|
|
119
119
|
};
|
|
120
|
-
var VALID_SPEC_VERSIONS = /* @__PURE__ */ new Set([
|
|
120
|
+
var VALID_SPEC_VERSIONS = /* @__PURE__ */ new Set(["0.3"]);
|
|
121
121
|
var validateCircuitryGraphInternal = (graph, standard = {}, options) => {
|
|
122
122
|
const resolvedStandard = createCircuitryValidationStandard(
|
|
123
123
|
standard,
|
|
@@ -141,19 +141,22 @@ var validateCircuitryGraphInternal = (graph, standard = {}, options) => {
|
|
|
141
141
|
}
|
|
142
142
|
if (options.sourceFormat) {
|
|
143
143
|
if (!graphObject.resources || Object.keys(graphObject.resources).length === 0) {
|
|
144
|
-
addError("missing_resources", "Circuitry v0.
|
|
144
|
+
addError("missing_resources", "Circuitry v0.3 graphs must use a resources: section", ["resources"]);
|
|
145
145
|
}
|
|
146
146
|
if (graphObject.agents && Object.keys(graphObject.agents).length > 0) {
|
|
147
|
-
addError("forbidden_agents", "Circuitry v0.
|
|
147
|
+
addError("forbidden_agents", "Circuitry v0.3 graph files must not use top-level agents:; use resources:", ["agents"]);
|
|
148
148
|
}
|
|
149
149
|
if (graphObject.inputs && Object.keys(graphObject.inputs).length > 0) {
|
|
150
|
-
addError("forbidden_inputs", "Circuitry v0.
|
|
150
|
+
addError("forbidden_inputs", "Circuitry v0.3 graph files must not use top-level inputs:; use resources:", ["inputs"]);
|
|
151
151
|
}
|
|
152
152
|
if (graphObject.nodes && graphObject.nodes.length > 0) {
|
|
153
|
-
addError("forbidden_nodes", "Circuitry v0.
|
|
153
|
+
addError("forbidden_nodes", "Circuitry v0.3 graph files must not use top-level nodes:; use resources:", ["nodes"]);
|
|
154
154
|
}
|
|
155
155
|
if (graphObject.edges && graphObject.edges.length > 0) {
|
|
156
|
-
addError("forbidden_edges", "Circuitry v0.
|
|
156
|
+
addError("forbidden_edges", "Circuitry v0.3 graph files must not use top-level edges:; use resource inputs:", ["edges"]);
|
|
157
|
+
}
|
|
158
|
+
if (graphObject.links && graphObject.links.length > 0) {
|
|
159
|
+
addError("forbidden_links", "Circuitry v0.3 graph files must use imports: instead of links:", ["links"]);
|
|
157
160
|
}
|
|
158
161
|
}
|
|
159
162
|
const normalized = normalizeCircuitryGraph(graphObject);
|
|
@@ -837,11 +840,71 @@ var NodeCircuitryHost = class {
|
|
|
837
840
|
return { error: this.parseIssue(error, filename) };
|
|
838
841
|
}
|
|
839
842
|
}
|
|
843
|
+
async resolveGraphImports(graph, filename, standard, stack = []) {
|
|
844
|
+
const graphFile = path.resolve(filename);
|
|
845
|
+
if (stack.includes(graphFile)) {
|
|
846
|
+
throw new Error(`Circuitry graph import cycle: ${[...stack, graphFile].join(" -> ")}`);
|
|
847
|
+
}
|
|
848
|
+
const importedResources = {};
|
|
849
|
+
const aliasMap = {};
|
|
850
|
+
const nextStack = [...stack, graphFile];
|
|
851
|
+
for (const imp of graph.imports || []) {
|
|
852
|
+
const linkedFile = path.resolve(path.dirname(graphFile), imp.path);
|
|
853
|
+
const linkedText = await readFile(linkedFile, "utf8");
|
|
854
|
+
const parsed = parseCircuitryText(linkedText, linkedFile, standard, { validate: false });
|
|
855
|
+
const resolved = await this.resolveGraphImports(parsed, linkedFile, standard, nextStack);
|
|
856
|
+
const resourceId = imp.resource;
|
|
857
|
+
const resource = resolved.resources?.[resourceId];
|
|
858
|
+
if (!resource) {
|
|
859
|
+
throw new Error(`Imported resource not found: ${resourceId} in ${imp.path}`);
|
|
860
|
+
}
|
|
861
|
+
const localId = imp.as || resourceId;
|
|
862
|
+
if (importedResources[localId]) {
|
|
863
|
+
throw new Error(`Imported Circuitry resource id collision: ${localId} from ${imp.path}`);
|
|
864
|
+
}
|
|
865
|
+
if (imp.as) aliasMap[resourceId] = localId;
|
|
866
|
+
const resourceWithRewrittenInputs = this.rewriteImportInputs(resource, aliasMap);
|
|
867
|
+
importedResources[localId] = resourceWithRewrittenInputs;
|
|
868
|
+
}
|
|
869
|
+
return {
|
|
870
|
+
...graph,
|
|
871
|
+
resources: {
|
|
872
|
+
...importedResources,
|
|
873
|
+
...graph.resources || {}
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
/** Rewrite inputs in imported resource to use aliased resource ids. */
|
|
878
|
+
rewriteImportInputs(resource, aliasMap) {
|
|
879
|
+
if (resource.type === "agent" || resource.type === "tool") {
|
|
880
|
+
const newInputs = (resource.inputs || []).map((input) => aliasMap[input] || input);
|
|
881
|
+
return { ...resource, inputs: newInputs };
|
|
882
|
+
}
|
|
883
|
+
return resource;
|
|
884
|
+
}
|
|
885
|
+
async parseAndResolveGraph(text, filename, standard) {
|
|
886
|
+
const parsed = this.parseGraphForValidation(text, filename, standard);
|
|
887
|
+
if (!parsed.graph) return parsed;
|
|
888
|
+
try {
|
|
889
|
+
return { graph: await this.resolveGraphImports(parsed.graph, filename, standard) };
|
|
890
|
+
} catch (error) {
|
|
891
|
+
return { error: this.parseIssue(error, filename) };
|
|
892
|
+
}
|
|
893
|
+
}
|
|
840
894
|
async readGraphFile(filename) {
|
|
841
895
|
const graphFile = this.resolveGraphFile(filename);
|
|
842
896
|
const text = await readFile(graphFile, "utf8");
|
|
843
|
-
const
|
|
844
|
-
|
|
897
|
+
const parsed = await this.parseAndResolveGraph(text, graphFile);
|
|
898
|
+
if (!parsed.graph) throw new Error(`Invalid Circuitry graph:
|
|
899
|
+
${parsed.error?.message}`);
|
|
900
|
+
const validation = validateCircuitryGraphWithStandard(parsed.graph);
|
|
901
|
+
if (validation.errors.length) {
|
|
902
|
+
throw new Error(
|
|
903
|
+
`Invalid Circuitry graph:
|
|
904
|
+
${validation.errors.map((e) => e.message).join("\n")}`
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
return { graphFile, text, graph: normalizeCircuitryGraph(parsed.graph) };
|
|
845
908
|
}
|
|
846
909
|
async readGraph(input = {}) {
|
|
847
910
|
const { graphFile, text, graph } = await this.readGraphFile(input.filename);
|
|
@@ -853,8 +916,8 @@ var NodeCircuitryHost = class {
|
|
|
853
916
|
if (input.graph)
|
|
854
917
|
return validateCircuitryGraphWithStandard(input.graph, input.standard);
|
|
855
918
|
const filename = input.filename || defaultFilename;
|
|
856
|
-
const parsed = this.
|
|
857
|
-
if (parsed
|
|
919
|
+
const parsed = await this.parseAndResolveGraph(input.text, filename, input.standard);
|
|
920
|
+
if ("error" in parsed) {
|
|
858
921
|
return {
|
|
859
922
|
ok: false,
|
|
860
923
|
errors: [parsed.error],
|
|
@@ -865,7 +928,7 @@ var NodeCircuitryHost = class {
|
|
|
865
928
|
}
|
|
866
929
|
async writeGraph(input) {
|
|
867
930
|
const graphFile = this.resolveGraphFile(input.filename);
|
|
868
|
-
const parsed = input.graph ? { graph: input.graph } : this.
|
|
931
|
+
const parsed = input.graph ? { graph: input.graph } : await this.parseAndResolveGraph(
|
|
869
932
|
input.text,
|
|
870
933
|
input.filename || graphFile,
|
|
871
934
|
input.standard
|
|
@@ -896,7 +959,7 @@ ${validation.errors.map((e) => e.message).join("\n")}`
|
|
|
896
959
|
async runGraph(input = {}) {
|
|
897
960
|
const source = input.source || (input.text ? "text" : "current");
|
|
898
961
|
const graphFile = this.resolveGraphFile(input.filename);
|
|
899
|
-
const parsed = source === "text" ? this.
|
|
962
|
+
const parsed = source === "text" ? await this.parseAndResolveGraph(
|
|
900
963
|
input.text,
|
|
901
964
|
input.filename || graphFile,
|
|
902
965
|
input.standard
|