@fiado/type-kit 3.517.0 → 3.518.0
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/_test_/unit/rewardsEligibility/backofficeBarrel.test.ts +1 -0
- package/_test_/unit/rewardsEligibility/events.test.ts +1 -1
- package/_test_/unit/rewardsEligibility/generateRulesRequest.test.ts +50 -0
- package/_test_/unit/rewardsEligibility/generateRulesResponse.test.ts +12 -0
- package/_test_/unit/rewardsEligibility/ruleCatalogRich.test.ts +18 -0
- package/_test_/unit/rewardsEligibility/rulesAiEnums.test.ts +15 -0
- package/bin/rewardsEligibility/constants/BackofficeLimits.d.ts +4 -0
- package/bin/rewardsEligibility/constants/BackofficeLimits.js +5 -1
- package/bin/rewardsEligibility/dtos/backoffice/GenerateRulesRequest.d.ts +17 -0
- package/bin/rewardsEligibility/dtos/backoffice/GenerateRulesRequest.js +44 -0
- package/bin/rewardsEligibility/dtos/backoffice/GenerateRulesResponse.d.ts +18 -0
- package/bin/rewardsEligibility/dtos/backoffice/GenerateRulesResponse.js +12 -0
- package/bin/rewardsEligibility/dtos/backoffice/RuleCatalogResponse.d.ts +6 -1
- package/bin/rewardsEligibility/dtos/backoffice/RulesChatTurn.d.ts +6 -0
- package/bin/rewardsEligibility/dtos/backoffice/RulesChatTurn.js +32 -0
- package/bin/rewardsEligibility/enums/RewardsEligibilityErrorCodeEnum.d.ts +11 -1
- package/bin/rewardsEligibility/enums/RewardsEligibilityErrorCodeEnum.js +10 -0
- package/bin/rewardsEligibility/enums/RulesChatRoleEnum.d.ts +5 -0
- package/bin/rewardsEligibility/enums/RulesChatRoleEnum.js +9 -0
- package/bin/rewardsEligibility/index.d.ts +4 -0
- package/bin/rewardsEligibility/index.js +4 -0
- package/package.json +1 -1
- package/src/rewardsEligibility/constants/BackofficeLimits.ts +4 -0
- package/src/rewardsEligibility/dtos/backoffice/GenerateRulesRequest.ts +33 -0
- package/src/rewardsEligibility/dtos/backoffice/GenerateRulesResponse.ts +17 -0
- package/src/rewardsEligibility/dtos/backoffice/RuleCatalogResponse.ts +6 -2
- package/src/rewardsEligibility/dtos/backoffice/RulesChatTurn.ts +17 -0
- package/src/rewardsEligibility/enums/RewardsEligibilityErrorCodeEnum.ts +10 -0
- package/src/rewardsEligibility/enums/RulesChatRoleEnum.ts +5 -0
- package/src/rewardsEligibility/index.ts +4 -0
|
@@ -10,6 +10,7 @@ describe('barrel rewardsEligibility incluye el backoffice', () => {
|
|
|
10
10
|
'CreateRunRequest', 'PopulationRunRequest', 'ApproveRunRequest', 'QuotaImpactResponse', 'RunResponse', 'RunListResponse',
|
|
11
11
|
'RunResultResponse', 'RunResultListResponse', 'CreateRunResponse', 'MetricsPointResponse', 'FailedConditionStatResponse', 'MetricsQuery',
|
|
12
12
|
'MetricsDimensionEnum', 'RuleValueTypeEnum', 'ELIGIBILITY_ID_PATTERN', 'EVENT_KEY_PATTERN', 'REQUEST_ID_PATTERN', 'MAX_QUOTAS_PER_CAMPAIGN',
|
|
13
|
+
'RulesChatRoleEnum', 'RulesChatTurn', 'GenerateRulesRequest', 'GenerateRulesResponse', 'RULES_CHAT_TURN_MAX_LENGTH', 'RULES_CHAT_MAX_TURNS_HARD',
|
|
13
14
|
])('exporta %s', (name) => {
|
|
14
15
|
expect((kit as Record<string, object | string | number | RegExp>)[name]).toBeDefined();
|
|
15
16
|
});
|
|
@@ -77,7 +77,7 @@ describe('enums de rewardsEligibility (valores que viajan por HTTP)', () => {
|
|
|
77
77
|
expect(Object.values(TriggerTypeEnum).sort()).toEqual(['CRON', 'EVENT', 'MANUAL']);
|
|
78
78
|
const codes = Object.values(RewardsEligibilityErrorCodeEnum);
|
|
79
79
|
expect(codes).toEqual(expect.arrayContaining(['EVENT_TYPE_NOT_FOUND', 'INPUT_INVALID', 'RUN_NOT_FOUND']));
|
|
80
|
-
expect(codes).toHaveLength(
|
|
80
|
+
expect(codes).toHaveLength(35);
|
|
81
81
|
});
|
|
82
82
|
});
|
|
83
83
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import { InputFieldTypeEnum } from '../../../src/dynamicForm/enums/InputFieldTypeEnum';
|
|
5
|
+
import { GenerateRulesRequest } from '../../../src/rewardsEligibility/dtos/backoffice/GenerateRulesRequest';
|
|
6
|
+
|
|
7
|
+
const parse = async (body: object) => {
|
|
8
|
+
const value = plainToInstance(GenerateRulesRequest, body, { excludeExtraneousValues: true });
|
|
9
|
+
return { value, errors: await validate(value) };
|
|
10
|
+
};
|
|
11
|
+
const input = { key: 'buyerDirectoryId', type: InputFieldTypeEnum.DIRECTORY, label: 'Comprador', required: true };
|
|
12
|
+
const turn = (content: string, role = 'user') => ({ role, content });
|
|
13
|
+
const valid = { history: [turn('cuentas de menos de 7 días')], inputs: [input] };
|
|
14
|
+
|
|
15
|
+
describe('GenerateRulesRequest', () => {
|
|
16
|
+
it('acepta un chat con reglas actuales y el contrato de entrada', async () => {
|
|
17
|
+
const { errors, value } = await parse({ ...valid, currentRules: { match: 'ALL', groups: [] } });
|
|
18
|
+
expect(errors).toEqual([]);
|
|
19
|
+
expect(value.history[0]?.content).toBe('cuentas de menos de 7 días');
|
|
20
|
+
expect(value.currentRules).toEqual({ match: 'ALL', groups: [] });
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('acepta historial vacío y contrato vacío (el lambda decide con AI_CHAT_HISTORY_EMPTY)', async () => {
|
|
24
|
+
expect((await parse({ history: [], inputs: [] })).errors).toEqual([]);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('rechaza un rol inventado', async () => {
|
|
28
|
+
expect((await parse({ ...valid, history: [turn('hola', 'system')] })).errors.length).toBeGreaterThan(0);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('rechaza un turno vacío y uno de más de 4000 caracteres', async () => {
|
|
32
|
+
expect((await parse({ ...valid, history: [turn('')] })).errors.length).toBeGreaterThan(0);
|
|
33
|
+
expect((await parse({ ...valid, history: [turn('x'.repeat(4001))] })).errors.length).toBeGreaterThan(0);
|
|
34
|
+
expect((await parse({ ...valid, history: [turn('x'.repeat(4000))] })).errors).toEqual([]);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('rechaza más de 50 turnos (tope de seguridad del DTO)', async () => {
|
|
38
|
+
expect((await parse({ ...valid, history: Array.from({ length: 51 }, () => turn('a')) })).errors.length).toBeGreaterThan(0);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('rechaza inputs que no es un arreglo y currentRules que no es un objeto', async () => {
|
|
42
|
+
expect((await parse({ ...valid, inputs: 'x' })).errors.length).toBeGreaterThan(0);
|
|
43
|
+
expect((await parse({ ...valid, currentRules: 'x' })).errors.length).toBeGreaterThan(0);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('descarta propiedades que no son del contrato', async () => {
|
|
47
|
+
const { value } = await parse({ ...valid, hack: true });
|
|
48
|
+
expect('hack' in value).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { GenerateRulesResponse } from '../../../src/rewardsEligibility/dtos/backoffice/GenerateRulesResponse';
|
|
2
|
+
|
|
3
|
+
describe('GenerateRulesResponse (forma pública)', () => {
|
|
4
|
+
it('las tres salidas posibles del chat se pueden armar con la forma pública', () => {
|
|
5
|
+
const ready: GenerateRulesResponse = { explanation: 'Cuentas de hasta 7 días.', rules: { match: 'ALL', groups: [] }, valid: true };
|
|
6
|
+
const question: GenerateRulesResponse = { explanation: '¿A qué grupo te refieres?', valid: true };
|
|
7
|
+
const failed: GenerateRulesResponse = { explanation: 'No pude.', valid: false, problems: ['rules.groups[0].conditions[0].field: campo desconocido'] };
|
|
8
|
+
expect(ready.rules).toBeDefined();
|
|
9
|
+
expect(question.rules).toBeUndefined();
|
|
10
|
+
expect(failed.problems).toHaveLength(1);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { RuleValueTypeEnum } from '../../../src/rewardsEligibility/enums/RuleValueTypeEnum';
|
|
2
|
+
import type { RuleCatalogFieldResponse } from '../../../src/rewardsEligibility/dtos/backoffice/RuleCatalogResponse';
|
|
3
|
+
|
|
4
|
+
describe('RuleCatalogFieldResponse enriquecido', () => {
|
|
5
|
+
it('un campo puede traer descripción, frases de ejemplo y descripción por opción', () => {
|
|
6
|
+
const field: RuleCatalogFieldResponse = {
|
|
7
|
+
field: 'status', label: 'Estado de la cuenta', valueType: RuleValueTypeEnum.STRING, operators: ['EQUALS'],
|
|
8
|
+
description: 'Estado operativo del directorio del usuario.',
|
|
9
|
+
examplePhrases: ['usuarios activos'],
|
|
10
|
+
options: [{ value: 'ACTIVE', label: 'ACTIVE', description: 'cuenta operativa' }],
|
|
11
|
+
};
|
|
12
|
+
expect(field.options?.[0]?.description).toBe('cuenta operativa');
|
|
13
|
+
});
|
|
14
|
+
it('sigue siendo válido sin los campos nuevos', () => {
|
|
15
|
+
const field: RuleCatalogFieldResponse = { field: 'x', label: 'x', valueType: RuleValueTypeEnum.NUMBER, operators: ['GT'] };
|
|
16
|
+
expect(field.description).toBeUndefined();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RewardsEligibilityErrorCodeEnum } from '../../../src/rewardsEligibility/enums/RewardsEligibilityErrorCodeEnum';
|
|
2
|
+
import { RulesChatRoleEnum } from '../../../src/rewardsEligibility/enums/RulesChatRoleEnum';
|
|
3
|
+
|
|
4
|
+
describe('enums de la generación de reglas con IA', () => {
|
|
5
|
+
it('los roles del chat son user y assistant (los mismos del prompt de benefits)', () => {
|
|
6
|
+
expect(Object.values(RulesChatRoleEnum)).toEqual(['user', 'assistant']);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it.each(['AI_CHAT_HISTORY_EMPTY', 'AI_CHAT_HISTORY_TOO_LONG', 'AI_GENERATION_FAILED', 'AI_RESPONSE_UNPARSEABLE', 'AI_GENERATION_TIMEOUT'] as const)(
|
|
10
|
+
'el código %s existe y su valor es su nombre',
|
|
11
|
+
(code) => {
|
|
12
|
+
expect(RewardsEligibilityErrorCodeEnum[code]).toBe(code);
|
|
13
|
+
},
|
|
14
|
+
);
|
|
15
|
+
});
|
|
@@ -10,3 +10,7 @@ export declare const REQUEST_ID_PATTERN: RegExp;
|
|
|
10
10
|
export declare const MAX_QUOTAS_PER_CAMPAIGN = 9;
|
|
11
11
|
/** Tope de `limit` de los listados paginados. */
|
|
12
12
|
export declare const LIST_PAGE_MAX = 100;
|
|
13
|
+
/** Largo máximo del texto de un turno del chat que genera reglas. */
|
|
14
|
+
export declare const RULES_CHAT_TURN_MAX_LENGTH = 4000;
|
|
15
|
+
/** Tope de seguridad de turnos que acepta el DTO (el límite funcional, 10, lo aplica el lambda con `AI_CHAT_HISTORY_TOO_LONG`). */
|
|
16
|
+
export declare const RULES_CHAT_MAX_TURNS_HARD = 50;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LIST_PAGE_MAX = exports.MAX_QUOTAS_PER_CAMPAIGN = exports.REQUEST_ID_PATTERN = exports.DATE_PATTERN = exports.EVENT_KEY_PATTERN = exports.ELIGIBILITY_ID_PATTERN = void 0;
|
|
3
|
+
exports.RULES_CHAT_MAX_TURNS_HARD = exports.RULES_CHAT_TURN_MAX_LENGTH = exports.LIST_PAGE_MAX = exports.MAX_QUOTAS_PER_CAMPAIGN = exports.REQUEST_ID_PATTERN = exports.DATE_PATTERN = exports.EVENT_KEY_PATTERN = exports.ELIGIBILITY_ID_PATTERN = void 0;
|
|
4
4
|
/** Id de campaña, evaluación (minúsculas, dígitos y guion; 2 a 64; sin `#` ni `:` porque entran en llaves compuestas y en la idempotencyKey). */
|
|
5
5
|
exports.ELIGIBILITY_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$/;
|
|
6
6
|
/** `eventKey` de un tipo de evento: MAYÚSCULAS con guion bajo (ej. `PHONE_SALES_CODE_REDEEMED`). */
|
|
@@ -13,3 +13,7 @@ exports.REQUEST_ID_PATTERN = /^[A-Za-z0-9_-]{8,64}$/;
|
|
|
13
13
|
exports.MAX_QUOTAS_PER_CAMPAIGN = 9;
|
|
14
14
|
/** Tope de `limit` de los listados paginados. */
|
|
15
15
|
exports.LIST_PAGE_MAX = 100;
|
|
16
|
+
/** Largo máximo del texto de un turno del chat que genera reglas. */
|
|
17
|
+
exports.RULES_CHAT_TURN_MAX_LENGTH = 4000;
|
|
18
|
+
/** Tope de seguridad de turnos que acepta el DTO (el límite funcional, 10, lo aplica el lambda con `AI_CHAT_HISTORY_TOO_LONG`). */
|
|
19
|
+
exports.RULES_CHAT_MAX_TURNS_HARD = 50;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { JsonValue } from '../../../common';
|
|
2
|
+
import { InputField } from '../../../dynamicForm/dtos/InputField';
|
|
3
|
+
import { RulesChatTurn } from './RulesChatTurn';
|
|
4
|
+
/**
|
|
5
|
+
* `POST /rules/generate`: el chat del editor de reglas. El lambda arma el prompt con el catálogo de fuentes y ESTE contrato de entrada
|
|
6
|
+
* (qué sujetos `DIRECTORY` y qué campos de `input` existen), genera `{ match, groups[] }` y lo valida con el mismo `validateRule` de la evaluación.
|
|
7
|
+
*/
|
|
8
|
+
export declare class GenerateRulesRequest {
|
|
9
|
+
/** Del turno más viejo al más nuevo; el último es del admin (`user`). Entre 1 y 10 turnos (el lambda responde `AI_CHAT_HISTORY_EMPTY` / `AI_CHAT_HISTORY_TOO_LONG`). */
|
|
10
|
+
history: RulesChatTurn[];
|
|
11
|
+
/** Las reglas que el editor tiene ahora (`{ match, groups[] }`), para refinarlas. Ausente = regla nueva. */
|
|
12
|
+
currentRules?: {
|
|
13
|
+
[key: string]: JsonValue;
|
|
14
|
+
};
|
|
15
|
+
/** Contrato de entrada de la evaluación que se está editando (`InputField[]`, dominio `dynamicForm`): de aquí salen los `subject` y los campos de la fuente `input`. */
|
|
16
|
+
inputs: InputField[];
|
|
17
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.GenerateRulesRequest = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
const BackofficeLimits_1 = require("../../constants/BackofficeLimits");
|
|
16
|
+
const RulesChatTurn_1 = require("./RulesChatTurn");
|
|
17
|
+
/**
|
|
18
|
+
* `POST /rules/generate`: el chat del editor de reglas. El lambda arma el prompt con el catálogo de fuentes y ESTE contrato de entrada
|
|
19
|
+
* (qué sujetos `DIRECTORY` y qué campos de `input` existen), genera `{ match, groups[] }` y lo valida con el mismo `validateRule` de la evaluación.
|
|
20
|
+
*/
|
|
21
|
+
class GenerateRulesRequest {
|
|
22
|
+
}
|
|
23
|
+
exports.GenerateRulesRequest = GenerateRulesRequest;
|
|
24
|
+
__decorate([
|
|
25
|
+
(0, class_transformer_1.Expose)(),
|
|
26
|
+
(0, class_validator_1.IsArray)(),
|
|
27
|
+
(0, class_validator_1.ArrayMaxSize)(BackofficeLimits_1.RULES_CHAT_MAX_TURNS_HARD),
|
|
28
|
+
(0, class_validator_1.ValidateNested)({ each: true }),
|
|
29
|
+
(0, class_transformer_1.Type)(() => RulesChatTurn_1.RulesChatTurn),
|
|
30
|
+
__metadata("design:type", Array)
|
|
31
|
+
], GenerateRulesRequest.prototype, "history", void 0);
|
|
32
|
+
__decorate([
|
|
33
|
+
(0, class_transformer_1.Expose)(),
|
|
34
|
+
(0, class_validator_1.IsOptional)(),
|
|
35
|
+
(0, class_validator_1.IsObject)(),
|
|
36
|
+
__metadata("design:type", Object)
|
|
37
|
+
], GenerateRulesRequest.prototype, "currentRules", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, class_transformer_1.Expose)(),
|
|
40
|
+
(0, class_validator_1.IsArray)(),
|
|
41
|
+
(0, class_validator_1.ArrayMaxSize)(30),
|
|
42
|
+
(0, class_validator_1.IsObject)({ each: true }),
|
|
43
|
+
__metadata("design:type", Array)
|
|
44
|
+
], GenerateRulesRequest.prototype, "inputs", void 0);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { JsonValue } from '../../../common';
|
|
2
|
+
/**
|
|
3
|
+
* Respuesta de `POST /rules/generate`. Tres casos:
|
|
4
|
+
* - Reglas listas: `valid: true` + `rules` (ya validadas contra el catálogo y los inputs: el editor puede cargarlas tal cual).
|
|
5
|
+
* - La IA pidió una aclaración (o no podía con lo pedido): `valid: true`, SIN `rules`; la pregunta va en `explanation`.
|
|
6
|
+
* - La IA generó reglas que no pasaron la validación ni tras el reintento: `valid: false`, SIN `rules`, con `problems`.
|
|
7
|
+
*/
|
|
8
|
+
export declare class GenerateRulesResponse {
|
|
9
|
+
/** Qué hizo (o qué preguntó) la IA, en español. Siempre viene. */
|
|
10
|
+
explanation: string;
|
|
11
|
+
/** `{ match, groups[] }` de `@fiado/rules-engine`. */
|
|
12
|
+
rules?: {
|
|
13
|
+
[key: string]: JsonValue;
|
|
14
|
+
};
|
|
15
|
+
valid: boolean;
|
|
16
|
+
/** Mensajes legibles de la última salida inválida. Solo con `valid: false`. */
|
|
17
|
+
problems?: string[];
|
|
18
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GenerateRulesResponse = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Respuesta de `POST /rules/generate`. Tres casos:
|
|
6
|
+
* - Reglas listas: `valid: true` + `rules` (ya validadas contra el catálogo y los inputs: el editor puede cargarlas tal cual).
|
|
7
|
+
* - La IA pidió una aclaración (o no podía con lo pedido): `valid: true`, SIN `rules`; la pregunta va en `explanation`.
|
|
8
|
+
* - La IA generó reglas que no pasaron la validación ni tras el reintento: `valid: false`, SIN `rules`, con `problems`.
|
|
9
|
+
*/
|
|
10
|
+
class GenerateRulesResponse {
|
|
11
|
+
}
|
|
12
|
+
exports.GenerateRulesResponse = GenerateRulesResponse;
|
|
@@ -9,11 +9,16 @@ export declare class RuleCatalogFieldResponse {
|
|
|
9
9
|
operators: string[];
|
|
10
10
|
/** Params del campo (ej. ventana y moneda de `sumAmount`), como formulario dinámico. */
|
|
11
11
|
params?: InputField[];
|
|
12
|
-
/** Valores posibles si es un enum. */
|
|
12
|
+
/** Valores posibles si es un enum (con qué significa cada uno, si se sabe). */
|
|
13
13
|
options?: {
|
|
14
14
|
value: string;
|
|
15
15
|
label: string;
|
|
16
|
+
description?: string;
|
|
16
17
|
}[];
|
|
18
|
+
/** Qué es este campo, en una frase (tooltip del editor). */
|
|
19
|
+
description?: string;
|
|
20
|
+
/** Frases de ejemplo que típicamente piden este campo (ayuda del chat de IA). */
|
|
21
|
+
examplePhrases?: string[];
|
|
17
22
|
}
|
|
18
23
|
export declare class RuleCatalogSourceResponse {
|
|
19
24
|
source: string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.RulesChatTurn = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
const BackofficeLimits_1 = require("../../constants/BackofficeLimits");
|
|
16
|
+
const RulesChatRoleEnum_1 = require("../../enums/RulesChatRoleEnum");
|
|
17
|
+
/** Un turno del chat que genera reglas con IA. */
|
|
18
|
+
class RulesChatTurn {
|
|
19
|
+
}
|
|
20
|
+
exports.RulesChatTurn = RulesChatTurn;
|
|
21
|
+
__decorate([
|
|
22
|
+
(0, class_transformer_1.Expose)(),
|
|
23
|
+
(0, class_validator_1.IsEnum)(RulesChatRoleEnum_1.RulesChatRoleEnum),
|
|
24
|
+
__metadata("design:type", String)
|
|
25
|
+
], RulesChatTurn.prototype, "role", void 0);
|
|
26
|
+
__decorate([
|
|
27
|
+
(0, class_transformer_1.Expose)(),
|
|
28
|
+
(0, class_validator_1.IsString)(),
|
|
29
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
30
|
+
(0, class_validator_1.MaxLength)(BackofficeLimits_1.RULES_CHAT_TURN_MAX_LENGTH),
|
|
31
|
+
__metadata("design:type", String)
|
|
32
|
+
], RulesChatTurn.prototype, "content", void 0);
|
|
@@ -49,5 +49,15 @@ export declare enum RewardsEligibilityErrorCodeEnum {
|
|
|
49
49
|
/** 400: el rango pedido excede el tope de filas de la exportación. */
|
|
50
50
|
EXPORT_TOO_LARGE = "EXPORT_TOO_LARGE",
|
|
51
51
|
/** 503: la tabla de métricas no responde o no existe aún. */
|
|
52
|
-
METRICS_UNAVAILABLE = "METRICS_UNAVAILABLE"
|
|
52
|
+
METRICS_UNAVAILABLE = "METRICS_UNAVAILABLE",
|
|
53
|
+
/** 400: `POST /rules/generate` sin ningún turno de chat. */
|
|
54
|
+
AI_CHAT_HISTORY_EMPTY = "AI_CHAT_HISTORY_EMPTY",
|
|
55
|
+
/** 400: el chat tiene más de 10 turnos (se acota el prompt). */
|
|
56
|
+
AI_CHAT_HISTORY_TOO_LONG = "AI_CHAT_HISTORY_TOO_LONG",
|
|
57
|
+
/** 503: el motor de IA no respondió o falló. Reintentar. */
|
|
58
|
+
AI_GENERATION_FAILED = "AI_GENERATION_FAILED",
|
|
59
|
+
/** 503: la IA respondió algo que no se pudo leer como `{ explanation, rules }`. Reintentar. */
|
|
60
|
+
AI_RESPONSE_UNPARSEABLE = "AI_RESPONSE_UNPARSEABLE",
|
|
61
|
+
/** 503: la IA no contestó dentro del presupuesto de tiempo (el gateway corta a los 29 s). Reintentar. */
|
|
62
|
+
AI_GENERATION_TIMEOUT = "AI_GENERATION_TIMEOUT"
|
|
53
63
|
}
|
|
@@ -55,4 +55,14 @@ var RewardsEligibilityErrorCodeEnum;
|
|
|
55
55
|
RewardsEligibilityErrorCodeEnum["EXPORT_TOO_LARGE"] = "EXPORT_TOO_LARGE";
|
|
56
56
|
/** 503: la tabla de métricas no responde o no existe aún. */
|
|
57
57
|
RewardsEligibilityErrorCodeEnum["METRICS_UNAVAILABLE"] = "METRICS_UNAVAILABLE";
|
|
58
|
+
/** 400: `POST /rules/generate` sin ningún turno de chat. */
|
|
59
|
+
RewardsEligibilityErrorCodeEnum["AI_CHAT_HISTORY_EMPTY"] = "AI_CHAT_HISTORY_EMPTY";
|
|
60
|
+
/** 400: el chat tiene más de 10 turnos (se acota el prompt). */
|
|
61
|
+
RewardsEligibilityErrorCodeEnum["AI_CHAT_HISTORY_TOO_LONG"] = "AI_CHAT_HISTORY_TOO_LONG";
|
|
62
|
+
/** 503: el motor de IA no respondió o falló. Reintentar. */
|
|
63
|
+
RewardsEligibilityErrorCodeEnum["AI_GENERATION_FAILED"] = "AI_GENERATION_FAILED";
|
|
64
|
+
/** 503: la IA respondió algo que no se pudo leer como `{ explanation, rules }`. Reintentar. */
|
|
65
|
+
RewardsEligibilityErrorCodeEnum["AI_RESPONSE_UNPARSEABLE"] = "AI_RESPONSE_UNPARSEABLE";
|
|
66
|
+
/** 503: la IA no contestó dentro del presupuesto de tiempo (el gateway corta a los 29 s). Reintentar. */
|
|
67
|
+
RewardsEligibilityErrorCodeEnum["AI_GENERATION_TIMEOUT"] = "AI_GENERATION_TIMEOUT";
|
|
58
68
|
})(RewardsEligibilityErrorCodeEnum || (exports.RewardsEligibilityErrorCodeEnum = RewardsEligibilityErrorCodeEnum = {}));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RulesChatRoleEnum = void 0;
|
|
4
|
+
/** Quién habló en un turno del chat que genera reglas con IA (`POST /rules/generate`). */
|
|
5
|
+
var RulesChatRoleEnum;
|
|
6
|
+
(function (RulesChatRoleEnum) {
|
|
7
|
+
RulesChatRoleEnum["USER"] = "user";
|
|
8
|
+
RulesChatRoleEnum["ASSISTANT"] = "assistant";
|
|
9
|
+
})(RulesChatRoleEnum || (exports.RulesChatRoleEnum = RulesChatRoleEnum = {}));
|
|
@@ -31,6 +31,7 @@ export * from './dtos/EvaluationReward';
|
|
|
31
31
|
export * from './dtos/EvaluationTrigger';
|
|
32
32
|
export * from './enums/MetricsDimensionEnum';
|
|
33
33
|
export * from './enums/RuleValueTypeEnum';
|
|
34
|
+
export * from './enums/RulesChatRoleEnum';
|
|
34
35
|
export * from './constants/BackofficeLimits';
|
|
35
36
|
export * from './dtos/backoffice/CampaignRequest';
|
|
36
37
|
export * from './dtos/backoffice/CampaignStatusRequest';
|
|
@@ -51,6 +52,9 @@ export * from './dtos/backoffice/SimulateResponse';
|
|
|
51
52
|
export * from './dtos/backoffice/RuleCatalogResponse';
|
|
52
53
|
export * from './dtos/backoffice/PopulationSourceResponse';
|
|
53
54
|
export * from './dtos/backoffice/InputTypeResponse';
|
|
55
|
+
export * from './dtos/backoffice/RulesChatTurn';
|
|
56
|
+
export * from './dtos/backoffice/GenerateRulesRequest';
|
|
57
|
+
export * from './dtos/backoffice/GenerateRulesResponse';
|
|
54
58
|
export * from './dtos/backoffice/CreateRunRequest';
|
|
55
59
|
export * from './dtos/backoffice/PopulationRunRequest';
|
|
56
60
|
export * from './dtos/backoffice/ApproveRunRequest';
|
|
@@ -53,6 +53,7 @@ __exportStar(require("./dtos/EvaluationTrigger"), exports);
|
|
|
53
53
|
//Backoffice (fase 3): enums, constantes y DTOs
|
|
54
54
|
__exportStar(require("./enums/MetricsDimensionEnum"), exports);
|
|
55
55
|
__exportStar(require("./enums/RuleValueTypeEnum"), exports);
|
|
56
|
+
__exportStar(require("./enums/RulesChatRoleEnum"), exports);
|
|
56
57
|
__exportStar(require("./constants/BackofficeLimits"), exports);
|
|
57
58
|
__exportStar(require("./dtos/backoffice/CampaignRequest"), exports);
|
|
58
59
|
__exportStar(require("./dtos/backoffice/CampaignStatusRequest"), exports);
|
|
@@ -73,6 +74,9 @@ __exportStar(require("./dtos/backoffice/SimulateResponse"), exports);
|
|
|
73
74
|
__exportStar(require("./dtos/backoffice/RuleCatalogResponse"), exports);
|
|
74
75
|
__exportStar(require("./dtos/backoffice/PopulationSourceResponse"), exports);
|
|
75
76
|
__exportStar(require("./dtos/backoffice/InputTypeResponse"), exports);
|
|
77
|
+
__exportStar(require("./dtos/backoffice/RulesChatTurn"), exports);
|
|
78
|
+
__exportStar(require("./dtos/backoffice/GenerateRulesRequest"), exports);
|
|
79
|
+
__exportStar(require("./dtos/backoffice/GenerateRulesResponse"), exports);
|
|
76
80
|
__exportStar(require("./dtos/backoffice/CreateRunRequest"), exports);
|
|
77
81
|
__exportStar(require("./dtos/backoffice/PopulationRunRequest"), exports);
|
|
78
82
|
__exportStar(require("./dtos/backoffice/ApproveRunRequest"), exports);
|
package/package.json
CHANGED
|
@@ -10,3 +10,7 @@ export const REQUEST_ID_PATTERN = /^[A-Za-z0-9_-]{8,64}$/;
|
|
|
10
10
|
export const MAX_QUOTAS_PER_CAMPAIGN = 9;
|
|
11
11
|
/** Tope de `limit` de los listados paginados. */
|
|
12
12
|
export const LIST_PAGE_MAX = 100;
|
|
13
|
+
/** Largo máximo del texto de un turno del chat que genera reglas. */
|
|
14
|
+
export const RULES_CHAT_TURN_MAX_LENGTH = 4000;
|
|
15
|
+
/** Tope de seguridad de turnos que acepta el DTO (el límite funcional, 10, lo aplica el lambda con `AI_CHAT_HISTORY_TOO_LONG`). */
|
|
16
|
+
export const RULES_CHAT_MAX_TURNS_HARD = 50;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Expose, Type } from 'class-transformer';
|
|
2
|
+
import { ArrayMaxSize, IsArray, IsObject, IsOptional, ValidateNested } from 'class-validator';
|
|
3
|
+
import { JsonValue } from '../../../common';
|
|
4
|
+
import { InputField } from '../../../dynamicForm/dtos/InputField';
|
|
5
|
+
import { RULES_CHAT_MAX_TURNS_HARD } from '../../constants/BackofficeLimits';
|
|
6
|
+
import { RulesChatTurn } from './RulesChatTurn';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* `POST /rules/generate`: el chat del editor de reglas. El lambda arma el prompt con el catálogo de fuentes y ESTE contrato de entrada
|
|
10
|
+
* (qué sujetos `DIRECTORY` y qué campos de `input` existen), genera `{ match, groups[] }` y lo valida con el mismo `validateRule` de la evaluación.
|
|
11
|
+
*/
|
|
12
|
+
export class GenerateRulesRequest {
|
|
13
|
+
/** Del turno más viejo al más nuevo; el último es del admin (`user`). Entre 1 y 10 turnos (el lambda responde `AI_CHAT_HISTORY_EMPTY` / `AI_CHAT_HISTORY_TOO_LONG`). */
|
|
14
|
+
@Expose()
|
|
15
|
+
@IsArray()
|
|
16
|
+
@ArrayMaxSize(RULES_CHAT_MAX_TURNS_HARD)
|
|
17
|
+
@ValidateNested({ each: true })
|
|
18
|
+
@Type(() => RulesChatTurn)
|
|
19
|
+
history: RulesChatTurn[];
|
|
20
|
+
|
|
21
|
+
/** Las reglas que el editor tiene ahora (`{ match, groups[] }`), para refinarlas. Ausente = regla nueva. */
|
|
22
|
+
@Expose()
|
|
23
|
+
@IsOptional()
|
|
24
|
+
@IsObject()
|
|
25
|
+
currentRules?: { [key: string]: JsonValue };
|
|
26
|
+
|
|
27
|
+
/** Contrato de entrada de la evaluación que se está editando (`InputField[]`, dominio `dynamicForm`): de aquí salen los `subject` y los campos de la fuente `input`. */
|
|
28
|
+
@Expose()
|
|
29
|
+
@IsArray()
|
|
30
|
+
@ArrayMaxSize(30)
|
|
31
|
+
@IsObject({ each: true })
|
|
32
|
+
inputs: InputField[];
|
|
33
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { JsonValue } from '../../../common';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Respuesta de `POST /rules/generate`. Tres casos:
|
|
5
|
+
* - Reglas listas: `valid: true` + `rules` (ya validadas contra el catálogo y los inputs: el editor puede cargarlas tal cual).
|
|
6
|
+
* - La IA pidió una aclaración (o no podía con lo pedido): `valid: true`, SIN `rules`; la pregunta va en `explanation`.
|
|
7
|
+
* - La IA generó reglas que no pasaron la validación ni tras el reintento: `valid: false`, SIN `rules`, con `problems`.
|
|
8
|
+
*/
|
|
9
|
+
export class GenerateRulesResponse {
|
|
10
|
+
/** Qué hizo (o qué preguntó) la IA, en español. Siempre viene. */
|
|
11
|
+
explanation: string;
|
|
12
|
+
/** `{ match, groups[] }` de `@fiado/rules-engine`. */
|
|
13
|
+
rules?: { [key: string]: JsonValue };
|
|
14
|
+
valid: boolean;
|
|
15
|
+
/** Mensajes legibles de la última salida inválida. Solo con `valid: false`. */
|
|
16
|
+
problems?: string[];
|
|
17
|
+
}
|
|
@@ -10,8 +10,12 @@ export class RuleCatalogFieldResponse {
|
|
|
10
10
|
operators: string[];
|
|
11
11
|
/** Params del campo (ej. ventana y moneda de `sumAmount`), como formulario dinámico. */
|
|
12
12
|
params?: InputField[];
|
|
13
|
-
/** Valores posibles si es un enum. */
|
|
14
|
-
options?: { value: string; label: string }[];
|
|
13
|
+
/** Valores posibles si es un enum (con qué significa cada uno, si se sabe). */
|
|
14
|
+
options?: { value: string; label: string; description?: string }[];
|
|
15
|
+
/** Qué es este campo, en una frase (tooltip del editor). */
|
|
16
|
+
description?: string;
|
|
17
|
+
/** Frases de ejemplo que típicamente piden este campo (ayuda del chat de IA). */
|
|
18
|
+
examplePhrases?: string[];
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
export class RuleCatalogSourceResponse {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Expose } from 'class-transformer';
|
|
2
|
+
import { IsEnum, IsNotEmpty, IsString, MaxLength } from 'class-validator';
|
|
3
|
+
import { RULES_CHAT_TURN_MAX_LENGTH } from '../../constants/BackofficeLimits';
|
|
4
|
+
import { RulesChatRoleEnum } from '../../enums/RulesChatRoleEnum';
|
|
5
|
+
|
|
6
|
+
/** Un turno del chat que genera reglas con IA. */
|
|
7
|
+
export class RulesChatTurn {
|
|
8
|
+
@Expose()
|
|
9
|
+
@IsEnum(RulesChatRoleEnum)
|
|
10
|
+
role: RulesChatRoleEnum;
|
|
11
|
+
|
|
12
|
+
@Expose()
|
|
13
|
+
@IsString()
|
|
14
|
+
@IsNotEmpty()
|
|
15
|
+
@MaxLength(RULES_CHAT_TURN_MAX_LENGTH)
|
|
16
|
+
content: string;
|
|
17
|
+
}
|
|
@@ -52,4 +52,14 @@ export enum RewardsEligibilityErrorCodeEnum {
|
|
|
52
52
|
EXPORT_TOO_LARGE = 'EXPORT_TOO_LARGE',
|
|
53
53
|
/** 503: la tabla de métricas no responde o no existe aún. */
|
|
54
54
|
METRICS_UNAVAILABLE = 'METRICS_UNAVAILABLE',
|
|
55
|
+
/** 400: `POST /rules/generate` sin ningún turno de chat. */
|
|
56
|
+
AI_CHAT_HISTORY_EMPTY = 'AI_CHAT_HISTORY_EMPTY',
|
|
57
|
+
/** 400: el chat tiene más de 10 turnos (se acota el prompt). */
|
|
58
|
+
AI_CHAT_HISTORY_TOO_LONG = 'AI_CHAT_HISTORY_TOO_LONG',
|
|
59
|
+
/** 503: el motor de IA no respondió o falló. Reintentar. */
|
|
60
|
+
AI_GENERATION_FAILED = 'AI_GENERATION_FAILED',
|
|
61
|
+
/** 503: la IA respondió algo que no se pudo leer como `{ explanation, rules }`. Reintentar. */
|
|
62
|
+
AI_RESPONSE_UNPARSEABLE = 'AI_RESPONSE_UNPARSEABLE',
|
|
63
|
+
/** 503: la IA no contestó dentro del presupuesto de tiempo (el gateway corta a los 29 s). Reintentar. */
|
|
64
|
+
AI_GENERATION_TIMEOUT = 'AI_GENERATION_TIMEOUT',
|
|
55
65
|
}
|
|
@@ -42,6 +42,7 @@ export * from './dtos/EvaluationTrigger';
|
|
|
42
42
|
//Backoffice (fase 3): enums, constantes y DTOs
|
|
43
43
|
export * from './enums/MetricsDimensionEnum';
|
|
44
44
|
export * from './enums/RuleValueTypeEnum';
|
|
45
|
+
export * from './enums/RulesChatRoleEnum';
|
|
45
46
|
export * from './constants/BackofficeLimits';
|
|
46
47
|
export * from './dtos/backoffice/CampaignRequest';
|
|
47
48
|
export * from './dtos/backoffice/CampaignStatusRequest';
|
|
@@ -62,6 +63,9 @@ export * from './dtos/backoffice/SimulateResponse';
|
|
|
62
63
|
export * from './dtos/backoffice/RuleCatalogResponse';
|
|
63
64
|
export * from './dtos/backoffice/PopulationSourceResponse';
|
|
64
65
|
export * from './dtos/backoffice/InputTypeResponse';
|
|
66
|
+
export * from './dtos/backoffice/RulesChatTurn';
|
|
67
|
+
export * from './dtos/backoffice/GenerateRulesRequest';
|
|
68
|
+
export * from './dtos/backoffice/GenerateRulesResponse';
|
|
65
69
|
export * from './dtos/backoffice/CreateRunRequest';
|
|
66
70
|
export * from './dtos/backoffice/PopulationRunRequest';
|
|
67
71
|
export * from './dtos/backoffice/ApproveRunRequest';
|