open-agents-nexus 0.1.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.
Files changed (67) hide show
  1. package/ARCHITECTURE.md +2104 -0
  2. package/LICENSE +28 -0
  3. package/README.md +198 -0
  4. package/dist/chat/index.d.ts +24 -0
  5. package/dist/chat/index.js +56 -0
  6. package/dist/chat/index.js.map +1 -0
  7. package/dist/chat/messages.d.ts +28 -0
  8. package/dist/chat/messages.js +33 -0
  9. package/dist/chat/messages.js.map +1 -0
  10. package/dist/chat/room.d.ts +49 -0
  11. package/dist/chat/room.js +123 -0
  12. package/dist/chat/room.js.map +1 -0
  13. package/dist/cli.d.ts +8 -0
  14. package/dist/cli.js +222 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/config.d.ts +22 -0
  17. package/dist/config.js +19 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/dht/index.d.ts +16 -0
  20. package/dist/dht/index.js +33 -0
  21. package/dist/dht/index.js.map +1 -0
  22. package/dist/dht/registry.d.ts +24 -0
  23. package/dist/dht/registry.js +103 -0
  24. package/dist/dht/registry.js.map +1 -0
  25. package/dist/discovery.d.ts +43 -0
  26. package/dist/discovery.js +70 -0
  27. package/dist/discovery.js.map +1 -0
  28. package/dist/identity/index.d.ts +34 -0
  29. package/dist/identity/index.js +46 -0
  30. package/dist/identity/index.js.map +1 -0
  31. package/dist/identity/keys.d.ts +26 -0
  32. package/dist/identity/keys.js +49 -0
  33. package/dist/identity/keys.js.map +1 -0
  34. package/dist/index.d.ts +83 -0
  35. package/dist/index.js +299 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/logger.d.ts +8 -0
  38. package/dist/logger.js +32 -0
  39. package/dist/logger.js.map +1 -0
  40. package/dist/node.d.ts +47 -0
  41. package/dist/node.js +136 -0
  42. package/dist/node.js.map +1 -0
  43. package/dist/protocol/index.d.ts +11 -0
  44. package/dist/protocol/index.js +66 -0
  45. package/dist/protocol/index.js.map +1 -0
  46. package/dist/protocol/types.d.ts +197 -0
  47. package/dist/protocol/types.js +18 -0
  48. package/dist/protocol/types.js.map +1 -0
  49. package/dist/signaling/onboarding.d.ts +10 -0
  50. package/dist/signaling/onboarding.js +40 -0
  51. package/dist/signaling/onboarding.js.map +1 -0
  52. package/dist/signaling/server.d.ts +35 -0
  53. package/dist/signaling/server.js +140 -0
  54. package/dist/signaling/server.js.map +1 -0
  55. package/dist/storage/index.d.ts +31 -0
  56. package/dist/storage/index.js +103 -0
  57. package/dist/storage/index.js.map +1 -0
  58. package/dist/storage/mirror.d.ts +9 -0
  59. package/dist/storage/mirror.js +24 -0
  60. package/dist/storage/mirror.js.map +1 -0
  61. package/dist/storage/pin.d.ts +8 -0
  62. package/dist/storage/pin.js +42 -0
  63. package/dist/storage/pin.js.map +1 -0
  64. package/dist/storage/propagation.d.ts +32 -0
  65. package/dist/storage/propagation.js +89 -0
  66. package/dist/storage/propagation.js.map +1 -0
  67. package/package.json +122 -0
