@voidly/agent-sdk 3.2.3 → 3.2.5
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 +12 -6
- package/dist/index.js +0 -1
- package/examples/censorship-monitor.mjs +69 -0
- package/examples/conversation.mjs +45 -0
- package/examples/encrypted-channel.mjs +39 -0
- package/examples/quickstart.mjs +30 -0
- package/examples/rpc.mjs +42 -0
- package/package.json +18 -3
- package/dist/index.d.mts +0 -1254
package/README.md
CHANGED
|
@@ -191,13 +191,19 @@ const agent = await VoidlyAgent.register({
|
|
|
191
191
|
|
|
192
192
|
## Examples
|
|
193
193
|
|
|
194
|
-
|
|
194
|
+
```bash
|
|
195
|
+
node examples/quickstart.mjs
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
| Example | What it shows |
|
|
199
|
+
|---------|---------------|
|
|
200
|
+
| [quickstart.mjs](examples/quickstart.mjs) | Register, send, receive in 15 lines |
|
|
201
|
+
| [encrypted-channel.mjs](examples/encrypted-channel.mjs) | Group messaging with client-side encryption |
|
|
202
|
+
| [rpc.mjs](examples/rpc.mjs) | Remote procedure calls between agents |
|
|
203
|
+
| [conversation.mjs](examples/conversation.mjs) | Threaded dialog with waitForReply |
|
|
204
|
+
| [censorship-monitor.mjs](examples/censorship-monitor.mjs) | Real-world: censorship data + encrypted alerts |
|
|
195
205
|
|
|
196
|
-
-
|
|
197
|
-
- **encrypted-channel.mjs** — Group messaging with client-side encryption
|
|
198
|
-
- **rpc.mjs** — Remote procedure calls between agents
|
|
199
|
-
- **conversation.mjs** — Threaded dialog with waitForReply
|
|
200
|
-
- **censorship-monitor.mjs** — Combine censorship data + agent messaging
|
|
206
|
+
All examples are self-contained and run against the public relay. No API key needed.
|
|
201
207
|
|
|
202
208
|
## Protocol
|
|
203
209
|
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Censorship Monitor — Real-world use case combining Voidly data + agent messaging.
|
|
4
|
+
*
|
|
5
|
+
* Run: node examples/censorship-monitor.mjs
|
|
6
|
+
*
|
|
7
|
+
* Fetches live censorship data from the Voidly API, checks for high block
|
|
8
|
+
* rates, and sends an encrypted alert to a subscriber agent.
|
|
9
|
+
*/
|
|
10
|
+
import { VoidlyAgent } from '@voidly/agent-sdk';
|
|
11
|
+
|
|
12
|
+
const ALERT_THRESHOLD = 50; // Alert if censorship score > 50 (out of 100)
|
|
13
|
+
|
|
14
|
+
// Register a monitor agent and a subscriber agent
|
|
15
|
+
const monitor = await VoidlyAgent.register({ name: 'censorship-monitor' });
|
|
16
|
+
const subscriber = await VoidlyAgent.register({ name: 'alert-subscriber' });
|
|
17
|
+
|
|
18
|
+
console.log(`Monitor: ${monitor.did}`);
|
|
19
|
+
console.log(`Subscriber: ${subscriber.did}\n`);
|
|
20
|
+
|
|
21
|
+
// Fetch live censorship index from Voidly public API
|
|
22
|
+
console.log('Fetching live censorship data...');
|
|
23
|
+
const res = await fetch('https://api.voidly.ai/data/censorship-index.json');
|
|
24
|
+
const index = await res.json();
|
|
25
|
+
const countries = index.countries;
|
|
26
|
+
console.log(`Loaded data for ${countries.length} countries.\n`);
|
|
27
|
+
|
|
28
|
+
// Find countries above the alert threshold
|
|
29
|
+
const alerts = countries
|
|
30
|
+
.filter((c) => c.score > ALERT_THRESHOLD)
|
|
31
|
+
.sort((a, b) => b.score - a.score)
|
|
32
|
+
.slice(0, 5);
|
|
33
|
+
|
|
34
|
+
if (alerts.length === 0) {
|
|
35
|
+
console.log('No countries above alert threshold.');
|
|
36
|
+
} else {
|
|
37
|
+
console.log(`${alerts.length} countries with censorship score > ${ALERT_THRESHOLD}:\n`);
|
|
38
|
+
|
|
39
|
+
for (const country of alerts) {
|
|
40
|
+
const alertMsg = JSON.stringify({
|
|
41
|
+
type: 'censorship_alert',
|
|
42
|
+
country: country.country,
|
|
43
|
+
code: country.code,
|
|
44
|
+
score: country.score,
|
|
45
|
+
level: country.level,
|
|
46
|
+
samples: country.samples,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Send encrypted alert
|
|
50
|
+
await monitor.send(subscriber.did, alertMsg, {
|
|
51
|
+
contentType: 'application/json',
|
|
52
|
+
messageType: 'alert',
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
console.log(` ⚠ ${country.country} (${country.code}): score ${country.score}/100 [${country.level}]`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Subscriber receives encrypted alerts
|
|
59
|
+
console.log('\nSubscriber receiving alerts...');
|
|
60
|
+
const messages = await subscriber.receive({ limit: 10 });
|
|
61
|
+
console.log(`Received ${messages.length} encrypted alerts.`);
|
|
62
|
+
|
|
63
|
+
for (const msg of messages) {
|
|
64
|
+
const data = JSON.parse(msg.content);
|
|
65
|
+
console.log(` ✓ ${data.country}: score ${data.score}/100 — signature valid: ${msg.signatureValid}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.log('\n✓ Done — censorship monitoring with E2E encrypted alerts.');
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Conversations — Threaded dialog between agents.
|
|
4
|
+
*
|
|
5
|
+
* Run: node examples/conversation.mjs
|
|
6
|
+
*
|
|
7
|
+
* Uses conversation() to auto-thread messages and waitForReply()
|
|
8
|
+
* for synchronous back-and-forth. Great for LLM agent dialogs.
|
|
9
|
+
*/
|
|
10
|
+
import { VoidlyAgent } from '@voidly/agent-sdk';
|
|
11
|
+
|
|
12
|
+
const researcher = await VoidlyAgent.register({ name: 'conv-researcher' });
|
|
13
|
+
const analyst = await VoidlyAgent.register({ name: 'conv-analyst' });
|
|
14
|
+
|
|
15
|
+
console.log(`Researcher: ${researcher.did}`);
|
|
16
|
+
console.log(`Analyst: ${analyst.did}\n`);
|
|
17
|
+
|
|
18
|
+
// Start a threaded conversation
|
|
19
|
+
const conv = researcher.conversation(analyst.did);
|
|
20
|
+
|
|
21
|
+
// Researcher sends first message
|
|
22
|
+
await conv.say('Is twitter.com currently blocked in Iran?');
|
|
23
|
+
console.log('Researcher: "Is twitter.com currently blocked in Iran?"');
|
|
24
|
+
|
|
25
|
+
// Simulate the analyst responding (in a real app, the analyst's
|
|
26
|
+
// listener would process the question and reply automatically)
|
|
27
|
+
const analystConv = analyst.conversation(researcher.did, conv.threadId);
|
|
28
|
+
await analystConv.say('Yes — DNS poisoning detected across 3 major ISPs. Block rate: 94%.');
|
|
29
|
+
console.log('Analyst: "Yes — DNS poisoning detected across 3 major ISPs."');
|
|
30
|
+
|
|
31
|
+
// Researcher waits for the reply
|
|
32
|
+
const reply = await conv.waitForReply(10000);
|
|
33
|
+
console.log(`\nResearcher received reply: "${reply.content}"`);
|
|
34
|
+
console.log(` Thread: ${reply.threadId}`);
|
|
35
|
+
console.log(` Signature valid: ${reply.signatureValid}`);
|
|
36
|
+
|
|
37
|
+
// View full conversation history
|
|
38
|
+
const history = await conv.history();
|
|
39
|
+
console.log(`\nConversation history: ${history.length} messages`);
|
|
40
|
+
for (const msg of history) {
|
|
41
|
+
const who = msg.from === researcher.did ? 'Researcher' : 'Analyst';
|
|
42
|
+
console.log(` ${who}: "${msg.content}"`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log('\n✓ Done — threaded conversation with E2E encryption.');
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Encrypted Channels — Group messaging with client-side encryption.
|
|
4
|
+
*
|
|
5
|
+
* Run: node examples/encrypted-channel.mjs
|
|
6
|
+
*
|
|
7
|
+
* Channel key is generated locally. The relay stores opaque ciphertext
|
|
8
|
+
* and cannot read channel messages.
|
|
9
|
+
*/
|
|
10
|
+
import { VoidlyAgent } from '@voidly/agent-sdk';
|
|
11
|
+
|
|
12
|
+
// Register two agents
|
|
13
|
+
const alice = await VoidlyAgent.register({ name: 'chan-alice' });
|
|
14
|
+
const bob = await VoidlyAgent.register({ name: 'chan-bob' });
|
|
15
|
+
|
|
16
|
+
// Alice creates an encrypted channel (key generated client-side)
|
|
17
|
+
const { id: channelId, channelKey } = await alice.createEncryptedChannel({
|
|
18
|
+
name: 'research-team',
|
|
19
|
+
description: 'Private research coordination',
|
|
20
|
+
});
|
|
21
|
+
console.log(`Channel created: ${channelId}\n`);
|
|
22
|
+
|
|
23
|
+
// Bob joins
|
|
24
|
+
await bob.joinChannel(channelId);
|
|
25
|
+
console.log('Bob joined the channel.\n');
|
|
26
|
+
|
|
27
|
+
// Alice posts an encrypted message
|
|
28
|
+
await alice.postEncrypted(channelId, 'New censorship incident detected in IR', channelKey);
|
|
29
|
+
console.log('Alice posted: "New censorship incident detected in IR"\n');
|
|
30
|
+
|
|
31
|
+
// Bob reads and decrypts with the shared channel key
|
|
32
|
+
const { messages } = await bob.readEncrypted(channelId, channelKey);
|
|
33
|
+
for (const msg of messages) {
|
|
34
|
+
console.log(`Bob read: "${msg.content}"`);
|
|
35
|
+
console.log(` From: ${msg.from}`);
|
|
36
|
+
console.log(` Signature valid: ${msg.signatureValid}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log('\n✓ Done — group messages encrypted with NaCl secretbox.');
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Quickstart — Register two agents, send an encrypted message, receive it.
|
|
4
|
+
*
|
|
5
|
+
* Run: node examples/quickstart.mjs
|
|
6
|
+
*
|
|
7
|
+
* All encryption happens client-side. The relay never sees plaintext.
|
|
8
|
+
*/
|
|
9
|
+
import { VoidlyAgent } from '@voidly/agent-sdk';
|
|
10
|
+
|
|
11
|
+
const alice = await VoidlyAgent.register({ name: 'example-alice' });
|
|
12
|
+
const bob = await VoidlyAgent.register({ name: 'example-bob' });
|
|
13
|
+
|
|
14
|
+
console.log(`Alice: ${alice.did}`);
|
|
15
|
+
console.log(`Bob: ${bob.did}\n`);
|
|
16
|
+
|
|
17
|
+
// Alice sends an encrypted message to Bob
|
|
18
|
+
await alice.send(bob.did, 'Hello from Alice!');
|
|
19
|
+
console.log('Alice → Bob: "Hello from Alice!" (encrypted + signed)\n');
|
|
20
|
+
|
|
21
|
+
// Bob receives and decrypts
|
|
22
|
+
const messages = await bob.receive();
|
|
23
|
+
for (const msg of messages) {
|
|
24
|
+
console.log(`Bob received: "${msg.content}"`);
|
|
25
|
+
console.log(` From: ${msg.from}`);
|
|
26
|
+
console.log(` Signature valid: ${msg.signatureValid}`);
|
|
27
|
+
console.log(` Encrypted: client-side (relay never saw plaintext)`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log('\n✓ Done — two agents communicated with E2E encryption.');
|
package/examples/rpc.mjs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Agent RPC — Call functions on remote agents.
|
|
4
|
+
*
|
|
5
|
+
* Run: node examples/rpc.mjs
|
|
6
|
+
*
|
|
7
|
+
* Agent A exposes a "translate" method. Agent B invokes it remotely.
|
|
8
|
+
* The RPC payload is E2E encrypted — the relay never sees the request or response.
|
|
9
|
+
*/
|
|
10
|
+
import { VoidlyAgent } from '@voidly/agent-sdk';
|
|
11
|
+
|
|
12
|
+
// Register a "translator" agent and a "client" agent
|
|
13
|
+
const translator = await VoidlyAgent.register({
|
|
14
|
+
name: 'rpc-translator',
|
|
15
|
+
capabilities: ['translate'],
|
|
16
|
+
});
|
|
17
|
+
const client = await VoidlyAgent.register({ name: 'rpc-client' });
|
|
18
|
+
|
|
19
|
+
console.log(`Translator: ${translator.did}`);
|
|
20
|
+
console.log(`Client: ${client.did}\n`);
|
|
21
|
+
|
|
22
|
+
// Translator registers an RPC handler
|
|
23
|
+
translator.onInvoke('translate', async (params) => {
|
|
24
|
+
console.log(`Translator received RPC: translate("${params.text}" → ${params.to})`);
|
|
25
|
+
// Simulate translation (real agent would call an LLM or translation API)
|
|
26
|
+
const translations = { es: 'Hola', fr: 'Bonjour', de: 'Hallo', ja: 'こんにちは' };
|
|
27
|
+
return { translated: translations[params.to] || params.text, lang: params.to };
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Start the translator's listener so it can receive RPC calls
|
|
31
|
+
const stop = translator.listen(() => {});
|
|
32
|
+
|
|
33
|
+
// Client invokes the translator's "translate" method
|
|
34
|
+
console.log('Client calling translate("Hello" → "es")...');
|
|
35
|
+
const result = await client.invoke(translator.did, 'translate', {
|
|
36
|
+
text: 'Hello',
|
|
37
|
+
to: 'es',
|
|
38
|
+
});
|
|
39
|
+
console.log(`Result: ${JSON.stringify(result)}`);
|
|
40
|
+
|
|
41
|
+
stop(); // Stop listening
|
|
42
|
+
console.log('\n✓ Done — remote procedure call over E2E encrypted channel.');
|
package/package.json
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voidly/agent-sdk",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.5",
|
|
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
|
-
"dist"
|
|
16
|
+
"dist",
|
|
17
|
+
"examples"
|
|
10
18
|
],
|
|
11
19
|
"scripts": {
|
|
12
20
|
"build": "tsup",
|
|
@@ -24,13 +32,20 @@
|
|
|
24
32
|
},
|
|
25
33
|
"keywords": [
|
|
26
34
|
"agent",
|
|
35
|
+
"ai-agent",
|
|
36
|
+
"multi-agent",
|
|
27
37
|
"encryption",
|
|
28
38
|
"e2e",
|
|
39
|
+
"double-ratchet",
|
|
40
|
+
"post-quantum",
|
|
29
41
|
"nacl",
|
|
30
42
|
"did",
|
|
43
|
+
"privacy",
|
|
31
44
|
"voidly",
|
|
32
45
|
"mcp",
|
|
33
|
-
"a2a"
|
|
46
|
+
"a2a",
|
|
47
|
+
"langchain",
|
|
48
|
+
"crewai"
|
|
34
49
|
],
|
|
35
50
|
"license": "MIT",
|
|
36
51
|
"repository": {
|