@backendkit-labs/aval-tools 0.1.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/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # @backendkit-labs/aval-tools
2
+
3
+ Herramientas de pago para agentes de `@backendkit-labs/agent-core` que gastan a través de una
4
+ instancia de [AVAL](../../../../workspace-ideas/internet) — credencial por agente, presupuesto
5
+ previo y bitácora encadenada.
6
+
7
+ ## Qué trae
8
+
9
+ - **`pay`** — la vía amarrada: el agente pide un techo de gasto, AVAL decide y paga. Devuelve
10
+ el resultado como texto: pagado (con el coste real y la referencia del carril), retenido
11
+ (con el `authorizationId` para consultar después) o denegado (con el motivo).
12
+ - **`check_payment`** — consulta el estado de una autorización propia por `authorizationId`.
13
+ Es la pieza que le faltaba al framework para la vía "retenido": nada bloquea una sesión
14
+ esperando a un humano, así que un gasto retenido se resuelve volviendo a preguntar más
15
+ tarde — en otra invocación, disparada por un trigger o por el propio usuario.
16
+
17
+ Ninguna herramienta guarda dinero ni credenciales del proveedor: eso lo tiene AVAL.
18
+
19
+ ## Instalación
20
+
21
+ ```bash
22
+ npm install @backendkit-labs/aval-tools
23
+ ```
24
+
25
+ ## Uso
26
+
27
+ ```ts
28
+ import { AgentEngine, ToolRegistry } from '@backendkit-labs/agent-core';
29
+ import { createAvalTools } from '@backendkit-labs/aval-tools';
30
+
31
+ const tools = new ToolRegistry();
32
+ for (const tool of createAvalTools({ baseUrl: 'https://aval.internal' })) {
33
+ tools.register(tool);
34
+ }
35
+
36
+ const profile = {
37
+ id: 'expedientes-bot',
38
+ // ...
39
+ allowedTools: ['pay', 'check_payment' /* ... */],
40
+ // La clave vive en el perfil de ESTE agente, no en una variable de entorno
41
+ // compartida por todos. Cárgala desde donde guardes secretos (vault,
42
+ // gestor de secretos del proveedor de nube, etc.), nunca en texto plano
43
+ // en un fichero que se vaya a commitear.
44
+ secrets: { AVAL_KEY: process.env.EXPEDIENTES_BOT_AVAL_KEY! },
45
+ };
46
+ ```
47
+
48
+ ## Configuración
49
+
50
+ ```ts
51
+ interface AvalToolsConfig {
52
+ baseUrl: string; // dónde está AVAL
53
+ secretName?: string; // nombre de la credencial en ctx.secrets — por defecto "AVAL_KEY"
54
+ timeoutMs?: number; // por defecto 15000
55
+ maxAttempts?: number; // por defecto 3
56
+ }
57
+ ```
58
+
59
+ ## El flujo de un gasto retenido
60
+
61
+ ```
62
+ 1. El agente llama a pay("tarifas.aduana", 0.70, "Actualización trimestral").
63
+ → "Retenido para aprobación humana. authorizationId=auth_xyz. [...]"
64
+ El turno del agente termina ahí. No hace falta que la sesión siga viva.
65
+
66
+ 2. Horas después, alguien aprueba el gasto desde la consola de AVAL —
67
+ aprobar es pagar: AVAL usa su propia credencial, el agente no interviene.
68
+
69
+ 3. Una invocación nueva del agente (un cron, un webhook, o simplemente el
70
+ usuario preguntando "¿ya se aprobó eso?") llama a
71
+ check_payment("auth_xyz").
72
+ → "auth_xyz → liquidado — el pago se completó. [...]"
73
+ ```
74
+
75
+ ## Por qué reintentar no duplica el gasto
76
+
77
+ `pay` deriva una clave de idempotencia a partir de la sesión y los argumentos exactos de la
78
+ llamada (`sha256(sessionId:counterparty:ceiling:purpose)`). Un reintento del propio agente
79
+ tras un timeout de red produce la misma clave y AVAL lo trata como una repetición, no como un
80
+ segundo gasto. Una llamada genuinamente distinta —otro importe, otro propósito, otra sesión—
81
+ obtiene una clave distinta por sí sola.
82
+
83
+ ## Qué pasa si AVAL no responde
84
+
85
+ `pay` y `check_payment` reintentan automáticamente ante errores de red o 5xx (backoff
86
+ exponencial con `jitter`, tres intentos por defecto). Los 4xx —denegado, credencial revocada,
87
+ límite superado— nunca se reintentan: son respuestas de negocio, no fallos de transporte, y
88
+ se devuelven al agente como texto para que decida qué hacer.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=check-payment.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-payment.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/check-payment.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const check_payment_1 = require("../check-payment");
4
+ function makeCtx(overrides = {}) {
5
+ return {
6
+ agentId: 'expedientes-bot',
7
+ sessionId: 'session-1',
8
+ memory: { get: () => undefined, set: () => undefined, getAll: () => ({}) },
9
+ askAgent: async () => '',
10
+ ...overrides,
11
+ };
12
+ }
13
+ function jsonResponse(status, body) {
14
+ return { status, ok: status >= 200 && status < 300, json: async () => body };
15
+ }
16
+ const config = { baseUrl: 'https://aval.test' };
17
+ const checkPayment = (0, check_payment_1.createCheckPaymentTool)(config);
18
+ beforeEach(() => {
19
+ global.fetch = jest.fn();
20
+ });
21
+ describe('check_payment', () => {
22
+ it('requires a credential before calling out', async () => {
23
+ const result = await checkPayment.execute({ authorizationId: 'auth_1' }, makeCtx());
24
+ expect(result).toMatch(/no tiene credencial de AVAL/);
25
+ expect(fetch).not.toHaveBeenCalled();
26
+ });
27
+ it('reports a resolved (settled) authorization', async () => {
28
+ fetch.mockResolvedValueOnce(jsonResponse(200, {
29
+ authorizationId: 'auth_2',
30
+ state: 'settled',
31
+ amount: 589500,
32
+ vendor: 'tarifas.aduana',
33
+ purpose: 'Padrón arancelario completo — trimestre',
34
+ rail: 'proxy',
35
+ reasons: ['Pagado por proxy: $0,5895.'],
36
+ createdAt: '2026-08-07T00:00:00.000Z',
37
+ }));
38
+ const result = await checkPayment.execute({ authorizationId: 'auth_2' }, makeCtx({ secrets: { AVAL_KEY: 'k' } }));
39
+ expect(result).toMatch(/liquidado/);
40
+ expect(result).toMatch(/\$0\.5895/); // 589500 micro-dollars, shown to sub-cent precision
41
+ expect(result).toMatch(/tarifas\.aduana/);
42
+ });
43
+ it('still shows "held" while nobody has decided yet', async () => {
44
+ fetch.mockResolvedValueOnce(jsonResponse(200, {
45
+ authorizationId: 'auth_3',
46
+ state: 'held',
47
+ amount: 700000,
48
+ vendor: 'tarifas.aduana',
49
+ purpose: 'Actualización trimestral',
50
+ rail: 'proxy',
51
+ reasons: [],
52
+ createdAt: '2026-08-07T00:00:00.000Z',
53
+ }));
54
+ const result = await checkPayment.execute({ authorizationId: 'auth_3' }, makeCtx({ secrets: { AVAL_KEY: 'k' } }));
55
+ expect(result).toMatch(/retenido/);
56
+ expect(result).toMatch(/todavía no se gastó nada/);
57
+ });
58
+ it('reports 404 as a plain not-found message, not a raw error', async () => {
59
+ fetch.mockResolvedValueOnce(jsonResponse(404, { error: 'No existe la autorización.' }));
60
+ const result = await checkPayment.execute({ authorizationId: 'auth_ghost' }, makeCtx({ secrets: { AVAL_KEY: 'k' } }));
61
+ expect(result).toMatch(/No existe/);
62
+ });
63
+ it('reports 403 as an ownership message when the authorization is not this agent\'s', async () => {
64
+ fetch.mockResolvedValueOnce(jsonResponse(403, { error: 'no es de este agente' }));
65
+ const result = await checkPayment.execute({ authorizationId: 'auth_other' }, makeCtx({ secrets: { AVAL_KEY: 'k' } }));
66
+ expect(result).toMatch(/no pertenece a este agente/);
67
+ });
68
+ });
69
+ //# sourceMappingURL=check-payment.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-payment.test.js","sourceRoot":"","sources":["../../src/__tests__/check-payment.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pay.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pay.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/pay.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const pay_1 = require("../pay");
4
+ function makeCtx(overrides = {}) {
5
+ return {
6
+ agentId: 'expedientes-bot',
7
+ sessionId: 'session-1',
8
+ memory: { get: () => undefined, set: () => undefined, getAll: () => ({}) },
9
+ askAgent: async () => '',
10
+ ...overrides,
11
+ };
12
+ }
13
+ function jsonResponse(status, body) {
14
+ return { status, ok: status >= 200 && status < 300, json: async () => body };
15
+ }
16
+ const config = { baseUrl: 'https://aval.test' };
17
+ const pay = (0, pay_1.createPayTool)(config);
18
+ beforeEach(() => {
19
+ global.fetch = jest.fn();
20
+ });
21
+ describe('pay', () => {
22
+ it('rejects without touching the network when the agent has no AVAL credential', async () => {
23
+ const result = await pay.execute({ counterparty: 'ocr.docs', ceilingUsd: 0.3, purpose: 'test' }, makeCtx());
24
+ expect(result).toMatch(/no tiene credencial de AVAL/);
25
+ expect(fetch).not.toHaveBeenCalled();
26
+ });
27
+ it('sends the ceiling in micro-dollars and a bearer token from ctx.secrets', async () => {
28
+ fetch.mockResolvedValueOnce(jsonResponse(200, {
29
+ decision: 'authorized',
30
+ authorizationId: 'auth_1',
31
+ rail: 'proxy',
32
+ reasons: [],
33
+ capability: {
34
+ rail: 'proxy',
35
+ kind: 'respuesta',
36
+ actual: 280000,
37
+ payment: { rail: 'proxy', asset: 'USD', nativeAmount: 280000, rate: 1, ref: 'req_abc' },
38
+ },
39
+ }));
40
+ await pay.execute({ counterparty: 'ocr.docs', ceilingUsd: 0.3, purpose: 'Lectura del pedimento' }, makeCtx({ secrets: { AVAL_KEY: 'aval_sk_test_secret' } }));
41
+ const [url, init] = fetch.mock.calls[0];
42
+ expect(url).toBe('https://aval.test/api/v1/spend');
43
+ expect(init.headers.authorization).toBe('Bearer aval_sk_test_secret');
44
+ const body = JSON.parse(init.body);
45
+ expect(body.ceiling).toBe(300000); // $0.30 → 300000 micro-dollars
46
+ expect(body.counterparty).toBe('ocr.docs');
47
+ expect(typeof body.idempotencyKey).toBe('string');
48
+ });
49
+ it('derives the same idempotency key for the same session and args, a different one for different args', async () => {
50
+ fetch.mockResolvedValue(jsonResponse(200, { decision: 'denied', reasons: [] }));
51
+ const ctx = makeCtx({ secrets: { AVAL_KEY: 'k' } });
52
+ await pay.execute({ counterparty: 'ocr.docs', ceilingUsd: 0.3, purpose: 'A' }, ctx);
53
+ await pay.execute({ counterparty: 'ocr.docs', ceilingUsd: 0.3, purpose: 'A' }, ctx);
54
+ await pay.execute({ counterparty: 'ocr.docs', ceilingUsd: 0.31, purpose: 'A' }, ctx);
55
+ const keys = fetch.mock.calls.map(([, init]) => JSON.parse(init.body).idempotencyKey);
56
+ expect(keys[0]).toBe(keys[1]);
57
+ expect(keys[0]).not.toBe(keys[2]);
58
+ });
59
+ it('reports a held spend without claiming money moved', async () => {
60
+ fetch.mockResolvedValueOnce(jsonResponse(200, {
61
+ decision: 'held',
62
+ authorizationId: 'auth_2',
63
+ reasons: ['$0,70 supera el umbral de $0,60: requiere aprobación de María Restrepo.'],
64
+ }));
65
+ const result = await pay.execute({ counterparty: 'tarifas.aduana', ceilingUsd: 0.7, purpose: 'Padrón' }, makeCtx({ secrets: { AVAL_KEY: 'k' } }));
66
+ expect(result).toMatch(/Retenido/);
67
+ expect(result).toMatch(/auth_2/);
68
+ expect(result).toMatch(/check_payment/);
69
+ expect(result).not.toMatch(/Pagado/);
70
+ });
71
+ it('surfaces the denial reason instead of a raw error', async () => {
72
+ fetch.mockResolvedValueOnce(jsonResponse(200, { decision: 'denied', reasons: ['$0,90 supera el tope por operación de $0,80.'] }));
73
+ const result = await pay.execute({ counterparty: 'tarifas.aduana', ceilingUsd: 0.9, purpose: 'Descarga' }, makeCtx({ secrets: { AVAL_KEY: 'k' } }));
74
+ expect(result).toMatch(/Denegado/);
75
+ expect(result).toMatch(/tope por operación/);
76
+ });
77
+ it('surfaces rate limiting with the retry window', async () => {
78
+ fetch.mockResolvedValueOnce(jsonResponse(429, { error: 'Demasiados intentos.', retryAfterSeconds: 57 }));
79
+ const result = await pay.execute({ counterparty: 'ocr.docs', ceilingUsd: 0.1, purpose: 'x' }, makeCtx({ secrets: { AVAL_KEY: 'k' } }));
80
+ expect(result).toMatch(/57 s/);
81
+ });
82
+ });
83
+ //# sourceMappingURL=pay.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pay.test.js","sourceRoot":"","sources":["../../src/__tests__/pay.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type AvalToolsConfig } from './client';
2
+ /**
3
+ * Creates the `check_payment` tool: the other half of the async approval
4
+ * story. `pay` can return "retenido" and end the turn there — nothing in the
5
+ * framework blocks waiting for a human. This tool is how a later invocation
6
+ * (a cron trigger, a follow-up prompt, a human asking "¿ya se aprobó?") finds
7
+ * out what happened without needing the console credential AVAL's dashboard
8
+ * requires.
9
+ */
10
+ export declare function createCheckPaymentTool(config: AvalToolsConfig): import("@backendkit-labs/agent-core").ToolDefinition;
11
+ //# sourceMappingURL=check-payment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-payment.d.ts","sourceRoot":"","sources":["../src/check-payment.ts"],"names":[],"mappings":"AACA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAyBtE;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,wDAoC7D"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCheckPaymentTool = createCheckPaymentTool;
4
+ const agent_core_1 = require("@backendkit-labs/agent-core");
5
+ const client_1 = require("./client");
6
+ const USD_PER_UNIT = 1_000_000;
7
+ const usdFormat = new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 6 });
8
+ const formatUsd = (units) => `$${usdFormat.format(units / USD_PER_UNIT)}`;
9
+ const STATE_LABEL = {
10
+ held: 'retenido — esperando aprobación humana, todavía no se gastó nada',
11
+ authorized: 'autorizado — AVAL está pagando o ya pagó, aún sin confirmar el coste final',
12
+ settled: 'liquidado — el pago se completó',
13
+ released: 'liberado — se rechazó o falló, no se gastó nada',
14
+ };
15
+ /**
16
+ * Creates the `check_payment` tool: the other half of the async approval
17
+ * story. `pay` can return "retenido" and end the turn there — nothing in the
18
+ * framework blocks waiting for a human. This tool is how a later invocation
19
+ * (a cron trigger, a follow-up prompt, a human asking "¿ya se aprobó?") finds
20
+ * out what happened without needing the console credential AVAL's dashboard
21
+ * requires.
22
+ */
23
+ function createCheckPaymentTool(config) {
24
+ return (0, agent_core_1.defineTool)({
25
+ name: 'check_payment',
26
+ description: 'Consulta el estado de un gasto pedido antes con pay, usando su authorizationId. ' +
27
+ 'Úsalo para saber si un gasto "retenido" ya fue aprobado o rechazado.',
28
+ input: agent_core_1.z.object({
29
+ authorizationId: agent_core_1.z.string().describe('El authorizationId que devolvió pay.'),
30
+ }),
31
+ execute: async ({ authorizationId }, ctx) => {
32
+ const token = (0, client_1.avalKey)(config, ctx.secrets);
33
+ if (!token) {
34
+ return `Error: este agente no tiene credencial de AVAL configurada ` +
35
+ `(falta ctx.secrets.${config.secretName ?? 'AVAL_KEY'} en su perfil).`;
36
+ }
37
+ const { status, body } = await (0, client_1.avalRequest)(config, token, 'GET', `/api/v1/spend/${encodeURIComponent(authorizationId)}`);
38
+ if (status === 404)
39
+ return `No existe ninguna autorización con id "${authorizationId}".`;
40
+ if (status === 403)
41
+ return `Esa autorización no pertenece a este agente.`;
42
+ if (status === 401)
43
+ return `Error de credencial: ${body.error}`;
44
+ if (!body.state)
45
+ return `Error: respuesta inesperada de AVAL (${status}): ${body.error ?? JSON.stringify(body)}`;
46
+ const reasons = body.reasons?.length ? `\nMotivo: ${body.reasons.join(' ')}` : '';
47
+ return (`${authorizationId} → ${STATE_LABEL[body.state]}.\n` +
48
+ `${formatUsd(body.amount)} · ${body.vendor}${body.rail ? ` · vía ${body.rail}` : ''} · ${body.purpose}` +
49
+ reasons);
50
+ },
51
+ });
52
+ }
53
+ //# sourceMappingURL=check-payment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-payment.js","sourceRoot":"","sources":["../src/check-payment.ts"],"names":[],"mappings":";;AAkCA,wDAoCC;AAtED,4DAA4D;AAC5D,qCAAsE;AAEtE,MAAM,YAAY,GAAG,SAAS,CAAC;AAC/B,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,qBAAqB,EAAE,CAAC,EAAE,qBAAqB,EAAE,CAAC,EAAE,CAAC,CAAC;AACzG,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,GAAG,YAAY,CAAC,EAAE,CAAC;AAclF,MAAM,WAAW,GAAqD;IAClE,IAAI,EAAE,kEAAkE;IACxE,UAAU,EAAE,4EAA4E;IACxF,OAAO,EAAE,iCAAiC;IAC1C,QAAQ,EAAE,iDAAiD;CAC9D,CAAC;AAEF;;;;;;;GAOG;AACH,SAAgB,sBAAsB,CAAC,MAAuB;IAC1D,OAAO,IAAA,uBAAU,EAAC;QACd,IAAI,EAAE,eAAe;QACrB,WAAW,EACP,kFAAkF;YAClF,sEAAsE;QAC1E,KAAK,EAAE,cAAC,CAAC,MAAM,CAAC;YACZ,eAAe,EAAE,cAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;SAC/E,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,eAAe,EAAE,EAAE,GAAG,EAAE,EAAE;YACxC,MAAM,KAAK,GAAG,IAAA,gBAAO,EAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;YAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;gBACT,OAAO,6DAA6D;oBAChE,sBAAsB,MAAM,CAAC,UAAU,IAAI,UAAU,iBAAiB,CAAC;YAC/E,CAAC;YAED,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAA,oBAAW,EACtC,MAAM,EACN,KAAK,EACL,KAAK,EACL,iBAAiB,kBAAkB,CAAC,eAAe,CAAC,EAAE,CACzD,CAAC;YAEF,IAAI,MAAM,KAAK,GAAG;gBAAE,OAAO,0CAA0C,eAAe,IAAI,CAAC;YACzF,IAAI,MAAM,KAAK,GAAG;gBAAE,OAAO,8CAA8C,CAAC;YAC1E,IAAI,MAAM,KAAK,GAAG;gBAAE,OAAO,wBAAwB,IAAI,CAAC,KAAK,EAAE,CAAC;YAChE,IAAI,CAAC,IAAI,CAAC,KAAK;gBAAE,OAAO,wCAAwC,MAAM,MAAM,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YAEjH,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClF,OAAO,CACH,GAAG,eAAe,MAAM,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK;gBACpD,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,OAAO,EAAE;gBACvG,OAAO,CACV,CAAC;QACN,CAAC;KACJ,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,33 @@
1
+ export interface AvalToolsConfig {
2
+ /** Where AVAL is reachable, e.g. "https://aval.internal" or "http://localhost:3000". */
3
+ baseUrl: string;
4
+ /**
5
+ * Name of the credential inside ExecutionContext.secrets that holds this
6
+ * agent's AVAL key (aval_sk_… or a JWT). Defaults to "AVAL_KEY" so most
7
+ * callers never need to set this.
8
+ */
9
+ secretName?: string;
10
+ timeoutMs?: number;
11
+ maxAttempts?: number;
12
+ }
13
+ export interface AvalResponse<T> {
14
+ status: number;
15
+ ok: boolean;
16
+ body: T;
17
+ }
18
+ /**
19
+ * fetch() wrapper for AVAL, scoped to one call rather than one process: the
20
+ * bearer token is a parameter, not baked into the client, because it's the
21
+ * calling agent's own credential (ExecutionContext.secrets), not a shared
22
+ * process-wide key.
23
+ *
24
+ * Unlike a generic HTTP client, 4xx responses are NOT thrown here — AVAL's 400
25
+ * (denied), 401 (revoked/caducada), 403 (no es tuya), 404 (no existe) and 429
26
+ * (límite) are meaningful domain answers a tool has to turn into text an agent
27
+ * can act on, not transport failures. Only network errors and 5xx retry; only
28
+ * those, and a response body that isn't JSON, throw.
29
+ */
30
+ export declare function avalRequest<T>(config: AvalToolsConfig, token: string, method: 'GET' | 'POST', path: string, body?: unknown): Promise<AvalResponse<T>>;
31
+ /** Reads this agent's AVAL credential from its own secrets, never a shared env var. */
32
+ export declare function avalKey(config: AvalToolsConfig, secrets: Record<string, string> | undefined): string | null;
33
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC5B,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY,CAAC,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,CAAC,CAAC;CACX;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAC/B,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,KAAK,GAAG,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,GACf,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAgD1B;AAED,uFAAuF;AACvF,wBAAgB,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAE3G"}
package/dist/client.js ADDED
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.avalRequest = avalRequest;
4
+ exports.avalKey = avalKey;
5
+ const retry_1 = require("@backendkit-labs/retry");
6
+ const DEFAULT_TIMEOUT_MS = 15_000;
7
+ const DEFAULT_MAX_ATTEMPTS = 3;
8
+ /**
9
+ * fetch() wrapper for AVAL, scoped to one call rather than one process: the
10
+ * bearer token is a parameter, not baked into the client, because it's the
11
+ * calling agent's own credential (ExecutionContext.secrets), not a shared
12
+ * process-wide key.
13
+ *
14
+ * Unlike a generic HTTP client, 4xx responses are NOT thrown here — AVAL's 400
15
+ * (denied), 401 (revoked/caducada), 403 (no es tuya), 404 (no existe) and 429
16
+ * (límite) are meaningful domain answers a tool has to turn into text an agent
17
+ * can act on, not transport failures. Only network errors and 5xx retry; only
18
+ * those, and a response body that isn't JSON, throw.
19
+ */
20
+ async function avalRequest(config, token, method, path, body) {
21
+ const url = `${config.baseUrl.replace(/\/$/, '')}${path}`;
22
+ const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
23
+ const attempt = async () => {
24
+ const controller = new AbortController();
25
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
26
+ let res;
27
+ try {
28
+ res = await fetch(url, {
29
+ method,
30
+ signal: controller.signal,
31
+ headers: {
32
+ 'content-type': 'application/json',
33
+ authorization: `Bearer ${token}`,
34
+ },
35
+ ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
36
+ });
37
+ }
38
+ catch (err) {
39
+ const aborted = err instanceof Error && err.name === 'AbortError';
40
+ // eslint-disable-next-line @typescript-eslint/no-throw-literal
41
+ throw {
42
+ type: 'network',
43
+ message: aborted
44
+ ? `AVAL ${method} ${path} → timed out after ${timeoutMs}ms`
45
+ : `AVAL ${method} ${path} → network error: ${err.message}`,
46
+ };
47
+ }
48
+ finally {
49
+ clearTimeout(timer);
50
+ }
51
+ if (res.status >= 500) {
52
+ // eslint-disable-next-line @typescript-eslint/no-throw-literal
53
+ throw { type: 'http', status: res.status, message: `AVAL ${method} ${path} → ${res.status}` };
54
+ }
55
+ const json = (await res.json().catch(() => ({})));
56
+ return { status: res.status, ok: res.ok, body: json };
57
+ };
58
+ const result = await (0, retry_1.retry)(attempt, {
59
+ maxAttempts: config.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,
60
+ backoff: { type: 'exponential', baseDelay: 500, maxDelay: 4_000, jitter: 'full' },
61
+ retryIf: (e) => e.type === 'network' || e.type === 'http',
62
+ });
63
+ if (!result.ok)
64
+ throw new Error(result.error.message);
65
+ return result.value;
66
+ }
67
+ /** Reads this agent's AVAL credential from its own secrets, never a shared env var. */
68
+ function avalKey(config, secrets) {
69
+ return secrets?.[config.secretName ?? 'AVAL_KEY'] ?? null;
70
+ }
71
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ export type { AvalToolsConfig } from './client';
2
+ export { avalKey, avalRequest } from './client';
3
+ export { createPayTool } from './pay';
4
+ export { createCheckPaymentTool } from './check-payment';
5
+ import type { AvalToolsConfig } from './client';
6
+ /**
7
+ * The two AVAL tools together, ready to spread into an agent's tool list.
8
+ *
9
+ * Wiring an agent up to AVAL is then: give the agent's profile a `secrets`
10
+ * entry with its AVAL key, add "pay" and "check_payment" to its
11
+ * `allowedTools`, and register these with the engine's ToolRegistry.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { createAvalTools } from '@backendkit-labs/aval-tools';
16
+ *
17
+ * const avalTools = createAvalTools({ baseUrl: 'https://aval.internal' });
18
+ * for (const tool of avalTools) tools.register(tool);
19
+ *
20
+ * const profile: AgentProfile = {
21
+ * // ...
22
+ * allowedTools: ['pay', 'check_payment', ...],
23
+ * secrets: { AVAL_KEY: process.env.EXPEDIENTES_BOT_AVAL_KEY! },
24
+ * };
25
+ * ```
26
+ */
27
+ export declare function createAvalTools(config: AvalToolsConfig): readonly [import("@backendkit-labs/agent-core").ToolDefinition, import("@backendkit-labs/agent-core").ToolDefinition];
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,yHAEtD"}
package/dist/index.js ADDED
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCheckPaymentTool = exports.createPayTool = exports.avalRequest = exports.avalKey = void 0;
4
+ exports.createAvalTools = createAvalTools;
5
+ const pay_1 = require("./pay");
6
+ const check_payment_1 = require("./check-payment");
7
+ var client_1 = require("./client");
8
+ Object.defineProperty(exports, "avalKey", { enumerable: true, get: function () { return client_1.avalKey; } });
9
+ Object.defineProperty(exports, "avalRequest", { enumerable: true, get: function () { return client_1.avalRequest; } });
10
+ var pay_2 = require("./pay");
11
+ Object.defineProperty(exports, "createPayTool", { enumerable: true, get: function () { return pay_2.createPayTool; } });
12
+ var check_payment_2 = require("./check-payment");
13
+ Object.defineProperty(exports, "createCheckPaymentTool", { enumerable: true, get: function () { return check_payment_2.createCheckPaymentTool; } });
14
+ /**
15
+ * The two AVAL tools together, ready to spread into an agent's tool list.
16
+ *
17
+ * Wiring an agent up to AVAL is then: give the agent's profile a `secrets`
18
+ * entry with its AVAL key, add "pay" and "check_payment" to its
19
+ * `allowedTools`, and register these with the engine's ToolRegistry.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { createAvalTools } from '@backendkit-labs/aval-tools';
24
+ *
25
+ * const avalTools = createAvalTools({ baseUrl: 'https://aval.internal' });
26
+ * for (const tool of avalTools) tools.register(tool);
27
+ *
28
+ * const profile: AgentProfile = {
29
+ * // ...
30
+ * allowedTools: ['pay', 'check_payment', ...],
31
+ * secrets: { AVAL_KEY: process.env.EXPEDIENTES_BOT_AVAL_KEY! },
32
+ * };
33
+ * ```
34
+ */
35
+ function createAvalTools(config) {
36
+ return [(0, pay_1.createPayTool)(config), (0, check_payment_1.createCheckPaymentTool)(config)];
37
+ }
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AA+BA,0CAEC;AAjCD,+BAAsC;AACtC,mDAAyD;AAGzD,mCAAgD;AAAvC,iGAAA,OAAO,OAAA;AAAE,qGAAA,WAAW,OAAA;AAC7B,6BAAsC;AAA7B,oGAAA,aAAa,OAAA;AACtB,iDAAyD;AAAhD,uHAAA,sBAAsB,OAAA;AAI/B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,eAAe,CAAC,MAAuB;IACnD,OAAO,CAAC,IAAA,mBAAa,EAAC,MAAM,CAAC,EAAE,IAAA,sCAAsB,EAAC,MAAM,CAAC,CAAU,CAAC;AAC5E,CAAC"}
package/dist/pay.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { type AvalToolsConfig } from './client';
2
+ /**
3
+ * Creates the `pay` tool: the amarrada path into AVAL. The agent asks for a
4
+ * ceiling; AVAL decides and, if authorized, pays through its own rail — the
5
+ * agent never sees a vendor credential to bypass.
6
+ */
7
+ export declare function createPayTool(config: AvalToolsConfig): import("@backendkit-labs/agent-core").ToolDefinition;
8
+ //# sourceMappingURL=pay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pay.d.ts","sourceRoot":"","sources":["../src/pay.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAuDtE;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,wDAuEpD"}
package/dist/pay.js ADDED
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createPayTool = createPayTool;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const agent_core_1 = require("@backendkit-labs/agent-core");
6
+ const client_1 = require("./client");
7
+ const USD_PER_UNIT = 1_000_000;
8
+ /**
9
+ * A deterministic idempotency key from what the call actually is, not a
10
+ * random one: an agent that retries the exact same request after a timeout
11
+ * gets the exact same key and AVAL treats it as a replay instead of a second
12
+ * charge. A genuinely new request — different args, or a later turn — gets a
13
+ * different key on its own.
14
+ */
15
+ function deriveIdempotencyKey(sessionId, counterparty, ceilingUsd, purpose) {
16
+ return (0, node_crypto_1.createHash)('sha256').update(`${sessionId}:${counterparty}:${ceilingUsd}:${purpose}`).digest('hex').slice(0, 24);
17
+ }
18
+ const usdFormat = new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 6 });
19
+ /** Mirrors AVAL's own money() formatter: two decimals normally, up to six for sub-cent amounts. */
20
+ function formatUsd(units) {
21
+ return `$${usdFormat.format(units / USD_PER_UNIT)}`;
22
+ }
23
+ /**
24
+ * Creates the `pay` tool: the amarrada path into AVAL. The agent asks for a
25
+ * ceiling; AVAL decides and, if authorized, pays through its own rail — the
26
+ * agent never sees a vendor credential to bypass.
27
+ */
28
+ function createPayTool(config) {
29
+ return (0, agent_core_1.defineTool)({
30
+ name: 'pay',
31
+ description: 'Solicita un gasto a AVAL para pagar a una contraparte registrada. AVAL decide si se ' +
32
+ 'autoriza, se retiene para aprobación humana, o se deniega, y si autoriza, paga él mismo ' +
33
+ 'por el carril que corresponda. Nunca gastes por tu cuenta: si la respuesta no es ' +
34
+ '"authorized", no hay pago que hacer.',
35
+ input: agent_core_1.z.object({
36
+ counterparty: agent_core_1.z.string().describe('Identificador de la contraparte registrada en AVAL, p. ej. "ocr.docs".'),
37
+ ceilingUsd: agent_core_1.z.number().positive().describe('Techo del gasto en dólares, p. ej. 0.42 para 42 centavos. El coste real puede ser menor.'),
38
+ purpose: agent_core_1.z.string().describe('Motivo del gasto, en una frase clara: queda escrito en el registro de AVAL.'),
39
+ idempotencyKey: agent_core_1.z
40
+ .string()
41
+ .optional()
42
+ .describe('Sólo si necesitas forzar una clave concreta. Por defecto se deriva de la sesión y los argumentos.'),
43
+ }),
44
+ execute: async ({ counterparty, ceilingUsd, purpose, idempotencyKey }, ctx) => {
45
+ const token = (0, client_1.avalKey)(config, ctx.secrets);
46
+ if (!token) {
47
+ return `Error: este agente no tiene credencial de AVAL configurada ` +
48
+ `(falta ctx.secrets.${config.secretName ?? 'AVAL_KEY'} en su perfil).`;
49
+ }
50
+ const ceiling = Math.round(ceilingUsd * USD_PER_UNIT);
51
+ const key = idempotencyKey ?? deriveIdempotencyKey(ctx.sessionId, counterparty, ceiling, purpose);
52
+ const { status, body } = await (0, client_1.avalRequest)(config, token, 'POST', '/api/v1/spend', {
53
+ counterparty,
54
+ ceiling,
55
+ purpose,
56
+ idempotencyKey: key,
57
+ });
58
+ if (status === 429) {
59
+ return `AVAL frenó la petición (demasiados intentos o llamadas). ` +
60
+ `Reintenta en ${body.retryAfterSeconds ?? '?'} s. ${body.error ?? ''}`.trim();
61
+ }
62
+ if (status === 401 || status === 403) {
63
+ return `Error de credencial: ${body.error}`;
64
+ }
65
+ if (!body.decision) {
66
+ return `Error: respuesta inesperada de AVAL (${status}): ${body.error ?? JSON.stringify(body)}`;
67
+ }
68
+ const warning = body.credential?.warning ? `\nAviso de credencial: ${body.credential.warning}` : '';
69
+ const reasons = body.reasons?.length ? `\nMotivo: ${body.reasons.join(' ')}` : '';
70
+ if (body.decision === 'denied') {
71
+ return `Denegado.${reasons}${warning}`;
72
+ }
73
+ if (body.decision === 'held') {
74
+ return (`Retenido para aprobación humana. authorizationId="${body.authorizationId}".` +
75
+ `${reasons}\nUsa check_payment con este authorizationId más tarde para saber si ya se resolvió — ` +
76
+ `no se ha gastado nada todavía.${warning}`);
77
+ }
78
+ // authorized
79
+ const cap = body.capability;
80
+ const actual = cap ? formatUsd(cap.actual) : formatUsd(body.amount ?? ceiling);
81
+ const nativo = cap ? `${cap.payment.nativeAmount} ${cap.payment.asset}` : '';
82
+ return (`Pagado. authorizationId="${body.authorizationId}", carril=${body.rail ?? cap?.rail}, ` +
83
+ `coste real=${actual}${nativo ? ` (${nativo})` : ''}, ref=${cap?.payment.ref ?? '—'}.` +
84
+ `${reasons}${warning}`);
85
+ },
86
+ });
87
+ }
88
+ //# sourceMappingURL=pay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pay.js","sourceRoot":"","sources":["../src/pay.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@backendkit-labs/aval-tools",
3
+ "version": "0.1.0",
4
+ "description": "Payment tools for @backendkit-labs/agent-core agents to spend through an AVAL instance",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": ["dist/", "README.md"],
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/BackendKit-labs/backendkit-agent-framework.git",
11
+ "directory": "packages/aval-tools"
12
+ },
13
+ "publishConfig": { "access": "public" },
14
+ "engines": { "node": ">=20.0.0" },
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "dev": "tsc --watch",
18
+ "typecheck": "tsc --noEmit",
19
+ "test": "jest",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "dependencies": {
23
+ "@backendkit-labs/agent-core": "*"
24
+ },
25
+ "devDependencies": {
26
+ "@types/jest": "^29.0.0",
27
+ "@types/node": "^20.0.0",
28
+ "jest": "^29.0.0",
29
+ "ts-jest": "^29.0.0",
30
+ "typescript": "^5.4.0"
31
+ }
32
+ }