@sema-agent/core
Version:
Stateless, task-oriented AI agent core
92 lines (91 loc) • 2.41 kB
JavaScript
import { thrownText } from "./thrown-value.js";
function containedError(thrown) {
try {
if (thrown instanceof Error && typeof thrown.message === "string")
return thrown;
return new Error(String(thrown));
}
catch {
return new Error(`a thrown value of type ${typeof thrown} that cannot be inspected or converted to text`);
}
}
export function safeErrorMessage(error) {
try {
const m = error?.message;
if (typeof m === "string")
return m;
return thrownText(error);
}
catch {
return "a failure whose message could not be read";
}
}
export function createSafeNotifier(opts) {
const onError = opts?.onError;
let sites;
let total = 0;
const record = (site, thrown) => {
const error = containedError(thrown);
total += 1;
if (sites === undefined)
sites = new Map();
const state = sites.get(site);
if (state !== undefined) {
state.count += 1;
state.last = error;
return;
}
sites.set(site, { count: 1, last: error });
if (onError === undefined)
return;
try {
onError({ site, error, failures: 1 });
}
catch {
}
};
return {
notify(run, site) {
try {
run();
return true;
}
catch (e) {
record(site, e);
return false;
}
},
async notifyAsync(run, site) {
try {
await run();
return true;
}
catch (e) {
record(site, e);
return false;
}
},
get failures() {
return total;
},
failuresAt(site) {
return sites?.get(site)?.count ?? 0;
},
lastErrorAt(site) {
return sites?.get(site)?.last;
},
failedSites() {
return sites === undefined ? [] : [...sites.keys()];
},
};
}
export function observeThenableRejection(r, notifier, site) {
if (typeof r?.then === "function") {
r.then(undefined, (err) => {
const error = containedError(err);
notifier.notify(() => {
throw error;
}, site);
});
}
}