prova-agent-kit 0.1.0 → 0.1.2

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 CHANGED
@@ -50,17 +50,19 @@ const agent = new SolanaAgentKit(new ProvaWallet(realWallet, { attester }), RPC_
50
50
  ```
51
51
 
52
52
  ### No bloquea al agente
53
- Las atestaciones son **fire-and-forget con batching**: un fallo de Prova nunca rompe ni frena una acción del agente. Los items se acumulan y se envían con `batchAttest` (hasta 100/tx) cada `maxSize` items o `flushIntervalMs` ms.
53
+ Las atestaciones son **fire-and-forget con batching por debounce**: un fallo de Prova nunca rompe ni frena una acción del agente. Una ráfaga de tool calls (multi-tool-calling) se agrupa y se envía en **UNA sola tx** (`batchAttest`, hasta 100) apenas la ráfaga se detiene (`flushDelayMs`), o al llegar a `maxSize`.
54
54
 
55
55
  ```typescript
56
56
  attachProva(agent, {
57
57
  attester,
58
58
  rules: (name) => name !== 'fetchPrice', // qué acciones atestar (default: todas)
59
- batch: { maxSize: 25, flushIntervalMs: 10_000 },
59
+ batch: { maxSize: 25, flushDelayMs: 1000 }, // agrupa la ráfaga y envía ~1s tras la última acción
60
60
  onError: (err, ctx) => logger.warn(ctx.action, err),
61
61
  });
62
62
  ```
63
63
 
64
+ > **Importante:** llama a `handle.stop()` cuando el agente termine su turno para garantizar el flush final de lo pendiente.
65
+
64
66
  ## Modelo de claves
65
67
  Prova atesta con **su propio par operador/agente de Devnet**, independiente del wallet de trading del agente. Ventajas: no necesita la private key de trading, funciona con wallets Privy/Turnkey, y el operador Prova es la identidad que avala al agente. Registra el agente una vez con `prova.registerAgent({ operatorKeypair })`.
66
68
 
package/dist/adapter.js CHANGED
@@ -1,5 +1,8 @@
1
+ "use strict";
1
2
  // Puente entre el `ProvaClient` real (prova-agent-sdk) y la interfaz
2
3
  // `ProvaAttester` que usa el adapter. Tipado estructural → no importamos el SDK.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.attesterFromProvaClient = attesterFromProvaClient;
3
6
  /**
4
7
  * Construye un `ProvaAttester` a partir de un `ProvaClient` real, la función
5
8
  * estática `ProvaClient.hashAction` y la keypair operadora de Prova.
@@ -7,7 +10,7 @@
7
10
  * @example
8
11
  * const attester = attesterFromProvaClient(prova, ProvaClient.hashAction, operatorKeypair);
9
12
  */
10
- export function attesterFromProvaClient(client, hashAction, operatorKeypair) {
13
+ function attesterFromProvaClient(client, hashAction, operatorKeypair) {
11
14
  return {
12
15
  hashAction,
13
16
  attest: (item) => client.attest({
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,iFAAiF;AAiBjF;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAAuB,EACvB,UAAoD,EACpD,eAAwB;IAExB,OAAO;QACL,UAAU;QACV,MAAM,EAAE,CAAC,IAAqB,EAAE,EAAE,CAChC,MAAM,CAAC,MAAM,CAAC;YACZ,eAAe;YACf,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC;QACJ,WAAW,EAAE,CAAC,KAAwB,EAAE,EAAE,CACxC,MAAM,CAAC,WAAW,CAAC,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":";AAAA,qEAAqE;AACrE,iFAAiF;;AAwBjF,0DAgBC;AAvBD;;;;;;GAMG;AACH,SAAgB,uBAAuB,CACrC,MAAuB,EACvB,UAAoD,EACpD,eAAwB;IAExB,OAAO;QACL,UAAU;QACV,MAAM,EAAE,CAAC,IAAqB,EAAE,EAAE,CAChC,MAAM,CAAC,MAAM,CAAC;YACZ,eAAe;YACf,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC;QACJ,WAAW,EAAE,CAAC,KAAwB,EAAE,EAAE,CACxC,MAAM,CAAC,WAAW,CAAC,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC"}
package/dist/attach.js CHANGED
@@ -1,15 +1,18 @@
1
+ "use strict";
1
2
  // Enfoque B: envuelve los handlers de las acciones del agente para atestar cada
2
3
  // ejecución en Prova. Es el mecanismo principal de captura (semántica rica:
3
4
  // nombre + input + output). Llamar DESPUÉS de registrar todos los plugins.
4
- import { buildPayload, mapActionType } from './payload';
5
- import { createBatcher } from './batcher';
6
- import { warn } from './runtime';
7
- export function attachProva(agent, options) {
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.attachProva = attachProva;
7
+ const payload_1 = require("./payload");
8
+ const batcher_1 = require("./batcher");
9
+ const runtime_1 = require("./runtime");
10
+ function attachProva(agent, options) {
8
11
  const { attester } = options;
9
12
  const should = options.rules ?? (() => true);
10
13
  const onError = options.onError ??
11
- ((error, context) => warn(`[Prova] attest failed for "${context.action}":`, error));
12
- const batcher = createBatcher(attester, options.batch, (error) => onError(error, { action: 'batch' }));
14
+ ((error, context) => (0, runtime_1.warn)(`[Prova] attest failed for "${context.action}":`, error));
15
+ const batcher = (0, batcher_1.createBatcher)(attester, options.batch, (error) => onError(error, { action: 'batch' }));
13
16
  agent.actions = agent.actions.map((action) => {
14
17
  if (!should(action.name))
15
18
  return action;
@@ -30,8 +33,8 @@ export function attachProva(agent, options) {
30
33
  };
31
34
  }
32
35
  async function captureAction(attester, batcher, name, input, result) {
33
- const payload = buildPayload(name, input, result);
36
+ const payload = (0, payload_1.buildPayload)(name, input, result);
34
37
  const actionHash = await attester.hashAction(JSON.stringify(payload));
35
- batcher.add({ actionHash, actionType: mapActionType(name, result) });
38
+ batcher.add({ actionHash, actionType: (0, payload_1.mapActionType)(name, result) });
36
39
  }
37
40
  //# sourceMappingURL=attach.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"attach.js","sourceRoot":"","sources":["../src/attach.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,4EAA4E;AAC5E,2EAA2E;AAG3E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,aAAa,EAAgB,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,MAAM,UAAU,WAAW,CAAC,KAAgB,EAAE,OAA2B;IACvE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,OAAO,GACX,OAAO,CAAC,OAAO;QACf,CAAC,CAAC,KAAc,EAAE,OAA2B,EAAE,EAAE,CAC/C,IAAI,CAAC,8BAA8B,OAAO,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAEnE,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAC/D,OAAO,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CACpC,CAAC;IAEF,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAkB,EAAc,EAAE;QACnE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,OAAO,MAAM,CAAC;QACxC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC;QAChC,OAAO;YACL,GAAG,MAAM;YACT,OAAO,EAAE,KAAK,EAAE,CAAU,EAAE,KAA8B,EAAE,EAAE;gBAC5D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;gBACxC,qEAAqE;gBACrE,KAAK,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAChF,OAAO,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CACxC,CAAC;gBACF,OAAO,MAAM,CAAC;YAChB,CAAC;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE;QAC5B,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE;KAC3B,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,QAAuB,EACvB,OAAgB,EAChB,IAAY,EACZ,KAA8B,EAC9B,MAA+B;IAE/B,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AACvE,CAAC"}
1
+ {"version":3,"file":"attach.js","sourceRoot":"","sources":["../src/attach.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,4EAA4E;AAC5E,2EAA2E;;AAc3E,kCAgCC;AA3CD,uCAAwD;AACxD,uCAAwD;AACxD,uCAAiC;AASjC,SAAgB,WAAW,CAAC,KAAgB,EAAE,OAA2B;IACvE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,OAAO,GACX,OAAO,CAAC,OAAO;QACf,CAAC,CAAC,KAAc,EAAE,OAA2B,EAAE,EAAE,CAC/C,IAAA,cAAI,EAAC,8BAA8B,OAAO,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAEnE,MAAM,OAAO,GAAG,IAAA,uBAAa,EAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAC/D,OAAO,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CACpC,CAAC;IAEF,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAkB,EAAc,EAAE;QACnE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,OAAO,MAAM,CAAC;QACxC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC;QAChC,OAAO;YACL,GAAG,MAAM;YACT,OAAO,EAAE,KAAK,EAAE,CAAU,EAAE,KAA8B,EAAE,EAAE;gBAC5D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;gBACxC,qEAAqE;gBACrE,KAAK,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAChF,OAAO,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CACxC,CAAC;gBACF,OAAO,MAAM,CAAC;YAChB,CAAC;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE;QAC5B,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE;KAC3B,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,QAAuB,EACvB,OAAgB,EAChB,IAAY,EACZ,KAA8B,EAC9B,MAA+B;IAE/B,MAAM,OAAO,GAAG,IAAA,sBAAY,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,IAAA,uBAAa,EAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AACvE,CAAC"}
package/dist/batcher.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import type { AttestationItem, BatchOptions, ProvaAttester } from './types';
2
2
  export interface Batcher {
3
- /** Encola una atestación; dispara flush si se alcanza maxSize. */
3
+ /** Encola una atestación; programa el flush (o lo dispara si se alcanza maxSize). */
4
4
  add(item: AttestationItem): void;
5
5
  /** Envía inmediatamente lo pendiente. */
6
6
  flush(): Promise<void>;
7
- /** Detiene el timer y hace un último flush. */
7
+ /** Cancela el timer y hace un último flush (llamar al cerrar el agente). */
8
8
  stop(): Promise<void>;
9
9
  }
10
10
  export declare function createBatcher(attester: ProvaAttester, options?: BatchOptions, onError?: (error: unknown) => void): Batcher;
@@ -1 +1 @@
1
- {"version":3,"file":"batcher.d.ts","sourceRoot":"","sources":["../src/batcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG5E,MAAM,WAAW,OAAO;IACtB,kEAAkE;IAClE,GAAG,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,yCAAyC;IACzC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,+CAA+C;IAC/C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAMD,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,aAAa,EACvB,OAAO,GAAE,YAAiB,EAC1B,OAAO,GAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAqD,GACjF,OAAO,CA2CT"}
1
+ {"version":3,"file":"batcher.d.ts","sourceRoot":"","sources":["../src/batcher.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG5E,MAAM,WAAW,OAAO;IACtB,qFAAqF;IACrF,GAAG,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,yCAAyC;IACzC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,4EAA4E;IAC5E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAMD,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,aAAa,EACvB,OAAO,GAAE,YAAiB,EAC1B,OAAO,GAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAqD,GACjF,OAAO,CAwDT"}
package/dist/batcher.js CHANGED
@@ -1,16 +1,28 @@
1
- // Buffer de atestaciones: acumula items y los envía en lote (batchAttest) cada
2
- // N items o cada T ms, lo que ocurra primero. Aísla la latencia/coste de Solana
3
- // del hot-path del agente.
4
- import { clearIntervalSafe, setIntervalSafe, warn } from './runtime';
1
+ "use strict";
2
+ // Buffer de atestaciones con flush por DEBOUNCE: agrupa una ráfaga de acciones
3
+ // (multi-tool-calling) y las envía en UNA sola tx (batchAttest, hasta 100) apenas
4
+ // la ráfaga se detiene. Esto arregla el bug de "N tool calls seguidos → 0 guardadas":
5
+ // antes el flush solo ocurría a los 25 items o cada 10s, así que una ráfaga corta
6
+ // que terminaba antes quedaba sin enviar.
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.createBatcher = createBatcher;
9
+ const runtime_1 = require("./runtime");
5
10
  const DEFAULT_MAX_SIZE = 25;
6
- const DEFAULT_INTERVAL_MS = 10_000;
11
+ const DEFAULT_FLUSH_DELAY_MS = 1000;
7
12
  const HARD_BATCH_LIMIT = 100;
8
- export function createBatcher(attester, options = {}, onError = (error) => warn('[Prova] batch error:', error)) {
13
+ function createBatcher(attester, options = {}, onError = (error) => (0, runtime_1.warn)('[Prova] batch error:', error)) {
9
14
  const maxSize = Math.min(Math.max(options.maxSize ?? DEFAULT_MAX_SIZE, 1), HARD_BATCH_LIMIT);
10
- const intervalMs = options.flushIntervalMs ?? DEFAULT_INTERVAL_MS;
15
+ const flushDelayMs = options.flushDelayMs ?? DEFAULT_FLUSH_DELAY_MS;
11
16
  let buffer = [];
12
17
  let timer;
18
+ function clearTimer() {
19
+ if (timer !== undefined) {
20
+ (0, runtime_1.clearTimeoutSafe)(timer);
21
+ timer = undefined;
22
+ }
23
+ }
13
24
  async function flush() {
25
+ clearTimer();
14
26
  if (buffer.length === 0)
15
27
  return;
16
28
  const batch = buffer;
@@ -27,24 +39,29 @@ export function createBatcher(attester, options = {}, onError = (error) => warn(
27
39
  onError(error);
28
40
  }
29
41
  }
30
- function ensureTimer() {
31
- if (intervalMs > 0 && timer === undefined) {
32
- timer = setIntervalSafe(() => void flush(), intervalMs);
42
+ // Debounce: cada acción reinicia el timer, de modo que el flush ocurre
43
+ // `flushDelayMs` ms DESPUÉS de la última acción de la ráfaga → todo en 1 tx.
44
+ function scheduleFlush() {
45
+ clearTimer();
46
+ if (flushDelayMs <= 0) {
47
+ void flush();
48
+ return;
33
49
  }
50
+ timer = (0, runtime_1.setTimeoutSafe)(() => void flush(), flushDelayMs);
34
51
  }
35
52
  return {
36
53
  add(item) {
37
54
  buffer.push(item);
38
- ensureTimer();
39
- if (buffer.length >= maxSize)
40
- void flush();
55
+ if (buffer.length >= maxSize) {
56
+ void flush(); // llegó al tope → envía ya
57
+ }
58
+ else {
59
+ scheduleFlush(); // si no, agrupa la ráfaga y envía al detenerse
60
+ }
41
61
  },
42
62
  flush,
43
63
  async stop() {
44
- if (timer !== undefined) {
45
- clearIntervalSafe(timer);
46
- timer = undefined;
47
- }
64
+ clearTimer();
48
65
  await flush();
49
66
  },
50
67
  };
@@ -1 +1 @@
1
- {"version":3,"file":"batcher.js","sourceRoot":"","sources":["../src/batcher.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,gFAAgF;AAChF,2BAA2B;AAG3B,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,IAAI,EAAgB,MAAM,WAAW,CAAC;AAWnF,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,MAAM,mBAAmB,GAAG,MAAM,CAAC;AACnC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B,MAAM,UAAU,aAAa,CAC3B,QAAuB,EACvB,UAAwB,EAAE,EAC1B,UAAoC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC;IAElF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,gBAAgB,EAAE,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAC7F,MAAM,UAAU,GAAG,OAAO,CAAC,eAAe,IAAI,mBAAmB,CAAC;IAElE,IAAI,MAAM,GAAsB,EAAE,CAAC;IACnC,IAAI,KAA0B,CAAC;IAE/B,KAAK,UAAU,KAAK;QAClB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAChC,MAAM,KAAK,GAAG,MAAM,CAAC;QACrB,MAAM,GAAG,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;YACnC,CAAC;iBAAM,CAAC;gBACN,MAAM,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED,SAAS,WAAW;QAClB,IAAI,UAAU,GAAG,CAAC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC1C,KAAK,GAAG,eAAe,CAAC,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE,EAAE,UAAU,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG,CAAC,IAAqB;YACvB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,WAAW,EAAE,CAAC;YACd,IAAI,MAAM,CAAC,MAAM,IAAI,OAAO;gBAAE,KAAK,KAAK,EAAE,CAAC;QAC7C,CAAC;QACD,KAAK;QACL,KAAK,CAAC,IAAI;YACR,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,iBAAiB,CAAC,KAAK,CAAC,CAAC;gBACzB,KAAK,GAAG,SAAS,CAAC;YACpB,CAAC;YACD,MAAM,KAAK,EAAE,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"batcher.js","sourceRoot":"","sources":["../src/batcher.ts"],"names":[],"mappings":";AAAA,+EAA+E;AAC/E,kFAAkF;AAClF,sFAAsF;AACtF,kFAAkF;AAClF,0CAA0C;;AAkB1C,sCA4DC;AA3ED,uCAAiF;AAWjF,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,MAAM,sBAAsB,GAAG,IAAI,CAAC;AACpC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B,SAAgB,aAAa,CAC3B,QAAuB,EACvB,UAAwB,EAAE,EAC1B,UAAoC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAA,cAAI,EAAC,sBAAsB,EAAE,KAAK,CAAC;IAElF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,gBAAgB,EAAE,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAC7F,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,sBAAsB,CAAC;IAEpE,IAAI,MAAM,GAAsB,EAAE,CAAC;IACnC,IAAI,KAA0B,CAAC;IAE/B,SAAS,UAAU;QACjB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAA,0BAAgB,EAAC,KAAK,CAAC,CAAC;YACxB,KAAK,GAAG,SAAS,CAAC;QACpB,CAAC;IACH,CAAC;IAED,KAAK,UAAU,KAAK;QAClB,UAAU,EAAE,CAAC;QACb,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAChC,MAAM,KAAK,GAAG,MAAM,CAAC;QACrB,MAAM,GAAG,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;YACnC,CAAC;iBAAM,CAAC;gBACN,MAAM,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,6EAA6E;IAC7E,SAAS,aAAa;QACpB,UAAU,EAAE,CAAC;QACb,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;YACtB,KAAK,KAAK,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QACD,KAAK,GAAG,IAAA,wBAAc,EAAC,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE,EAAE,YAAY,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO;QACL,GAAG,CAAC,IAAqB;YACvB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,IAAI,MAAM,CAAC,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,KAAK,KAAK,EAAE,CAAC,CAAC,2BAA2B;YAC3C,CAAC;iBAAM,CAAC;gBACN,aAAa,EAAE,CAAC,CAAC,+CAA+C;YAClE,CAAC;QACH,CAAC;QACD,KAAK;QACL,KAAK,CAAC,IAAI;YACR,UAAU,EAAE,CAAC;YACb,MAAM,KAAK,EAAE,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/index.js CHANGED
@@ -1,7 +1,17 @@
1
+ "use strict";
1
2
  // API pública del adapter Prova ↔ Solana Agent Kit.
2
- export { attachProva } from './attach';
3
- export { ProvaWallet } from './wallet';
4
- export { attesterFromProvaClient } from './adapter';
5
- export { createBatcher } from './batcher';
6
- export { buildPayload, mapActionType, extractSignature } from './payload';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.extractSignature = exports.mapActionType = exports.buildPayload = exports.createBatcher = exports.attesterFromProvaClient = exports.ProvaWallet = exports.attachProva = void 0;
5
+ var attach_1 = require("./attach");
6
+ Object.defineProperty(exports, "attachProva", { enumerable: true, get: function () { return attach_1.attachProva; } });
7
+ var wallet_1 = require("./wallet");
8
+ Object.defineProperty(exports, "ProvaWallet", { enumerable: true, get: function () { return wallet_1.ProvaWallet; } });
9
+ var adapter_1 = require("./adapter");
10
+ Object.defineProperty(exports, "attesterFromProvaClient", { enumerable: true, get: function () { return adapter_1.attesterFromProvaClient; } });
11
+ var batcher_1 = require("./batcher");
12
+ Object.defineProperty(exports, "createBatcher", { enumerable: true, get: function () { return batcher_1.createBatcher; } });
13
+ var payload_1 = require("./payload");
14
+ Object.defineProperty(exports, "buildPayload", { enumerable: true, get: function () { return payload_1.buildPayload; } });
15
+ Object.defineProperty(exports, "mapActionType", { enumerable: true, get: function () { return payload_1.mapActionType; } });
16
+ Object.defineProperty(exports, "extractSignature", { enumerable: true, get: function () { return payload_1.extractSignature; } });
7
17
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAGpD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,oDAAoD;;;AAEpD,mCAAuC;AAA9B,qGAAA,WAAW,OAAA;AAGpB,mCAAuC;AAA9B,qGAAA,WAAW,OAAA;AAGpB,qCAAoD;AAA3C,kHAAA,uBAAuB,OAAA;AAGhC,qCAA0C;AAAjC,wGAAA,aAAa,OAAA;AAGtB,qCAA0E;AAAjE,uGAAA,YAAY,OAAA;AAAE,wGAAA,aAAa,OAAA;AAAE,2GAAA,gBAAgB,OAAA"}
package/dist/payload.js CHANGED
@@ -1,9 +1,14 @@
1
+ "use strict";
1
2
  // Funciones puras: derivan el payload y el tipo de atestación a partir de la
2
3
  // acción de SAK y su resultado. Sin efectos secundarios → fáciles de testear.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.extractSignature = extractSignature;
6
+ exports.mapActionType = mapActionType;
7
+ exports.buildPayload = buildPayload;
3
8
  const SIGNATURE_KEYS = ['signature', 'txSignature', 'txid', 'tx'];
4
9
  const DECISION_PATTERN = /decision|choose|select|rebalance|hold|exit|approve|reject/i;
5
10
  /** Extrae la firma on-chain del result de una acción, si está presente. */
6
- export function extractSignature(result) {
11
+ function extractSignature(result) {
7
12
  for (const key of SIGNATURE_KEYS) {
8
13
  const value = result[key];
9
14
  if (typeof value === 'string' && value.length > 0)
@@ -12,7 +17,7 @@ export function extractSignature(result) {
12
17
  return undefined;
13
18
  }
14
19
  /** Mapea el nombre de una acción de SAK al `ActionType` de Prova. */
15
- export function mapActionType(actionName, result) {
20
+ function mapActionType(actionName, result) {
16
21
  if (extractSignature(result))
17
22
  return 'Transaction';
18
23
  if (DECISION_PATTERN.test(actionName))
@@ -20,7 +25,7 @@ export function mapActionType(actionName, result) {
20
25
  return 'ToolCall';
21
26
  }
22
27
  /** Construye el objeto que se serializa y hashea para producir el action_hash. */
23
- export function buildPayload(actionName, input, result) {
28
+ function buildPayload(actionName, input, result) {
24
29
  const signature = extractSignature(result);
25
30
  if (signature) {
26
31
  return { kind: 'transaction', action: actionName, signature, input };
@@ -1 +1 @@
1
- {"version":3,"file":"payload.js","sourceRoot":"","sources":["../src/payload.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,8EAA8E;AAI9E,MAAM,cAAc,GAAG,CAAC,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,CAAU,CAAC;AAC3E,MAAM,gBAAgB,GAAG,4DAA4D,CAAC;AAEtF,2EAA2E;AAC3E,MAAM,UAAU,gBAAgB,CAAC,MAAoB;IACnD,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;IAClE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAE,MAAoB;IACpE,IAAI,gBAAgB,CAAC,MAAM,CAAC;QAAE,OAAO,aAAa,CAAC;IACnD,IAAI,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IACzD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAC1B,UAAkB,EAClB,KAA8B,EAC9B,MAAoB;IAEpB,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACvE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AACjE,CAAC"}
1
+ {"version":3,"file":"payload.js","sourceRoot":"","sources":["../src/payload.ts"],"names":[],"mappings":";AAAA,6EAA6E;AAC7E,8EAA8E;;AAQ9E,4CAMC;AAGD,sCAIC;AAGD,oCAUC;AA9BD,MAAM,cAAc,GAAG,CAAC,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,CAAU,CAAC;AAC3E,MAAM,gBAAgB,GAAG,4DAA4D,CAAC;AAEtF,2EAA2E;AAC3E,SAAgB,gBAAgB,CAAC,MAAoB;IACnD,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;IAClE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,qEAAqE;AACrE,SAAgB,aAAa,CAAC,UAAkB,EAAE,MAAoB;IACpE,IAAI,gBAAgB,CAAC,MAAM,CAAC;QAAE,OAAO,aAAa,CAAC;IACnD,IAAI,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IACzD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,kFAAkF;AAClF,SAAgB,YAAY,CAC1B,UAAkB,EAClB,KAA8B,EAC9B,MAAoB;IAEpB,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACvE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AACjE,CAAC"}
package/dist/runtime.d.ts CHANGED
@@ -2,8 +2,8 @@
2
2
  export type TimerId = number | {
3
3
  readonly __timer?: unique symbol;
4
4
  };
5
- /** setInterval que no bloquea la salida del proceso (unref en Node si existe). */
6
- export declare function setIntervalSafe(handler: () => void, ms: number): TimerId;
7
- export declare function clearIntervalSafe(id: TimerId): void;
5
+ /** setTimeout que no bloquea la salida del proceso (unref en Node si existe). */
6
+ export declare function setTimeoutSafe(handler: () => void, ms: number): TimerId;
7
+ export declare function clearTimeoutSafe(id: TimerId): void;
8
8
  export declare function warn(...args: unknown[]): void;
9
9
  //# sourceMappingURL=runtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAIA,6EAA6E;AAC7E,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,MAAM,CAAA;CAAE,CAAC;AAUpE,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAKxE;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAEnD;AAED,wBAAgB,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAE7C"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAIA,6EAA6E;AAC7E,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,MAAM,CAAA;CAAE,CAAC;AAUpE,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAKvE;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAElD;AAED,wBAAgB,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAE7C"}
package/dist/runtime.js CHANGED
@@ -1,19 +1,24 @@
1
+ "use strict";
1
2
  // Acceso tipado a globales de runtime (timers, console) sin depender de
2
3
  // @types/node ni de los tipos del DOM. En ejecución real los provee Node o el
3
4
  // navegador; aquí los declaramos mínimamente para mantener el adapter ligero.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.setTimeoutSafe = setTimeoutSafe;
7
+ exports.clearTimeoutSafe = clearTimeoutSafe;
8
+ exports.warn = warn;
4
9
  const runtime = globalThis;
5
- /** setInterval que no bloquea la salida del proceso (unref en Node si existe). */
6
- export function setIntervalSafe(handler, ms) {
7
- const id = runtime.setInterval(handler, ms);
10
+ /** setTimeout que no bloquea la salida del proceso (unref en Node si existe). */
11
+ function setTimeoutSafe(handler, ms) {
12
+ const id = runtime.setTimeout(handler, ms);
8
13
  const maybe = id;
9
14
  if (typeof maybe.unref === 'function')
10
15
  maybe.unref();
11
16
  return id;
12
17
  }
13
- export function clearIntervalSafe(id) {
14
- runtime.clearInterval(id);
18
+ function clearTimeoutSafe(id) {
19
+ runtime.clearTimeout(id);
15
20
  }
16
- export function warn(...args) {
21
+ function warn(...args) {
17
22
  runtime.console.warn(...args);
18
23
  }
19
24
  //# sourceMappingURL=runtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,8EAA8E;AAC9E,8EAA8E;AAW9E,MAAM,OAAO,GAAG,UAAuC,CAAC;AAExD,kFAAkF;AAClF,MAAM,UAAU,eAAe,CAAC,OAAmB,EAAE,EAAU;IAC7D,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,EAAuC,CAAC;IACtD,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU;QAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IACrD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAW;IAC3C,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAG,IAAe;IACrC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":";AAAA,wEAAwE;AACxE,8EAA8E;AAC9E,8EAA8E;;AAc9E,wCAKC;AAED,4CAEC;AAED,oBAEC;AAhBD,MAAM,OAAO,GAAG,UAAuC,CAAC;AAExD,iFAAiF;AACjF,SAAgB,cAAc,CAAC,OAAmB,EAAE,EAAU;IAC5D,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,EAAuC,CAAC;IACtD,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU;QAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IACrD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAgB,gBAAgB,CAAC,EAAW;IAC1C,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED,SAAgB,IAAI,CAAC,GAAG,IAAe;IACrC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAChC,CAAC"}
package/dist/types.d.ts CHANGED
@@ -45,10 +45,14 @@ export interface ProvaAttester {
45
45
  }
46
46
  /** Configuración del batching de atestaciones. */
47
47
  export interface BatchOptions {
48
- /** Nº máximo de atestaciones por transacción (1–100). Default 25. */
48
+ /** Nº máximo de atestaciones por transacción (1–100). Al alcanzarlo, flush inmediato. Default 25. */
49
49
  maxSize?: number;
50
- /** Flush automático cada N ms. Default 10000. 0 = sin flush por tiempo. */
51
- flushIntervalMs?: number;
50
+ /**
51
+ * Debounce: hace flush este nº de ms tras la ÚLTIMA acción. Así una ráfaga de
52
+ * tool calls (multi-tool-calling) se agrupa en UNA sola tx on-chain apenas
53
+ * termina la ráfaga. Default 1000. 0 = flush inmediato en cada acción (sin batch).
54
+ */
55
+ flushDelayMs?: number;
52
56
  }
53
57
  /** Opciones de `attachProva`. */
54
58
  export interface AttachProvaOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAKA,yDAAyD;AACzD,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEnD,wEAAwE;AACxE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IACnF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,IAAI,MAAM,CAAA;KAAE,CAAC;IAC3C,eAAe,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/C,mBAAmB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACxD,sBAAsB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7F,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACvD;AAED,6EAA6E;AAC7E,MAAM,MAAM,eAAe,GACvB,aAAa,GACb,UAAU,GACV,iBAAiB,GACjB,UAAU,GACV,gBAAgB,GAChB,aAAa,GACb,QAAQ,CAAC;AAEb,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,eAAe,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACjD,MAAM,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,WAAW,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzE;AAED,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,iCAAiC;AACjC,MAAM,WAAW,kBAAkB;IACjC,0DAA0D;IAC1D,QAAQ,EAAE,aAAa,CAAC;IACxB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,iCAAiC;IACjC,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACjE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAKA,yDAAyD;AACzD,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEnD,wEAAwE;AACxE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IACnF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,IAAI,MAAM,CAAA;KAAE,CAAC;IAC3C,eAAe,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/C,mBAAmB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACxD,sBAAsB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7F,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACvD;AAED,6EAA6E;AAC7E,MAAM,MAAM,eAAe,GACvB,aAAa,GACb,UAAU,GACV,iBAAiB,GACjB,UAAU,GACV,gBAAgB,GAChB,aAAa,GACb,QAAQ,CAAC;AAEb,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,eAAe,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACjD,MAAM,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,WAAW,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzE;AAED,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,qGAAqG;IACrG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,iCAAiC;AACjC,MAAM,WAAW,kBAAkB;IACjC,0DAA0D;IAC1D,QAAQ,EAAE,aAAa,CAAC;IACxB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,iCAAiC;IACjC,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACjE"}
package/dist/types.js CHANGED
@@ -1,6 +1,7 @@
1
+ "use strict";
1
2
  // Tipos del adapter. Reflejamos estructuralmente la API pública de Solana Agent
2
3
  // Kit v2 (BaseWallet, Action, SolanaAgentKit) para NO importar el paquete y
3
4
  // mantener el adapter como peerDependency ligera. La compatibilidad se apoya en
4
5
  // el tipado estructural de TypeScript.
5
- export {};
6
+ Object.defineProperty(exports, "__esModule", { value: true });
6
7
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,4EAA4E;AAC5E,gFAAgF;AAChF,uCAAuC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,4EAA4E;AAC5E,gFAAgF;AAChF,uCAAuC"}
package/dist/wallet.js CHANGED
@@ -1,15 +1,18 @@
1
+ "use strict";
1
2
  // Enfoque A: decorador de BaseWallet (SAK v2). Captura la firma on-chain real
2
3
  // de cada transacción firmada/enviada, sin importar qué plugin la produjo. Es
3
4
  // el "cinturón de seguridad" que complementa a `attachProva`.
4
- import { createBatcher } from './batcher';
5
- export class ProvaWallet {
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ProvaWallet = void 0;
7
+ const batcher_1 = require("./batcher");
8
+ class ProvaWallet {
6
9
  inner;
7
10
  attester;
8
11
  batcher;
9
12
  constructor(inner, options) {
10
13
  this.inner = inner;
11
14
  this.attester = options.attester;
12
- this.batcher = createBatcher(options.attester, options.batch, options.onError);
15
+ this.batcher = (0, batcher_1.createBatcher)(options.attester, options.batch, options.onError);
13
16
  }
14
17
  get publicKey() {
15
18
  return this.inner.publicKey;
@@ -43,4 +46,5 @@ export class ProvaWallet {
43
46
  this.batcher.add({ actionHash, actionType: 'Transaction' });
44
47
  }
45
48
  }
49
+ exports.ProvaWallet = ProvaWallet;
46
50
  //# sourceMappingURL=wallet.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wallet.js","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,8EAA8E;AAC9E,8DAA8D;AAG9D,OAAO,EAAE,aAAa,EAAgB,MAAM,WAAW,CAAC;AAQxD,MAAM,OAAO,WAAW;IACL,KAAK,CAAa;IAClB,QAAQ,CAAgB;IACxB,OAAO,CAAU;IAElC,YAAY,KAAiB,EAAE,OAA2B;QACxD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACjF,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;IAC9B,CAAC;IAED,eAAe,CAAI,WAAc;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IACjD,CAAC;IAED,mBAAmB,CAAI,YAAiB;QACtC,OAAO,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACtD,CAAC;IAED,WAAW,CAAC,OAAmB;QAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAI,WAAc,EAAE,OAAiB;QAC/D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC7E,sDAAsD;QACtD,KAAK,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC7D,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,sDAAsD;IACtD,KAAK;QACH,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED,gDAAgD;IAChD,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,SAAiB;QAC9C,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACrE,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC;IAC9D,CAAC;CACF"}
1
+ {"version":3,"file":"wallet.js","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":";AAAA,8EAA8E;AAC9E,8EAA8E;AAC9E,8DAA8D;;;AAG9D,uCAAwD;AAQxD,MAAa,WAAW;IACL,KAAK,CAAa;IAClB,QAAQ,CAAgB;IACxB,OAAO,CAAU;IAElC,YAAY,KAAiB,EAAE,OAA2B;QACxD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,IAAA,uBAAa,EAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACjF,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;IAC9B,CAAC;IAED,eAAe,CAAI,WAAc;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IACjD,CAAC;IAED,mBAAmB,CAAI,YAAiB;QACtC,OAAO,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACtD,CAAC;IAED,WAAW,CAAC,OAAmB;QAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAI,WAAc,EAAE,OAAiB;QAC/D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC7E,sDAAsD;QACtD,KAAK,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC7D,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,sDAAsD;IACtD,KAAK;QACH,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED,gDAAgD;IAChD,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,SAAiB;QAC9C,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACrE,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC;IAC9D,CAAC;CACF;AAjDD,kCAiDC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prova-agent-kit",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Prova Labs",
6
6
  "description": "Prova adapter for Solana Agent Kit — emit verifiable on-chain receipts for every action a SAK agent executes",
@@ -29,7 +29,7 @@ describe('attachProva', () => {
29
29
 
30
30
  const handle = attachProva(agent, {
31
31
  attester,
32
- batch: { maxSize: 1, flushIntervalMs: 0 },
32
+ batch: { maxSize: 1, flushDelayMs: 0 },
33
33
  });
34
34
 
35
35
  const result = await agent.actions[0]!.handler(agent, { amount: 10 });
@@ -72,7 +72,7 @@ describe('attachProva', () => {
72
72
  const handle = attachProva(agent, {
73
73
  attester,
74
74
  rules: (name) => name === 'trade',
75
- batch: { maxSize: 1, flushIntervalMs: 0 },
75
+ batch: { maxSize: 1, flushDelayMs: 0 },
76
76
  });
77
77
 
78
78
  await agent.actions[0]!.handler(agent, {});
@@ -0,0 +1,70 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createBatcher } from './batcher';
3
+ import type { AttestationItem, ProvaAttester } from './types';
4
+
5
+ function recordingAttester() {
6
+ const attests: AttestationItem[] = [];
7
+ const batches: AttestationItem[][] = [];
8
+ const attester: ProvaAttester = {
9
+ hashAction: async () => new Uint8Array(32),
10
+ attest: async (item) => {
11
+ attests.push(item);
12
+ return { txSignature: 'tx' };
13
+ },
14
+ batchAttest: async (items) => {
15
+ batches.push(items);
16
+ return { txSignature: 'tx' };
17
+ },
18
+ };
19
+ return { attester, attests, batches };
20
+ }
21
+
22
+ const item = (): AttestationItem => ({ actionHash: new Uint8Array(32), actionType: 'ToolCall' });
23
+ const wait = (ms: number) => new Promise((r) => setTimeout(r, ms));
24
+
25
+ describe('createBatcher — multi-tool-calling (bug del mentor)', () => {
26
+ it('agrupa una RÁFAGA de 11 acciones en UNA sola batchAttest', async () => {
27
+ const { attester, attests, batches } = recordingAttester();
28
+ const batcher = createBatcher(attester, { maxSize: 25, flushDelayMs: 20 });
29
+
30
+ for (let i = 0; i < 11; i++) batcher.add(item());
31
+
32
+ await wait(50); // pasa el debounce
33
+ expect(batches).toHaveLength(1); // UNA sola tx
34
+ expect(batches[0]).toHaveLength(11); // con las 11 dentro
35
+ expect(attests).toHaveLength(0); // ninguna suelta
36
+ });
37
+
38
+ it('no pierde nada si el agente cierra antes del debounce (stop hace flush)', async () => {
39
+ const { attester, batches } = recordingAttester();
40
+ const batcher = createBatcher(attester, { maxSize: 25, flushDelayMs: 5000 });
41
+
42
+ for (let i = 0; i < 11; i++) batcher.add(item());
43
+ await batcher.stop(); // cierre inmediato
44
+
45
+ expect(batches).toHaveLength(1);
46
+ expect(batches[0]).toHaveLength(11);
47
+ });
48
+
49
+ it('hace flush inmediato al alcanzar maxSize', async () => {
50
+ const { attester, batches } = recordingAttester();
51
+ const batcher = createBatcher(attester, { maxSize: 5, flushDelayMs: 5000 });
52
+
53
+ for (let i = 0; i < 5; i++) batcher.add(item());
54
+ await wait(0);
55
+
56
+ expect(batches).toHaveLength(1);
57
+ expect(batches[0]).toHaveLength(5);
58
+ });
59
+
60
+ it('una sola acción usa attest (no batchAttest)', async () => {
61
+ const { attester, attests, batches } = recordingAttester();
62
+ const batcher = createBatcher(attester, { flushDelayMs: 10 });
63
+
64
+ batcher.add(item());
65
+ await wait(30);
66
+
67
+ expect(attests).toHaveLength(1);
68
+ expect(batches).toHaveLength(0);
69
+ });
70
+ });
package/src/batcher.ts CHANGED
@@ -1,21 +1,23 @@
1
- // Buffer de atestaciones: acumula items y los envía en lote (batchAttest) cada
2
- // N items o cada T ms, lo que ocurra primero. Aísla la latencia/coste de Solana
3
- // del hot-path del agente.
1
+ // Buffer de atestaciones con flush por DEBOUNCE: agrupa una ráfaga de acciones
2
+ // (multi-tool-calling) y las envía en UNA sola tx (batchAttest, hasta 100) apenas
3
+ // la ráfaga se detiene. Esto arregla el bug de "N tool calls seguidos → 0 guardadas":
4
+ // antes el flush solo ocurría a los 25 items o cada 10s, así que una ráfaga corta
5
+ // que terminaba antes quedaba sin enviar.
4
6
 
5
7
  import type { AttestationItem, BatchOptions, ProvaAttester } from './types';
6
- import { clearIntervalSafe, setIntervalSafe, warn, type TimerId } from './runtime';
8
+ import { clearTimeoutSafe, setTimeoutSafe, warn, type TimerId } from './runtime';
7
9
 
8
10
  export interface Batcher {
9
- /** Encola una atestación; dispara flush si se alcanza maxSize. */
11
+ /** Encola una atestación; programa el flush (o lo dispara si se alcanza maxSize). */
10
12
  add(item: AttestationItem): void;
11
13
  /** Envía inmediatamente lo pendiente. */
12
14
  flush(): Promise<void>;
13
- /** Detiene el timer y hace un último flush. */
15
+ /** Cancela el timer y hace un último flush (llamar al cerrar el agente). */
14
16
  stop(): Promise<void>;
15
17
  }
16
18
 
17
19
  const DEFAULT_MAX_SIZE = 25;
18
- const DEFAULT_INTERVAL_MS = 10_000;
20
+ const DEFAULT_FLUSH_DELAY_MS = 1000;
19
21
  const HARD_BATCH_LIMIT = 100;
20
22
 
21
23
  export function createBatcher(
@@ -24,12 +26,20 @@ export function createBatcher(
24
26
  onError: (error: unknown) => void = (error) => warn('[Prova] batch error:', error),
25
27
  ): Batcher {
26
28
  const maxSize = Math.min(Math.max(options.maxSize ?? DEFAULT_MAX_SIZE, 1), HARD_BATCH_LIMIT);
27
- const intervalMs = options.flushIntervalMs ?? DEFAULT_INTERVAL_MS;
29
+ const flushDelayMs = options.flushDelayMs ?? DEFAULT_FLUSH_DELAY_MS;
28
30
 
29
31
  let buffer: AttestationItem[] = [];
30
32
  let timer: TimerId | undefined;
31
33
 
34
+ function clearTimer(): void {
35
+ if (timer !== undefined) {
36
+ clearTimeoutSafe(timer);
37
+ timer = undefined;
38
+ }
39
+ }
40
+
32
41
  async function flush(): Promise<void> {
42
+ clearTimer();
33
43
  if (buffer.length === 0) return;
34
44
  const batch = buffer;
35
45
  buffer = [];
@@ -44,24 +54,29 @@ export function createBatcher(
44
54
  }
45
55
  }
46
56
 
47
- function ensureTimer(): void {
48
- if (intervalMs > 0 && timer === undefined) {
49
- timer = setIntervalSafe(() => void flush(), intervalMs);
57
+ // Debounce: cada acción reinicia el timer, de modo que el flush ocurre
58
+ // `flushDelayMs` ms DESPUÉS de la última acción de la ráfaga → todo en 1 tx.
59
+ function scheduleFlush(): void {
60
+ clearTimer();
61
+ if (flushDelayMs <= 0) {
62
+ void flush();
63
+ return;
50
64
  }
65
+ timer = setTimeoutSafe(() => void flush(), flushDelayMs);
51
66
  }
52
67
 
53
68
  return {
54
69
  add(item: AttestationItem): void {
55
70
  buffer.push(item);
56
- ensureTimer();
57
- if (buffer.length >= maxSize) void flush();
71
+ if (buffer.length >= maxSize) {
72
+ void flush(); // llegó al tope → envía ya
73
+ } else {
74
+ scheduleFlush(); // si no, agrupa la ráfaga y envía al detenerse
75
+ }
58
76
  },
59
77
  flush,
60
78
  async stop(): Promise<void> {
61
- if (timer !== undefined) {
62
- clearIntervalSafe(timer);
63
- timer = undefined;
64
- }
79
+ clearTimer();
65
80
  await flush();
66
81
  },
67
82
  };
package/src/runtime.ts CHANGED
@@ -6,23 +6,23 @@
6
6
  export type TimerId = number | { readonly __timer?: unique symbol };
7
7
 
8
8
  interface RuntimeGlobals {
9
- setInterval(handler: () => void, ms: number): TimerId;
10
- clearInterval(id: TimerId): void;
9
+ setTimeout(handler: () => void, ms: number): TimerId;
10
+ clearTimeout(id: TimerId): void;
11
11
  console: { warn(...args: unknown[]): void };
12
12
  }
13
13
 
14
14
  const runtime = globalThis as unknown as RuntimeGlobals;
15
15
 
16
- /** setInterval que no bloquea la salida del proceso (unref en Node si existe). */
17
- export function setIntervalSafe(handler: () => void, ms: number): TimerId {
18
- const id = runtime.setInterval(handler, ms);
16
+ /** setTimeout que no bloquea la salida del proceso (unref en Node si existe). */
17
+ export function setTimeoutSafe(handler: () => void, ms: number): TimerId {
18
+ const id = runtime.setTimeout(handler, ms);
19
19
  const maybe = id as unknown as { unref?: () => void };
20
20
  if (typeof maybe.unref === 'function') maybe.unref();
21
21
  return id;
22
22
  }
23
23
 
24
- export function clearIntervalSafe(id: TimerId): void {
25
- runtime.clearInterval(id);
24
+ export function clearTimeoutSafe(id: TimerId): void {
25
+ runtime.clearTimeout(id);
26
26
  }
27
27
 
28
28
  export function warn(...args: unknown[]): void {
package/src/types.ts CHANGED
@@ -56,10 +56,14 @@ export interface ProvaAttester {
56
56
 
57
57
  /** Configuración del batching de atestaciones. */
58
58
  export interface BatchOptions {
59
- /** Nº máximo de atestaciones por transacción (1–100). Default 25. */
59
+ /** Nº máximo de atestaciones por transacción (1–100). Al alcanzarlo, flush inmediato. Default 25. */
60
60
  maxSize?: number;
61
- /** Flush automático cada N ms. Default 10000. 0 = sin flush por tiempo. */
62
- flushIntervalMs?: number;
61
+ /**
62
+ * Debounce: hace flush este nº de ms tras la ÚLTIMA acción. Así una ráfaga de
63
+ * tool calls (multi-tool-calling) se agrupa en UNA sola tx on-chain apenas
64
+ * termina la ráfaga. Default 1000. 0 = flush inmediato en cada acción (sin batch).
65
+ */
66
+ flushDelayMs?: number;
63
67
  }
64
68
 
65
69
  /** Opciones de `attachProva`. */