You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

87 lines
2.5 KiB

// Some models may attempt to call an expensive or annoying function many times and in that case we will want
// to implement some stateful tracking during that agent session. GPT4 and other more powerful models are smart
// enough to realize this, but models like 3.5 lack this. Open source models suffer greatly from this issue.
// eg: "save something to file..."
// agent -> saves
// agent -> saves
// agent -> saves
// agent -> saves
// ... do random # of times.
// We want to block all the reruns of a plugin, so we can add this to prevent that behavior from
// spamming the user (or other costly function) that have the exact same signatures.
// Track Run/isDuplicate prevents _exact_ data re-runs based on the SHA of their inputs
// StartCooldown/isOnCooldown does prevention of _near-duplicate_ runs based on only the function name that is running.
// isUnique/markUnique/removeUniqueConstraint prevents one-time functions from re-running. EG: charting.
const crypto = require("crypto");
const DEFAULT_COOLDOWN_MS = 5 * 1000;
class Deduplicator {
#hashes = {};
#cooldowns = {};
#uniques = {};
constructor() {}
trackRun(key, params = {}) {
const hash = crypto
.createHash("sha256")
.update(JSON.stringify({ key, params }))
.digest("hex");
this.#hashes[hash] = Number(new Date());
}
isDuplicate(key, params = {}) {
const newSig = crypto
.createHash("sha256")
.update(JSON.stringify({ key, params }))
.digest("hex");
return this.#hashes.hasOwnProperty(newSig);
}
/**
* Resets the object property for this instance of the Deduplicator class
* @param {('runs'|'cooldowns'|'uniques')} type - The type of prop to reset
*/
reset(type = "runs") {
switch (type) {
case "runs":
this.#hashes = {};
break;
case "cooldowns":
this.#cooldowns = {};
break;
case "uniques":
this.#uniques = {};
break;
}
return;
}
startCooldown(
key,
parameters = {
cooldownInMs: DEFAULT_COOLDOWN_MS,
}
) {
this.#cooldowns[key] = Number(new Date()) + Number(parameters.cooldownInMs);
}
isOnCooldown(key) {
if (!this.#cooldowns.hasOwnProperty(key)) return false;
return Number(new Date()) <= this.#cooldowns[key];
}
isUnique(key) {
return !this.#uniques.hasOwnProperty(key);
}
removeUniqueConstraint(key) {
delete this.#uniques[key];
}
markUnique(key) {
this.#uniques[key] = Number(new Date());
}
}
module.exports.Deduplicator = Deduplicator;