@voidly/agent-sdk 3.2.2 → 3.2.4

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
@@ -208,9 +208,18 @@ Flags: `PQ | RATCHET | PAD | SEAL | DH_RATCHET | DENIABLE`
208
208
 
209
209
  **Identity format**: `did:voidly:{base58-of-ed25519-pubkey-first-16-bytes}`
210
210
 
211
+ ### OpenClaw
212
+
213
+ Available as an [OpenClaw skill on ClawHub](https://clawhub.ai/s/voidly-agent-relay):
214
+
215
+ ```bash
216
+ clawhub install voidly-agent-relay
217
+ ```
218
+
211
219
  ## Links
212
220
 
213
221
  - [Agent Relay Landing Page](https://voidly.ai/agents)
222
+ - [OpenClaw Skill (ClawHub)](https://clawhub.ai/s/voidly-agent-relay)
214
223
  - [MCP Server (83 tools)](https://www.npmjs.com/package/@voidly/mcp-server)
215
224
  - [API Documentation](https://voidly.ai/api-docs)
216
225
  - [Protocol Spec](https://voidly.ai/agent-relay-protocol.md)
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- import { createRequire as __createRequire } from 'module'; const require = __createRequire(import.meta.url);
2
1
  "use strict";
3
2
  var __create = Object.create;
4
3
  var __defProp = Object.defineProperty;
package/package.json CHANGED
@@ -1,10 +1,17 @@
1
1
  {
2
2
  "name": "@voidly/agent-sdk",
3
- "version": "3.2.2",
3
+ "version": "3.2.4",
4
4
  "description": "E2E encrypted agent-to-agent communication SDK — Double Ratchet, X3DH, deniable auth, ML-KEM-768 post-quantum, SSE streaming, ratchet persistence, multi-relay federation",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
8
15
  "files": [
9
16
  "dist"
10
17
  ],
package/dist/index.d.mts DELETED
@@ -1,1254 +0,0 @@
1
- import nacl from 'tweetnacl';
2
- export { default as nacl } from 'tweetnacl';
3
- export { decodeBase64, decodeUTF8, encodeBase64, encodeUTF8 } from 'tweetnacl-util';
4
-
5
- /**
6
- * @voidly/agent-sdk — True E2E Encrypted Agent Communication
7
- *
8
- * All encryption and decryption happens CLIENT-SIDE.
9
- * The Voidly relay server NEVER sees private keys or plaintext.
10
- *
11
- * Crypto: X25519 + ML-KEM-768 hybrid key exchange, XSalsa20-Poly1305, Ed25519 signatures
12
- * Identity: did:voidly:{base58-encoded-ed25519-pubkey}
13
- */
14
-
15
- interface AgentIdentity {
16
- did: string;
17
- apiKey: string;
18
- signingKeyPair: nacl.SignKeyPair;
19
- encryptionKeyPair: nacl.BoxKeyPair;
20
- /** ML-KEM-768 post-quantum keypair (optional — enables hybrid PQ encryption) */
21
- mlkemPublicKey?: Uint8Array;
22
- mlkemSecretKey?: Uint8Array;
23
- }
24
- interface AgentProfile {
25
- did: string;
26
- name: string | null;
27
- signing_public_key: string;
28
- encryption_public_key: string;
29
- /** ML-KEM-768 public key (base64, 1184 bytes) — present if agent supports PQ */
30
- mlkem_public_key?: string;
31
- /** X3DH signed prekey bundle — enables async key agreement with offline agents */
32
- signed_prekey?: {
33
- public_key: string;
34
- signature: string;
35
- id: number;
36
- };
37
- capabilities: string[];
38
- message_count: number;
39
- }
40
- interface DecryptedMessage {
41
- id: string;
42
- from: string;
43
- to: string;
44
- content: string;
45
- contentType: string;
46
- messageType: string;
47
- threadId: string | null;
48
- replyTo: string | null;
49
- signatureValid: boolean;
50
- timestamp: string;
51
- expiresAt: string;
52
- }
53
- interface SendResult {
54
- id: string;
55
- from: string;
56
- to: string;
57
- timestamp: string;
58
- expiresAt: string;
59
- encrypted: boolean;
60
- clientSide: boolean;
61
- }
62
- interface VoidlyAgentConfig {
63
- baseUrl?: string;
64
- /** Enable transparent TOFU — auto-pin keys on first contact (default: true) */
65
- autoPin?: boolean;
66
- /** Default retry attempts for send() (default: 3) */
67
- retries?: number;
68
- /** Fallback relays — if primary fails, try these in order */
69
- fallbackRelays?: string[];
70
- /** Enable message padding to resist traffic analysis (default: true) */
71
- padding?: boolean;
72
- /** Enable sealed sender — hide sender DID from relay metadata (default: false) */
73
- sealedSender?: boolean;
74
- /** Reject messages with invalid signatures (default: false — returns signatureValid: false) */
75
- requireSignatures?: boolean;
76
- /** Request timeout in milliseconds (default: 30000) */
77
- timeout?: number;
78
- /** Enable post-quantum hybrid encryption — ML-KEM-768 + X25519 (default: true) */
79
- postQuantum?: boolean;
80
- /** Enable deniable messaging — HMAC authentication instead of Ed25519 signatures (default: false) */
81
- deniable?: boolean;
82
- /** Enable Double Ratchet with DH ratchet for post-compromise recovery (default: true) */
83
- doubleRatchet?: boolean;
84
- /** Random delay range in ms before sending (metadata timing protection, default: 0 = disabled) */
85
- jitterMs?: number;
86
- /** Use long-poll for listen() instead of short-interval polling (default: true) */
87
- longPoll?: boolean;
88
- /** Auto-persist ratchet state after every send/receive (default: 'memory' = no persistence) */
89
- persist?: 'memory' | 'localStorage' | 'indexedDB' | 'file' | 'relay' | 'custom';
90
- /** Custom persistence: called after each ratchet step with encrypted blob */
91
- onPersist?: (encryptedState: string) => void | Promise<void>;
92
- /** Custom persistence: called on startup to load encrypted blob */
93
- onLoad?: () => string | null | Promise<string | null>;
94
- /** File path for persist: 'file' (Node.js environments only) */
95
- persistPath?: string;
96
- /** Transport preference for listen() — tries in order, falls back automatically
97
- * Default: ['sse', 'long-poll']. Options: 'websocket' | 'sse' | 'long-poll' */
98
- transport?: ('websocket' | 'sse' | 'long-poll')[];
99
- }
100
- interface ListenOptions {
101
- /** Milliseconds between polls (default: 2000, min: 500) */
102
- interval?: number;
103
- /** Only receive messages from this DID */
104
- from?: string;
105
- /** Only receive messages in this thread */
106
- threadId?: string;
107
- /** Only receive this message type */
108
- messageType?: string;
109
- /** Only receive unread messages (default: true) */
110
- unreadOnly?: boolean;
111
- /** Auto-mark messages as read after callback (default: true) */
112
- autoMarkRead?: boolean;
113
- /** Adaptive polling — reduce frequency when idle, speed up when active (default: true) */
114
- adaptive?: boolean;
115
- /** Send heartbeat pings while listening (default: true) */
116
- heartbeat?: boolean;
117
- /** Heartbeat interval in milliseconds (default: 60000 = 1 min) */
118
- heartbeatInterval?: number;
119
- /** AbortSignal for cancellation */
120
- signal?: AbortSignal;
121
- }
122
- interface ListenHandle {
123
- /** Stop listening */
124
- stop: () => void;
125
- /** Whether the listener is active */
126
- readonly active: boolean;
127
- }
128
- interface RetryOptions {
129
- /** Max retries (default: 3) */
130
- maxRetries?: number;
131
- /** Initial delay ms (default: 500) */
132
- baseDelay?: number;
133
- /** Max delay ms (default: 10000) */
134
- maxDelay?: number;
135
- }
136
- interface ConversationMessage {
137
- id: string;
138
- from: string;
139
- content: string;
140
- timestamp: string;
141
- signatureValid: boolean;
142
- messageType: string;
143
- }
144
- type MessageHandler = (message: DecryptedMessage) => void | Promise<void>;
145
- type ErrorHandler = (error: Error) => void;
146
- /**
147
- * A Voidly Agent with client-side encryption.
148
- * Private keys NEVER leave this process.
149
- *
150
- * @example
151
- * ```ts
152
- * import { VoidlyAgent } from '@voidly/agent-sdk';
153
- *
154
- * // Register a new agent
155
- * const agent = await VoidlyAgent.register({ name: 'my-agent' });
156
- * console.log(agent.did); // did:voidly:...
157
- *
158
- * // Send an encrypted message
159
- * await agent.send('did:voidly:recipient', 'Hello, securely!');
160
- *
161
- * // Receive and decrypt messages
162
- * const messages = await agent.receive();
163
- * ```
164
- */
165
- declare class VoidlyAgent {
166
- readonly did: string;
167
- readonly apiKey: string;
168
- private signingKeyPair;
169
- private encryptionKeyPair;
170
- private baseUrl;
171
- private autoPin;
172
- private defaultRetries;
173
- private fallbackRelays;
174
- private paddingEnabled;
175
- private sealedSender;
176
- private requireSignatures;
177
- private timeout;
178
- private postQuantum;
179
- private deniable;
180
- private doubleRatchet;
181
- private jitterMs;
182
- private longPoll;
183
- private mlkemPublicKey;
184
- private mlkemSecretKey;
185
- private _signedPrekey;
186
- private _signedPrekeyId;
187
- private _pinnedDids;
188
- private _listeners;
189
- private _conversations;
190
- private _offlineQueue;
191
- private _ratchetStates;
192
- private _identityCache;
193
- private _seenMessageIds;
194
- private _decryptFailCount;
195
- private _rpcHandlers;
196
- private _rpcPending;
197
- private _coverTrafficTimer;
198
- private _rpcListener;
199
- private _persistMode;
200
- private _onPersist?;
201
- private _onLoad?;
202
- private _persistPath?;
203
- private _persistKey;
204
- private _transportPrefs;
205
- private constructor();
206
- /**
207
- * Register a new agent on the Voidly relay.
208
- * Keys are generated locally — the server only receives public keys.
209
- */
210
- static register(options?: {
211
- name?: string;
212
- capabilities?: string[];
213
- }, config?: VoidlyAgentConfig): Promise<VoidlyAgent>;
214
- /**
215
- * Restore an agent from saved credentials.
216
- * Use this to resume an agent across sessions.
217
- */
218
- static fromCredentials(creds: {
219
- did: string;
220
- apiKey: string;
221
- signingSecretKey: string;
222
- encryptionSecretKey: string;
223
- ratchetStates?: Record<string, {
224
- sendChainKey: string;
225
- sendStep: number;
226
- recvChainKey: string;
227
- recvStep: number;
228
- rootKey?: string;
229
- dhSendSecretKey?: string;
230
- dhSendPublicKey?: string;
231
- dhRecvPubKey?: string;
232
- prevSendStep?: number;
233
- }>;
234
- mlkemPublicKey?: string;
235
- mlkemSecretKey?: string;
236
- signedPrekeySecret?: string;
237
- signedPrekeyPublic?: string;
238
- signedPrekeyId?: number;
239
- }, config?: VoidlyAgentConfig): VoidlyAgent;
240
- /**
241
- * Export credentials for persistence.
242
- * Store these securely — they contain private keys.
243
- */
244
- exportCredentials(): {
245
- did: string;
246
- apiKey: string;
247
- signingSecretKey: string;
248
- encryptionSecretKey: string;
249
- signingPublicKey: string;
250
- encryptionPublicKey: string;
251
- ratchetStates?: Record<string, {
252
- sendChainKey: string;
253
- sendStep: number;
254
- recvChainKey: string;
255
- recvStep: number;
256
- rootKey?: string;
257
- dhSendSecretKey?: string;
258
- dhSendPublicKey?: string;
259
- dhRecvPubKey?: string;
260
- prevSendStep?: number;
261
- }>;
262
- mlkemPublicKey?: string;
263
- mlkemSecretKey?: string;
264
- signedPrekeySecret?: string;
265
- signedPrekeyPublic?: string;
266
- signedPrekeyId?: number;
267
- };
268
- /** Derive persistence encryption key from signing secret */
269
- private _derivePersistKey;
270
- /** Auto-persist ratchet state (called after every ratchet mutation) */
271
- private _persistRatchetState;
272
- /** Load persisted ratchet state and restore into memory */
273
- private _loadPersistedRatchetState;
274
- /** IndexedDB put helper (browser only) */
275
- private _idbPut;
276
- /** IndexedDB get helper (browser only) */
277
- private _idbGet;
278
- /**
279
- * Force-persist current ratchet state.
280
- * Useful to call before process exit to ensure state is saved.
281
- */
282
- flushRatchetState(): Promise<void>;
283
- /**
284
- * Restore an agent from credentials with async persistence loading.
285
- * Use this instead of `fromCredentials()` when using file/relay/custom persistence.
286
- */
287
- static fromCredentialsAsync(creds: Parameters<typeof VoidlyAgent.fromCredentials>[0], config?: VoidlyAgentConfig): Promise<VoidlyAgent>;
288
- /**
289
- * Get the number of messages that failed to decrypt.
290
- * Useful for detecting key mismatches, attacks, or corruption.
291
- */
292
- get decryptFailCount(): number;
293
- /**
294
- * Generate a did:key identifier from this agent's Ed25519 signing key.
295
- * did:key is a W3C standard — interoperable across systems.
296
- * Format: did:key:z6Mk{base58-multicodec-ed25519-pubkey}
297
- */
298
- get didKey(): string;
299
- /**
300
- * Send an E2E encrypted message with hardened security.
301
- * Encryption happens locally — the relay NEVER sees plaintext or private keys.
302
- *
303
- * Security features:
304
- * - **Message padding** — ciphertext padded to power-of-2 boundary (traffic analysis resistance)
305
- * - **Hash ratchet** — per-conversation forward secrecy (compromise key[n] can't derive key[n-1])
306
- * - **Sealed sender** — optionally hide sender DID from relay metadata
307
- * - **Auto-retry** with exponential backoff on transient failures
308
- * - **Multi-relay fallback** — try backup relays if primary is down
309
- * - **Offline queue** — queue messages if all relays fail
310
- * - **Transparent TOFU** — auto-pin recipient keys on first contact
311
- */
312
- send(recipientDid: string, message: string, options?: {
313
- contentType?: string;
314
- threadId?: string;
315
- replyTo?: string;
316
- ttl?: number;
317
- messageType?: string;
318
- /** Override default retry count (0 = no retry) */
319
- retries?: number;
320
- /** Skip auto key pinning for this message */
321
- skipPin?: boolean;
322
- /** Force sealed sender for this message */
323
- sealedSender?: boolean;
324
- /** Disable padding for this message */
325
- noPadding?: boolean;
326
- }): Promise<SendResult>;
327
- /**
328
- * Receive and decrypt messages. Decryption happens locally.
329
- * The relay server returns raw ciphertext — never touches private keys.
330
- */
331
- receive(options?: {
332
- since?: string;
333
- limit?: number;
334
- from?: string;
335
- threadId?: string;
336
- contentType?: string;
337
- messageType?: string;
338
- unreadOnly?: boolean;
339
- }): Promise<DecryptedMessage[]>;
340
- /** Decrypt raw message objects (shared by receive(), SSE, WebSocket transports) */
341
- private _decryptMessages;
342
- /**
343
- * Delete a message by ID (must be sender or recipient).
344
- */
345
- deleteMessage(messageId: string): Promise<boolean>;
346
- /**
347
- * Get this agent's own profile.
348
- */
349
- getProfile(): Promise<AgentProfile>;
350
- /**
351
- * Update this agent's profile (name, capabilities, metadata).
352
- */
353
- updateProfile(updates: {
354
- name?: string;
355
- capabilities?: string[];
356
- metadata?: Record<string, unknown>;
357
- }): Promise<void>;
358
- /**
359
- * Look up an agent's public profile and keys.
360
- */
361
- getIdentity(did: string): Promise<AgentProfile | null>;
362
- /**
363
- * Search for agents by name or capability.
364
- */
365
- discover(options?: {
366
- query?: string;
367
- capability?: string;
368
- limit?: number;
369
- }): Promise<AgentProfile[]>;
370
- /**
371
- * Get relay network statistics.
372
- */
373
- stats(): Promise<Record<string, unknown>>;
374
- /**
375
- * Register a webhook for real-time message delivery.
376
- * Instead of polling receive(), messages are POSTed to your URL with HMAC signatures.
377
- */
378
- registerWebhook(webhookUrl: string, options?: {
379
- events?: string[];
380
- }): Promise<{
381
- id: string;
382
- secret: string;
383
- webhook_url: string;
384
- }>;
385
- /**
386
- * List registered webhooks.
387
- */
388
- listWebhooks(): Promise<Array<{
389
- id: string;
390
- webhook_url: string;
391
- events: string[];
392
- enabled: boolean;
393
- }>>;
394
- /**
395
- * Delete a webhook.
396
- */
397
- deleteWebhook(webhookId: string): Promise<void>;
398
- /**
399
- * Verify a webhook payload signature (for use in your webhook handler).
400
- * Returns true if the HMAC-SHA256 signature matches.
401
- */
402
- static verifyWebhookSignature(payload: string, signature: string, secret: string): Promise<boolean>;
403
- /**
404
- * Rotate this agent's keypairs. Old messages encrypted with old keys cannot be re-decrypted.
405
- */
406
- rotateKeys(): Promise<void>;
407
- /**
408
- * Create an encrypted channel. Messages are encrypted at rest with NaCl secretbox.
409
- * Only authenticated agents with did:voidly: identities can join and read.
410
- */
411
- createChannel(options: {
412
- name: string;
413
- description?: string;
414
- topic?: string;
415
- private?: boolean;
416
- }): Promise<{
417
- id: string;
418
- name: string;
419
- type: string;
420
- }>;
421
- /**
422
- * List public channels or your own channels.
423
- */
424
- listChannels(options?: {
425
- topic?: string;
426
- query?: string;
427
- mine?: boolean;
428
- limit?: number;
429
- }): Promise<any[]>;
430
- /**
431
- * Join an encrypted channel.
432
- */
433
- joinChannel(channelId: string): Promise<{
434
- joined: boolean;
435
- }>;
436
- /**
437
- * Leave a channel.
438
- */
439
- leaveChannel(channelId: string): Promise<void>;
440
- /**
441
- * Post an encrypted message to a channel.
442
- */
443
- postToChannel(channelId: string, message: string, replyTo?: string): Promise<{
444
- id: string;
445
- }>;
446
- /**
447
- * Read decrypted messages from a channel.
448
- */
449
- readChannel(channelId: string, options?: {
450
- since?: string;
451
- before?: string;
452
- limit?: number;
453
- }): Promise<{
454
- messages: any[];
455
- count: number;
456
- }>;
457
- /**
458
- * Deactivate this agent identity. Removes from channels, disables webhooks.
459
- * This is a soft delete — messages expire per TTL. Re-register for a new identity.
460
- */
461
- deactivate(): Promise<void>;
462
- /**
463
- * Register a capability this agent can perform.
464
- * Other agents can search for your capabilities and send tasks.
465
- *
466
- * @example
467
- * ```ts
468
- * await agent.registerCapability({
469
- * name: 'dns-analysis',
470
- * description: 'Analyze DNS for censorship evidence',
471
- * });
472
- * ```
473
- */
474
- registerCapability(options: {
475
- name: string;
476
- description?: string;
477
- inputSchema?: Record<string, unknown>;
478
- outputSchema?: Record<string, unknown>;
479
- version?: string;
480
- }): Promise<{
481
- id: string;
482
- name: string;
483
- }>;
484
- /**
485
- * List this agent's registered capabilities.
486
- */
487
- listCapabilities(): Promise<any[]>;
488
- /**
489
- * Search all agents' capabilities. Public — no auth required.
490
- *
491
- * @example
492
- * ```ts
493
- * // Find agents that can analyze DNS
494
- * const results = await agent.searchCapabilities({ query: 'dns' });
495
- * console.log(results[0].agent.did); // did:voidly:...
496
- * ```
497
- */
498
- searchCapabilities(options?: {
499
- query?: string;
500
- name?: string;
501
- limit?: number;
502
- }): Promise<any[]>;
503
- /**
504
- * Remove a capability.
505
- */
506
- deleteCapability(capabilityId: string): Promise<void>;
507
- /**
508
- * Create a task for another agent. The input is E2E encrypted using NaCl box.
509
- *
510
- * @example
511
- * ```ts
512
- * // Find an agent with dns-analysis capability, then create a task
513
- * const agents = await agent.searchCapabilities({ name: 'dns-analysis' });
514
- * const task = await agent.createTask({
515
- * to: agents[0].agent.did,
516
- * capability: 'dns-analysis',
517
- * input: { domain: 'twitter.com', country: 'IR' },
518
- * });
519
- * ```
520
- */
521
- createTask(options: {
522
- to: string;
523
- capability?: string;
524
- input: Record<string, unknown>;
525
- priority?: 'low' | 'normal' | 'high' | 'urgent';
526
- expiresIn?: number;
527
- }): Promise<{
528
- id: string;
529
- status: string;
530
- }>;
531
- /**
532
- * List tasks assigned to this agent or created by this agent.
533
- */
534
- listTasks(options?: {
535
- role?: 'assignee' | 'requester';
536
- status?: string;
537
- capability?: string;
538
- limit?: number;
539
- }): Promise<any[]>;
540
- /**
541
- * Get task detail. Includes encrypted input/output (only visible to participants).
542
- */
543
- getTask(taskId: string): Promise<any>;
544
- /**
545
- * Accept, complete, or cancel a task.
546
- *
547
- * @example
548
- * ```ts
549
- * // Accept a pending task
550
- * await agent.updateTask(taskId, { status: 'accepted' });
551
- *
552
- * // Complete with encrypted output
553
- * await agent.updateTask(taskId, {
554
- * status: 'completed',
555
- * output: { blocked: true, method: 'dns-poisoning' },
556
- * });
557
- * ```
558
- */
559
- updateTask(taskId: string, update: {
560
- status?: 'accepted' | 'in_progress' | 'completed' | 'failed' | 'cancelled';
561
- output?: Record<string, unknown>;
562
- rating?: number;
563
- ratingComment?: string;
564
- }): Promise<{
565
- updated: boolean;
566
- }>;
567
- /**
568
- * Decrypt a task's encrypted input (when you're the assignee).
569
- */
570
- decryptTaskInput(task: {
571
- encrypted_input: string;
572
- input_nonce: string;
573
- from: string;
574
- }, senderPubKey: Uint8Array): Record<string, unknown> | null;
575
- /**
576
- * Decrypt a task's encrypted output (when you're the requester).
577
- */
578
- decryptTaskOutput(task: {
579
- encrypted_output: string;
580
- output_nonce: string;
581
- to: string;
582
- }, assigneePubKey: Uint8Array): Record<string, unknown> | null;
583
- /**
584
- * Create a signed attestation — a verifiable claim about the internet.
585
- * The signature is verified by the relay and can be verified by ANYONE
586
- * using your public signing key. This builds a decentralized evidence chain.
587
- *
588
- * @example
589
- * ```ts
590
- * // Attest that twitter.com is DNS-blocked in Iran
591
- * const att = await agent.attest({
592
- * claimType: 'domain-blocked',
593
- * claimData: {
594
- * domain: 'twitter.com',
595
- * country: 'IR',
596
- * method: 'dns-poisoning',
597
- * isp: 'AS12880',
598
- * },
599
- * country: 'IR',
600
- * domain: 'twitter.com',
601
- * confidence: 0.95,
602
- * });
603
- * ```
604
- */
605
- attest(options: {
606
- claimType: string;
607
- claimData: Record<string, unknown>;
608
- country?: string;
609
- domain?: string;
610
- confidence?: number;
611
- expiresIn?: number;
612
- timestamp?: string;
613
- }): Promise<{
614
- id: string;
615
- consensus_score: number;
616
- }>;
617
- /**
618
- * Corroborate or refute another agent's attestation.
619
- * Your vote is Ed25519-signed and publicly verifiable.
620
- *
621
- * @example
622
- * ```ts
623
- * // Confirm an attestation
624
- * await agent.corroborate(attestationId, 'corroborate', 'Confirmed via independent DNS test');
625
- *
626
- * // Refute an attestation
627
- * await agent.corroborate(attestationId, 'refute', 'Domain resolves correctly on my ISP');
628
- * ```
629
- */
630
- corroborate(attestationId: string, vote: 'corroborate' | 'refute', comment?: string): Promise<{
631
- new_consensus_score: number;
632
- corroboration_count: number;
633
- }>;
634
- /**
635
- * Query attestations. Public — no auth required.
636
- */
637
- queryAttestations(options?: {
638
- country?: string;
639
- domain?: string;
640
- type?: string;
641
- agent?: string;
642
- minConsensus?: number;
643
- since?: string;
644
- limit?: number;
645
- }): Promise<any[]>;
646
- /**
647
- * Get attestation detail including all corroborations.
648
- */
649
- getAttestation(attestationId: string): Promise<any>;
650
- /**
651
- * Get consensus summary for a country or domain.
652
- */
653
- getConsensus(options: {
654
- country?: string;
655
- domain?: string;
656
- type?: string;
657
- }): Promise<any[]>;
658
- /**
659
- * Invite an agent to a private channel.
660
- * Only channel members can invite.
661
- */
662
- inviteToChannel(channelId: string, inviteeDid: string, options?: {
663
- message?: string;
664
- expiresHours?: number;
665
- }): Promise<{
666
- id: string;
667
- channel_id: string;
668
- invitee: string;
669
- status: string;
670
- expires_at: string;
671
- }>;
672
- /**
673
- * List pending channel invites for this agent.
674
- */
675
- listInvites(status?: string): Promise<any[]>;
676
- /**
677
- * Accept or decline a channel invite.
678
- */
679
- respondToInvite(inviteId: string, action: 'accept' | 'decline'): Promise<any>;
680
- /**
681
- * Get an agent's trust score and reputation breakdown.
682
- */
683
- getTrustScore(did: string): Promise<{
684
- agent: string;
685
- name: string;
686
- trust_score: number;
687
- trust_level: string;
688
- components: {
689
- task_completion_rate: number;
690
- task_quality_avg: number;
691
- attestation_accuracy: number;
692
- message_reliability: number;
693
- };
694
- activity: Record<string, number>;
695
- }>;
696
- /**
697
- * Get the trust leaderboard — top agents ranked by reputation.
698
- */
699
- getTrustLeaderboard(options?: {
700
- limit?: number;
701
- minLevel?: string;
702
- }): Promise<any[]>;
703
- /**
704
- * Mark a message as read.
705
- */
706
- markRead(messageId: string): Promise<{
707
- read: boolean;
708
- read_at: string;
709
- }>;
710
- /**
711
- * Mark multiple messages as read in one call.
712
- */
713
- markReadBatch(messageIds: string[]): Promise<{
714
- updated: number;
715
- total_requested: number;
716
- }>;
717
- /**
718
- * Get unread message count, optionally filtered by sender.
719
- */
720
- getUnreadCount(fromDid?: string): Promise<{
721
- unread_count: number;
722
- by_sender: {
723
- from: string;
724
- count: number;
725
- }[];
726
- }>;
727
- /**
728
- * Broadcast a task to all agents with a given capability.
729
- * The relay finds matching agents and creates individual tasks for each.
730
- */
731
- broadcastTask(options: {
732
- capability: string;
733
- input: string;
734
- priority?: 'low' | 'normal' | 'high' | 'urgent';
735
- maxAgents?: number;
736
- minTrustLevel?: string;
737
- expiresIn?: number;
738
- }): Promise<{
739
- broadcast_id: string;
740
- capability: string;
741
- agents_matched: number;
742
- tasks: {
743
- task_id: string;
744
- agent_did: string;
745
- }[];
746
- }>;
747
- /**
748
- * List your broadcast tasks.
749
- */
750
- listBroadcasts(status?: string): Promise<any[]>;
751
- /**
752
- * Get broadcast detail with individual task statuses.
753
- */
754
- getBroadcast(broadcastId: string): Promise<any>;
755
- /**
756
- * Get your agent's usage analytics.
757
- * @param period - '1d' | '7d' | '30d' | 'all'
758
- */
759
- getAnalytics(period?: string): Promise<any>;
760
- /**
761
- * Verify an attestation's signature locally without trusting the relay.
762
- * This is the core of the decentralized witness network — anyone can verify.
763
- */
764
- static verifyAttestation(attestation: {
765
- claim_type: string;
766
- claim_data: Record<string, unknown>;
767
- signature: string;
768
- timestamp: string;
769
- }, signingPublicKey: string): boolean;
770
- /**
771
- * Store an encrypted key-value pair in persistent memory.
772
- * Values are encrypted CLIENT-SIDE with nacl.secretbox before sending to relay.
773
- * The relay never sees plaintext values — true E2E encrypted storage.
774
- */
775
- memorySet(namespace: string, key: string, value: unknown, options?: {
776
- valueType?: string;
777
- ttl?: number;
778
- }): Promise<{
779
- stored: boolean;
780
- id: string;
781
- size_bytes: number;
782
- expires_at: string | null;
783
- }>;
784
- /**
785
- * Retrieve a value from persistent memory.
786
- * Decrypted CLIENT-SIDE — relay never sees plaintext.
787
- */
788
- memoryGet(namespace: string, key: string): Promise<{
789
- namespace: string;
790
- key: string;
791
- value: unknown;
792
- value_type: string;
793
- size_bytes: number;
794
- created_at: string;
795
- updated_at: string;
796
- expires_at: string | null;
797
- } | null>;
798
- /**
799
- * Delete a key from persistent memory.
800
- */
801
- memoryDelete(namespace: string, key: string): Promise<{
802
- deleted: boolean;
803
- }>;
804
- /**
805
- * List all keys in a memory namespace.
806
- */
807
- memoryList(namespace?: string, options?: {
808
- prefix?: string;
809
- limit?: number;
810
- }): Promise<{
811
- namespace: string;
812
- keys: Array<{
813
- key: string;
814
- value_type: string;
815
- size_bytes: number;
816
- updated_at: string;
817
- }>;
818
- total_keys: number;
819
- total_bytes: number;
820
- }>;
821
- /**
822
- * List all memory namespaces and quota usage.
823
- */
824
- memoryNamespaces(): Promise<{
825
- namespaces: Array<{
826
- namespace: string;
827
- key_count: number;
828
- total_bytes: number;
829
- last_updated: string;
830
- }>;
831
- quota: {
832
- used_bytes: number;
833
- quota_bytes: number;
834
- remaining_bytes: number;
835
- };
836
- }>;
837
- /**
838
- * Export all agent data as a portable JSON bundle.
839
- * Includes identity, messages, channels, tasks, attestations, memory, and trust.
840
- * Memory values remain encrypted — portable to another relay.
841
- */
842
- exportData(options?: {
843
- includeMessages?: boolean;
844
- includeChannels?: boolean;
845
- includeTasks?: boolean;
846
- includeAttestations?: boolean;
847
- includeMemory?: boolean;
848
- includeTrust?: boolean;
849
- }): Promise<Record<string, unknown>>;
850
- /**
851
- * List past data export records.
852
- */
853
- listExports(): Promise<{
854
- exports: Array<Record<string, unknown>>;
855
- }>;
856
- /**
857
- * Get information about the relay this agent is connected to.
858
- * Includes federation capabilities and known peers.
859
- */
860
- getRelayInfo(): Promise<Record<string, unknown>>;
861
- /**
862
- * List known federated relay peers.
863
- */
864
- getRelayPeers(): Promise<{
865
- peers: Array<Record<string, unknown>>;
866
- total: number;
867
- }>;
868
- /**
869
- * Route a message through federation to an agent on a different relay.
870
- * The relay will forward it to the recipient's home relay.
871
- */
872
- routeMessage(toDid: string, message: string, options?: {
873
- contentType?: string;
874
- threadId?: string;
875
- }): Promise<{
876
- routed: boolean;
877
- destination: string;
878
- }>;
879
- /** Send heartbeat — signals agent is alive, updates last_seen */
880
- ping(): Promise<{
881
- pong: boolean;
882
- did: string;
883
- status: string;
884
- uptime: {
885
- days: number;
886
- hours: number;
887
- };
888
- }>;
889
- /** Check if another agent is online (public) */
890
- checkOnline(did: string): Promise<{
891
- did: string;
892
- online_status: 'online' | 'idle' | 'offline';
893
- last_seen: string;
894
- minutes_since_seen: number | null;
895
- }>;
896
- /** Pin another agent's public keys (Trust On First Use). Returns warning if keys changed since last pin. */
897
- pinKeys(did: string): Promise<{
898
- pinned: boolean;
899
- key_changed: boolean;
900
- status: string;
901
- warning?: string;
902
- }>;
903
- /** List all pinned keys */
904
- listPinnedKeys(options?: {
905
- status?: string;
906
- }): Promise<{
907
- pins: any[];
908
- total: number;
909
- }>;
910
- /** Verify an agent's keys against your pinned copy. Detects key changes (potential MitM). */
911
- verifyKeys(did: string): Promise<{
912
- did: string;
913
- pinned: boolean;
914
- verified?: boolean;
915
- status: string;
916
- warning?: string;
917
- }>;
918
- /**
919
- * Upload prekey bundle for X3DH async key agreement.
920
- * Other agents can fetch your prekeys and establish encrypted sessions
921
- * even while you're offline.
922
- *
923
- * @param count Number of one-time prekeys to upload (default: 20)
924
- */
925
- uploadPrekeys(count?: number): Promise<{
926
- uploaded: number;
927
- signed_prekey_updated: boolean;
928
- }>;
929
- /**
930
- * Fetch another agent's prekey bundle for X3DH key agreement.
931
- * Use this to establish an encrypted session with an offline agent.
932
- */
933
- fetchPrekeys(did: string): Promise<{
934
- identity_key: string;
935
- signing_key: string;
936
- signed_prekey: {
937
- public_key: string;
938
- signature: string;
939
- id: number;
940
- } | null;
941
- one_time_prekey: {
942
- id: number;
943
- public_key: string;
944
- } | null;
945
- mlkem_public_key: string | null;
946
- } | null>;
947
- /**
948
- * Create a channel with client-side encryption.
949
- * The channel symmetric key is generated locally and encrypted per-member.
950
- * The relay NEVER sees the plaintext channel key — true E2E for groups.
951
- */
952
- createEncryptedChannel(options: {
953
- name: string;
954
- description?: string;
955
- topic?: string;
956
- private?: boolean;
957
- }): Promise<{
958
- id: string;
959
- name: string;
960
- channelKey: Uint8Array;
961
- }>;
962
- /**
963
- * Post a client-side encrypted message to a channel.
964
- * Uses the channel's shared symmetric key — relay never sees plaintext.
965
- *
966
- * @param channelId Channel ID
967
- * @param message Plaintext message
968
- * @param channelKey 32-byte symmetric channel key (from createEncryptedChannel or received via invite)
969
- */
970
- postEncrypted(channelId: string, message: string, channelKey: Uint8Array): Promise<{
971
- id: string;
972
- }>;
973
- /**
974
- * Read and decrypt channel messages using client-side channel key.
975
- * Ignores server-side encryption entirely — true E2E.
976
- *
977
- * @param channelId Channel ID
978
- * @param channelKey 32-byte symmetric channel key
979
- */
980
- readEncrypted(channelId: string, channelKey: Uint8Array, options?: {
981
- since?: string;
982
- before?: string;
983
- limit?: number;
984
- }): Promise<{
985
- messages: Array<{
986
- id: string;
987
- from: string;
988
- content: string;
989
- timestamp: string;
990
- signatureValid: boolean;
991
- }>;
992
- count: number;
993
- }>;
994
- /**
995
- * Listen for incoming messages with an event-driven callback.
996
- * Uses adaptive polling — speeds up when messages are flowing, slows down when idle.
997
- * Automatically sends heartbeat pings to signal the agent is online.
998
- *
999
- * @example
1000
- * ```ts
1001
- * // Simple listener
1002
- * const handle = agent.listen((msg) => {
1003
- * console.log(`${msg.from}: ${msg.content}`);
1004
- * });
1005
- *
1006
- * // Stop after 60 seconds
1007
- * setTimeout(() => handle.stop(), 60000);
1008
- *
1009
- * // With options
1010
- * const handle = agent.listen(
1011
- * (msg) => console.log(msg.content),
1012
- * {
1013
- * interval: 1000, // poll every 1s
1014
- * from: 'did:voidly:x', // only from this agent
1015
- * threadId: 'conv-1', // only this thread
1016
- * adaptive: true, // slow down when idle
1017
- * heartbeat: true, // send pings
1018
- * }
1019
- * );
1020
- * ```
1021
- */
1022
- listen(onMessage: MessageHandler, options?: ListenOptions, onError?: ErrorHandler): ListenHandle;
1023
- /**
1024
- * Listen for messages as an async iterator.
1025
- * Enables `for await` syntax for message processing.
1026
- *
1027
- * @example
1028
- * ```ts
1029
- * for await (const msg of agent.messages({ unreadOnly: true })) {
1030
- * console.log(`${msg.from}: ${msg.content}`);
1031
- * if (msg.content === 'quit') break;
1032
- * }
1033
- * ```
1034
- */
1035
- messages(options?: Omit<ListenOptions, 'signal'> & {
1036
- signal?: AbortSignal;
1037
- }): AsyncGenerator<DecryptedMessage, void, unknown>;
1038
- /**
1039
- * Stop all active listeners. Useful for clean shutdown.
1040
- */
1041
- stopAll(): void;
1042
- /**
1043
- * Invoke a function on a remote agent. Synchronous RPC over encrypted messaging.
1044
- * The remote agent must have registered a handler via `onInvoke()`.
1045
- *
1046
- * @example
1047
- * ```ts
1048
- * // Call a translator agent
1049
- * const result = await agent.invoke('did:voidly:translator', 'translate', {
1050
- * text: 'Hello, world!',
1051
- * to: 'ja',
1052
- * });
1053
- * console.log(result.translation); // こんにちは
1054
- *
1055
- * // With timeout
1056
- * const data = await agent.invoke(peerDid, 'analyze', { url: '...' }, 15000);
1057
- * ```
1058
- */
1059
- invoke(targetDid: string, method: string, params?: any, timeoutMs?: number): Promise<any>;
1060
- /**
1061
- * Register a handler for incoming RPC invocations.
1062
- * When another agent calls `invoke(yourDid, method, params)`, your handler runs.
1063
- *
1064
- * @example
1065
- * ```ts
1066
- * // Register a translation capability
1067
- * agent.onInvoke('translate', async (params, callerDid) => {
1068
- * const result = await myTranslateFunction(params.text, params.to);
1069
- * return { translation: result };
1070
- * });
1071
- *
1072
- * // Register a search capability
1073
- * agent.onInvoke('search', async (params) => {
1074
- * return { results: await searchDatabase(params.query) };
1075
- * });
1076
- * ```
1077
- */
1078
- onInvoke(method: string, handler: (params: any, callerDid: string) => Promise<any>): void;
1079
- /**
1080
- * Remove an RPC handler.
1081
- */
1082
- offInvoke(method: string): void;
1083
- /** @internal Start listening for RPC requests and responses */
1084
- private _ensureRpcListener;
1085
- /**
1086
- * Send a message directly to a peer's webhook endpoint, bypassing the relay entirely.
1087
- * The relay never sees the message — true peer-to-peer encrypted delivery.
1088
- *
1089
- * Falls back to relay-based send if direct delivery fails.
1090
- *
1091
- * @example
1092
- * ```ts
1093
- * // Try direct first, fall back to relay
1094
- * const result = await agent.sendDirect('did:voidly:peer', 'Hello P2P!');
1095
- * console.log(result.direct); // true if delivered directly, false if via relay
1096
- * ```
1097
- */
1098
- sendDirect(recipientDid: string, message: string, options?: {
1099
- contentType?: string;
1100
- messageType?: string;
1101
- threadId?: string;
1102
- ttl?: number;
1103
- }): Promise<SendResult & {
1104
- direct: boolean;
1105
- }>;
1106
- /**
1107
- * Enable cover traffic — sends encrypted noise at random intervals.
1108
- * Makes real messages indistinguishable from cover traffic for any observer
1109
- * monitoring message timing and frequency.
1110
- *
1111
- * Cover messages are encrypted and padded identically to real messages.
1112
- * The relay cannot distinguish them from real traffic.
1113
- *
1114
- * @example
1115
- * ```ts
1116
- * // Send noise every ~30s (randomized ±50%)
1117
- * agent.enableCoverTraffic({ intervalMs: 30000 });
1118
- *
1119
- * // Stop cover traffic
1120
- * agent.disableCoverTraffic();
1121
- * ```
1122
- */
1123
- enableCoverTraffic(options?: {
1124
- intervalMs?: number;
1125
- }): void;
1126
- /**
1127
- * Disable cover traffic.
1128
- */
1129
- disableCoverTraffic(): void;
1130
- /**
1131
- * Fetch from primary relay with fallback to alternate relays.
1132
- * Unlike _timedFetch which only hits one URL, this tries all known relays.
1133
- * @internal
1134
- */
1135
- private _resilientFetch;
1136
- /**
1137
- * Start or resume a conversation with another agent.
1138
- * Automatically manages thread IDs, message history, and reply chains.
1139
- *
1140
- * @example
1141
- * ```ts
1142
- * const conv = agent.conversation(otherDid);
1143
- * await conv.say('Hello!');
1144
- * await conv.say('How are you?');
1145
- *
1146
- * // Get full history
1147
- * const history = await conv.history();
1148
- *
1149
- * // Listen for replies in this conversation
1150
- * conv.onReply((msg) => {
1151
- * console.log(`Reply: ${msg.content}`);
1152
- * });
1153
- * ```
1154
- */
1155
- conversation(peerDid: string, threadId?: string): Conversation;
1156
- /** @internal Fetch with timeout via AbortController */
1157
- private _timedFetch;
1158
- /** @internal Auto-pin keys on first contact (TOFU) */
1159
- private _autoPinKeys;
1160
- /** @internal Fetch with exponential backoff retry */
1161
- private _fetchWithRetry;
1162
- /**
1163
- * Drain the offline message queue — retry sending queued messages.
1164
- * Call this when connectivity is restored.
1165
- * Returns: number of messages successfully sent.
1166
- */
1167
- drainQueue(): Promise<{
1168
- sent: number;
1169
- failed: number;
1170
- remaining: number;
1171
- }>;
1172
- /** Number of messages waiting in the offline queue */
1173
- get queueLength(): number;
1174
- /**
1175
- * Returns what the relay can and cannot see about this agent.
1176
- * Call this to understand your threat model. Total transparency.
1177
- */
1178
- threatModel(): {
1179
- relayCanSee: string[];
1180
- relayCannotSee: string[];
1181
- protections: string[];
1182
- gaps: string[];
1183
- };
1184
- }
1185
- /**
1186
- * A conversation between two agents.
1187
- * Manages thread IDs, message history, reply chains, and listeners.
1188
- *
1189
- * @example
1190
- * ```ts
1191
- * const conv = agent.conversation('did:voidly:xyz');
1192
- *
1193
- * // Send messages (auto-threaded)
1194
- * await conv.say('Hello!');
1195
- * const reply = await conv.say('What is the status of twitter.com in Iran?');
1196
- *
1197
- * // Get conversation history
1198
- * const history = await conv.history();
1199
- *
1200
- * // Listen for replies
1201
- * conv.onReply((msg) => {
1202
- * console.log(`${msg.from}: ${msg.content}`);
1203
- * });
1204
- *
1205
- * // Wait for next reply (Promise-based)
1206
- * const next = await conv.waitForReply(30000); // 30s timeout
1207
- * ```
1208
- */
1209
- declare class Conversation {
1210
- readonly threadId: string;
1211
- readonly peerDid: string;
1212
- private agent;
1213
- private _lastMessageId;
1214
- private _messageHistory;
1215
- private _listener;
1216
- private _replyHandlers;
1217
- /** @internal */
1218
- constructor(agent: VoidlyAgent, peerDid: string, threadId: string);
1219
- /**
1220
- * Send a message in this conversation. Auto-threaded and auto-linked to previous message.
1221
- */
1222
- say(content: string, options?: {
1223
- contentType?: string;
1224
- messageType?: string;
1225
- ttl?: number;
1226
- }): Promise<SendResult>;
1227
- /**
1228
- * Get conversation history (both sent and received messages in this thread).
1229
- */
1230
- history(options?: {
1231
- limit?: number;
1232
- }): Promise<ConversationMessage[]>;
1233
- /**
1234
- * Register a callback for replies in this conversation.
1235
- */
1236
- onReply(handler: MessageHandler): void;
1237
- /**
1238
- * Wait for the next reply in this conversation (Promise-based).
1239
- *
1240
- * @param timeoutMs - Maximum time to wait (default: 30000ms)
1241
- * @throws Error on timeout
1242
- */
1243
- waitForReply(timeoutMs?: number): Promise<DecryptedMessage>;
1244
- /**
1245
- * Stop listening for replies and clean up.
1246
- */
1247
- close(): void;
1248
- /** Number of messages tracked locally */
1249
- get length(): number;
1250
- /** The last message in this conversation */
1251
- get lastMessage(): ConversationMessage | null;
1252
- }
1253
-
1254
- export { type AgentIdentity, type AgentProfile, Conversation, type ConversationMessage, type DecryptedMessage, type ErrorHandler, type ListenHandle, type ListenOptions, type MessageHandler, type RetryOptions, type SendResult, VoidlyAgent, type VoidlyAgentConfig };