@darkhorseprojects/circuitry 0.2.20 → 0.2.21
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.d.ts +0 -1
- package/dist/index.js +8 -241
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -176,7 +176,7 @@ var validateCircuitryGraphWithStandard = (graph, standard = {}) => {
|
|
|
176
176
|
graph && typeof graph === "object" && !Array.isArray(graph) ? graph : void 0
|
|
177
177
|
);
|
|
178
178
|
const errors = [];
|
|
179
|
-
const addError = (code, message,
|
|
179
|
+
const addError = (code, message, path2) => errors.push({ code, message, ...path2 ? { path: path2 } : {} });
|
|
180
180
|
if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
|
|
181
181
|
addError("invalid_graph", "Circuitry graph must be an object");
|
|
182
182
|
return { ok: false, errors, standard: resolvedStandard };
|
|
@@ -253,19 +253,19 @@ var validateCircuitryGraphWithStandard = (graph, standard = {}) => {
|
|
|
253
253
|
}
|
|
254
254
|
const visiting = /* @__PURE__ */ new Set();
|
|
255
255
|
const visited = /* @__PURE__ */ new Set();
|
|
256
|
-
const
|
|
256
|
+
const path = [];
|
|
257
257
|
let cycleMessage = "";
|
|
258
258
|
const visit = (id) => {
|
|
259
259
|
if (cycleMessage) return;
|
|
260
260
|
if (visiting.has(id)) {
|
|
261
|
-
cycleMessage = [...
|
|
261
|
+
cycleMessage = [...path.slice(path.indexOf(id)), id].join(" -> ");
|
|
262
262
|
return;
|
|
263
263
|
}
|
|
264
264
|
if (visited.has(id)) return;
|
|
265
265
|
visiting.add(id);
|
|
266
|
-
|
|
266
|
+
path.push(id);
|
|
267
267
|
for (const next of adjacency.get(id) || []) visit(next);
|
|
268
|
-
|
|
268
|
+
path.pop();
|
|
269
269
|
visiting.delete(id);
|
|
270
270
|
visited.add(id);
|
|
271
271
|
};
|
|
@@ -315,15 +315,15 @@ var validateCircuitryGraphWithStandard = (graph, standard = {}) => {
|
|
|
315
315
|
}
|
|
316
316
|
continue;
|
|
317
317
|
}
|
|
318
|
-
const checkString = (target, subject, id, match,
|
|
318
|
+
const checkString = (target, subject, id, match, path2) => {
|
|
319
319
|
const value = getField(subject, match.field);
|
|
320
320
|
const text = typeof value === "string" ? value : "";
|
|
321
321
|
const includes = text.includes(match.value);
|
|
322
322
|
if (rule.rule === "require-string" && !includes) {
|
|
323
|
-
addError("missing_required_string", `${target} ${id} field ${match.field} must include string: ${match.value}`,
|
|
323
|
+
addError("missing_required_string", `${target} ${id} field ${match.field} must include string: ${match.value}`, path2);
|
|
324
324
|
}
|
|
325
325
|
if (rule.rule === "reject-string" && includes) {
|
|
326
|
-
addError("rejected_string", `${target} ${id} field ${match.field} must not include string: ${match.value}`,
|
|
326
|
+
addError("rejected_string", `${target} ${id} field ${match.field} must not include string: ${match.value}`, path2);
|
|
327
327
|
}
|
|
328
328
|
};
|
|
329
329
|
for (const match of rule.graph || []) checkString("graph", normalized, "<root>", match, fieldPath(match.field));
|
|
@@ -1086,237 +1086,6 @@ var createCircuitryTools = (host) => [
|
|
|
1086
1086
|
createCircuitryRunGraphTool(host),
|
|
1087
1087
|
createCircuitryValidateGraphTool(host)
|
|
1088
1088
|
];
|
|
1089
|
-
|
|
1090
|
-
// src/node.ts
|
|
1091
|
-
import { access, readFile, writeFile } from "node:fs/promises";
|
|
1092
|
-
import fs from "node:fs";
|
|
1093
|
-
import path from "node:path";
|
|
1094
|
-
import os from "node:os";
|
|
1095
|
-
var loadPiSDK = async () => {
|
|
1096
|
-
const possiblePaths = [
|
|
1097
|
-
path.join(process.cwd(), "node_modules/@earendil-works/pi-coding-agent/dist/index.js"),
|
|
1098
|
-
path.join(os.homedir(), ".npm-global/lib/node_modules/@earendil-works/pi-coding-agent/dist/index.js")
|
|
1099
|
-
];
|
|
1100
|
-
for (const modulePath of possiblePaths) {
|
|
1101
|
-
if (fs.existsSync(modulePath)) {
|
|
1102
|
-
return await import(modulePath);
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
return await import("@earendil-works/pi-coding-agent");
|
|
1106
|
-
};
|
|
1107
|
-
var extractAssistantText = (message) => {
|
|
1108
|
-
if (!message || message.role !== "assistant") return "";
|
|
1109
|
-
if (typeof message.content === "string") return message.content;
|
|
1110
|
-
if (!Array.isArray(message.content)) return "";
|
|
1111
|
-
return message.content.filter((part) => part?.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
|
|
1112
|
-
};
|
|
1113
|
-
var withTimeout = async (promise, timeoutMs) => {
|
|
1114
|
-
let timeout;
|
|
1115
|
-
try {
|
|
1116
|
-
return await Promise.race([
|
|
1117
|
-
promise,
|
|
1118
|
-
new Promise((_, reject) => {
|
|
1119
|
-
timeout = setTimeout(
|
|
1120
|
-
() => reject(new Error(`Pi SDK request timed out after ${timeoutMs}ms`)),
|
|
1121
|
-
timeoutMs
|
|
1122
|
-
);
|
|
1123
|
-
})
|
|
1124
|
-
]);
|
|
1125
|
-
} finally {
|
|
1126
|
-
clearTimeout(timeout);
|
|
1127
|
-
}
|
|
1128
|
-
};
|
|
1129
|
-
var runNodeWithPiSDK = async ({
|
|
1130
|
-
model,
|
|
1131
|
-
prompt,
|
|
1132
|
-
images = [],
|
|
1133
|
-
tools = [],
|
|
1134
|
-
thinkingLevel = "off"
|
|
1135
|
-
}) => {
|
|
1136
|
-
let sdk;
|
|
1137
|
-
try {
|
|
1138
|
-
sdk = await loadPiSDK();
|
|
1139
|
-
} catch (error) {
|
|
1140
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1141
|
-
throw new Error(
|
|
1142
|
-
[
|
|
1143
|
-
"Circuitry could not load the Pi SDK package for execution.",
|
|
1144
|
-
"Ensure @earendil-works/pi-coding-agent is installed.",
|
|
1145
|
-
message
|
|
1146
|
-
].join("\n")
|
|
1147
|
-
);
|
|
1148
|
-
}
|
|
1149
|
-
const { AuthStorage, ModelRegistry, SessionManager, createAgentSession } = sdk;
|
|
1150
|
-
const authStorage = AuthStorage.create();
|
|
1151
|
-
const modelRegistry = ModelRegistry.create(authStorage);
|
|
1152
|
-
const [provider, ...modelParts] = String(model || "").split("/");
|
|
1153
|
-
const modelId = modelParts.join("/");
|
|
1154
|
-
const available = await modelRegistry.getAvailable();
|
|
1155
|
-
const selectedModel = (provider && modelId ? modelRegistry.find(provider, modelId) : void 0) || available.find((entry) => {
|
|
1156
|
-
if (!modelId) return false;
|
|
1157
|
-
return `${entry.provider}/${entry.id}` === `${provider}/${modelId}` || entry.id === modelId;
|
|
1158
|
-
}) || available[0];
|
|
1159
|
-
if (!selectedModel) {
|
|
1160
|
-
throw new Error("No Pi SDK models are available. Configure ~/.pi/agent/auth.json");
|
|
1161
|
-
}
|
|
1162
|
-
const { session } = await createAgentSession({
|
|
1163
|
-
model: selectedModel,
|
|
1164
|
-
thinkingLevel,
|
|
1165
|
-
sessionManager: SessionManager.inMemory(),
|
|
1166
|
-
authStorage,
|
|
1167
|
-
modelRegistry
|
|
1168
|
-
});
|
|
1169
|
-
session.setActiveToolsByName(Array.isArray(tools) ? tools.map((tool) => String(tool)) : []);
|
|
1170
|
-
let output = "";
|
|
1171
|
-
const unsubscribe = session.subscribe((event) => {
|
|
1172
|
-
if ((event.type === "message_update" || event.type === "message_end") && event.message?.role === "assistant") {
|
|
1173
|
-
output = extractAssistantText(event.message);
|
|
1174
|
-
}
|
|
1175
|
-
if (event.type === "agent_end" && Array.isArray(event.messages)) {
|
|
1176
|
-
const assistantMessage = [...event.messages].reverse().find((message) => message.role === "assistant");
|
|
1177
|
-
output = extractAssistantText(assistantMessage);
|
|
1178
|
-
}
|
|
1179
|
-
});
|
|
1180
|
-
try {
|
|
1181
|
-
const promptImages = images.filter((image) => image?.mediaType && image?.data).map((image) => ({
|
|
1182
|
-
type: "image",
|
|
1183
|
-
source: { type: "base64", mediaType: image.mediaType, data: image.data }
|
|
1184
|
-
}));
|
|
1185
|
-
await withTimeout(session.prompt(prompt, { images: promptImages }), 18e4);
|
|
1186
|
-
return { output: output.trim() };
|
|
1187
|
-
} finally {
|
|
1188
|
-
unsubscribe();
|
|
1189
|
-
session.dispose();
|
|
1190
|
-
}
|
|
1191
|
-
};
|
|
1192
|
-
var defaultFilename = "graph.circuitry.yaml";
|
|
1193
|
-
var NodeCircuitryHost = class {
|
|
1194
|
-
resolveGraphFile(filename) {
|
|
1195
|
-
return path.resolve(
|
|
1196
|
-
process.cwd(),
|
|
1197
|
-
filename || process.env.CIRCUITRY_GRAPH || defaultFilename
|
|
1198
|
-
);
|
|
1199
|
-
}
|
|
1200
|
-
runFileFor(filename) {
|
|
1201
|
-
return `${filename}.run.json`;
|
|
1202
|
-
}
|
|
1203
|
-
async exists(filename) {
|
|
1204
|
-
try {
|
|
1205
|
-
await access(filename);
|
|
1206
|
-
return true;
|
|
1207
|
-
} catch {
|
|
1208
|
-
return false;
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
parseIssue(error, filename) {
|
|
1212
|
-
return {
|
|
1213
|
-
code: "parse_error",
|
|
1214
|
-
message: error instanceof Error ? error.message : String(error),
|
|
1215
|
-
path: [filename]
|
|
1216
|
-
};
|
|
1217
|
-
}
|
|
1218
|
-
parseGraphForValidation(text, filename, standard) {
|
|
1219
|
-
try {
|
|
1220
|
-
return {
|
|
1221
|
-
graph: parseCircuitryText(text || "", filename, standard, {
|
|
1222
|
-
validate: false
|
|
1223
|
-
})
|
|
1224
|
-
};
|
|
1225
|
-
} catch (error) {
|
|
1226
|
-
return { error: this.parseIssue(error, filename) };
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
async readGraphFile(filename) {
|
|
1230
|
-
const graphFile = this.resolveGraphFile(filename);
|
|
1231
|
-
const text = await readFile(graphFile, "utf8");
|
|
1232
|
-
const graph = parseCircuitryText(text, graphFile);
|
|
1233
|
-
return { graphFile, text, graph };
|
|
1234
|
-
}
|
|
1235
|
-
async readGraph(input = {}) {
|
|
1236
|
-
const { graphFile, text, graph } = await this.readGraphFile(input.filename);
|
|
1237
|
-
const lastRunFile = this.runFileFor(graphFile);
|
|
1238
|
-
const lastRun = await this.exists(lastRunFile) ? JSON.parse(await readFile(lastRunFile, "utf8")) : void 0;
|
|
1239
|
-
return { filename: graphFile, graph, text, lastRun };
|
|
1240
|
-
}
|
|
1241
|
-
async validateGraph(input) {
|
|
1242
|
-
if (input.graph)
|
|
1243
|
-
return validateCircuitryGraphWithStandard(input.graph, input.standard);
|
|
1244
|
-
const filename = input.filename || defaultFilename;
|
|
1245
|
-
const parsed = this.parseGraphForValidation(input.text, filename, input.standard);
|
|
1246
|
-
if (parsed.error) {
|
|
1247
|
-
return {
|
|
1248
|
-
ok: false,
|
|
1249
|
-
errors: [parsed.error],
|
|
1250
|
-
standard: validateCircuitryGraphWithStandard({}, input.standard).standard
|
|
1251
|
-
};
|
|
1252
|
-
}
|
|
1253
|
-
return validateCircuitryGraphWithStandard(parsed.graph, input.standard);
|
|
1254
|
-
}
|
|
1255
|
-
async writeGraph(input) {
|
|
1256
|
-
const graphFile = this.resolveGraphFile(input.filename);
|
|
1257
|
-
const parsed = input.graph ? { graph: input.graph } : this.parseGraphForValidation(
|
|
1258
|
-
input.text,
|
|
1259
|
-
input.filename || graphFile,
|
|
1260
|
-
input.standard
|
|
1261
|
-
);
|
|
1262
|
-
if (!parsed.graph)
|
|
1263
|
-
throw new Error(`Invalid Circuitry graph:
|
|
1264
|
-
${parsed.error?.message}`);
|
|
1265
|
-
const validation = await this.validateGraph({
|
|
1266
|
-
graph: parsed.graph,
|
|
1267
|
-
standard: input.standard
|
|
1268
|
-
});
|
|
1269
|
-
if (validation.errors.length)
|
|
1270
|
-
throw new Error(
|
|
1271
|
-
`Invalid Circuitry graph:
|
|
1272
|
-
${validation.errors.map((e) => e.message).join("\n")}`
|
|
1273
|
-
);
|
|
1274
|
-
await writeFile(
|
|
1275
|
-
graphFile,
|
|
1276
|
-
stringifyCircuitryText(parsed.graph, graphFile),
|
|
1277
|
-
"utf8"
|
|
1278
|
-
);
|
|
1279
|
-
return {
|
|
1280
|
-
filename: graphFile,
|
|
1281
|
-
graph: parsed.graph,
|
|
1282
|
-
mode: "replace"
|
|
1283
|
-
};
|
|
1284
|
-
}
|
|
1285
|
-
async runGraph(input = {}) {
|
|
1286
|
-
const source = input.source || (input.text ? "text" : "current");
|
|
1287
|
-
const graphFile = this.resolveGraphFile(input.filename);
|
|
1288
|
-
const parsed = source === "text" ? this.parseGraphForValidation(
|
|
1289
|
-
input.text,
|
|
1290
|
-
input.filename || graphFile,
|
|
1291
|
-
input.standard
|
|
1292
|
-
) : { graph: (await this.readGraphFile(input.filename)).graph };
|
|
1293
|
-
if (!parsed.graph)
|
|
1294
|
-
throw new Error(`Invalid Circuitry graph:
|
|
1295
|
-
${parsed.error?.message}`);
|
|
1296
|
-
const validation = await this.validateGraph({
|
|
1297
|
-
graph: parsed.graph,
|
|
1298
|
-
standard: input.standard
|
|
1299
|
-
});
|
|
1300
|
-
if (validation.errors.length)
|
|
1301
|
-
throw new Error(
|
|
1302
|
-
`Invalid Circuitry graph:
|
|
1303
|
-
${validation.errors.map((e) => e.message).join("\n")}`
|
|
1304
|
-
);
|
|
1305
|
-
const runItems = await runCircuitryGraphExecution({
|
|
1306
|
-
graph: parsed.graph,
|
|
1307
|
-
selectedNodeId: input.selectedNodeId,
|
|
1308
|
-
executeNode: (req) => runNodeWithPiSDK(req)
|
|
1309
|
-
});
|
|
1310
|
-
const result = { completedAt: (/* @__PURE__ */ new Date()).toISOString(), runItems };
|
|
1311
|
-
if (source !== "text")
|
|
1312
|
-
await writeFile(
|
|
1313
|
-
this.runFileFor(graphFile),
|
|
1314
|
-
JSON.stringify(result, null, 2),
|
|
1315
|
-
"utf8"
|
|
1316
|
-
);
|
|
1317
|
-
return result;
|
|
1318
|
-
}
|
|
1319
|
-
};
|
|
1320
1089
|
export {
|
|
1321
1090
|
BUNDLE_MIME,
|
|
1322
1091
|
CIRCUITRY_AGENT_PRESET_DIRS,
|
|
@@ -1327,7 +1096,6 @@ export {
|
|
|
1327
1096
|
DEFAULT_CIRCUITRY_VALIDATION_RULES,
|
|
1328
1097
|
DEFAULT_CIRCUITRY_VALIDATION_STANDARD,
|
|
1329
1098
|
DEFAULT_MAX_PARALLEL_RUNS,
|
|
1330
|
-
NodeCircuitryHost,
|
|
1331
1099
|
applyAgentPresets,
|
|
1332
1100
|
buildCircuitryExecutionGraph,
|
|
1333
1101
|
buildSimulationGraph,
|
|
@@ -1353,7 +1121,6 @@ export {
|
|
|
1353
1121
|
runCircuitryGraphExecution,
|
|
1354
1122
|
runDependencySimulation,
|
|
1355
1123
|
runGraphExecution,
|
|
1356
|
-
runNodeWithPiSDK,
|
|
1357
1124
|
standardSchema,
|
|
1358
1125
|
stringifyCircuitryJson,
|
|
1359
1126
|
stringifyCircuitryText,
|