@darkhorseprojects/circuitry 0.2.99 → 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 CHANGED
@@ -1,4 +1,4 @@
1
- export declare const CIRCUITRY_SPEC_VERSION: "0.2.99";
1
+ export declare const CIRCUITRY_SPEC_VERSION: "0.3.0";
2
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;
@@ -170,20 +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
- export type CircuitryGraphLink = string | {
173
+ /** Import declaration for bringing resources from another graph file. */
174
+ export type CircuitryImport = {
174
175
  /** Path to another .circuitry.yaml/.json file, resolved relative to this file. */
175
176
  path: string;
176
- /** Optional id prefix applied to imported resources. */
177
- prefix?: 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;
178
181
  };
179
182
  export type CircuitryGraph = {
180
- /** Spec version. Use "0.2.99" for linked graph files. */
183
+ /** Spec version. Use "0.3.0" for import-based graph files. */
181
184
  circuitry: CircuitrySpecVersion | string;
182
185
  id?: string;
183
186
  title?: string;
184
187
  description?: string;
185
- /** Files whose resources are merged into this graph before validation/execution. */
186
- links?: CircuitryGraphLink[];
188
+ /** Explicit imports of specific resources from other graph files. */
189
+ imports?: CircuitryImport[];
187
190
  resources?: Record<string, CircuitryResourceEntry>;
188
191
  /** Internal normalized execution nodes. Authored graph files must not set this. */
189
192
  nodes?: CircuitryNode[];
@@ -223,7 +226,7 @@ export type CircuitryValidationResult = {
223
226
  };
224
227
  export declare const DEFAULT_CIRCUITRY_VALIDATION_RULES: CircuitryValidationRuleEntry[];
225
228
  export declare const DEFAULT_CIRCUITRY_VALIDATION_STANDARD: {
226
- readonly version: "0.2.99";
229
+ readonly version: "0.3.0";
227
230
  readonly requireSpecVersion: true;
228
231
  readonly rules: CircuitryValidationRuleEntry[];
229
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.2.99";
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(["0.2", CIRCUITRY_SPEC_VERSION]);
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.2 graphs must use a resources: section", ["resources"]);
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.2 graph files must not use top-level agents:; use resources:", ["agents"]);
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.2 graph files must not use top-level inputs:; use resources:", ["inputs"]);
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.2 graph files must not use top-level nodes:; use resources:", ["nodes"]);
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.2 graph files must not use top-level edges:; use resource inputs:", ["edges"]);
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,11 +8,9 @@ export declare class NodeCircuitryHost implements CircuitryHost {
8
8
  private exists;
9
9
  private parseIssue;
10
10
  private parseGraphForValidation;
11
- private linkPath;
12
- private linkPrefix;
13
- private prefixResourceIds;
14
- private mergeResources;
15
- private resolveGraphLinks;
11
+ private resolveGraphImports;
12
+ /** Rewrite inputs in imported resource to use aliased resource ids. */
13
+ private rewriteImportInputs;
16
14
  private parseAndResolveGraph;
17
15
  private readGraphFile;
18
16
  readGraph(input?: {
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.2.99";
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(["0.2", CIRCUITRY_SPEC_VERSION]);
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.2 graphs must use a resources: section", ["resources"]);
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.2 graph files must not use top-level agents:; use resources:", ["agents"]);
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.2 graph files must not use top-level inputs:; use resources:", ["inputs"]);
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.2 graph files must not use top-level nodes:; use resources:", ["nodes"]);
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.2 graph files must not use top-level edges:; use resource inputs:", ["edges"]);
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,66 +840,53 @@ var NodeCircuitryHost = class {
837
840
  return { error: this.parseIssue(error, filename) };
838
841
  }
839
842
  }
840
- linkPath(link) {
841
- return typeof link === "string" ? link : link.path;
842
- }
843
- linkPrefix(link) {
844
- return typeof link === "string" ? "" : link.prefix || "";
845
- }
846
- prefixResourceIds(resources, prefix) {
847
- if (!prefix) return resources;
848
- const ids = new Set(Object.keys(resources));
849
- const prefixed = {};
850
- for (const [id, resource] of Object.entries(resources)) {
851
- const next = { ...resource };
852
- if ((next.type === "agent" || next.type === "tool") && next.inputs) {
853
- next.inputs = next.inputs.map((input) => ids.has(input) ? `${prefix}${input}` : input);
854
- }
855
- prefixed[`${prefix}${id}`] = next;
856
- }
857
- return prefixed;
858
- }
859
- mergeResources(target, source, fromFile) {
860
- for (const [id, resource] of Object.entries(source)) {
861
- if (target[id]) {
862
- throw new Error(`Linked Circuitry resource id collision: ${id} from ${fromFile}`);
863
- }
864
- target[id] = resource;
865
- }
866
- }
867
- async resolveGraphLinks(graph, filename, standard, stack = []) {
843
+ async resolveGraphImports(graph, filename, standard, stack = []) {
868
844
  const graphFile = path.resolve(filename);
869
845
  if (stack.includes(graphFile)) {
870
- throw new Error(`Circuitry graph link cycle: ${[...stack, graphFile].join(" -> ")}`);
846
+ throw new Error(`Circuitry graph import cycle: ${[...stack, graphFile].join(" -> ")}`);
871
847
  }
872
- const linkedResources = {};
848
+ const importedResources = {};
849
+ const aliasMap = {};
873
850
  const nextStack = [...stack, graphFile];
874
- for (const link of graph.links || []) {
875
- const rawPath = this.linkPath(link);
876
- if (!rawPath) throw new Error(`Circuitry graph link is missing path in ${graphFile}`);
877
- const linkedFile = path.resolve(path.dirname(graphFile), rawPath);
851
+ for (const imp of graph.imports || []) {
852
+ const linkedFile = path.resolve(path.dirname(graphFile), imp.path);
878
853
  const linkedText = await readFile(linkedFile, "utf8");
879
854
  const parsed = parseCircuitryText(linkedText, linkedFile, standard, { validate: false });
880
- const resolved = await this.resolveGraphLinks(parsed, linkedFile, standard, nextStack);
881
- this.mergeResources(
882
- linkedResources,
883
- this.prefixResourceIds(resolved.resources || {}, this.linkPrefix(link)),
884
- linkedFile
885
- );
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;
886
868
  }
887
869
  return {
888
870
  ...graph,
889
871
  resources: {
890
- ...linkedResources,
872
+ ...importedResources,
891
873
  ...graph.resources || {}
892
874
  }
893
875
  };
894
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
+ }
895
885
  async parseAndResolveGraph(text, filename, standard) {
896
886
  const parsed = this.parseGraphForValidation(text, filename, standard);
897
887
  if (!parsed.graph) return parsed;
898
888
  try {
899
- return { graph: await this.resolveGraphLinks(parsed.graph, filename, standard) };
889
+ return { graph: await this.resolveGraphImports(parsed.graph, filename, standard) };
900
890
  } catch (error) {
901
891
  return { error: this.parseIssue(error, filename) };
902
892
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darkhorseprojects/circuitry",
3
- "version": "0.2.99",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",