@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
142 lines • 5.85 kB
JavaScript
/**
* Finding the sandbox kit at runtime, the way an app's `@vite()` finds its assets: the Vite plugin
* running in this process (dev), the descriptor it wrote (dev, Vite in another process), or the
* production manifest (`genui-sandbox-kit.json` and the assets it names). And turning what is found
* into what the sandbox definition tells the model and what `GET <agent>/config` tells the browser.
*/
import { existsSync, readFileSync, statSync } from 'node:fs';
import { join, resolve } from 'node:path';
import { sandboxKitManifestKeys } from './plugin.js';
function readJson(path) {
try {
return JSON.parse(readFileSync(path, 'utf8'));
}
catch {
return undefined;
}
}
function isDescriptor(value) {
return (typeof value === 'object' &&
value !== null &&
value.version === 2 &&
Array.isArray(value.components) &&
typeof value.assets === 'object');
}
/** Find the kit (re-read when the files change — dev rewrites them). */
export function sandboxKitDiscovery(options) {
const production = options.production ?? process.env.NODE_ENV === 'production';
const cache = new Map();
const cached = (path) => {
if (!existsSync(path))
return undefined;
const mtime = statSync(path).mtimeMs;
const hit = cache.get(path);
if (hit !== undefined && hit.mtime === mtime)
return hit.value;
const value = readJson(path);
cache.set(path, { mtime, value });
return value;
};
const mtimeOf = (path) => {
try {
return statSync(path).mtimeMs;
}
catch {
return 0;
}
};
/** The build's descriptor, and when it was written. */
const fromManifest = () => {
if (options.manifest === undefined)
return null;
const manifest = cached(resolve(options.root, options.manifest.file));
const file = manifest?.[sandboxKitManifestKeys(options.name).descriptor]?.file;
if (file === undefined)
return null;
const path = join(resolve(options.root, options.manifest.outDir), file);
const value = cached(path);
return isDescriptor(value) ? { value, mtime: mtimeOf(path) } : null;
};
/** The dev server's descriptor file, and when it was written. */
const fromDevFile = () => {
if (options.descriptor === undefined)
return null;
const path = resolve(options.root, options.descriptor);
const value = cached(path);
return isDescriptor(value) ? { value, mtime: mtimeOf(path) } : null;
};
const find = () => {
// A dev server in this process is current by definition.
const live = options.plugin?.()?.descriptor();
if (live !== undefined && live !== null)
return live;
const built = fromManifest();
if (production)
return built?.value ?? fromDevFile()?.value ?? null;
// Outside production, a dev descriptor left over from an earlier `vite dev` must not shadow a
// newer build (or the other way round): the one written last wins.
const dev = fromDevFile();
if (dev === null || built === null)
return dev?.value ?? built?.value ?? null;
return dev.mtime >= built.mtime ? dev.value : built.value;
};
return {
...(options.name !== undefined ? { name: options.name } : {}),
descriptor() {
const found = find();
if (found === null ||
(options.kitUrl === undefined &&
options.cssUrl === undefined &&
options.tailwindUrl === undefined))
return found;
const assets = { ...found.assets };
if (options.kitUrl !== undefined)
assets.kit = { url: options.kitUrl };
if (options.cssUrl !== undefined)
assets.css = { url: options.cssUrl };
if (options.tailwindUrl !== undefined)
assets.tailwind = {
url: options.tailwindUrl,
...(found.assets.tailwind?.css !== undefined ? { css: found.assets.tailwind.css } : {}),
};
return { ...found, ...(options.kitUrl !== undefined ? { jsx: true } : {}), assets };
},
};
}
/**
* `sandbox: { kit: true }` (or `true`) as the definition and the browser need it: docs and theme
* names from the discovery, asset urls for the client. What was asked for but not found is left out
* of what the browser is told (and of what the model is told), so a missing build degrades to the
* plain sandbox.
*/
export function resolveSandboxServer(sandbox, discovery) {
const given = sandbox === true ? {} : sandbox;
const kitAsked = given.kit === true;
const docs = () => {
const found = discovery.descriptor();
return found === null ? undefined : found;
};
const themeOn = given.theme !== false;
const define = {
...given,
...(kitAsked ? { kit: docs } : {}),
...(themeOn && typeof given.theme !== 'object'
? { theme: { vars: () => docs()?.theme?.vars } }
: {}),
};
return {
define,
client() {
const kitOn = given.kit !== undefined && given.kit !== false;
const assets = kitOn ? discovery.descriptor()?.assets : undefined;
return {
theme: themeOn,
...(assets !== undefined && discovery.name !== undefined ? { name: discovery.name } : {}),
...(assets?.kit ? { kit: assets.kit } : {}),
...(assets?.css ? { css: assets.css } : {}),
...(assets?.tailwind ? { tailwind: assets.tailwind } : {}),
};
},
};
}
//# sourceMappingURL=discover.js.map