@runnerpro/backend 1.21.8 → 1.21.9
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/lib/cjs/prompt/ai.js
CHANGED
|
@@ -16,6 +16,7 @@ const modelPricing_1 = require("./modelPricing");
|
|
|
16
16
|
const constants_1 = require("./constants");
|
|
17
17
|
const googleModel_1 = require("./googleModel");
|
|
18
18
|
const slack_1 = require("../slack");
|
|
19
|
+
const llmCacheStore_1 = require("./llmCacheStore");
|
|
19
20
|
const MIN_RETRIES = 1;
|
|
20
21
|
// ✅ Detección de Chain-of-Thought (CoT) que se cuela en la respuesta final del modelo
|
|
21
22
|
const COT_HTML_TAG = /<\/?(thinking|thought|reasoning)\b/i;
|
|
@@ -204,6 +205,17 @@ function generateObject(options) {
|
|
|
204
205
|
return __awaiter(this, void 0, void 0, function* () {
|
|
205
206
|
let lastError;
|
|
206
207
|
let currentOptions = options;
|
|
208
|
+
// [llm-cache] cache-aside: HIT → output guardado sin llamar al modelo (opt-out con options.cache === false)
|
|
209
|
+
const co = currentOptions;
|
|
210
|
+
const useCache = co.cache !== false;
|
|
211
|
+
const schemaSig = useCache ? (0, llmCacheStore_1.schemaSignature)(co.schema) : null;
|
|
212
|
+
let cacheKey = null;
|
|
213
|
+
if (useCache) {
|
|
214
|
+
cacheKey = (0, llmCacheStore_1.llmCacheKey)({ system: co.system, prompt: co.prompt, schemaSig, temperature: co.temperature });
|
|
215
|
+
const hit = yield (0, llmCacheStore_1.lookup)(cacheKey);
|
|
216
|
+
if (hit !== null && hit !== undefined)
|
|
217
|
+
return { object: hit, cost: { inputTokens: 0, outputTokens: 0, cost: 0 } };
|
|
218
|
+
}
|
|
207
219
|
const fallbackNames = ((_a = currentOptions.model) === null || _a === void 0 ? void 0 : _a._fallbackModelNames) || [];
|
|
208
220
|
const maxAttempts = (1 + fallbackNames.length) * (1 + MIN_RETRIES);
|
|
209
221
|
let transientRetries = 0;
|
|
@@ -216,6 +228,8 @@ function generateObject(options) {
|
|
|
216
228
|
const tracker = costTrackingStorage.getStore();
|
|
217
229
|
if (tracker)
|
|
218
230
|
tracker.push(cost);
|
|
231
|
+
if (useCache && cacheKey)
|
|
232
|
+
(0, llmCacheStore_1.store)(cacheKey, { modelName, system: co.system, prompt: co.prompt, schemaSig, temperature: co.temperature, output: object });
|
|
219
233
|
return { object, cost };
|
|
220
234
|
}
|
|
221
235
|
catch (error) {
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.store = exports.lookup = exports.llmCacheKey = exports.schemaSignature = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* Caché LLM (cache-aside) para `generateObject`.
|
|
15
|
+
*
|
|
16
|
+
* Antes de cada llamada se busca por (modelo + system + input + schema + temperatura); si existe se
|
|
17
|
+
* devuelve el output guardado SIN llamar al modelo; si no, se llama y se guarda. Una poda periódica
|
|
18
|
+
* (Cron-backend /cron/operations/llmCacheEvict) elimina las entradas de un solo uso rancias.
|
|
19
|
+
*
|
|
20
|
+
* Fail-safe: un único chequeo `to_regclass` desactiva la caché en silencio si la tabla "LLM CACHE" no
|
|
21
|
+
* existe (migración no aplicada) o la BBDD falla. Así nunca rompe ni hace spam de errores.
|
|
22
|
+
*
|
|
23
|
+
* Tabla: ver migración en IA-backend docs/llm-cache-prod/001-llm-cache-table.sql.
|
|
24
|
+
*/
|
|
25
|
+
const node_crypto_1 = require("node:crypto");
|
|
26
|
+
const db_1 = require("../db");
|
|
27
|
+
let _ready = null; // null=sin comprobar, true=tabla disponible, false=desactivada
|
|
28
|
+
function ensureReady() {
|
|
29
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
if (_ready !== null)
|
|
31
|
+
return _ready;
|
|
32
|
+
try {
|
|
33
|
+
const rows = yield (0, db_1.query)('SELECT to_regclass(?) AS t', ['"LLM CACHE"']);
|
|
34
|
+
_ready = !!(rows && rows[0] && rows[0].t);
|
|
35
|
+
}
|
|
36
|
+
catch (_a) {
|
|
37
|
+
_ready = false;
|
|
38
|
+
}
|
|
39
|
+
return _ready;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** Firma ligera del schema (zod) para distinguir llamadas con el mismo prompt pero distinta forma. */
|
|
43
|
+
function schemaSignature(schema) {
|
|
44
|
+
var _a, _b;
|
|
45
|
+
try {
|
|
46
|
+
if (!schema)
|
|
47
|
+
return 'noschema';
|
|
48
|
+
const tn = ((_a = schema === null || schema === void 0 ? void 0 : schema._def) === null || _a === void 0 ? void 0 : _a.typeName) || ((_b = schema === null || schema === void 0 ? void 0 : schema.constructor) === null || _b === void 0 ? void 0 : _b.name) || 'schema';
|
|
49
|
+
let shape = schema === null || schema === void 0 ? void 0 : schema.shape;
|
|
50
|
+
if (!shape && (schema === null || schema === void 0 ? void 0 : schema._def))
|
|
51
|
+
shape = typeof schema._def.shape === 'function' ? schema._def.shape() : schema._def.shape;
|
|
52
|
+
const keys = shape ? Object.keys(shape).sort().join(',') : '';
|
|
53
|
+
return `${tn}:${keys}`;
|
|
54
|
+
}
|
|
55
|
+
catch (_c) {
|
|
56
|
+
return 'schema';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.schemaSignature = schemaSignature;
|
|
60
|
+
/**
|
|
61
|
+
* Clave determinista de una llamada: SYSTEM + INPUT + SCHEMA + TEMPERATURE.
|
|
62
|
+
* NO incluye el modelo a propósito: si esos 4 coinciden, se reutiliza el output guardado (lo haya
|
|
63
|
+
* generado el modelo que sea). Implica que cambiar de modelo NO invalida la caché.
|
|
64
|
+
*/
|
|
65
|
+
function llmCacheKey(opts) {
|
|
66
|
+
var _a;
|
|
67
|
+
const payload = JSON.stringify({
|
|
68
|
+
system: opts.system || '',
|
|
69
|
+
prompt: opts.prompt || '',
|
|
70
|
+
schema: opts.schemaSig || 'noschema',
|
|
71
|
+
temperature: (_a = opts.temperature) !== null && _a !== void 0 ? _a : null,
|
|
72
|
+
});
|
|
73
|
+
return (0, node_crypto_1.createHash)('sha256').update(payload).digest('hex');
|
|
74
|
+
}
|
|
75
|
+
exports.llmCacheKey = llmCacheKey;
|
|
76
|
+
/** HIT: incrementa USE COUNT + LAST USED y devuelve OUTPUT (atómico). null en MISS o ante error. */
|
|
77
|
+
function lookup(key) {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
if (!(yield ensureReady()))
|
|
80
|
+
return null;
|
|
81
|
+
try {
|
|
82
|
+
const rows = yield (0, db_1.query)('UPDATE "LLM CACHE" SET "USE COUNT" = "USE COUNT" + 1, "LAST USED AT" = now() WHERE "KEY" = ? RETURNING "OUTPUT"', [key]);
|
|
83
|
+
return rows && rows[0] ? rows[0].output : null;
|
|
84
|
+
}
|
|
85
|
+
catch (_a) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
exports.lookup = lookup;
|
|
91
|
+
/** MISS: inserta (ON CONFLICT cubre la carrera). Fire-and-forget, nunca lanza. */
|
|
92
|
+
function store(key, data) {
|
|
93
|
+
void ensureReady()
|
|
94
|
+
.then((ok) => {
|
|
95
|
+
var _a, _b;
|
|
96
|
+
if (!ok)
|
|
97
|
+
return undefined;
|
|
98
|
+
return (0, db_1.query)('INSERT INTO "LLM CACHE" ("KEY","MODEL","SYSTEM PROMPT","INPUT PROMPT","SCHEMA SIG","TEMPERATURE","OUTPUT") VALUES (?,?,?,?,?,?,?::jsonb) ON CONFLICT ("KEY") DO UPDATE SET "USE COUNT" = "LLM CACHE"."USE COUNT" + 1, "LAST USED AT" = now()', [key, data.modelName || null, data.system || null, data.prompt || null, data.schemaSig || null, (_a = data.temperature) !== null && _a !== void 0 ? _a : null, JSON.stringify((_b = data.output) !== null && _b !== void 0 ? _b : null)]);
|
|
99
|
+
})
|
|
100
|
+
.catch(() => { });
|
|
101
|
+
}
|
|
102
|
+
exports.store = store;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../../../src/prompt/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,IAAI,sBAAsB,EAAE,YAAY,IAAI,oBAAoB,EAAE,MAAM,IAAI,CAAC;AAEpG,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../../../src/prompt/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,IAAI,sBAAsB,EAAE,YAAY,IAAI,oBAAoB,EAAE,MAAM,IAAI,CAAC;AAEpG,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAwKhE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,iBAAe,cAAc,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,CAoD/H;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,iBAAe,YAAY,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,CA0C5H;AA2ED;;;;;;;;;;;;;;;;;GAiBG;AACH,iBAAe,mBAAmB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,SAAS,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAc5H;AAED,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Firma ligera del schema (zod) para distinguir llamadas con el mismo prompt pero distinta forma. */
|
|
2
|
+
declare function schemaSignature(schema: any): string;
|
|
3
|
+
/**
|
|
4
|
+
* Clave determinista de una llamada: SYSTEM + INPUT + SCHEMA + TEMPERATURE.
|
|
5
|
+
* NO incluye el modelo a propósito: si esos 4 coinciden, se reutiliza el output guardado (lo haya
|
|
6
|
+
* generado el modelo que sea). Implica que cambiar de modelo NO invalida la caché.
|
|
7
|
+
*/
|
|
8
|
+
declare function llmCacheKey(opts: {
|
|
9
|
+
system?: string;
|
|
10
|
+
prompt?: string;
|
|
11
|
+
schemaSig?: string | null;
|
|
12
|
+
temperature?: number | null;
|
|
13
|
+
}): string;
|
|
14
|
+
/** HIT: incrementa USE COUNT + LAST USED y devuelve OUTPUT (atómico). null en MISS o ante error. */
|
|
15
|
+
declare function lookup(key: string): Promise<any | null>;
|
|
16
|
+
/** MISS: inserta (ON CONFLICT cubre la carrera). Fire-and-forget, nunca lanza. */
|
|
17
|
+
declare function store(key: string, data: {
|
|
18
|
+
modelName?: string;
|
|
19
|
+
system?: string;
|
|
20
|
+
prompt?: string;
|
|
21
|
+
schemaSig?: string | null;
|
|
22
|
+
temperature?: number | null;
|
|
23
|
+
output: any;
|
|
24
|
+
}): void;
|
|
25
|
+
export { schemaSignature, llmCacheKey, lookup, store };
|
|
26
|
+
//# sourceMappingURL=llmCacheStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llmCacheStore.d.ts","sourceRoot":"","sources":["../../../../src/prompt/llmCacheStore.ts"],"names":[],"mappings":"AA4BA,sGAAsG;AACtG,iBAAS,eAAe,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,CAW5C;AAED;;;;GAIG;AACH,iBAAS,WAAW,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,MAAM,CAQ/H;AAED,oGAAoG;AACpG,iBAAe,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAQtD;AAED,kFAAkF;AAClF,iBAAS,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,GAAG,IAAI,CAUrK;AAED,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runnerpro/backend",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.9",
|
|
4
4
|
"description": "A collection of common backend functions",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./lib/cjs/index.js"
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"@ai-sdk/amazon-bedrock": "^4.0.89",
|
|
66
|
+
"@ai-sdk/azure": "^3.0.74",
|
|
66
67
|
"@ai-sdk/google": "^3.0.43",
|
|
67
68
|
"@ai-sdk/google-vertex": "^4.0.102",
|
|
68
69
|
"@google-cloud/speech": "^7.2.1",
|