@intentgate-app/intentgate 0.3.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.
@@ -0,0 +1,537 @@
1
+ /**
2
+ * Memory provenance primitives for the IntentGate TypeScript SDK.
3
+ *
4
+ * This module implements the SDK side of the AAI03 (Memory Poisoning)
5
+ * defense. The agent wraps its memory backend (vector DB, Redis,
6
+ * in-memory dict, anything) with {@link MemoryStore}, which signs
7
+ * every write with an HMAC-SHA256 keyed by a per-session signing key
8
+ * derived (via HKDF) from the capability token. At tool-call time the
9
+ * agent declares which memory entries influenced the call via the
10
+ * `memoryProvenance` parameter on `Gateway.toolCall`; the gateway
11
+ * re-derives the session key and verifies each entry.
12
+ *
13
+ * # Cross-implementation contract
14
+ *
15
+ * The byte encoding of an {@link Envelope} (see {@link canonical})
16
+ * MUST match the Go gateway's `internal/provenance.Canonical`
17
+ * byte-for-byte AND match the Python SDK's `intentgate.memory.canonical`
18
+ * byte-for-byte. The KDF MUST be HKDF-SHA256 with info=
19
+ * `intentgate-memory-v1`. The HMAC MUST be HMAC-SHA256.
20
+ *
21
+ * Drift in any of these contracts means the SDK and the gateway
22
+ * silently disagree on signatures — a class of bug caught by the
23
+ * cross-implementation KAT test in `tests/memory.test.ts`. If you
24
+ * change anything in this file, run that test against the Go gateway's
25
+ * `TestDeriveSessionKey_KnownAnswer` and the Python SDK's
26
+ * `test_hkdf_kat_matches_go_gateway` to confirm the wire contract
27
+ * still holds.
28
+ *
29
+ * # Zero runtime dependencies
30
+ *
31
+ * Uses only `node:crypto` (createHmac, createHash, hkdfSync,
32
+ * timingSafeEqual, randomUUID). No third-party crypto package. The
33
+ * Node 18+ baseline is documented in package.json.
34
+ */
35
+ /** Length of a derived session signing key in bytes. Matches the Go
36
+ * gateway's SessionKeySize and the Python SDK's SESSION_KEY_SIZE. */
37
+ declare const SESSION_KEY_SIZE = 32;
38
+ /** The conventional PrevHash value for the first entry in a session.
39
+ * Named so the special-case is obvious at the call site. */
40
+ declare const ZERO_HASH: Buffer;
41
+ /**
42
+ * Raised when the SDK cannot produce or verify a memory envelope.
43
+ * Distinct from the gateway-side `ProvenanceError` in `errors.ts`
44
+ * (which is raised by `Gateway.toolCall` when the gateway rejected
45
+ * the provenance check). This class is for SDK-internal failures —
46
+ * a tampered entry detected at read time, a malformed envelope, etc.
47
+ */
48
+ declare class MemoryProvenanceError extends Error {
49
+ constructor(message: string);
50
+ }
51
+ /**
52
+ * Derive the per-session memory signing key.
53
+ *
54
+ * Matches the gateway's `provenance.DeriveSessionKey` and the Python
55
+ * SDK's `derive_session_key`: HKDF-SHA256 with salt = `sessionId` (as
56
+ * UTF-8 bytes), info = `intentgate-memory-v1`, length = 32.
57
+ *
58
+ * @throws if `masterKey` is empty or `sessionId` is empty.
59
+ */
60
+ declare function deriveSessionKey(masterKey: Buffer | Uint8Array, sessionId: string): Buffer;
61
+ /** One signed memory entry. Stored opaquely by the customer's memory
62
+ * backend; produced by `MemoryStore.write`; verified by the gateway. */
63
+ interface Envelope {
64
+ /** Stable identifier for the entry. */
65
+ id: string;
66
+ /** The capability token's `jti` whose signing key signed this. */
67
+ sessionId: string;
68
+ /** Creation time as Unix milliseconds. */
69
+ timestamp: number;
70
+ /** Application-level payload bytes. */
71
+ data: Buffer;
72
+ /** SHA-256 of the canonical bytes of the previous entry in this
73
+ * session, or ZERO_HASH for the first entry. */
74
+ prevHash: Buffer;
75
+ /** HMAC-SHA256 of canonical(envelope) under the session key. */
76
+ hmac: Buffer;
77
+ }
78
+ /**
79
+ * Produce the byte sequence the envelope's HMAC covers.
80
+ *
81
+ * Encoding is a length-prefixed concatenation of the immutable fields
82
+ * in order: sessionId (utf-8), id (utf-8), timestamp (big-endian
83
+ * uint64), prevHash, data. Lengths are big-endian uint32.
84
+ *
85
+ * The encoding is deliberately NOT JSON — same byte sequence the Go
86
+ * gateway produces in `provenance.Canonical` and the Python SDK
87
+ * produces in `canonical`. Cross-verified by the KAT test.
88
+ *
89
+ * The `hmac` field is excluded (a signature cannot cover itself).
90
+ */
91
+ declare function canonical(env: Pick<Envelope, "id" | "sessionId" | "timestamp" | "data" | "prevHash">): Buffer;
92
+ /**
93
+ * Return a copy of `env` with the `hmac` field populated.
94
+ *
95
+ * Used at memory-write time by `MemoryStore.write` and by tests.
96
+ * Computes `HMAC-SHA256(sessionKey, canonical(env))`.
97
+ *
98
+ * @throws if `sessionKey` is empty.
99
+ */
100
+ declare function sign(sessionKey: Buffer, env: Omit<Envelope, "hmac">): Envelope;
101
+ /**
102
+ * Check `env.hmac` against `sessionKey`. Returns `undefined` on a
103
+ * valid signature; throws {@link MemoryProvenanceError} otherwise.
104
+ * Comparison uses `timingSafeEqual` — constant-time with respect to
105
+ * signature contents.
106
+ */
107
+ declare function verify(sessionKey: Buffer, env: Envelope): void;
108
+ /**
109
+ * Check a list of envelopes as a per-session chain.
110
+ *
111
+ * Each entry's HMAC must verify and each entry's `prevHash` must
112
+ * equal SHA-256 of the canonical bytes of the previous entry. The
113
+ * first entry's `prevHash` must equal {@link ZERO_HASH}.
114
+ *
115
+ * Empty chain is valid (let policy decide whether absence of memory
116
+ * provenance is a deny condition for the tool).
117
+ */
118
+ declare function verifyChain(sessionKey: Buffer, chain: readonly Envelope[]): void;
119
+ /** Customer-supplied write hook for a backing store. */
120
+ type MemoryWriteHook = (entryId: string, env: Envelope) => void;
121
+ /** Customer-supplied read hook. Must throw if entry not found. */
122
+ type MemoryReadHook = (entryId: string) => Envelope;
123
+ /**
124
+ * Sign-on-write, verify-on-read wrapper around a memory backend.
125
+ *
126
+ * The customer plugs their underlying memory store (Pinecone, Redis,
127
+ * pgvector, an in-memory Map, anything) into this wrapper by
128
+ * supplying two callables: a write-hook and a read-hook. The wrapper
129
+ * signs entries on write and verifies them on read, so a tampered
130
+ * entry surfaces immediately at the agent's read site rather than
131
+ * waiting until the gateway rejects the tool call.
132
+ *
133
+ * The default storage backend is an in-memory Map — suitable for SDK
134
+ * tests, demos, and small agents. Production agents pass their real
135
+ * backend's read/write callables.
136
+ */
137
+ declare class MemoryStore {
138
+ private readonly sessionId;
139
+ private readonly key;
140
+ private readonly fallback;
141
+ private readonly writeHook?;
142
+ private readonly readHook?;
143
+ private chainHead;
144
+ /**
145
+ * @param sessionId The `jti` of the capability token this store is bound to.
146
+ * Used as the HKDF salt to derive the signing key.
147
+ * @param memorySigningKey The 32-byte signing key returned by
148
+ * `POST /v1/admin/mint` when `with_memory_signing_key: true`.
149
+ * @param options Optional `writeHook` / `readHook` callables; when
150
+ * absent the wrapper uses an in-memory Map fallback.
151
+ */
152
+ constructor(sessionId: string, memorySigningKey: Buffer | Uint8Array, options?: {
153
+ writeHook?: MemoryWriteHook;
154
+ readHook?: MemoryReadHook;
155
+ });
156
+ /**
157
+ * Sign `data` into a new envelope and store it. Returns the entry
158
+ * ID, which the caller passes to `Gateway.toolCall` via the
159
+ * `memoryProvenance` list.
160
+ *
161
+ * `data` may be a Buffer, a string (utf-8 encoded), or any JSON-
162
+ * serializable value (encoded with sorted keys + no whitespace so
163
+ * equivalent inputs produce identical envelope bytes).
164
+ */
165
+ write(data: Buffer | string | Record<string, unknown> | unknown[]): string;
166
+ /**
167
+ * Fetch and verify the envelope identified by `entryId`.
168
+ *
169
+ * @throws if the entry is missing (`Error`) or if the HMAC fails
170
+ * ({@link MemoryProvenanceError}, indicating the entry was
171
+ * tampered with after writing).
172
+ */
173
+ read(entryId: string): Envelope;
174
+ /**
175
+ * Build the wire-format provenance entries for a tool call. Each
176
+ * entry is verified before inclusion — if any envelope was tampered
177
+ * with at the storage layer, {@link MemoryProvenanceError} is
178
+ * raised here rather than at the gateway.
179
+ *
180
+ * The returned objects use base64url (no padding) encoding for byte
181
+ * fields — same shape the Go gateway parses.
182
+ */
183
+ provenanceFor(entryIds: readonly string[]): Array<{
184
+ id: string;
185
+ session_id: string;
186
+ ts: number;
187
+ data: string;
188
+ prev_hash: string;
189
+ hmac: string;
190
+ }>;
191
+ /** Number of entries in the fallback in-memory store. */
192
+ get size(): number;
193
+ }
194
+
195
+ /**
196
+ * Exception hierarchy for the IntentGate SDK.
197
+ *
198
+ * Every gateway response that isn't a clean allow becomes a typed
199
+ * Error. The hierarchy lets callers catch broadly (`catch (e) { if
200
+ * (e instanceof IntentGateError) ... }`) or narrowly (`if (e instanceof
201
+ * CapabilityError) ...`) depending on whether they want to distinguish
202
+ * which check fired.
203
+ *
204
+ * Stage codes are stable across gateway versions:
205
+ *
206
+ * CapabilityError -32010
207
+ * IntentError -32011
208
+ * PolicyError -32012
209
+ * BudgetError -32013
210
+ * ProvenanceError -32014 (opt-in, AAI03 memory-poisoning defense)
211
+ *
212
+ * Anything else (parse errors, method not found, internal errors) is
213
+ * a `ProtocolError`. Network and HTTP transport failures (timeouts,
214
+ * connection refused, non-JSON responses) are `GatewayError` —
215
+ * distinguish "the gateway is unreachable" from "the gateway said no".
216
+ */
217
+ declare class IntentGateError extends Error {
218
+ /** JSON-RPC error code from the gateway, or 0 if client-side. */
219
+ readonly code: number;
220
+ /** Optional structured payload from the gateway's `error.data`. */
221
+ readonly data: unknown;
222
+ constructor(message: string, opts?: {
223
+ code?: number;
224
+ data?: unknown;
225
+ cause?: unknown;
226
+ });
227
+ /**
228
+ * Human-friendly string. When `data` is a string, it usually carries
229
+ * the operator-facing reason (e.g. the Rego rule's explanation), so
230
+ * we surface it on `toString`.
231
+ */
232
+ toString(): string;
233
+ }
234
+ /** Network or transport failure reaching the gateway. */
235
+ declare class GatewayError extends IntentGateError {
236
+ constructor(message: string, opts?: {
237
+ code?: number;
238
+ data?: unknown;
239
+ cause?: unknown;
240
+ });
241
+ }
242
+ /** JSON-RPC error not in the four stage-specific codes. */
243
+ declare class ProtocolError extends IntentGateError {
244
+ constructor(message: string, opts?: {
245
+ code?: number;
246
+ data?: unknown;
247
+ cause?: unknown;
248
+ });
249
+ }
250
+ /** Capability stage denied: token signature, expiry, agent lock, etc. */
251
+ declare class CapabilityError extends IntentGateError {
252
+ constructor(message: string, opts?: {
253
+ code?: number;
254
+ data?: unknown;
255
+ cause?: unknown;
256
+ });
257
+ }
258
+ /** Intent stage denied: requested tool isn't in the extracted intent. */
259
+ declare class IntentError extends IntentGateError {
260
+ constructor(message: string, opts?: {
261
+ code?: number;
262
+ data?: unknown;
263
+ cause?: unknown;
264
+ });
265
+ }
266
+ /** Policy stage denied: a Rego rule fired. */
267
+ declare class PolicyError extends IntentGateError {
268
+ constructor(message: string, opts?: {
269
+ code?: number;
270
+ data?: unknown;
271
+ cause?: unknown;
272
+ });
273
+ }
274
+ /** Budget stage denied: max-calls caveat exhausted. */
275
+ declare class BudgetError extends IntentGateError {
276
+ constructor(message: string, opts?: {
277
+ code?: number;
278
+ data?: unknown;
279
+ cause?: unknown;
280
+ });
281
+ }
282
+ /**
283
+ * Provenance stage denied: the opt-in AAI03 memory-poisoning defense
284
+ * rejected the call. Raised when the X-Intent-Memory-Provenance header
285
+ * carries an entry whose HMAC does not verify, whose prev_hash chain
286
+ * is broken, or whose envelope is structurally malformed.
287
+ *
288
+ * JSON-RPC code -32014. Only emitted by gateways with provenance
289
+ * enabled (INTENTGATE_PROVENANCE_ENABLED=true); not raised against
290
+ * the default four-check pipeline.
291
+ */
292
+ declare class ProvenanceError extends IntentGateError {
293
+ constructor(message: string, opts?: {
294
+ code?: number;
295
+ data?: unknown;
296
+ cause?: unknown;
297
+ });
298
+ }
299
+ /**
300
+ * Pick the typed exception class for a JSON-RPC error code. Codes in
301
+ * the stage range produce the matching stage class; anything else
302
+ * (parse, invalid request, method not found, internal error,
303
+ * out-of-range custom codes) maps to ProtocolError.
304
+ */
305
+ declare function forCode(code: number): typeof IntentGateError;
306
+
307
+ /** One piece of the tool's response, in MCP shape. */
308
+ interface ContentBlock {
309
+ type: string;
310
+ text?: string;
311
+ }
312
+ /**
313
+ * Per-call gateway decision metadata, lifted from the `_intentgate`
314
+ * vendor extension on the JSON-RPC result. Always present on a
315
+ * successful tool_call; the gateway populates it on every allow.
316
+ */
317
+ interface IntentGateMetadata {
318
+ decision: string;
319
+ reason: string;
320
+ check: string;
321
+ latencyMs: number;
322
+ }
323
+ /** Successful tool-call response. */
324
+ interface ToolCallResult {
325
+ content: ContentBlock[];
326
+ /** Tool's own `isError` flag — distinct from gateway transport errors. */
327
+ isError: boolean;
328
+ intentgate: IntentGateMetadata | null;
329
+ }
330
+ interface ToolCallOptions {
331
+ /** Tool arguments. The gateway logs only the keys, never the values. */
332
+ arguments?: Record<string, unknown>;
333
+ /**
334
+ * The user's original prompt. Sent in `X-Intent-Prompt`; the gateway
335
+ * feeds it to the intent extractor and verifies the requested tool
336
+ * is consistent with the extracted intent. Optional, but strongly
337
+ * recommended in production — without it the intent check is
338
+ * skipped (or denies in strict mode).
339
+ */
340
+ intentPrompt?: string;
341
+ /**
342
+ * JSON-RPC request id. When unset, the Gateway uses a sequential
343
+ * per-instance counter — fine for most agents.
344
+ */
345
+ requestId?: number | string;
346
+ /**
347
+ * Optional list of memory entry IDs that influenced this tool call.
348
+ * When supplied together with `memoryStore`, the SDK looks up the
349
+ * corresponding signed envelopes and packs them into the
350
+ * `X-Intent-Memory-Provenance` header. The gateway re-derives the
351
+ * session signing key from the capability token's jti, verifies
352
+ * each HMAC, and walks the chain — closing the sophisticated AAI03
353
+ * (Memory Poisoning) case. Used only when the gateway has
354
+ * provenance enabled; otherwise the header is ignored. See
355
+ * `MemoryStore`.
356
+ */
357
+ memoryProvenance?: readonly string[];
358
+ /**
359
+ * MemoryStore instance the SDK queries for the envelopes named in
360
+ * `memoryProvenance`. Required iff `memoryProvenance` is non-empty.
361
+ */
362
+ memoryStore?: MemoryStore;
363
+ }
364
+ interface GatewayOptions {
365
+ /**
366
+ * Capability token from `igctl mint` or your tenant's mint service.
367
+ * When omitted, no Authorization header is sent and the gateway
368
+ * will reject with CapabilityError if it's in strict mode.
369
+ */
370
+ token?: string;
371
+ /** Per-request timeout in milliseconds. Default 10s. */
372
+ timeoutMs?: number;
373
+ /**
374
+ * Pluggable fetch implementation. Defaults to the global
375
+ * `fetch` (Node 18+, browsers, and most modern runtimes). Useful
376
+ * for test injection, custom transports, or shared connection
377
+ * pooling.
378
+ */
379
+ fetch?: typeof fetch;
380
+ }
381
+ /**
382
+ * Thin client for the IntentGate gateway.
383
+ *
384
+ * @example
385
+ * ```ts
386
+ * import { Gateway } from "@intentgate-app/intentgate";
387
+ *
388
+ * const gw = new Gateway("http://localhost:8080", {
389
+ * token: process.env.INTENTGATE_TOKEN,
390
+ * });
391
+ * const result = await gw.toolCall("read_invoice", {
392
+ * arguments: { id: "123" },
393
+ * intentPrompt: "Process today's AP invoices",
394
+ * });
395
+ * ```
396
+ */
397
+ declare class Gateway {
398
+ private readonly url;
399
+ private readonly token;
400
+ private readonly timeoutMs;
401
+ private readonly fetchImpl;
402
+ private nextId;
403
+ constructor(url: string, opts?: GatewayOptions);
404
+ /**
405
+ * Invoke a tool through the gateway.
406
+ *
407
+ * Resolves with a {@link ToolCallResult} for an allowed call. Throws
408
+ * one of the typed errors (CapabilityError / IntentError /
409
+ * PolicyError / BudgetError / ProtocolError / GatewayError) when
410
+ * the gateway denies, the request fails to reach the gateway, or
411
+ * the response isn't well-formed JSON-RPC.
412
+ */
413
+ toolCall(tool: string, opts?: ToolCallOptions): Promise<ToolCallResult>;
414
+ }
415
+
416
+ /**
417
+ * Pure-TypeScript capability-token helpers.
418
+ *
419
+ * The IntentGate gateway issues capability tokens with a Macaroons-
420
+ * style chained-HMAC signature: a token holder can derive a strictly
421
+ * more restrictive child token by appending a caveat and HMAC'ing it
422
+ * under the parent's signature **without ever touching the master
423
+ * key**. That is the defining property of capability tokens, and the
424
+ * reason this module ships in the SDK.
425
+ *
426
+ * Use case. A parent agent receives a token allowing tools `[a, b,
427
+ * c]`, spawns a sub-agent for one task, and wants the sub-agent's
428
+ * token to allow only `[a]`. The parent calls {@link attenuate} and
429
+ * hands the resulting token string to the sub-agent. The gateway
430
+ * (which has the master key) accepts the attenuated token and rejects
431
+ * any sub-agent call that would have needed `b` or `c`.
432
+ *
433
+ * What we don't do here:
434
+ *
435
+ * - **No master key access.** By design — that's what makes
436
+ * attenuation safe. To mint a brand-new root token, use the
437
+ * gateway's `POST /v1/admin/mint` endpoint, not this module.
438
+ * - **No semantic narrowing check.** Adding a "broader" caveat
439
+ * doesn't widen the chain because the parent's narrower caveat
440
+ * fires first on the gateway side. We don't second-guess the
441
+ * caller; policy belongs in the gateway, not the SDK.
442
+ *
443
+ * # Wire format
444
+ *
445
+ * We mirror the Go gateway's serialization byte-for-byte on the one
446
+ * place it matters: the new caveat's canonical JSON, which seeds the
447
+ * HMAC step. Anywhere else, JSON ordering doesn't affect correctness
448
+ * because the gateway re-marshals from its parsed Go struct during
449
+ * `Verify`. Every implementation in this package matches the Python
450
+ * SDK byte-for-byte against the same fixtures, so a token attenuated
451
+ * by either SDK verifies on the same gateway.
452
+ */
453
+ /**
454
+ * Caveat-type identifiers, kept in sync with the Go consts in
455
+ * gateway/internal/capability/token.go.
456
+ */
457
+ declare const CaveatType: {
458
+ readonly EXPIRY: "exp";
459
+ readonly TOOL_ALLOW: "tool_allow";
460
+ readonly TOOL_DENY: "tool_deny";
461
+ readonly AGENT_LOCK: "agent_lock";
462
+ readonly MAX_CALLS: "max_calls";
463
+ };
464
+ /**
465
+ * A structured restriction recorded in a token's chain. Only fields
466
+ * relevant to the {@link type} are emitted; the rest are omitted from
467
+ * the JSON output (matching Go's `omitempty` tags).
468
+ *
469
+ * Field order on the wire: `t, tools, agent, exp, max_calls`. This
470
+ * matches Go's encoding/json declaration-order behavior and seeds
471
+ * the HMAC step that derives the child's signature.
472
+ */
473
+ interface Caveat {
474
+ type: string;
475
+ tools?: string[];
476
+ agent?: string;
477
+ /** Unix seconds. */
478
+ expiry?: number;
479
+ maxCalls?: number;
480
+ }
481
+ declare class AttenuationError extends Error {
482
+ constructor(message: string, opts?: {
483
+ cause?: unknown;
484
+ });
485
+ }
486
+ /**
487
+ * Decode a base64url(JSON) token into its parsed object. No signature
488
+ * check (the gateway does that). Useful for inspecting the chain —
489
+ * `decodeToken(t).cav` lists the caveats bound to the token.
490
+ */
491
+ declare function decodeToken(token: string): Record<string, unknown>;
492
+ interface AttenuateOptions {
493
+ /** Narrow to this tool whitelist (caveat type `tool_allow`). */
494
+ addTools?: string[];
495
+ /** Add a deny list (caveat type `tool_deny`). Additive on top of any parent deny. */
496
+ denyTools?: string[];
497
+ /** Cap remaining calls (caveat type `max_calls`). The chain enforces the minimum. */
498
+ maxCalls?: number;
499
+ /** Set absolute expiry (Unix seconds). Caveat type `exp`. */
500
+ expiresAt?: number;
501
+ /** Convenience: now + N seconds. Caveat type `exp`. */
502
+ expiresInSeconds?: number;
503
+ /** User-supplied caveats appended last (advanced). */
504
+ extra?: Caveat[];
505
+ }
506
+ /**
507
+ * Append narrowing caveats to a parent token and return a new token
508
+ * string that the gateway accepts as a cryptographic descendant of
509
+ * the parent.
510
+ *
511
+ * Each option groups one common attenuation pattern. Multiple options
512
+ * combine; each generates one caveat in this order:
513
+ *
514
+ * 1. `addTools` → `tool_allow` caveat
515
+ * 2. `denyTools` → `tool_deny` caveat
516
+ * 3. `maxCalls` → `max_calls` caveat
517
+ * 4. `expiresAt` / → `exp` caveat (absolute Unix seconds)
518
+ * `expiresInSeconds`
519
+ * 5. `extra` → user-supplied caveats appended last
520
+ *
521
+ * @example
522
+ * ```ts
523
+ * import { attenuate } from "@intentgate-app/intentgate";
524
+ *
525
+ * // Parent token: agent allowed [search, read, email] for 1h.
526
+ * // Child: only [search, read], one call max.
527
+ * const child = attenuate(parentToken, {
528
+ * addTools: ["search", "read"],
529
+ * maxCalls: 1,
530
+ * });
531
+ *
532
+ * // Hand `child` to the sub-agent.
533
+ * ```
534
+ */
535
+ declare function attenuate(token: string, opts?: AttenuateOptions): string;
536
+
537
+ export { type AttenuateOptions, AttenuationError, BudgetError, CapabilityError, type Caveat, CaveatType, type ContentBlock, type Envelope, Gateway, GatewayError, type GatewayOptions, IntentError, IntentGateError, type IntentGateMetadata, MemoryProvenanceError, type MemoryReadHook, MemoryStore, type MemoryWriteHook, PolicyError, ProtocolError, ProvenanceError, SESSION_KEY_SIZE, type ToolCallOptions, type ToolCallResult, ZERO_HASH, attenuate, canonical, decodeToken, deriveSessionKey, forCode, sign, verify, verifyChain };