@atbash/sdk 0.9.2 → 0.10.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/dist/index.d.mts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Logger } from '@opentelemetry/api-logs';
2
+
1
3
  type JudgeEndpointConfig = {
2
4
  policy?: "default";
3
5
  endpoint?: string;
@@ -136,14 +138,24 @@ interface MemoryScanOptions {
136
138
  type Network = "public" | "private";
137
139
  /**
138
140
  * Per-call chain overrides. Pass exactly what you need to override —
139
- * `network` selects between the SDK's known chains, `blockchainRid` /
140
- * `nodeUrls` pin a fully custom chain. Pass none of these to fall back
141
- * to the SDK's defaults (or to org-resolved chain when `orgName` is set).
141
+ * `network` selects between the SDK's known chains, `blockchainRid` pins a
142
+ * custom one, and `endpoint` names the Dashboard the calls travel over. Pass
143
+ * none of these to fall back to the SDK's defaults (or to the org-resolved
144
+ * chain when `orgName` is set).
142
145
  */
143
146
  interface ChainOpts {
144
147
  network?: Network;
145
148
  blockchainRid?: string;
149
+ /**
150
+ * No longer dialled: memory reaches the chain through the Dashboard. Kept
151
+ * because callers and the other bindings still carry it as chain config.
152
+ */
146
153
  nodeUrls?: readonly string[];
154
+ /**
155
+ * Dashboard base URL. Memory reaches the chain through it, so this is where
156
+ * those requests go; defaults to the endpoint compiled into the core.
157
+ */
158
+ endpoint?: string;
147
159
  }
148
160
  /** Canonical verdict after normalization. */
149
161
  type Verdict = "ALLOW" | "HOLD" | "BLOCK" | "No verdict";
@@ -198,6 +210,11 @@ interface JudgeResult {
198
210
  * missing" — never infer the former from a null verdict alone.
199
211
  */
200
212
  status: string;
213
+ /**
214
+ * The judge's explicit refusal in the raw body (`explicitRefusal`): "BLOCK",
215
+ * "HOLD", or "" when it neither refused nor is a known refusal shape.
216
+ */
217
+ refusal?: "" | "BLOCK" | "HOLD";
201
218
  }
202
219
  interface JudgmentStatus {
203
220
  status: JudgmentState;
@@ -305,6 +322,13 @@ interface AtbashLogger {
305
322
  /** Options accepted by the `Atbash` constructor. */
306
323
  interface AtbashOptions {
307
324
  endpoint?: string;
325
+ /**
326
+ * Overall deadline for one `auditToolCall` decision, across every request
327
+ * it makes (org lookup, exists check, judge). Default 60 000 ms. When it
328
+ * passes the decision is an ERROR (denied unless `failClosed` is false).
329
+ * `timeoutMs` still bounds each single request.
330
+ */
331
+ decisionTimeoutMs?: number;
308
332
  timeoutMs?: number;
309
333
  /**
310
334
  * Full chain override — BRID + nodeUrls in one object. Wins over every
@@ -350,6 +374,16 @@ interface AtbashOptions {
350
374
  orgEncryptionPubKey?: string;
351
375
  /** When true (default), `auditToolCall` denies on any error. */
352
376
  failClosed?: boolean;
377
+ /**
378
+ * When true (the default), an answer that carries no enforcement decision
379
+ * (the audit tier's `{status:"logged"}` with no verdict) is refused:
380
+ * `auditToolCall` returns `{allow:false, verdict:"ERROR"}` whatever
381
+ * `failClosed` says, and `judgeAction().allow` / `getJudgmentStatus().allow`
382
+ * are false. Set it to `false` only to run deliberately in log-only mode
383
+ * (security review 2026-09-30, H6: an unsigned marker switched enforcement
384
+ * off).
385
+ */
386
+ requireEnforcement?: boolean;
353
387
  /**
354
388
  * Verbose diagnostics. Off by default. When on, a failed judge call also
355
389
  * logs the response body, which is the difference between "judge API failed"
@@ -400,6 +434,10 @@ interface FromConfigOptions {
400
434
  /** Default org name — see {@link AtbashOptions.orgName}. */
401
435
  orgName?: string;
402
436
  failClosed?: boolean;
437
+ /** See {@link AtbashOptions.requireEnforcement}. Default true. */
438
+ requireEnforcement?: boolean;
439
+ /** See {@link AtbashOptions.decisionTimeoutMs}. Default 60 000 ms. */
440
+ decisionTimeoutMs?: number;
403
441
  /** See {@link AtbashOptions.debug}. */
404
442
  debug?: boolean;
405
443
  logger?: AtbashLogger;
@@ -456,6 +494,10 @@ declare class Atbash {
456
494
  readonly orgEncryptionPubKey?: string;
457
495
  /** When true (default), `auditToolCall` denies on any error. */
458
496
  readonly failClosed: boolean;
497
+ /** When true (default), an unenforced (audit-tier) answer is refused. */
498
+ readonly requireEnforcement: boolean;
499
+ /** Overall deadline for one auditToolCall decision, in ms. */
500
+ readonly decisionTimeoutMs: number;
459
501
  /** Org key learned from the last agent-exists check, for this agent only. */
460
502
  private _orgKeyFromChain;
461
503
  private readonly debug;
@@ -497,12 +539,6 @@ declare class Atbash {
497
539
  */
498
540
  private _agentExistsCache;
499
541
  private static readonly AGENT_EXISTS_TTL_MS;
500
- /**
501
- * Cached bearer token for risk-engine / insurance read calls. Built
502
- * lazily as a signed `log_tool_call` tx and refreshed every 4 min so
503
- * server-side replay protection windows never expire it mid-session.
504
- */
505
- private _authBearers;
506
542
  /** Guards `logEnvironmentOnce` — hosts construct several clients. */
507
543
  private static environmentLogged;
508
544
  constructor(privkey: string, options?: AtbashOptions);
@@ -525,6 +561,48 @@ declare class Atbash {
525
561
  * validated against the trusted allowlist / self-hosted policy; a
526
562
  * self-hosted endpoint's `verifyPubKey` becomes the client default.
527
563
  */
564
+ /**
565
+ * Decide which key this client signs as.
566
+ *
567
+ * Most specific wins: a key passed in code, then a key file the host named,
568
+ * then the environment, then the default key file. `config.json` is absent
569
+ * from that list on purpose — it is a settings file, writable by anything
570
+ * that can write the user's home and read by every Atbash integration on the
571
+ * machine, so letting it name the key meant one stray value silently
572
+ * re-pointed who each of them signed as.
573
+ *
574
+ * A named `keyPath` that does not exist throws rather than falling through.
575
+ * The caller said which file holds its identity; quietly signing as a
576
+ * different one is the outcome worth refusing.
577
+ *
578
+ * @param options - The `fromConfig` options, read for `agentKey` and `keyPath`.
579
+ * @returns The resolved agent identity.
580
+ * @throws When a named key file is missing, or no identity can be found.
581
+ */
582
+ private static resolveIdentity;
583
+ /**
584
+ * Add the one thing a machine with no key file needs to hear.
585
+ *
586
+ * This is the only path where the operator cannot see what happened: no key
587
+ * file, and the key they are looking for sits in `config.json`, which no
588
+ * longer selects the identity. A bare "key file not found" sends them hunting
589
+ * for a key they already have. Only this branch gets the hint — a caller who
590
+ * named a `keyPath` is told about that path, where a stranded key is noise.
591
+ *
592
+ * @param err - The "key file not found" error from the default lookup.
593
+ * @returns The same error, or one that also names the key in config.json.
594
+ */
595
+ private static explainStrandedKey;
596
+ /**
597
+ * Say so when `config.json` still holds an agent key.
598
+ *
599
+ * Nothing signs with it any more, and silence would leave an operator
600
+ * believing one identity is in force while another is. The pubkey is named,
601
+ * not the key, so the line is safe in a log.
602
+ *
603
+ * @param logger - The host logger, when one was supplied.
604
+ */
605
+ private static warnOnStrandedKey;
528
606
  static fromConfig(options?: FromConfigOptions): Atbash;
529
607
  get pubkey(): string;
530
608
  get privkey(): string;
@@ -559,6 +637,23 @@ declare class Atbash {
559
637
  * explicitly false.
560
638
  */
561
639
  auditToolCall(input: ToolCallInput): Promise<Decision>;
640
+ /**
641
+ * The verify key for one call (R4, governor tier-2 review). A per-call key
642
+ * may only narrow what the client accepts: on a client pinned to a judge
643
+ * key it must be that same key, never a replacement; on an unpinned client
644
+ * it adds the check.
645
+ */
646
+ private effectiveVerifyKey;
647
+ /**
648
+ * Collapse a judge result into a {@link Decision}. The most restrictive
649
+ * signal wins (security review 2026-09-30, H1): `action_type`, `verdict`
650
+ * and the canonical `allow` are each able to deny, and only a result where
651
+ * all three agree may execute. A present `allow` / `decision.allow` that is
652
+ * not exactly `true` is the judge declining to grant permission, so it
653
+ * denies even under `failClosed: false` — that option relaxes *errors*, it
654
+ * never overrides a refusal.
655
+ */
656
+ private decide;
562
657
  /**
563
658
  * One exit for every judge failure.
564
659
  *
@@ -568,6 +663,12 @@ declare class Atbash {
568
663
  * The response body follows only under `debug`, since it can echo the action.
569
664
  */
570
665
  private failJudge;
666
+ /**
667
+ * The canonical permission for a response body under this client's
668
+ * settings: {@link canonicalAllow}, minus the audit tier when
669
+ * `requireEnforcement` is on. Never more permissive than `auditToolCall`.
670
+ */
671
+ private executable;
571
672
  private fail;
572
673
  /**
573
674
  * Return the current status of a previously submitted judgment.
@@ -886,22 +987,6 @@ declare const BOOT_SYNC_HINT = "check the chain endpoint and orgName if the caus
886
987
  */
887
988
  declare function bootSyncFailureLine(cause: unknown): string;
888
989
 
889
- /**
890
- * Make a chain query result crossable at the NAPI boundary.
891
- *
892
- * `postchain-client` decodes a Rell `byte_array` into a Node `Buffer`. The
893
- * core's `parse*` functions take `serde_json::Value`, and NAPI-RS cannot
894
- * convert a `Buffer` into one — it reaches the methods every `Uint8Array`
895
- * inherits and fails with "JS functions cannot be represented as a
896
- * serde_json::Value", which names functions for what is a plain Buffer.
897
- *
898
- * The conversion has to happen here because the failure is in the argument
899
- * conversion, before any core code runs. Of the shapes the core accepts —
900
- * hex string, `[u8]`, `{ data: [...] }` — hex is the cheapest to produce.
901
- */
902
- /** Recursively rewrite byte containers to hex, leaving everything else as-is. */
903
- declare function gtvToFfiSafe(value: unknown): unknown;
904
-
905
990
  /** Derive the 32-byte AES key from an agent's secp256k1 privkey (hex). Deterministic — same privkey always yields the same key. */
906
991
  declare function deriveMemoryKey(privkey: string): Promise<Buffer>;
907
992
  /** Encrypt UTF-8 plaintext. `ciphertext` has the 16-byte GCM auth tag appended, matching the SDK's on-chain byte layout. */
@@ -940,7 +1025,7 @@ interface CommitMemoryOptions {
940
1025
  filePath?: string;
941
1026
  /** Org name — when set, the SDK resolves which chain the agent lives on. */
942
1027
  orgName?: string;
943
- /** Atbash service endpoint for org→chain lookup. */
1028
+ /** Atbash service endpoint — where memory reaches the chain, and the org→chain lookup. */
944
1029
  endpoint?: string;
945
1030
  /** Self-hosted judge response-signing pubkey; required with a non-allowlisted `endpoint`. */
946
1031
  verifyPubKey?: string;
@@ -948,6 +1033,7 @@ interface CommitMemoryOptions {
948
1033
  }
949
1034
  interface RollbackMemoryOptions {
950
1035
  orgName?: string;
1036
+ /** Atbash service endpoint — where memory reaches the chain, and the org→chain lookup. */
951
1037
  endpoint?: string;
952
1038
  /** Self-hosted judge response-signing pubkey; required with a non-allowlisted `endpoint`. */
953
1039
  verifyPubKey?: string;
@@ -1121,6 +1207,17 @@ interface GuardMemoryWriteInput extends ClassifyMemoryWriteOptions {
1121
1207
  debug?: boolean;
1122
1208
  /** Optional logger for debug probe + persist-failure warnings. */
1123
1209
  logger?: GuardLogger;
1210
+ /** Agent home directory names to accept beyond the built-in list. */
1211
+ agentHomeDirs?: string[];
1212
+ /**
1213
+ * Root the caller keeps memory under, when it is not an agent home.
1214
+ *
1215
+ * Only pass a value the host stated outright. A root defaulted from the
1216
+ * process working directory would make whichever directory the host happened
1217
+ * to start in look like a memory store — which is how a stray MEMORY.md once
1218
+ * ended up inside a plugin checkout.
1219
+ */
1220
+ memoryRoot?: string;
1124
1221
  }
1125
1222
  /** Plugin-facing decision. Shape mirrors what plugins return from `before_tool_call`. */
1126
1223
  interface GuardMemoryDecision {
@@ -1139,19 +1236,17 @@ interface GuardMemoryWriteResult {
1139
1236
  committed?: boolean;
1140
1237
  }
1141
1238
  /**
1142
- * Guarded memory-write flow. Returns `{ handled: false }` when the tool
1143
- * call isn't a memory write, otherwise returns a `decision` the plugin
1144
- * should return from its hook.
1239
+ * Guard a memory write, and record what was decided.
1240
+ *
1241
+ * Wraps the decision rather than threading telemetry through its eight exits,
1242
+ * so a later return added inside cannot quietly stop being counted.
1145
1243
  *
1146
- * Verdict handling:
1147
- * - `red` → not persisted to chain; decision blocks (unless `enforce: false`)
1148
- * - `yellow` → persisted with its LLM score; decision allows once the chain confirms
1149
- * - `green` → persisted with its LLM score; decision allows once the chain confirms
1150
- * - anything else → not persisted; decision blocks (unless `enforce: false`)
1244
+ * Only a call this guard actually handled is recorded. A tool call that was
1245
+ * never a memory write is not a memory operation, and counting it would put
1246
+ * every unrelated edit into the number a memory migration reads.
1151
1247
  *
1152
- * A write is acknowledged only after the chain transaction confirms, for
1153
- * yellow exactly as for green. An unconfirmed write blocks in enforce mode
1154
- * and remains unaudited in observe mode.
1248
+ * @param input - The tool call and the agent to judge it for.
1249
+ * @returns What the guard decided; unchanged by the recording.
1155
1250
  */
1156
1251
  declare function guardMemoryWrite(input: GuardMemoryWriteInput): Promise<GuardMemoryWriteResult>;
1157
1252
 
@@ -1216,10 +1311,19 @@ declare class PointerStore {
1216
1311
  private cache;
1217
1312
  private loading;
1218
1313
  constructor(filePath: string);
1219
- /** Resolves the pointer for `agentPubkeyHex`, or a zero-pointer that will force a sync on first use. */
1220
- get(agentPubkeyHex: string): Promise<MemoryPointer>;
1221
- /** Persists an updated pointer. Failures are swallowed to a logger callback (if provided) so sync never blocks the caller. */
1222
- set(agentPubkeyHex: string, pointer: MemoryPointer, onError?: (err: Error) => void): Promise<void>;
1314
+ /**
1315
+ * The pointer for one agent's file, or a zero-pointer forcing a sync.
1316
+ *
1317
+ * @param filePath - The file's chain slot, i.e. its basename.
1318
+ */
1319
+ get(agentPubkeyHex: string, filePath: string): Promise<MemoryPointer>;
1320
+ /**
1321
+ * Persist one file's pointer, leaving the agent's other files alone.
1322
+ *
1323
+ * Write failures are reported to `onError` rather than thrown: a cache that
1324
+ * cannot be written must not take down the read it was speeding up.
1325
+ */
1326
+ set(agentPubkeyHex: string, filePath: string, pointer: MemoryPointer, onError?: (err: Error) => void): Promise<void>;
1223
1327
  private ensureLoaded;
1224
1328
  private loadOnce;
1225
1329
  private persist;
@@ -1314,6 +1418,17 @@ interface MemoryGuardManagerOptions {
1314
1418
  workspaceDir: string;
1315
1419
  /** Absolute MEMORY.md path. Default `<workspaceDir>/MEMORY.md`. */
1316
1420
  memoryFilePath?: string;
1421
+ /**
1422
+ * Root this host keeps memory under, when it is not an agent home.
1423
+ *
1424
+ * Only set this from a value the host stated outright — never from
1425
+ * `process.cwd()`. A guessed root makes whichever directory the host started
1426
+ * in look like a memory store, which is how a stray MEMORY.md once ended up
1427
+ * inside a plugin checkout.
1428
+ */
1429
+ memoryRoot?: string;
1430
+ /** Agent home directory names to accept beyond the built-in list. */
1431
+ agentHomeDirs?: string[];
1317
1432
  /** Persistent pointer file. Default `<workspaceDir>/.atbash/memory-pointer.json`. */
1318
1433
  pointerFilePath?: string;
1319
1434
  /** File-backed log. Default `<workspaceDir>/.atbash/plugin.log`. */
@@ -1360,6 +1475,10 @@ declare class MemoryGuardManager {
1360
1475
  private readonly pointerStore;
1361
1476
  private readonly logger;
1362
1477
  private readonly memoryFilePath;
1478
+ /** Base for resolving the relative paths a host sends. */
1479
+ private readonly workspaceDir;
1480
+ /** Set by `verifyOneFile` when the file it checked was actually on chain. */
1481
+ private lastVerified;
1363
1482
  private readonly ttlMs;
1364
1483
  private readonly rollbackMinScore;
1365
1484
  private readonly enforce;
@@ -1377,6 +1496,14 @@ declare class MemoryGuardManager {
1377
1496
  private _resolvedChainOpts;
1378
1497
  private _resolveChainInflight?;
1379
1498
  constructor(opts: MemoryGuardManagerOptions);
1499
+ /**
1500
+ * Carry this manager's host into `chainOpts`.
1501
+ *
1502
+ * Memory reads reach the chain through that host, and they are handed only
1503
+ * `chainOpts` — without this a self-hosted deployment would read from the
1504
+ * compiled-in default host while writing to its own.
1505
+ */
1506
+ private withEndpoint;
1380
1507
  /**
1381
1508
  * Resolve `orgName` → chain once, cache forever. `commitMemoryVersion`
1382
1509
  * already does this for writes; without the same call on the read
@@ -1394,15 +1521,27 @@ declare class MemoryGuardManager {
1394
1521
  */
1395
1522
  runBootProbe(): Promise<void>;
1396
1523
  /**
1397
- * Returns a `HookDecision` when the guard reached a decision about this event.
1398
- * Returns `null` for non-memory events, other files this manager does not
1399
- * own, or unverified observe-mode reads. An enforced read of the managed
1400
- * file blocks when verification cannot complete.
1524
+ * Bring one chain file into step with its local counterpart.
1401
1525
  *
1402
- * A returned decision carries `audited` (see `HookDecision`). Only
1403
- * `{ allow: true, audited: true }` means "checked and cleared"; anything else
1404
- * that allows is a call the host still needs to judge.
1526
+ * Only a file that already exists locally is touched. Restoring one that is
1527
+ * absent would mean choosing where to create it, and the root is a guess the
1528
+ * moment more than one could apply — the same guess that once wrote a
1529
+ * MEMORY.md into a plugin checkout.
1530
+ *
1531
+ * @returns What happened, for the single summary line the caller logs.
1405
1532
  */
1533
+ private syncOneAtBoot;
1534
+ /**
1535
+ * Where a chain slot's file lives locally, or null when we do not have it.
1536
+ *
1537
+ * A stated root is tried first, then each agent home that actually exists in
1538
+ * the user's home directory — the same rule that produced the slot, run
1539
+ * backwards. Only an existing file is returned: creating one would mean
1540
+ * picking a root, and picking is guessing.
1541
+ */
1542
+ private locate;
1543
+ /** Roots a chain slot may be joined to, most specific first. */
1544
+ private memoryRoots;
1406
1545
  handleBeforeToolCall(event: unknown, ctx: unknown): Promise<HookDecision | null>;
1407
1546
  private mapGuardResult;
1408
1547
  /**
@@ -1420,12 +1559,70 @@ declare class MemoryGuardManager {
1420
1559
  * also covers events carrying two different path keys, where the classifier
1421
1560
  * and the host could otherwise disagree about which one is authoritative.
1422
1561
  */
1423
- private vouchesForTarget;
1562
+ /**
1563
+ * The memory files this tool call reads, as absolute paths.
1564
+ *
1565
+ * Relative paths resolve against the workspace, not `process.cwd()`. The host
1566
+ * sends paths relative to the agent's workspace; resolving them against the
1567
+ * process's own directory made the guard protect whichever directory the host
1568
+ * happened to start in, which on one machine was a plugin checkout.
1569
+ *
1570
+ * @returns Every named target, de-duplicated; empty when the call names none.
1571
+ */
1572
+ private readTargets;
1573
+ /**
1574
+ * Say what the read classifier saw and what it concluded.
1575
+ *
1576
+ * The write path has `emitDebugProbe`; this is its counterpart, so a tool
1577
+ * call can be followed across the fork instead of only after it. `false` here
1578
+ * is the normal answer for a write — it means the call goes to the write
1579
+ * classifier next, not that it was ignored.
1580
+ *
1581
+ * @param isMemoryRead - What `classifyMemoryRead` returned.
1582
+ */
1583
+ private emitReadProbe;
1584
+ /**
1585
+ * The chain slot for a path, or null when the file gets no chain record.
1586
+ *
1587
+ * One helper so the boot probe and every read agree: taking a basename in one
1588
+ * place and a relative path in the other would verify a file against a record
1589
+ * that is not its own.
1590
+ */
1591
+ private slotFor;
1592
+ /**
1593
+ * Verify every memory file this call reads, each against its own chain slot.
1594
+ *
1595
+ * A call naming several files is only cleared when all of them are, so one
1596
+ * unverifiable file cannot ride along with a verified one.
1597
+ *
1598
+ * @returns A block for the first file that fails, an audited allow when all
1599
+ * were verified, or null when none of them is on chain.
1600
+ */
1424
1601
  private handleMemoryRead;
1602
+ /**
1603
+ * Check one memory file against the chain slot of the same name.
1604
+ *
1605
+ * A file with no chain version is passed through rather than blocked: there
1606
+ * is no claim to protect, so refusing would only stop an agent reading memory
1607
+ * it has never committed. A file that IS on chain must match, or the read is
1608
+ * refused — that is the whole guarantee.
1609
+ *
1610
+ * @returns A decision when the read must not proceed, else null.
1611
+ */
1612
+ private verifyOneFile;
1425
1613
  /** Complete queued audit-log writes before a host shuts down or removes its workspace. */
1426
1614
  flushLogs(): Promise<void>;
1615
+ /**
1616
+ * A read this guard could not verify.
1617
+ *
1618
+ * Enforcing, that is a block. Observing, the host audits it as usual — but
1619
+ * the reason is said out loud either way, or an unverified read looks
1620
+ * identical to a clean one in the log.
1621
+ */
1427
1622
  private unverifiedRead;
1428
1623
  private writeMemoryAtomic;
1624
+ /** Replace `target` in one step, so a reader never sees a half-written file. */
1625
+ private writeFileAtomic;
1429
1626
  }
1430
1627
  declare function createMemoryGuardManager(opts: MemoryGuardManagerOptions): MemoryGuardManager;
1431
1628
 
@@ -1459,6 +1656,20 @@ interface TelemetryConfig {
1459
1656
  * `{ Authorization: "Bearer <hex>" }`). Required to actually export.
1460
1657
  */
1461
1658
  getAuthHeaders?: () => Record<string, string>;
1659
+ /**
1660
+ * Hashes the agent key before it is emitted on a wide event.
1661
+ *
1662
+ * Defaults to an unsalted SHA-256, which is de-identification rather than
1663
+ * anonymisation: agent pubkeys are public on chain and can be enumerated, so
1664
+ * the mapping is recoverable by anyone holding that list. Supply a salted
1665
+ * hasher to make it uncorrelatable, at the cost of joining across
1666
+ * deployments.
1667
+ *
1668
+ * Injected rather than imported so the telemetry modules need nothing from
1669
+ * the native addon. Left unset, the agent field is dropped from events
1670
+ * rather than falling back to the raw key.
1671
+ */
1672
+ hashAgentKey?: (pubkeyHex: string) => string;
1462
1673
  }
1463
1674
  declare function setupTelemetry(config: TelemetryConfig): void;
1464
1675
  /**
@@ -1481,6 +1692,111 @@ declare function flushTelemetry(): Promise<void>;
1481
1692
  */
1482
1693
  declare function shutdownTelemetry(): Promise<void>;
1483
1694
 
1695
+ /**
1696
+ * Wide events: one row per SDK operation, alongside the counters.
1697
+ *
1698
+ * The counters in `telemetry.ts` are aggregated inside this process before
1699
+ * export, so Honeycomb never receives a per-operation row. That is fine for
1700
+ * "is it up" and useless for everything else: a question nobody attached an
1701
+ * attribute for in advance cannot be answered later, because the data to
1702
+ * answer it never existed. "Which org sees the most failures", "what preceded
1703
+ * a fail-closed", "is the new release slower" are all that shape.
1704
+ *
1705
+ * So each operation also emits one event carrying its whole context. The
1706
+ * counters stay — they are the right tool for health boards and alerts, and
1707
+ * they are not sampled.
1708
+ *
1709
+ * TWO RULES SHAPE THIS MODULE.
1710
+ *
1711
+ * The payload is METADATA ONLY, and the allowlist below is the whole of it:
1712
+ * function name, outcome, latency, error class, error status and path, SDK
1713
+ * version, chain, and a hash of the agent key. Action text, tool arguments, policy text, organisation
1714
+ * names and keys never appear — not as a field that is emptied, but as a field
1715
+ * that does not exist, so there is nothing to forget to strip.
1716
+ *
1717
+ * The agent key is hashed, never sent raw, and the hasher is INJECTED rather
1718
+ * than imported: this module needs nothing from the native addon. With no
1719
+ * hasher supplied the field is DROPPED rather than falling back to the raw
1720
+ * key, so the guarantee does not depend on wiring somebody could forget.
1721
+ *
1722
+ * NOTE on what hashing does and does not buy. Agent pubkeys are public on
1723
+ * chain and can be enumerated, so an UNSALTED hash is reversible by anyone who
1724
+ * can read the chain: it is de-identification, not anonymisation. A salted
1725
+ * hasher makes it uncorrelatable and costs cross-deployment joins. Which one
1726
+ * is wanted is the caller's decision; this module only guarantees the raw key
1727
+ * never leaves.
1728
+ *
1729
+ * And the richer payload has its own switch. Counters carry a function name
1730
+ * and a source. These events carry agent and org identity off a customer's
1731
+ * machine, which is a different proposition for a security product, so
1732
+ * `ATBASH_TELEMETRY_EVENTS_DISABLED=1` turns them off while leaving the health
1733
+ * counters on. Both remain subject to the existing global opt-out.
1734
+ */
1735
+
1736
+ /** Attributes an event may carry. Anything not listed here cannot be emitted. */
1737
+ interface OperationEvent {
1738
+ /** SDK function, matching the counter's `function.name` so the two join. */
1739
+ functionName: string;
1740
+ durationMs: number;
1741
+ status: "success" | "error";
1742
+ /**
1743
+ * Hex pubkey of the agent the call was made as. Hashed before it is emitted,
1744
+ * and omitted entirely when no hasher is configured.
1745
+ */
1746
+ agentPubkey?: string;
1747
+ /**
1748
+ * Blockchain RID of the chain this call concerned.
1749
+ *
1750
+ * The RID rather than a network label: it is public infrastructure, it is
1751
+ * unambiguous, and it identifies the deployment without naming a customer.
1752
+ */
1753
+ chain?: string;
1754
+ /** Constructor name of the thrown error, e.g. `AtbashAPIError`. */
1755
+ errorClass?: string;
1756
+ /** HTTP status, or 0 when the request never completed. */
1757
+ errorStatus?: number;
1758
+ /**
1759
+ * Request path the status came from, e.g. `/api/v1/judge`.
1760
+ *
1761
+ * The class alone does not say what failed: several routes answer one call
1762
+ * and more than one can 404, so `AtbashAPIError` cannot distinguish "this
1763
+ * agent is not registered" from "the chain-routing lookup did not resolve".
1764
+ * The path settles it.
1765
+ *
1766
+ * Carries no query string — `requestPath` strips it at the point the error
1767
+ * is built, because a query string carries org names, tool call ids and the
1768
+ * agent pubkey. Structured and already sanitised, so this stays inside the
1769
+ * metadata rule where an error message would not.
1770
+ */
1771
+ errorPath?: string;
1772
+ /**
1773
+ * Short categorical result, when "success" is too coarse — e.g. a memory
1774
+ * write that scanned clean but never reached the chain.
1775
+ *
1776
+ * Categorical by contract: a value a caller chooses from a fixed vocabulary,
1777
+ * never free text and never anything derived from user content.
1778
+ */
1779
+ outcome?: string;
1780
+ }
1781
+ /** Hashes an agent key for emission. Supplied by `setupTelemetry`. */
1782
+ type AgentKeyHasher = (pubkeyHex: string) => string;
1783
+ declare function configureEvents(next: Logger | null, opts?: {
1784
+ version?: string;
1785
+ source?: string;
1786
+ hashAgentKey?: AgentKeyHasher;
1787
+ }): void;
1788
+ /** True when an event would actually be emitted. Exported for tests and callers that build context lazily. */
1789
+ declare function eventsAreOn(): boolean;
1790
+ /**
1791
+ * Emit one wide event for a completed operation.
1792
+ *
1793
+ * Never throws and never blocks: telemetry failing must not change what the
1794
+ * caller observes. Does nothing when events are off.
1795
+ *
1796
+ * @param e - The completed operation.
1797
+ */
1798
+ declare function recordEvent(e: OperationEvent): void;
1799
+
1484
1800
  /**
1485
1801
  * Rust core does the work; `browser/encrypted-toolcall.ts` mirrors it for the
1486
1802
  * browser and must produce the same columns.
@@ -1578,4 +1894,4 @@ declare function containsSecret(text: string): boolean;
1578
1894
  declare function createMemorySnapshot(entries: MemoryEntry[], takenAt: number): MemorySnapshot;
1579
1895
  declare function diffMemorySnapshots(before: MemorySnapshot, after: MemorySnapshot): MemoryDiffResult;
1580
1896
 
1581
- export { type ActionType, type AgentAuth, type AgentLookupOptions, type AgentMemoryEntry, type AgentPolicy, type AnomalySeverity, type AnomalyType, Atbash, AtbashAPIError, type AtbashLogger, type AtbashOptions, type AtbashUserConfig, BOOT_SYNC_HINT, type ChainConfig, type ChainOpts, type ClassifierToolContext, type ClassifierToolEvent, type ClassifyMemoryReadOptions, type ClassifyMemoryWriteOptions, type ClientSource, type CommitMemoryOptions, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, DEFAULT_MEMORY_PATH_PATTERNS, DEFAULT_MEMORY_READ_TOOL_NAMES, DEFAULT_MEMORY_WRITE_TOOL_NAMES, type Decision, type DecisionVerdict, EciesDomain, type EncryptedMemory, type Envelope, type FromConfigOptions, type GuardLogger, type GuardMemoryDecision, type GuardMemoryWriteInput, type GuardMemoryWriteResult, type HeldAction, type HeldActionReview, type HookDecision, HttpClient, HttpTransportError, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentState, type JudgmentStatus, KEY_FILENAMES, type KeyPair, type LogToolCallOptions, type LogToolCallResult, type MemoryAnomaly, type MemoryDiffResult, type MemoryEntry, MemoryGuardManager, type MemoryGuardManagerOptions, MemoryIntegrityError, type MemoryPointer, type MemoryRollbackEvent, type MemoryScanOptions, type MemoryScanResult, type MemoryScanVerdict, type MemorySnapshot, type ModifiedEntry, type Network, type OrgSubscription, PRIVATE_CHAIN, PUBLIC_CHAIN, PointerStore, type Provider, type PubkeyValue, type RedactResult, type RollbackMemoryOptions, type SecretKind, type SecretMatch, SignatureVerificationError, type Subscription, type SyncMemoryOptions, type SyncMemoryResult, type TelemetryConfig, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, type WrappedLogger, bootSyncFailureLine, buildAllowedJudgeHosts, canonicalAllow, chainForNetwork, chooseKeyPath, claimHashHex, classifyMemoryRead, classifyMemoryWrite, columnAad, commitMemoryVersion, containsEvasionCharacters, containsSecret, createFileLogger, createMemoryGuardManager, createMemorySnapshot, decryptForOrg, decryptMemoryContent, defaultPluginLogPath, defaultPointerPath, deriveMemoryKey, derivePublicKey, diffMemorySnapshots, encryptForOrg, encryptMemoryContent, encryptedLength, flushTelemetry, generateKeypair, getActiveAgentMemory, getActiveMemoryId, getConfigDir, getConfigPath, getMemoryById, getMemoryHistory, getRecentAgentMemory, getRollbackHistory, gtvToFfiSafe, guardMemoryWrite, isEnvelope, isValidPrivateKey, keyFingerprintOf, keyPathCandidates, loadAgent, loadAgentFromFile, loadUserConfig, normalizeActionForHash, normalizeActionType, normalizeForMatching, normalizeStatus, normalizeVerdict, packEnvelope, parseEnvelope, pubkeyToHex, recordCall, recordDuration, redactJsonStrings, redactSecrets, resolve, resolveKeyPath, rollbackMemory, saveUserConfig, scanMemory, scanMemoryBatch, setupTelemetry, shutdownTelemetry, signEncryptedToolCall, signJudgeAction, signLogToolCall, syncLocalMemory, validateJudgeEndpoint, verifyJudgeResponseSignature, verifySignature };
1897
+ export { type ActionType, type AgentAuth, type AgentLookupOptions, type AgentMemoryEntry, type AgentPolicy, type AnomalySeverity, type AnomalyType, Atbash, AtbashAPIError, type AtbashLogger, type AtbashOptions, type AtbashUserConfig, BOOT_SYNC_HINT, type ChainConfig, type ChainOpts, type ClassifierToolContext, type ClassifierToolEvent, type ClassifyMemoryReadOptions, type ClassifyMemoryWriteOptions, type ClientSource, type CommitMemoryOptions, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, DEFAULT_MEMORY_PATH_PATTERNS, DEFAULT_MEMORY_READ_TOOL_NAMES, DEFAULT_MEMORY_WRITE_TOOL_NAMES, type Decision, type DecisionVerdict, EciesDomain, type EncryptedMemory, type Envelope, type FromConfigOptions, type GuardLogger, type GuardMemoryDecision, type GuardMemoryWriteInput, type GuardMemoryWriteResult, type HeldAction, type HeldActionReview, type HookDecision, HttpClient, HttpTransportError, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentState, type JudgmentStatus, KEY_FILENAMES, type KeyPair, type LogToolCallOptions, type LogToolCallResult, type MemoryAnomaly, type MemoryDiffResult, type MemoryEntry, MemoryGuardManager, type MemoryGuardManagerOptions, MemoryIntegrityError, type MemoryPointer, type MemoryRollbackEvent, type MemoryScanOptions, type MemoryScanResult, type MemoryScanVerdict, type MemorySnapshot, type ModifiedEntry, type Network, type OperationEvent, type OrgSubscription, PRIVATE_CHAIN, PUBLIC_CHAIN, PointerStore, type Provider, type PubkeyValue, type RedactResult, type RollbackMemoryOptions, type SecretKind, type SecretMatch, SignatureVerificationError, type Subscription, type SyncMemoryOptions, type SyncMemoryResult, type TelemetryConfig, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, type WrappedLogger, bootSyncFailureLine, buildAllowedJudgeHosts, canonicalAllow, chainForNetwork, chooseKeyPath, claimHashHex, classifyMemoryRead, classifyMemoryWrite, columnAad, commitMemoryVersion, configureEvents, containsEvasionCharacters, containsSecret, createFileLogger, createMemoryGuardManager, createMemorySnapshot, decryptForOrg, decryptMemoryContent, defaultPluginLogPath, defaultPointerPath, deriveMemoryKey, derivePublicKey, diffMemorySnapshots, encryptForOrg, encryptMemoryContent, encryptedLength, eventsAreOn, flushTelemetry, generateKeypair, getActiveAgentMemory, getActiveMemoryId, getConfigDir, getConfigPath, getMemoryById, getMemoryHistory, getRecentAgentMemory, getRollbackHistory, guardMemoryWrite, isEnvelope, isValidPrivateKey, keyFingerprintOf, keyPathCandidates, loadAgent, loadAgentFromFile, loadUserConfig, normalizeActionForHash, normalizeActionType, normalizeForMatching, normalizeStatus, normalizeVerdict, packEnvelope, parseEnvelope, pubkeyToHex, recordCall, recordDuration, recordEvent, redactJsonStrings, redactSecrets, resolve, resolveKeyPath, rollbackMemory, saveUserConfig, scanMemory, scanMemoryBatch, setupTelemetry, shutdownTelemetry, signEncryptedToolCall, signJudgeAction, signLogToolCall, syncLocalMemory, validateJudgeEndpoint, verifyJudgeResponseSignature, verifySignature };