package/dist/node.js ADDED
@@ -0,0 +1,136 @@
1
+ /**
2
+ * libp2p node creation and configuration
3
+ *
4
+ * Responsible for creating and configuring the libp2p node with:
5
+ * - Transport: TCP, WebSockets, Circuit Relay v2
6
+ * - Encryption: Noise
7
+ * - Muxer: Yamux
8
+ * - Discovery: mDNS, Bootstrap (when peers provided), Pubsub Peer Discovery
9
+ * - Services: Identify, KadDHT (/nexus/kad/1.0.0), GossipSub, Circuit Relay Server
10
+ *
11
+ * Discovery cascade (in priority order):
12
+ * 1. Signaling Server peers — callers must pass these in via signalingPeers
13
+ * 2. Public bootstrap WSS nodes — enabled by discoveryConfig.usePublicBootstrap
14
+ * 3. Pubsub peer discovery — all agents subscribe to NEXUS_DISCOVERY_TOPIC
15
+ * 4. mDNS — local-network zero-config discovery
16
+ * 5. Circuit Relay v2 — NAT traversal (enabled for non-light roles)
17
+ */
18
+ import { createLibp2p } from 'libp2p';
19
+ import { noise } from '@chainsafe/libp2p-noise';
20
+ import { yamux } from '@chainsafe/libp2p-yamux';
21
+ import { tcp } from '@libp2p/tcp';
22
+ import { webSockets } from '@libp2p/websockets';
23
+ import { kadDHT } from '@libp2p/kad-dht';
24
+ import { gossipsub } from '@libp2p/gossipsub';
25
+ import { identify } from '@libp2p/identify';
26
+ import { bootstrap } from '@libp2p/bootstrap';
27
+ import { mdns } from '@libp2p/mdns';
28
+ import { ping } from '@libp2p/ping';
29
+ import { circuitRelayTransport, circuitRelayServer } from '@libp2p/circuit-relay-v2';
30
+ import { pubsubPeerDiscovery } from '@libp2p/pubsub-peer-discovery';
31
+ import { msgIdFn as nexusMsgIdFn, PROTOCOLS } from './protocol/index.js';
32
+ import { resolveDiscovery, buildBootstrapList, NEXUS_DISCOVERY_TOPIC, } from './discovery.js';
33
+ import { createLogger } from './logger.js';
34
+ const log = createLogger('node');
35
+ /**
36
+ * Create and start a fully-configured libp2p nexus node.
37
+ *
38
+ * The node uses:
39
+ * - TCP + WebSockets + Circuit Relay v2 transports
40
+ * - Noise connection encryption
41
+ * - Yamux stream multiplexing
42
+ * - Identify service for protocol/address exchange
43
+ * - KadDHT on the /nexus/kad/1.0.0 protocol (client mode for 'light' role)
44
+ * - GossipSub for pub/sub messaging
45
+ * - Pubsub peer discovery on the global nexus discovery topic
46
+ * - mDNS for local-network peer discovery (controllable via discoveryConfig)
47
+ * - Bootstrap peer discovery (when the resolved bootstrap list is non-empty)
48
+ * - Circuit relay server for non-light roles (helps NAT'd peers connect)
49
+ *
50
+ * @param config - Nexus node configuration
51
+ * @param privateKey - Ed25519 private key for this node's identity
52
+ * @param discoveryConfig - Optional discovery cascade settings (defaults applied)
53
+ * @param signalingPeers - Bootstrap peers fetched from the signaling server (Level 1)
54
+ */
55
+ export async function createNexusNode(config, privateKey, discoveryConfig, signalingPeers = []) {
56
+ // Resolve discovery settings, merging config-level fields and explicit param
57
+ const discovery = resolveDiscovery({
58
+ usePublicBootstrap: config.usePublicBootstrap,
59
+ enableCircuitRelay: config.enableCircuitRelay,
60
+ enablePubsubDiscovery: config.enablePubsubDiscovery,
61
+ enableMdns: config.enableMdns,
62
+ ...discoveryConfig,
63
+ });
64
+ // Build the combined bootstrap peer list from all sources
65
+ // Merge config.bootstrapPeers (operator-supplied) into signalingPeers position
66
+ const allSignalingPeers = [...signalingPeers, ...config.bootstrapPeers];
67
+ const bootstrapList = buildBootstrapList(discovery, allSignalingPeers);
68
+ // Build peer discovery modules
69
+ const peerDiscovery = [];
70
+ if (bootstrapList.length > 0) {
71
+ peerDiscovery.push(bootstrap({ list: bootstrapList }));
72
+ }
73
+ if (discovery.enableMdns) {
74
+ peerDiscovery.push(mdns());
75
+ }
76
+ if (discovery.enablePubsubDiscovery) {
77
+ peerDiscovery.push(pubsubPeerDiscovery({
78
+ interval: 10_000, // Re-announce every 10 seconds
79
+ topics: [NEXUS_DISCOVERY_TOPIC],
80
+ listenOnly: false,
81
+ }));
82
+ }
83
+ // Build transport list — always include circuit relay transport so we can
84
+ // both dial and receive relay-mediated connections.
85
+ const transports = [
86
+ tcp(),
87
+ webSockets(),
88
+ ...(discovery.enableCircuitRelay ? [circuitRelayTransport()] : []),
89
+ ];
90
+ // Listen addresses — add /p2p-circuit so relay-connected peers can reach us
91
+ const listenAddresses = [
92
+ ...config.listenAddresses,
93
+ ...(discovery.enableCircuitRelay ? ['/p2p-circuit'] : []),
94
+ ];
95
+ // Adapt our protocol-level msgIdFn to the gossipsub MsgIdFn signature.
96
+ // Gossipsub guarantees msg.data is always a Uint8Array for received messages.
97
+ function gossipMsgIdFn(msg) {
98
+ return nexusMsgIdFn({ data: msg.data });
99
+ }
100
+ // Build services — full/storage nodes act as circuit relay servers, helping
101
+ // NAT'd light nodes connect to the rest of the network.
102
+ const isRelayServer = discovery.enableCircuitRelay && config.role !== 'light';
103
+ const node = await createLibp2p({
104
+ privateKey,
105
+ addresses: {
106
+ listen: listenAddresses,
107
+ },
108
+ transports,
109
+ connectionEncrypters: [noise()],
110
+ streamMuxers: [yamux()],
111
+ peerDiscovery,
112
+ services: {
113
+ identify: identify(),
114
+ ping: ping(),
115
+ dht: kadDHT({
116
+ protocol: PROTOCOLS.DHT,
117
+ clientMode: config.role === 'light',
118
+ }),
119
+ pubsub: gossipsub({
120
+ emitSelf: false,
121
+ allowPublishToZeroTopicPeers: true,
122
+ msgIdFn: gossipMsgIdFn,
123
+ }),
124
+ ...(isRelayServer ? { relay: circuitRelayServer() } : {}),
125
+ },
126
+ });
127
+ log.info(`Node created with PeerId: ${node.peerId.toString()}`);
128
+ log.info(`Role: ${config.role}`);
129
+ log.info(`Discovery: bootstrap=${bootstrapList.length} peers, ` +
130
+ `mdns=${discovery.enableMdns}, ` +
131
+ `pubsub=${discovery.enablePubsubDiscovery}, ` +
132
+ `relay=${discovery.enableCircuitRelay}`);
133
+ log.info(`Listening on: ${node.getMultiaddrs().map((a) => a.toString()).join(', ')}`);
134
+ return node;
135
+ }
136
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAGpE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEzE,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,GAEtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAmB,EACnB,UAAsB,EACtB,eAA0C,EAC1C,iBAA2B,EAAE;IAE7B,6EAA6E;IAC7E,MAAM,SAAS,GAAG,gBAAgB,CAAC;QACjC,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;QACnD,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,GAAG,eAAe;KACnB,CAAC,CAAC;IAEH,0DAA0D;IAC1D,+EAA+E;IAC/E,MAAM,iBAAiB,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IACxE,MAAM,aAAa,GAAG,kBAAkB,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAEvE,+BAA+B;IAC/B,MAAM,aAAa,GAEb,EAAE,CAAC;IAET,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;QACzB,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,SAAS,CAAC,qBAAqB,EAAE,CAAC;QACpC,aAAa,CAAC,IAAI,CAChB,mBAAmB,CAAC;YAClB,QAAQ,EAAE,MAAM,EAAE,+BAA+B;YACjD,MAAM,EAAE,CAAC,qBAAqB,CAAC;YAC/B,UAAU,EAAE,KAAK;SAClB,CAAC,CACH,CAAC;IACJ,CAAC;IAED,0EAA0E;IAC1E,oDAAoD;IACpD,MAAM,UAAU,GAAG;QACjB,GAAG,EAAE;QACL,UAAU,EAAE;QACZ,GAAG,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KACnE,CAAC;IAEF,4EAA4E;IAC5E,MAAM,eAAe,GAAG;QACtB,GAAG,MAAM,CAAC,eAAe;QACzB,GAAG,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1D,CAAC;IAEF,uEAAuE;IACvE,8EAA8E;IAC9E,SAAS,aAAa,CAAC,GAAY;QACjC,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,4EAA4E;IAC5E,wDAAwD;IACxD,MAAM,aAAa,GAAG,SAAS,CAAC,kBAAkB,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC;IAE9E,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC;QAC9B,UAAU;QACV,SAAS,EAAE;YACT,MAAM,EAAE,eAAe;SACxB;QACD,UAAU;QACV,oBAAoB,EAAE,CAAC,KAAK,EAAE,CAAC;QAC/B,YAAY,EAAE,CAAC,KAAK,EAAE,CAAC;QACvB,aAAa;QACb,QAAQ,EAAE;YACR,QAAQ,EAAE,QAAQ,EAAE;YACpB,IAAI,EAAE,IAAI,EAAE;YACZ,GAAG,EAAE,MAAM,CAAC;gBACV,QAAQ,EAAE,SAAS,CAAC,GAAG;gBACvB,UAAU,EAAE,MAAM,CAAC,IAAI,KAAK,OAAO;aACpC,CAAC;YACF,MAAM,EAAE,SAAS,CAAC;gBAChB,QAAQ,EAAE,KAAK;gBACf,4BAA4B,EAAE,IAAI;gBAClC,OAAO,EAAE,aAAa;aACvB,CAAC;YACF,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1D;KACF,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,6BAA6B,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAChE,GAAG,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,GAAG,CAAC,IAAI,CACN,wBAAwB,aAAa,CAAC,MAAM,UAAU;QACtD,QAAQ,SAAS,CAAC,UAAU,IAAI;QAChC,UAAU,SAAS,CAAC,qBAAqB,IAAI;QAC7C,SAAS,SAAS,CAAC,kBAAkB,EAAE,CACxC,CAAC;IACF,GAAG,CAAC,IAAI,CAAC,iBAAiB,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEtF,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type MessageType, type NexusMessage } from './types.js';
2
+ export * from './types.js';
3
+ export declare function uuidv7(): string;
4
+ export declare function createMessage(type: MessageType, topic: string, sender: string, payload: NexusMessage['payload'], references?: string[]): NexusMessage;
5
+ export declare function encodeMessage(msg: NexusMessage): Uint8Array;
6
+ export declare function decodeMessage(data: Uint8Array): NexusMessage;
7
+ export declare function msgIdFn(msg: {
8
+ data: Uint8Array | null;
9
+ }): Uint8Array;
10
+ export declare function roomTopic(roomId: string): string;
11
+ export declare function ephemeralTopic(sessionId: string): string;
@@ -0,0 +1,66 @@
1
+ import { PROTOCOL_VERSION, TOPICS, } from './types.js';
2
+ export * from './types.js';
3
+ // UUIDv7 generation (no external dependency)
4
+ // UUIDv7 = unix_ms (48 bits) + version (4 bits) + rand_a (12 bits) + variant (2 bits) + rand_b (62 bits)
5
+ export function uuidv7() {
6
+ const now = Date.now();
7
+ const bytes = new Uint8Array(16);
8
+ // timestamp (48 bits, big-endian)
9
+ bytes[0] = (now / 2 ** 40) & 0xff;
10
+ bytes[1] = (now / 2 ** 32) & 0xff;
11
+ bytes[2] = (now / 2 ** 24) & 0xff;
12
+ bytes[3] = (now / 2 ** 16) & 0xff;
13
+ bytes[4] = (now / 2 ** 8) & 0xff;
14
+ bytes[5] = now & 0xff;
15
+ // random (80 bits)
16
+ crypto.getRandomValues(bytes.subarray(6));
17
+ // version 7
18
+ bytes[6] = (bytes[6] & 0x0f) | 0x70;
19
+ // variant 10
20
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
21
+ const hex = Array.from(bytes)
22
+ .map((b) => b.toString(16).padStart(2, '0'))
23
+ .join('');
24
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
25
+ }
26
+ // Create a NexusMessage
27
+ export function createMessage(type, topic, sender, payload, references = []) {
28
+ return {
29
+ version: PROTOCOL_VERSION,
30
+ type,
31
+ id: uuidv7(),
32
+ timestamp: Date.now(),
33
+ sender,
34
+ topic,
35
+ payload,
36
+ references,
37
+ };
38
+ }
39
+ // Serialize/deserialize messages
40
+ export function encodeMessage(msg) {
41
+ return new TextEncoder().encode(JSON.stringify(msg));
42
+ }
43
+ export function decodeMessage(data) {
44
+ return JSON.parse(new TextDecoder().decode(data));
45
+ }
46
+ // Message ID function for GossipSub deduplication
47
+ export function msgIdFn(msg) {
48
+ if (!msg.data)
49
+ return new Uint8Array(0);
50
+ try {
51
+ const envelope = JSON.parse(new TextDecoder().decode(msg.data));
52
+ return new TextEncoder().encode(envelope.id);
53
+ }
54
+ catch {
55
+ // fallback: use raw data hash (we'll just use the first 32 bytes as a simple fingerprint)
56
+ return msg.data.subarray(0, 32);
57
+ }
58
+ }
59
+ // Topic helpers
60
+ export function roomTopic(roomId) {
61
+ return `${TOPICS.ROOM_PREFIX}${roomId}`;
62
+ }
63
+ export function ephemeralTopic(sessionId) {
64
+ return `${TOPICS.EPHEMERAL_PREFIX}${sessionId}`;
65
+ }
66
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/protocol/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,197 @@
1
+ export declare const PROTOCOL_VERSION: 1;
2
+ export declare const PROTOCOLS: {
3
+ readonly DHT: "/nexus/kad/1.0.0";
4
+ readonly SYNC: "/nexus/sync/1.0.0";
5
+ readonly HANDSHAKE: "/nexus/handshake/1.0.0";
6
+ readonly DM: "/nexus/dm/1.0.0";
7
+ readonly CAPABILITY_INVOKE: "/nexus/capability/invoke/1.0.0";
8
+ };
9
+ export declare const TOPICS: {
10
+ readonly META: "/nexus/meta";
11
+ readonly ROOM_PREFIX: "/nexus/room/";
12
+ readonly EPHEMERAL_PREFIX: "/nexus/ephemeral/";
13
+ readonly CAPABILITY_PREFIX: "/nexus/capability/";
14
+ };
15
+ export type MessageType = 'chat' | 'presence' | 'meta' | 'capability' | 'sync';
16
+ export type PresenceStatus = 'online' | 'idle' | 'busy' | 'offline';
17
+ export type AgentRole = 'light' | 'full' | 'storage';
18
+ export type RoomType = 'persistent' | 'ephemeral';
19
+ export type RoomAccess = 'public';
20
+ export type ContentFormat = 'text/plain' | 'text/markdown' | 'application/json';
21
+ export interface NexusMessage {
22
+ version: typeof PROTOCOL_VERSION;
23
+ type: MessageType;
24
+ id: string;
25
+ timestamp: number;
26
+ sender: string;
27
+ topic: string;
28
+ payload: ChatPayload | PresencePayload | MetaPayload | CapabilityPayload | SyncPayload;
29
+ references: string[];
30
+ }
31
+ export interface ChatPayload {
32
+ content: string;
33
+ format: ContentFormat;
34
+ replyTo: string | null;
35
+ threadId: string | null;
36
+ }
37
+ export interface PresencePayload {
38
+ status: PresenceStatus;
39
+ capabilities: string[];
40
+ agentName: string;
41
+ agentType: string;
42
+ version: string;
43
+ }
44
+ export interface MetaPayload {
45
+ action: string;
46
+ roomId?: string;
47
+ roomManifest?: string;
48
+ [key: string]: unknown;
49
+ }
50
+ export interface CapabilityPayload {
51
+ capabilities: CapabilityDefinition[];
52
+ }
53
+ export interface CapabilityDefinition {
54
+ name: string;
55
+ protocol: string;
56
+ description: string;
57
+ pricing: string;
58
+ rateLimit: string;
59
+ }
60
+ export interface SyncPayload {
61
+ action: 'request' | 'response';
62
+ since?: number;
63
+ limit?: number;
64
+ historyRoot?: string;
65
+ messageCount?: number;
66
+ oldestTimestamp?: number;
67
+ newestTimestamp?: number;
68
+ }
69
+ export interface AgentProfile {
70
+ schema: 'nexus:agent-profile:v1';
71
+ peerId: string;
72
+ name: string;
73
+ description: string;
74
+ type: string;
75
+ capabilities: CapabilityDefinition[];
76
+ role: AgentRole;
77
+ transports: string[];
78
+ createdAt: number;
79
+ updatedAt: number;
80
+ previousVersion: string | null;
81
+ }
82
+ export interface RoomManifest {
83
+ schema: 'nexus:room-manifest:v1';
84
+ roomId: string;
85
+ topic: string;
86
+ name: string;
87
+ description: string;
88
+ createdBy: string;
89
+ createdAt: number;
90
+ type: RoomType;
91
+ access: RoomAccess;
92
+ retention: {
93
+ policy: 'community-pinned';
94
+ minPinners: number;
95
+ archiveAfterMs: number;
96
+ };
97
+ historyRoot: string | null;
98
+ memberCount: number;
99
+ previousVersion: string | null;
100
+ }
101
+ export interface MessagePage {
102
+ schema: 'nexus:message-page:v1';
103
+ roomId: string;
104
+ pageIndex: number;
105
+ count: number;
106
+ timestamp: {
107
+ first: number;
108
+ last: number;
109
+ };
110
+ messages: StoredMessage[];
111
+ prev: {
112
+ '/': string;
113
+ } | null;
114
+ }
115
+ export interface StoredMessage {
116
+ id: string;
117
+ timestamp: number;
118
+ sender: string;
119
+ payload: ChatPayload;
120
+ }
121
+ export interface HandshakeInit {
122
+ protocolVersion: typeof PROTOCOL_VERSION;
123
+ agentName: string;
124
+ agentType: string;
125
+ capabilities: string[];
126
+ rooms: string[];
127
+ role: AgentRole;
128
+ clientVersion: string;
129
+ }
130
+ export interface HandshakeAck {
131
+ protocolVersion: typeof PROTOCOL_VERSION;
132
+ agentName: string;
133
+ agentType: string;
134
+ capabilities: string[];
135
+ rooms: string[];
136
+ role: AgentRole;
137
+ clientVersion: string;
138
+ }
139
+ export interface InvocationRequest {
140
+ requestId: string;
141
+ capability: string;
142
+ input: unknown;
143
+ maxWaitMs: number;
144
+ }
145
+ export interface InvocationResponse {
146
+ requestId: string;
147
+ status: 'success' | 'error';
148
+ output?: unknown;
149
+ error?: string;
150
+ processingMs: number;
151
+ }
152
+ export interface BootstrapResponse {
153
+ peers: string[];
154
+ network: {
155
+ peerCount: number;
156
+ roomCount: number;
157
+ protocolVersion: number;
158
+ minClientVersion: string;
159
+ };
160
+ }
161
+ export interface NetworkResponse {
162
+ peerCount: number;
163
+ roomCount: number;
164
+ messageRate: number;
165
+ storageProviders: number;
166
+ protocolVersion: number;
167
+ uptime: number;
168
+ rooms: RoomInfo[];
169
+ }
170
+ export interface RoomInfo {
171
+ roomId: string;
172
+ name: string;
173
+ topic: string;
174
+ memberCount: number;
175
+ type: RoomType;
176
+ access: RoomAccess;
177
+ manifest: string;
178
+ }
179
+ export interface ContributeOptions {
180
+ storage?: boolean;
181
+ relay?: boolean;
182
+ mirror?: string[];
183
+ }
184
+ export interface NexusEvents {
185
+ 'peer:discovered': (profile: AgentProfile) => void;
186
+ 'peer:connected': (peerId: string) => void;
187
+ 'peer:disconnected': (peerId: string) => void;
188
+ 'error': (error: Error) => void;
189
+ }
190
+ export interface RoomEvents {
191
+ 'message': (msg: NexusMessage) => void;
192
+ 'presence': (presence: NexusMessage) => void;
193
+ 'sync': (progress: {
194
+ loaded: number;
195
+ total: number;
196
+ }) => void;
197
+ }
@@ -0,0 +1,18 @@
1
+ // Protocol version
2
+ export const PROTOCOL_VERSION = 1;
3
+ // Custom protocol identifiers
4
+ export const PROTOCOLS = {
5
+ DHT: '/nexus/kad/1.0.0',
6
+ SYNC: '/nexus/sync/1.0.0',
7
+ HANDSHAKE: '/nexus/handshake/1.0.0',
8
+ DM: '/nexus/dm/1.0.0',
9
+ CAPABILITY_INVOKE: '/nexus/capability/invoke/1.0.0',
10
+ };
11
+ // GossipSub topic prefixes
12
+ export const TOPICS = {
13
+ META: '/nexus/meta',
14
+ ROOM_PREFIX: '/nexus/room/',
15
+ EPHEMERAL_PREFIX: '/nexus/ephemeral/',
16
+ CAPABILITY_PREFIX: '/nexus/capability/',
17
+ };
18
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/protocol/types.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAU,CAAC;AAE3C,8BAA8B;AAC9B,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,GAAG,EAAE,kBAAkB;IACvB,IAAI,EAAE,mBAAmB;IACzB,SAAS,EAAE,wBAAwB;IACnC,EAAE,EAAE,iBAAiB;IACrB,iBAAiB,EAAE,gCAAgC;CAC3C,CAAC;AAEX,2BAA2B;AAC3B,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,cAAc;IAC3B,gBAAgB,EAAE,mBAAmB;IACrC,iBAAiB,EAAE,oBAAoB;CAC/B,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Agent onboarding protocol
3
+ *
4
+ * Manages the process of new agents joining the network:
5
+ * - Identity verification
6
+ * - Capability announcement
7
+ * - Peer discovery and initial connections
8
+ */
9
+ import type { BootstrapResponse } from '../protocol/types.js';
10
+ export declare function fetchBootstrapPeers(signalingServer: string): Promise<BootstrapResponse>;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Agent onboarding protocol
3
+ *
4
+ * Manages the process of new agents joining the network:
5
+ * - Identity verification
6
+ * - Capability announcement
7
+ * - Peer discovery and initial connections
8
+ */
9
+ import { createLogger } from '../logger.js';
10
+ const log = createLogger('onboarding');
11
+ // Client-side onboarding: fetch bootstrap info from signaling server
12
+ export async function fetchBootstrapPeers(signalingServer) {
13
+ const url = `${signalingServer}/api/v1/bootstrap`;
14
+ log.info(`Fetching bootstrap peers from ${url}`);
15
+ try {
16
+ const response = await fetch(url, {
17
+ signal: AbortSignal.timeout(10_000),
18
+ });
19
+ if (!response.ok) {
20
+ throw new Error(`Bootstrap request failed: ${response.status} ${response.statusText}`);
21
+ }
22
+ const data = await response.json();
23
+ log.info(`Received ${data.peers.length} bootstrap peers`);
24
+ return data;
25
+ }
26
+ catch (err) {
27
+ log.warn(`Failed to fetch bootstrap peers: ${err}`);
28
+ // Return empty response — network can still function via mDNS or cached peers
29
+ return {
30
+ peers: [],
31
+ network: {
32
+ peerCount: 0,
33
+ roomCount: 0,
34
+ protocolVersion: 1,
35
+ minClientVersion: '0.1.0',
36
+ },
37
+ };
38
+ }
39
+ }
40
+ //# sourceMappingURL=onboarding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.js","sourceRoot":"","sources":["../../src/signaling/onboarding.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C,MAAM,GAAG,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;AAEvC,qEAAqE;AACrE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,eAAuB;IAC/D,MAAM,GAAG,GAAG,GAAG,eAAe,mBAAmB,CAAC;IAClD,GAAG,CAAC,IAAI,CAAC,iCAAiC,GAAG,EAAE,CAAC,CAAC;IAEjD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;SACpC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACzF,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAuB,CAAC;QACxD,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,MAAM,kBAAkB,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,oCAAoC,GAAG,EAAE,CAAC,CAAC;QACpD,8EAA8E;QAC9E,OAAO;YACL,KAAK,EAAE,EAAE;YACT,OAAO,EAAE;gBACP,SAAS,EAAE,CAAC;gBACZ,SAAS,EAAE,CAAC;gBACZ,eAAe,EAAE,CAAC;gBAClB,gBAAgB,EAAE,OAAO;aAC1B;SACF,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * HTTP/WebSocket signaling server
3
+ *
4
+ * Provides a signaling server for WebRTC peer connection establishment.
5
+ * Handles SDP offer/answer exchange and ICE candidate relay between agents.
6
+ */
7
+ import type { RoomInfo } from '../protocol/types.js';
8
+ export interface SignalingServerOptions {
9
+ port: number;
10
+ host?: string;
11
+ }
12
+ export declare class SignalingServer {
13
+ private server;
14
+ private port;
15
+ private host;
16
+ private bootstrapPeers;
17
+ private knownRooms;
18
+ private peerCount;
19
+ private startTime;
20
+ constructor(options: SignalingServerOptions);
21
+ start(): Promise<void>;
22
+ stop(): Promise<void>;
23
+ updateState(state: {
24
+ bootstrapPeers?: string[];
25
+ knownRooms?: RoomInfo[];
26
+ peerCount?: number;
27
+ }): void;
28
+ private handleRequest;
29
+ private handleBootstrap;
30
+ private handleNetwork;
31
+ private handleRooms;
32
+ private handleLanding;
33
+ private sendJSON;
34
+ private send404;
35
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * HTTP/WebSocket signaling server
3
+ *
4
+ * Provides a signaling server for WebRTC peer connection establishment.
5
+ * Handles SDP offer/answer exchange and ICE candidate relay between agents.
6
+ */
7
+ import { createServer } from 'node:http';
8
+ import { createLogger } from '../logger.js';
9
+ const log = createLogger('signaling');
10
+ export class SignalingServer {
11
+ server = null;
12
+ port;
13
+ host;
14
+ // Network state (populated by the nexus node)
15
+ bootstrapPeers = [];
16
+ knownRooms = [];
17
+ peerCount = 0;
18
+ startTime = Date.now();
19
+ constructor(options) {
20
+ this.port = options.port;
21
+ this.host = options.host ?? '0.0.0.0';
22
+ }
23
+ async start() {
24
+ return new Promise((resolve, reject) => {
25
+ this.server = createServer((req, res) => this.handleRequest(req, res));
26
+ this.server.on('error', reject);
27
+ this.server.listen(this.port, this.host, () => {
28
+ log.info(`Signaling server listening on ${this.host}:${this.port}`);
29
+ resolve();
30
+ });
31
+ });
32
+ }
33
+ async stop() {
34
+ return new Promise((resolve) => {
35
+ if (this.server) {
36
+ this.server.close(() => {
37
+ log.info('Signaling server stopped');
38
+ resolve();
39
+ });
40
+ }
41
+ else {
42
+ resolve();
43
+ }
44
+ });
45
+ }
46
+ // Update network state (called by the nexus node periodically)
47
+ updateState(state) {
48
+ if (state.bootstrapPeers)
49
+ this.bootstrapPeers = state.bootstrapPeers;
50
+ if (state.knownRooms)
51
+ this.knownRooms = state.knownRooms;
52
+ if (state.peerCount !== undefined)
53
+ this.peerCount = state.peerCount;
54
+ }
55
+ handleRequest(req, res) {
56
+ // CORS headers
57
+ res.setHeader('Access-Control-Allow-Origin', '*');
58
+ res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
59
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
60
+ if (req.method === 'OPTIONS') {
61
+ res.writeHead(204);
62
+ res.end();
63
+ return;
64
+ }
65
+ const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
66
+ switch (url.pathname) {
67
+ case '/api/v1/bootstrap':
68
+ this.handleBootstrap(res);
69
+ break;
70
+ case '/api/v1/network':
71
+ this.handleNetwork(res);
72
+ break;
73
+ case '/api/v1/rooms':
74
+ this.handleRooms(res);
75
+ break;
76
+ case '/':
77
+ this.handleLanding(res);
78
+ break;
79
+ default:
80
+ this.send404(res);
81
+ break;
82
+ }
83
+ }
84
+ handleBootstrap(res) {
85
+ const response = {
86
+ peers: this.bootstrapPeers.slice(0, 20), // max 20 peers
87
+ network: {
88
+ peerCount: this.peerCount,
89
+ roomCount: this.knownRooms.length,
90
+ protocolVersion: 1,
91
+ minClientVersion: '0.1.0',
92
+ },
93
+ };
94
+ this.sendJSON(res, response);
95
+ }
96
+ handleNetwork(res) {
97
+ const response = {
98
+ peerCount: this.peerCount,
99
+ roomCount: this.knownRooms.length,
100
+ messageRate: 0,
101
+ storageProviders: 0,
102
+ protocolVersion: 1,
103
+ uptime: Math.floor((Date.now() - this.startTime) / 1000),
104
+ rooms: this.knownRooms,
105
+ };
106
+ this.sendJSON(res, response);
107
+ }
108
+ handleRooms(res) {
109
+ this.sendJSON(res, { rooms: this.knownRooms });
110
+ }
111
+ handleLanding(res) {
112
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
113
+ res.end([
114
+ 'OpenAgents Nexus',
115
+ '================',
116
+ '',
117
+ 'Decentralized agent communication platform.',
118
+ 'No central authority. No data collection. No surveillance.',
119
+ '',
120
+ 'API Endpoints:',
121
+ ' GET /api/v1/bootstrap - Get bootstrap peers',
122
+ ' GET /api/v1/network - Network statistics',
123
+ ' GET /api/v1/rooms - Available rooms',
124
+ '',
125
+ 'Get started:',
126
+ ' npm install @openagents/nexus-client',
127
+ '',
128
+ 'Source: https://github.com/openagents/nexus',
129
+ ].join('\n'));
130
+ }
131
+ sendJSON(res, data) {
132
+ res.writeHead(200, { 'Content-Type': 'application/json' });
133
+ res.end(JSON.stringify(data));
134
+ }
135
+ send404(res) {
136
+ res.writeHead(404, { 'Content-Type': 'application/json' });
137
+ res.end(JSON.stringify({ error: 'Not found' }));
138
+ }
139
+ }
140
+ //# sourceMappingURL=server.js.map