@sema-agent/core
Version:
Stateless, task-oriented AI agent core
95 lines (94 loc) • 3.8 kB
JavaScript
import { mkdirSync, readFileSync, writeFileSync, existsSync } from "node:fs";
import { join, resolve, sep } from "node:path";
import { physicalPathOfExisting } from "../core/physical-path.js";
import { sanitizeScope } from "../stores/file/fs-atomic.js";
import { thrownText } from "../core/thrown-value.js";
function isPlainObject(v) {
return typeof v === "object" && v !== null && !Array.isArray(v);
}
export function mergeWorkflowArgs(callArgs, defaultArgs) {
const cloneDefaults = (v) => {
try {
return structuredClone(v);
}
catch {
return v;
}
};
if (callArgs === undefined)
return cloneDefaults(defaultArgs);
if (defaultArgs === undefined)
return callArgs;
if (isPlainObject(callArgs) && isPlainObject(defaultArgs)) {
return { ...cloneDefaults(defaultArgs), ...callArgs };
}
return callArgs;
}
export function normalizeStringArg(callArgs, defaultArgs, key = "topic") {
if (typeof callArgs === "string" && isPlainObject(defaultArgs))
return { [key]: callArgs };
return callArgs;
}
function safeFileStem(id) {
return /^[A-Za-z0-9._-]{1,120}$/.test(id) && !id.startsWith(".") ? id : undefined;
}
function containedBy(root, p) {
return p === root || p.startsWith(root + sep);
}
export function createFileWorkflowScriptStore(dir) {
const root = resolve(dir);
const scopeDir = (scope) => join(root, sanitizeScope(scope));
return {
scopePartitioned: true,
persist(runId, script, scope) {
const stem = safeFileStem(runId);
if (stem === undefined)
throw new Error(`workflow script store: unsafe runId for a filename: ${JSON.stringify(runId)}`);
const base = scopeDir(scope);
mkdirSync(base, { recursive: true, mode: 0o700 });
const path = join(base, `${stem}.js`);
writeFileSync(path, script, { encoding: "utf-8", mode: 0o600 });
return path;
},
load(scriptPath, scope) {
const base = scopeDir(scope);
const full = resolve(scriptPath);
if (!containedBy(base, full)) {
throw new Error(`workflow script store: scriptPath is outside this scope's script partition`);
}
const physRoot = physicalPathOfExisting(root);
const physBase = physicalPathOfExisting(base);
const physFull = physicalPathOfExisting(full);
const refusePhysical = () => {
throw new Error(`workflow script store: scriptPath is outside this scope's script partition after symlink resolution`);
};
if (!containedBy(physRoot, physBase))
refusePhysical();
if (!containedBy(physBase, physFull))
refusePhysical();
return readFileSync(physFull, "utf-8");
},
resolveName(name) {
if (/^wf_/i.test(name))
return undefined;
const stem = safeFileStem(name);
if (stem === undefined)
return undefined;
const path = join(root, `${stem}.js`);
if (!existsSync(path))
return undefined;
const script = readFileSync(path, "utf-8");
const argsPath = join(root, `${stem}.args.json`);
if (!existsSync(argsPath))
return { script };
let defaultArgs;
try {
defaultArgs = JSON.parse(readFileSync(argsPath, "utf-8"));
}
catch (err) {
throw new Error(`workflow script store: invalid defaultArgs JSON in ${stem}.args.json: ${thrownText(err)}`);
}
return { script, defaultArgs };
},
};
}