@olane/o-node 0.7.1
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 +1024 -0
- package/dist/src/connection/index.d.ts +5 -0
- package/dist/src/connection/index.d.ts.map +1 -0
- package/dist/src/connection/index.js +4 -0
- package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts +6 -0
- package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts.map +1 -0
- package/dist/src/connection/interfaces/o-node-connection-manager.config.js +1 -0
- package/dist/src/connection/interfaces/o-node-connection.config.d.ts +6 -0
- package/dist/src/connection/interfaces/o-node-connection.config.d.ts.map +1 -0
- package/dist/src/connection/interfaces/o-node-connection.config.js +1 -0
- package/dist/src/connection/o-node-connection.d.ts +13 -0
- package/dist/src/connection/o-node-connection.d.ts.map +1 -0
- package/dist/src/connection/o-node-connection.js +51 -0
- package/dist/src/connection/o-node-connection.manager.d.ts +17 -0
- package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -0
- package/dist/src/connection/o-node-connection.manager.js +68 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +9 -0
- package/dist/src/interfaces/o-node.config.d.ts +7 -0
- package/dist/src/interfaces/o-node.config.d.ts.map +1 -0
- package/dist/src/interfaces/o-node.config.js +1 -0
- package/dist/src/interfaces/o-node.tool-config.d.ts +4 -0
- package/dist/src/interfaces/o-node.tool-config.d.ts.map +1 -0
- package/dist/src/interfaces/o-node.tool-config.js +1 -0
- package/dist/src/lib/network-activity.lib.d.ts +1 -0
- package/dist/src/lib/network-activity.lib.d.ts.map +1 -0
- package/dist/src/lib/network-activity.lib.js +34 -0
- package/dist/src/nodes/client.node.d.ts +7 -0
- package/dist/src/nodes/client.node.d.ts.map +1 -0
- package/dist/src/nodes/client.node.js +16 -0
- package/dist/src/nodes/index.d.ts +4 -0
- package/dist/src/nodes/index.d.ts.map +1 -0
- package/dist/src/nodes/index.js +3 -0
- package/dist/src/nodes/server.node.d.ts +7 -0
- package/dist/src/nodes/server.node.d.ts.map +1 -0
- package/dist/src/nodes/server.node.js +20 -0
- package/dist/src/nodes/websocket.node.d.ts +7 -0
- package/dist/src/nodes/websocket.node.d.ts.map +1 -0
- package/dist/src/nodes/websocket.node.js +18 -0
- package/dist/src/o-node.d.ts +42 -0
- package/dist/src/o-node.d.ts.map +1 -0
- package/dist/src/o-node.hierarchy-manager.d.ts +15 -0
- package/dist/src/o-node.hierarchy-manager.d.ts.map +1 -0
- package/dist/src/o-node.hierarchy-manager.js +15 -0
- package/dist/src/o-node.js +242 -0
- package/dist/src/o-node.tool.d.ts +16 -0
- package/dist/src/o-node.tool.d.ts.map +1 -0
- package/dist/src/o-node.tool.js +48 -0
- package/dist/src/router/index.d.ts +6 -0
- package/dist/src/router/index.d.ts.map +1 -0
- package/dist/src/router/index.js +5 -0
- package/dist/src/router/interfaces/o-node-router.config.d.ts +3 -0
- package/dist/src/router/interfaces/o-node-router.config.d.ts.map +1 -0
- package/dist/src/router/interfaces/o-node-router.config.js +1 -0
- package/dist/src/router/interfaces/o-node-router.response.d.ts +8 -0
- package/dist/src/router/interfaces/o-node-router.response.d.ts.map +1 -0
- package/dist/src/router/interfaces/o-node-router.response.js +1 -0
- package/dist/src/router/o-node.address.d.ts +18 -0
- package/dist/src/router/o-node.address.d.ts.map +1 -0
- package/dist/src/router/o-node.address.js +29 -0
- package/dist/src/router/o-node.router.d.ts +12 -0
- package/dist/src/router/o-node.router.d.ts.map +1 -0
- package/dist/src/router/o-node.router.js +109 -0
- package/dist/src/router/o-node.transport.d.ts +11 -0
- package/dist/src/router/o-node.transport.d.ts.map +1 -0
- package/dist/src/router/o-node.transport.js +18 -0
- package/dist/src/router/resolvers/index.d.ts +4 -0
- package/dist/src/router/resolvers/index.d.ts.map +1 -0
- package/dist/src/router/resolvers/index.js +3 -0
- package/dist/src/router/resolvers/o-node.child-resolver.d.ts +11 -0
- package/dist/src/router/resolvers/o-node.child-resolver.d.ts.map +1 -0
- package/dist/src/router/resolvers/o-node.child-resolver.js +58 -0
- package/dist/src/router/resolvers/o-node.leader-resolver-fallback.d.ts +8 -0
- package/dist/src/router/resolvers/o-node.leader-resolver-fallback.d.ts.map +1 -0
- package/dist/src/router/resolvers/o-node.leader-resolver-fallback.js +35 -0
- package/dist/src/router/resolvers/o-node.resolver.d.ts +11 -0
- package/dist/src/router/resolvers/o-node.resolver.d.ts.map +1 -0
- package/dist/src/router/resolvers/o-node.resolver.js +41 -0
- package/dist/src/router/resolvers/o-node.search-resolver.d.ts +8 -0
- package/dist/src/router/resolvers/o-node.search-resolver.d.ts.map +1 -0
- package/dist/src/router/resolvers/o-node.search-resolver.js +60 -0
- package/dist/src/router/route.request.d.ts +14 -0
- package/dist/src/router/route.request.d.ts.map +1 -0
- package/dist/src/router/route.request.js +1 -0
- package/dist/src/utils/network.utils.d.ts +20 -0
- package/dist/src/utils/network.utils.d.ts.map +1 -0
- package/dist/src/utils/network.utils.js +74 -0
- package/dist/test/o-node.spec.d.ts +2 -0
- package/dist/test/o-node.spec.d.ts.map +1 -0
- package/dist/test/o-node.spec.js +20 -0
- package/package.json +68 -0
package/README.md
ADDED
|
@@ -0,0 +1,1024 @@
|
|
|
1
|
+
# @olane/o-node
|
|
2
|
+
|
|
3
|
+
The production distribution layer of Olane OS - build tool nodes that AI agents use, with real P2P networking via libp2p.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@olane/o-node)
|
|
6
|
+
[](https://opensource.org/licenses/ISC)
|
|
7
|
+
|
|
8
|
+
## What is o-node?
|
|
9
|
+
|
|
10
|
+
**o-node** is the **production-ready distribution layer** of Olane OS - like Ubuntu is to the Linux kernel. While [@olane/o-core](../o-core) defines the abstract kernel, o-node is the actual working OS that uses [libp2p](https://libp2p.io/) for real peer-to-peer networking, discovery, and distributed communication.
|
|
11
|
+
|
|
12
|
+
### The Three-Layer Model
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
┌─────────────────────────────────────────────┐
|
|
16
|
+
│ USERS: AI Agents (LLMs) │
|
|
17
|
+
│ - GPT-4, Claude, Gemini, etc. │
|
|
18
|
+
│ - Natural language interfaces │
|
|
19
|
+
│ - Intelligent reasoning brains │
|
|
20
|
+
└─────────────────────────────────────────────┘
|
|
21
|
+
⬇ use
|
|
22
|
+
┌─────────────────────────────────────────────┐
|
|
23
|
+
│ APPLICATIONS: Tool Nodes (you build) │
|
|
24
|
+
│ - Domain-specific capabilities │
|
|
25
|
+
│ - Business integrations (APIs, DBs) │
|
|
26
|
+
│ - Specialized tools and services │
|
|
27
|
+
└─────────────────────────────────────────────┘
|
|
28
|
+
⬇ run on
|
|
29
|
+
┌─────────────────────────────────────────────┐
|
|
30
|
+
│ OPERATING SYSTEM: Olane Runtime (o-node) │
|
|
31
|
+
│ - P2P networking (libp2p) │
|
|
32
|
+
│ - Tool node discovery │
|
|
33
|
+
│ - IPC & routing │
|
|
34
|
+
│ - Process management │
|
|
35
|
+
└─────────────────────────────────────────────┘
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Key Insight**: You build **tool nodes** (specialized applications) using o-node, which **AI agents** (LLMs) use as intelligent users to accomplish tasks.
|
|
39
|
+
|
|
40
|
+
## Key Features
|
|
41
|
+
|
|
42
|
+
- 🌐 **Peer-to-Peer Networking** - Built on libp2p for true decentralized communication
|
|
43
|
+
- 🔍 **Automatic Discovery** - DHT-based tool node discovery and routing
|
|
44
|
+
- 🔒 **Secure by Default** - Encrypted connections with connection gating
|
|
45
|
+
- 🚀 **Production Ready** - Battle-tested libp2p stack with NAT traversal
|
|
46
|
+
- 🏗️ **Multiple Node Types** - Server, client, and WebSocket-optimized variants
|
|
47
|
+
- 📡 **Network Registration** - Automatic registration with leader nodes
|
|
48
|
+
- 🔄 **Persistent Identity** - Seed-based peer IDs for consistent tool node identity
|
|
49
|
+
- 🛡️ **Hierarchical Security** - Parent-child access control built-in
|
|
50
|
+
- 🧠 **Generalist-Specialist Architecture** - One LLM brain serves many specialized tool nodes
|
|
51
|
+
|
|
52
|
+
## Relationship to o-core
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
┌─────────────────────────────────────┐
|
|
56
|
+
│ o-node (This Package) │
|
|
57
|
+
│ Production Distribution Layer │
|
|
58
|
+
│ │
|
|
59
|
+
│ • Real P2P networking (libp2p) │
|
|
60
|
+
│ • Tool node discovery & routing │
|
|
61
|
+
│ • Network registration │
|
|
62
|
+
│ • Ready-to-use variants │
|
|
63
|
+
└─────────────────────────────────────┘
|
|
64
|
+
⬇ implements
|
|
65
|
+
┌─────────────────────────────────────┐
|
|
66
|
+
│ @olane/o-core │
|
|
67
|
+
│ Abstract Kernel │
|
|
68
|
+
│ │
|
|
69
|
+
│ • Abstract base classes │
|
|
70
|
+
│ • Router & connection interfaces │
|
|
71
|
+
│ • Transport-agnostic design │
|
|
72
|
+
│ • Core lifecycle management │
|
|
73
|
+
└─────────────────────────────────────┘
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Think of it as**: o-core is the **Linux kernel**, o-node is the **Ubuntu distribution**
|
|
77
|
+
|
|
78
|
+
**Use o-node when:** Building tool nodes that AI agents will use (production systems)
|
|
79
|
+
**Use o-core when:** Building custom transport implementations or experimental architectures
|
|
80
|
+
|
|
81
|
+
## Installation
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npm install @olane/o-node @olane/o-core @olane/o-protocol @olane/o-config @olane/o-tool
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Quick Start
|
|
88
|
+
|
|
89
|
+
### Creating Your First P2P Tool Node
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { oServerNode, oNodeAddress } from '@olane/o-node';
|
|
93
|
+
import { NodeType, oRequest } from '@olane/o-core';
|
|
94
|
+
|
|
95
|
+
// Create a server node (listens for connections)
|
|
96
|
+
class MyToolNode extends oServerNode {
|
|
97
|
+
constructor(address: string) {
|
|
98
|
+
super({
|
|
99
|
+
address: new oNodeAddress(address),
|
|
100
|
+
type: NodeType.AGENT,
|
|
101
|
+
description: 'My first tool node for AI agents',
|
|
102
|
+
leader: null, // We'll be our own network for now
|
|
103
|
+
parent: null,
|
|
104
|
+
methods: {
|
|
105
|
+
greet: {
|
|
106
|
+
name: 'greet',
|
|
107
|
+
description: 'Greets the caller',
|
|
108
|
+
parameters: {
|
|
109
|
+
name: { type: 'string', required: true }
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Implement your tool node's logic
|
|
117
|
+
async execute(request: oRequest): Promise<any> {
|
|
118
|
+
const { method, params } = request;
|
|
119
|
+
|
|
120
|
+
if (method === 'greet') {
|
|
121
|
+
return {
|
|
122
|
+
message: `Hello, ${params.name}! I'm a tool node that AI agents can use.`,
|
|
123
|
+
peerId: this.peerId.toString()
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
throw new Error(`Unknown method: ${method}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Start the tool node
|
|
132
|
+
const toolNode = new MyToolNode('o://my-tool');
|
|
133
|
+
await toolNode.start();
|
|
134
|
+
|
|
135
|
+
console.log('Tool node running at:', toolNode.transports);
|
|
136
|
+
console.log('Peer ID:', toolNode.peerId.toString());
|
|
137
|
+
|
|
138
|
+
// AI agents can now use this tool node via its o:// address
|
|
139
|
+
const response = await toolNode.use(
|
|
140
|
+
toolNode.address,
|
|
141
|
+
{ method: 'greet', params: { name: 'World' } }
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
console.log(response.result);
|
|
145
|
+
// { message: "Hello, World! I'm a tool node that AI agents can use.", peerId: "..." }
|
|
146
|
+
|
|
147
|
+
await toolNode.stop();
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Creating a Network of Tool Nodes
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { oServerNode, oNodeAddress } from '@olane/o-node';
|
|
154
|
+
import { NodeType } from '@olane/o-core';
|
|
155
|
+
|
|
156
|
+
// 1. Create a leader node (network coordinator for tool nodes)
|
|
157
|
+
const leader = new oServerNode({
|
|
158
|
+
address: new oNodeAddress('o://leader'),
|
|
159
|
+
type: NodeType.LEADER,
|
|
160
|
+
description: 'Network coordinator',
|
|
161
|
+
leader: null,
|
|
162
|
+
parent: null
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
await leader.start();
|
|
166
|
+
console.log('Leader started:', leader.transports[0].toString());
|
|
167
|
+
|
|
168
|
+
// 2. Create tool nodes that connect to the leader
|
|
169
|
+
const salesTool = new oServerNode({
|
|
170
|
+
address: new oNodeAddress('o://sales-tool'),
|
|
171
|
+
type: NodeType.AGENT,
|
|
172
|
+
description: 'Sales analysis tool for AI agents',
|
|
173
|
+
leader: new oNodeAddress('o://leader', leader.transports),
|
|
174
|
+
parent: new oNodeAddress('o://leader', leader.transports)
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const analyticsTool = new oServerNode({
|
|
178
|
+
address: new oNodeAddress('o://analytics-tool'),
|
|
179
|
+
type: NodeType.AGENT,
|
|
180
|
+
description: 'Data analytics tool for AI agents',
|
|
181
|
+
leader: new oNodeAddress('o://leader', leader.transports),
|
|
182
|
+
parent: new oNodeAddress('o://leader', leader.transports)
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
await salesTool.start();
|
|
186
|
+
await analyticsTool.start();
|
|
187
|
+
|
|
188
|
+
// 3. Tool nodes can now communicate (and AI agents can discover them)!
|
|
189
|
+
const response = await salesTool.use(
|
|
190
|
+
new oNodeAddress('o://analytics-tool'),
|
|
191
|
+
{ method: 'analyze', params: { data: 'sales-data' } }
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
console.log('Tool node IPC successful! AI agents can now use these tools.');
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Persistent Tool Node Identity with Seeds
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
import { oServerNode, oNodeAddress } from '@olane/o-node';
|
|
201
|
+
|
|
202
|
+
// Create a tool node with a seed for consistent peer ID
|
|
203
|
+
const toolNode = new oServerNode({
|
|
204
|
+
address: new oNodeAddress('o://my-service-tool'),
|
|
205
|
+
type: NodeType.AGENT,
|
|
206
|
+
leader: leaderAddress,
|
|
207
|
+
parent: leaderAddress,
|
|
208
|
+
seed: 'my-secure-seed-string' // Same seed = same peer ID every restart
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
await toolNode.start();
|
|
212
|
+
|
|
213
|
+
// This peer ID will be the same every time with this seed
|
|
214
|
+
// Critical for tool nodes that agents depend on finding reliably
|
|
215
|
+
console.log('Consistent Peer ID:', toolNode.peerId.toString());
|
|
216
|
+
|
|
217
|
+
// Important: Secure your seed in production!
|
|
218
|
+
// Use environment variables or secure key management
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Core Concepts
|
|
222
|
+
|
|
223
|
+
### libp2p Networking
|
|
224
|
+
|
|
225
|
+
o-node uses libp2p for all networking, providing:
|
|
226
|
+
|
|
227
|
+
- **Multiple Transports**: TCP, WebSocket, WebRTC, QUIC
|
|
228
|
+
- **Peer Discovery**: DHT, mDNS, bootstrap nodes
|
|
229
|
+
- **Content Routing**: Distributed hash table (DHT)
|
|
230
|
+
- **NAT Traversal**: Automatic hole-punching and relaying
|
|
231
|
+
- **Multiplexing**: Multiple streams over single connection
|
|
232
|
+
- **Security**: Noise protocol encryption by default
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
// libp2p transports are automatically configured
|
|
236
|
+
const node = new oServerNode(config);
|
|
237
|
+
await node.start();
|
|
238
|
+
|
|
239
|
+
// Access the libp2p node directly if needed
|
|
240
|
+
console.log('Protocols:', node.p2pNode.getProtocols());
|
|
241
|
+
console.log('Connections:', node.p2pNode.getConnections());
|
|
242
|
+
console.log('Multiaddrs:', node.p2pNode.getMultiaddrs());
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Multiaddresses
|
|
246
|
+
|
|
247
|
+
o-node uses libp2p multiaddresses for network addressing:
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// A multiaddress contains all connection info
|
|
251
|
+
const multiaddr = '/ip4/192.168.1.100/tcp/4001/p2p/12D3KooW...';
|
|
252
|
+
|
|
253
|
+
// Multiaddresses are wrapped in oNodeTransport
|
|
254
|
+
const transport = new oNodeTransport(multiaddr);
|
|
255
|
+
const address = new oNodeAddress('o://my-agent', [transport]);
|
|
256
|
+
|
|
257
|
+
// When connecting, o-node uses these multiaddresses
|
|
258
|
+
await agent.use(address, { method: 'ping' });
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Network Registration
|
|
262
|
+
|
|
263
|
+
Agents automatically register with leader nodes:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
class MyAgent extends oServerNode {
|
|
267
|
+
async register(): Promise<void> {
|
|
268
|
+
// Automatically called during start()
|
|
269
|
+
// Registers with leader's registry service
|
|
270
|
+
await this.use(RegistryAddress, {
|
|
271
|
+
method: 'commit',
|
|
272
|
+
params: {
|
|
273
|
+
peerId: this.peerId.toString(),
|
|
274
|
+
address: this.address.toString(),
|
|
275
|
+
protocols: this.p2pNode.getProtocols(),
|
|
276
|
+
transports: this.transports,
|
|
277
|
+
staticAddress: this.staticAddress.toString()
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Hierarchical Addressing
|
|
285
|
+
|
|
286
|
+
Agents can be organized hierarchically with automatic address encapsulation:
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
// Parent address
|
|
290
|
+
const parent = new oNodeAddress('o://company');
|
|
291
|
+
|
|
292
|
+
// Child address will be encapsulated
|
|
293
|
+
const child = new oNodeAddress('o://sales');
|
|
294
|
+
|
|
295
|
+
// When child starts with parent, address becomes: o://company/sales
|
|
296
|
+
const childAgent = new oServerNode({
|
|
297
|
+
address: child,
|
|
298
|
+
parent: new oNodeAddress('o://company', parentTransports),
|
|
299
|
+
leader: leaderAddress
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
await childAgent.start();
|
|
303
|
+
console.log(childAgent.address.toString()); // "o://company/sales"
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Connection Security
|
|
307
|
+
|
|
308
|
+
o-node implements connection gating for hierarchical security:
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
// Child nodes only accept connections from their parent
|
|
312
|
+
connectionGater: {
|
|
313
|
+
denyInboundEncryptedConnection: (peerId, maConn) => {
|
|
314
|
+
// Only parent can call us
|
|
315
|
+
if (this.parentPeerId === peerId.toString()) {
|
|
316
|
+
return false; // Allow
|
|
317
|
+
}
|
|
318
|
+
// Deny all others
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Node Types
|
|
325
|
+
|
|
326
|
+
o-node provides specialized node implementations for different use cases:
|
|
327
|
+
|
|
328
|
+
### 1. oServerNode - Full-Featured Server
|
|
329
|
+
|
|
330
|
+
Best for: Long-running services, leader nodes, infrastructure agents
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
import { oServerNode } from '@olane/o-node';
|
|
334
|
+
|
|
335
|
+
const server = new oServerNode({
|
|
336
|
+
address: new oNodeAddress('o://my-service'),
|
|
337
|
+
type: NodeType.AGENT,
|
|
338
|
+
leader: leaderAddress,
|
|
339
|
+
parent: parentAddress
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
await server.start();
|
|
343
|
+
|
|
344
|
+
// Listens on multiple transports:
|
|
345
|
+
// - TCP (IPv4 and IPv6)
|
|
346
|
+
// - WebSocket (IPv4 and IPv6)
|
|
347
|
+
// - Memory transport (for testing)
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Features:
|
|
351
|
+
- ✅ Accepts incoming connections
|
|
352
|
+
- ✅ Full DHT participation
|
|
353
|
+
- ✅ Network advertising
|
|
354
|
+
- ✅ Suitable for 24/7 operation
|
|
355
|
+
|
|
356
|
+
### 2. oNode - Base Implementation
|
|
357
|
+
|
|
358
|
+
Best for: Custom configurations, specialized transports
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
import { oNode } from '@olane/o-node';
|
|
362
|
+
|
|
363
|
+
class CustomNode extends oNode {
|
|
364
|
+
configureTransports(): any[] {
|
|
365
|
+
// Customize your transport configuration
|
|
366
|
+
return [customTransport1, customTransport2];
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### 3. Client & WebSocket Variants
|
|
372
|
+
|
|
373
|
+
```typescript
|
|
374
|
+
// Client node (lightweight, dial-only)
|
|
375
|
+
import { oClientNode } from '@olane/o-node';
|
|
376
|
+
|
|
377
|
+
const client = new oClientNode({
|
|
378
|
+
address: new oNodeAddress('o://client'),
|
|
379
|
+
leader: leaderAddress
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// WebSocket-only node (browser-compatible)
|
|
383
|
+
import { oWebSocketNode } from '@olane/o-node';
|
|
384
|
+
|
|
385
|
+
const wsNode = new oWebSocketNode({
|
|
386
|
+
address: new oNodeAddress('o://ws-agent'),
|
|
387
|
+
leader: leaderAddress
|
|
388
|
+
});
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## Advanced Usage
|
|
392
|
+
|
|
393
|
+
### Custom Network Configuration
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
import { oServerNode } from '@olane/o-node';
|
|
397
|
+
import { tcp, webSockets } from '@olane/o-config';
|
|
398
|
+
|
|
399
|
+
const agent = new oServerNode({
|
|
400
|
+
address: new oNodeAddress('o://custom'),
|
|
401
|
+
type: NodeType.AGENT,
|
|
402
|
+
leader: leaderAddress,
|
|
403
|
+
parent: parentAddress,
|
|
404
|
+
network: {
|
|
405
|
+
// Custom listeners
|
|
406
|
+
listeners: [
|
|
407
|
+
'/ip4/0.0.0.0/tcp/4001',
|
|
408
|
+
'/ip4/0.0.0.0/tcp/4002/ws'
|
|
409
|
+
],
|
|
410
|
+
|
|
411
|
+
// Custom transports
|
|
412
|
+
transports: [tcp(), webSockets()],
|
|
413
|
+
|
|
414
|
+
// Connection management
|
|
415
|
+
connectionManager: {
|
|
416
|
+
minConnections: 5,
|
|
417
|
+
maxConnections: 50,
|
|
418
|
+
pollInterval: 2000,
|
|
419
|
+
autoDialInterval: 10000,
|
|
420
|
+
dialTimeout: 30000
|
|
421
|
+
},
|
|
422
|
+
|
|
423
|
+
// Peer discovery
|
|
424
|
+
peerDiscovery: [
|
|
425
|
+
bootstrap({
|
|
426
|
+
list: ['/dnsaddr/bootstrap.libp2p.io/p2p/...']
|
|
427
|
+
})
|
|
428
|
+
]
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
await agent.start();
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Custom Connection Gating
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
const agent = new oServerNode({
|
|
439
|
+
address: new oNodeAddress('o://secure'),
|
|
440
|
+
type: NodeType.AGENT,
|
|
441
|
+
leader: leaderAddress,
|
|
442
|
+
parent: parentAddress,
|
|
443
|
+
network: {
|
|
444
|
+
connectionGater: {
|
|
445
|
+
// Who can connect to us?
|
|
446
|
+
denyInboundEncryptedConnection: (peerId, maConn) => {
|
|
447
|
+
// Allow parent
|
|
448
|
+
if (peerId.toString() === parentPeerId) {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Allow whitelisted peers
|
|
453
|
+
if (whitelist.includes(peerId.toString())) {
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Deny everyone else
|
|
458
|
+
return true;
|
|
459
|
+
},
|
|
460
|
+
|
|
461
|
+
// Who can we connect to?
|
|
462
|
+
denyOutboundEncryptedConnection: (peerId, maConn) => {
|
|
463
|
+
// Custom outbound logic
|
|
464
|
+
return false; // Allow all outbound
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Network Utilities
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
import { NetworkUtils } from '@olane/o-node';
|
|
475
|
+
|
|
476
|
+
// Advertise your service on the network
|
|
477
|
+
await NetworkUtils.advertiseToNetwork(
|
|
478
|
+
address,
|
|
479
|
+
staticAddress,
|
|
480
|
+
p2pNode
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
// Find a peer on the network
|
|
484
|
+
const peer = await NetworkUtils.findPeer(p2pNode, peerId);
|
|
485
|
+
|
|
486
|
+
// Find a node by address
|
|
487
|
+
const { transports } = await NetworkUtils.findNode(p2pNode, address);
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Direct libp2p Access
|
|
491
|
+
|
|
492
|
+
When you need low-level control:
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
const agent = new oServerNode(config);
|
|
496
|
+
await agent.start();
|
|
497
|
+
|
|
498
|
+
// Access the underlying libp2p node
|
|
499
|
+
const libp2p = agent.p2pNode;
|
|
500
|
+
|
|
501
|
+
// Direct libp2p operations
|
|
502
|
+
const connections = libp2p.getConnections();
|
|
503
|
+
const peers = await libp2p.peerStore.all();
|
|
504
|
+
const protocols = libp2p.getProtocols();
|
|
505
|
+
|
|
506
|
+
// Listen for libp2p events
|
|
507
|
+
libp2p.addEventListener('peer:connect', (evt) => {
|
|
508
|
+
console.log('Peer connected:', evt.detail.toString());
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
libp2p.addEventListener('peer:disconnect', (evt) => {
|
|
512
|
+
console.log('Peer disconnected:', evt.detail.toString());
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
// Manual dialing
|
|
516
|
+
const connection = await libp2p.dial(multiaddr);
|
|
517
|
+
const stream = await connection.newStream('/my-protocol/1.0.0');
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### Implementing Custom Protocols
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
import { oServerNode } from '@olane/o-node';
|
|
524
|
+
import { pipe } from '@olane/o-config';
|
|
525
|
+
|
|
526
|
+
class CustomProtocolNode extends oServerNode {
|
|
527
|
+
async initialize(): Promise<void> {
|
|
528
|
+
await super.initialize();
|
|
529
|
+
|
|
530
|
+
// Register custom protocol handler
|
|
531
|
+
await this.p2pNode.handle('/my-custom-protocol/1.0.0', async ({ stream }) => {
|
|
532
|
+
pipe(
|
|
533
|
+
stream,
|
|
534
|
+
async function* (source) {
|
|
535
|
+
for await (const msg of source) {
|
|
536
|
+
// Process incoming messages
|
|
537
|
+
const data = new TextDecoder().decode(msg.subarray());
|
|
538
|
+
const response = await handleCustomMessage(data);
|
|
539
|
+
yield new TextEncoder().encode(response);
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
stream
|
|
543
|
+
);
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### Memory Transport for Testing
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
import { oServerNode, oNodeAddress } from '@olane/o-node';
|
|
553
|
+
|
|
554
|
+
// Create nodes with memory transport (no network required)
|
|
555
|
+
const agent1 = new oServerNode({
|
|
556
|
+
address: new oNodeAddress('o://agent1'),
|
|
557
|
+
type: NodeType.AGENT,
|
|
558
|
+
leader: null,
|
|
559
|
+
parent: null,
|
|
560
|
+
network: {
|
|
561
|
+
listeners: ['/memory/test-network']
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
const agent2 = new oServerNode({
|
|
566
|
+
address: new oNodeAddress('o://agent2'),
|
|
567
|
+
type: NodeType.AGENT,
|
|
568
|
+
leader: new oNodeAddress('o://agent1', agent1.transports),
|
|
569
|
+
parent: new oNodeAddress('o://agent1', agent1.transports)
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
await agent1.start();
|
|
573
|
+
await agent2.start();
|
|
574
|
+
|
|
575
|
+
// Agents can communicate in-memory (perfect for tests!)
|
|
576
|
+
const response = await agent1.use(agent2.address, {
|
|
577
|
+
method: 'test',
|
|
578
|
+
params: {}
|
|
579
|
+
});
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
## API Reference
|
|
583
|
+
|
|
584
|
+
### oNode Class
|
|
585
|
+
|
|
586
|
+
Extends `oToolBase` from `@olane/o-tool`, which extends `oCore` from `@olane/o-core`.
|
|
587
|
+
|
|
588
|
+
#### Constructor
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
new oNode(config: oNodeConfig)
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
#### Configuration
|
|
595
|
+
|
|
596
|
+
```typescript
|
|
597
|
+
interface oNodeConfig extends oCoreConfig {
|
|
598
|
+
leader: oNodeAddress | null; // Leader node address with transports
|
|
599
|
+
parent: oNodeAddress | null; // Parent node address with transports
|
|
600
|
+
seed?: string; // Seed for consistent peer ID
|
|
601
|
+
network?: Libp2pConfig; // libp2p configuration
|
|
602
|
+
}
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
#### Properties
|
|
606
|
+
|
|
607
|
+
| Property | Type | Description |
|
|
608
|
+
|----------|------|-------------|
|
|
609
|
+
| `p2pNode` | `Libp2p` | Underlying libp2p node instance |
|
|
610
|
+
| `peerId` | `PeerId` | This node's libp2p peer ID |
|
|
611
|
+
| `transports` | `oNodeTransport[]` | Available network transports |
|
|
612
|
+
| `address` | `oNodeAddress` | Full hierarchical address |
|
|
613
|
+
| `staticAddress` | `oNodeAddress` | Static (non-hierarchical) address |
|
|
614
|
+
| `leader` | `oNodeAddress \| null` | Leader node reference |
|
|
615
|
+
| `hierarchyManager` | `oNodeHierarchyManager` | Hierarchy management |
|
|
616
|
+
|
|
617
|
+
#### Methods
|
|
618
|
+
|
|
619
|
+
| Method | Purpose | Returns |
|
|
620
|
+
|--------|---------|---------|
|
|
621
|
+
| `async start()` | Start the node and join network | `Promise<void>` |
|
|
622
|
+
| `async stop()` | Stop the node gracefully | `Promise<void>` |
|
|
623
|
+
| `async initialize()` | Initialize libp2p and connections | `Promise<void>` |
|
|
624
|
+
| `async register()` | Register with leader node | `Promise<void>` |
|
|
625
|
+
| `async unregister()` | Unregister from leader | `Promise<void>` |
|
|
626
|
+
| `async connect(nextHop, target)` | Connect to another node | `Promise<oNodeConnection>` |
|
|
627
|
+
| `configureTransports()` | Configure libp2p transports | `any[]` |
|
|
628
|
+
|
|
629
|
+
### oNodeAddress Class
|
|
630
|
+
|
|
631
|
+
Extends `oAddress` from `@olane/o-core` with libp2p transport support.
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
// Create with transports
|
|
635
|
+
const address = new oNodeAddress(
|
|
636
|
+
'o://my-agent',
|
|
637
|
+
[transport1, transport2]
|
|
638
|
+
);
|
|
639
|
+
|
|
640
|
+
// Get libp2p-specific transports
|
|
641
|
+
const libp2pTransports = address.libp2pTransports;
|
|
642
|
+
|
|
643
|
+
// Convert to multiaddresses
|
|
644
|
+
const multiaddrs = libp2pTransports.map(t => t.toMultiaddr());
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### oNodeConnection Class
|
|
648
|
+
|
|
649
|
+
Extends `oConnection` from `@olane/o-core` with libp2p stream support.
|
|
650
|
+
|
|
651
|
+
```typescript
|
|
652
|
+
// Connection uses libp2p streams
|
|
653
|
+
class oNodeConnection extends oConnection {
|
|
654
|
+
protected p2pConnection: Connection;
|
|
655
|
+
|
|
656
|
+
async transmit(request: oRequest): Promise<oResponse> {
|
|
657
|
+
// Creates new stream, sends request, waits for response
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### oNodeRouter Class
|
|
663
|
+
|
|
664
|
+
Extends `oRouter` from `@olane/o-core` with libp2p routing.
|
|
665
|
+
|
|
666
|
+
```typescript
|
|
667
|
+
class oNodeRouter extends oRouter {
|
|
668
|
+
async translate(address, node): Promise<RouteResponse> {
|
|
669
|
+
// Resolves address to next hop with libp2p transports
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
isInternal(address, node): boolean {
|
|
673
|
+
// Determines if address is in local network
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
## Network Architecture Patterns
|
|
679
|
+
|
|
680
|
+
### Hub-and-Spoke (Star) Network
|
|
681
|
+
|
|
682
|
+
Best for: Centralized control, simple management
|
|
683
|
+
|
|
684
|
+
```typescript
|
|
685
|
+
// Leader (hub)
|
|
686
|
+
const leader = new oServerNode({
|
|
687
|
+
address: new oNodeAddress('o://leader'),
|
|
688
|
+
type: NodeType.LEADER,
|
|
689
|
+
leader: null,
|
|
690
|
+
parent: null
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
await leader.start();
|
|
694
|
+
|
|
695
|
+
// Spokes (all connect to leader)
|
|
696
|
+
const agents = await Promise.all([
|
|
697
|
+
createAgent('o://agent1', leader.transports),
|
|
698
|
+
createAgent('o://agent2', leader.transports),
|
|
699
|
+
createAgent('o://agent3', leader.transports)
|
|
700
|
+
]);
|
|
701
|
+
|
|
702
|
+
// All communication routes through leader
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
### Hierarchical Network
|
|
706
|
+
|
|
707
|
+
Best for: Large-scale deployments, organizational structure
|
|
708
|
+
|
|
709
|
+
```typescript
|
|
710
|
+
// Root leader
|
|
711
|
+
const root = await createLeader('o://company');
|
|
712
|
+
|
|
713
|
+
// Department leaders
|
|
714
|
+
const finance = await createAgent('o://company/finance', root);
|
|
715
|
+
const engineering = await createAgent('o://company/engineering', root);
|
|
716
|
+
|
|
717
|
+
// Team agents
|
|
718
|
+
const financeTeam1 = await createAgent('o://company/finance/accounting', finance);
|
|
719
|
+
const financeTeam2 = await createAgent('o://company/finance/payroll', finance);
|
|
720
|
+
|
|
721
|
+
// Agents inherit hierarchy automatically
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
### Mesh Network
|
|
725
|
+
|
|
726
|
+
Best for: High availability, redundancy
|
|
727
|
+
|
|
728
|
+
```typescript
|
|
729
|
+
// All agents connect to multiple peers
|
|
730
|
+
const agents = await Promise.all([
|
|
731
|
+
createAgent('o://agent1'),
|
|
732
|
+
createAgent('o://agent2'),
|
|
733
|
+
createAgent('o://agent3')
|
|
734
|
+
]);
|
|
735
|
+
|
|
736
|
+
// Configure each agent to know about all others
|
|
737
|
+
// libp2p will handle mesh routing automatically
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
## Best Practices
|
|
741
|
+
|
|
742
|
+
### 1. Always Use Seeds in Production
|
|
743
|
+
|
|
744
|
+
```typescript
|
|
745
|
+
// ✅ Good - Consistent peer ID
|
|
746
|
+
const agent = new oServerNode({
|
|
747
|
+
address: new oNodeAddress('o://service'),
|
|
748
|
+
seed: process.env.AGENT_SEED, // From secure source
|
|
749
|
+
leader: leaderAddress
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
// ❌ Bad - Peer ID changes on every restart
|
|
753
|
+
const agent = new oServerNode({
|
|
754
|
+
address: new oNodeAddress('o://service'),
|
|
755
|
+
// No seed - temporary peer ID
|
|
756
|
+
leader: leaderAddress
|
|
757
|
+
});
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
### 2. Handle Network Events
|
|
761
|
+
|
|
762
|
+
```typescript
|
|
763
|
+
const agent = new oServerNode(config);
|
|
764
|
+
await agent.start();
|
|
765
|
+
|
|
766
|
+
// Monitor connection health
|
|
767
|
+
agent.p2pNode.addEventListener('peer:connect', (evt) => {
|
|
768
|
+
console.log('Connected to:', evt.detail.toString());
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
agent.p2pNode.addEventListener('peer:disconnect', (evt) => {
|
|
772
|
+
console.warn('Disconnected from:', evt.detail.toString());
|
|
773
|
+
// Implement reconnection logic if needed
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
agent.p2pNode.addEventListener('connection:prune', () => {
|
|
777
|
+
console.log('Pruned inactive connections');
|
|
778
|
+
});
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
### 3. Configure Connection Limits
|
|
782
|
+
|
|
783
|
+
```typescript
|
|
784
|
+
const agent = new oServerNode({
|
|
785
|
+
address: new oNodeAddress('o://service'),
|
|
786
|
+
leader: leaderAddress,
|
|
787
|
+
network: {
|
|
788
|
+
connectionManager: {
|
|
789
|
+
minConnections: 10, // Stay connected to at least 10 peers
|
|
790
|
+
maxConnections: 100, // Don't exceed 100 connections
|
|
791
|
+
pollInterval: 2000, // Check every 2 seconds
|
|
792
|
+
autoDialInterval: 10000 // Dial new peers every 10 seconds
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
});
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
### 4. Implement Graceful Shutdown
|
|
799
|
+
|
|
800
|
+
```typescript
|
|
801
|
+
import { setupGracefulShutdown } from '@olane/o-core';
|
|
802
|
+
|
|
803
|
+
const agent = new oServerNode(config);
|
|
804
|
+
await agent.start();
|
|
805
|
+
|
|
806
|
+
setupGracefulShutdown(async () => {
|
|
807
|
+
console.log('Shutting down gracefully...');
|
|
808
|
+
|
|
809
|
+
// Unregister from network
|
|
810
|
+
await agent.unregister();
|
|
811
|
+
|
|
812
|
+
// Close connections
|
|
813
|
+
await agent.stop();
|
|
814
|
+
|
|
815
|
+
console.log('Shutdown complete');
|
|
816
|
+
});
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
### 5. Use Memory Transport for Tests
|
|
820
|
+
|
|
821
|
+
```typescript
|
|
822
|
+
// test.spec.ts
|
|
823
|
+
describe('Agent Communication', () => {
|
|
824
|
+
it('should communicate between agents', async () => {
|
|
825
|
+
const agent1 = new oServerNode({
|
|
826
|
+
address: new oNodeAddress('o://test1'),
|
|
827
|
+
network: { listeners: ['/memory/test'] }
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
const agent2 = new oServerNode({
|
|
831
|
+
address: new oNodeAddress('o://test2'),
|
|
832
|
+
leader: new oNodeAddress('o://test1', agent1.transports)
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
await agent1.start();
|
|
836
|
+
await agent2.start();
|
|
837
|
+
|
|
838
|
+
const response = await agent1.use(agent2.address, {
|
|
839
|
+
method: 'test'
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
expect(response.result).toBeDefined();
|
|
843
|
+
|
|
844
|
+
await agent1.stop();
|
|
845
|
+
await agent2.stop();
|
|
846
|
+
});
|
|
847
|
+
});
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
### 6. Monitor Network Health
|
|
851
|
+
|
|
852
|
+
```typescript
|
|
853
|
+
class MonitoredNode extends oServerNode {
|
|
854
|
+
private healthCheckInterval?: NodeJS.Timeout;
|
|
855
|
+
|
|
856
|
+
async start(): Promise<void> {
|
|
857
|
+
await super.start();
|
|
858
|
+
|
|
859
|
+
// Start health monitoring
|
|
860
|
+
this.healthCheckInterval = setInterval(() => {
|
|
861
|
+
const connections = this.p2pNode.getConnections();
|
|
862
|
+
const peers = this.p2pNode.getPeers();
|
|
863
|
+
|
|
864
|
+
console.log('Health Check:', {
|
|
865
|
+
connections: connections.length,
|
|
866
|
+
peers: peers.length,
|
|
867
|
+
protocols: this.p2pNode.getProtocols()
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
// Alert if disconnected
|
|
871
|
+
if (connections.length === 0 && this.leader) {
|
|
872
|
+
console.warn('No active connections! Attempting reconnect...');
|
|
873
|
+
this.reconnectToLeader();
|
|
874
|
+
}
|
|
875
|
+
}, 30000); // Every 30 seconds
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
async stop(): Promise<void> {
|
|
879
|
+
if (this.healthCheckInterval) {
|
|
880
|
+
clearInterval(this.healthCheckInterval);
|
|
881
|
+
}
|
|
882
|
+
await super.stop();
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
private async reconnectToLeader(): Promise<void> {
|
|
886
|
+
if (!this.leader) return;
|
|
887
|
+
|
|
888
|
+
try {
|
|
889
|
+
await this.register();
|
|
890
|
+
console.log('Reconnected to leader');
|
|
891
|
+
} catch (error) {
|
|
892
|
+
console.error('Failed to reconnect:', error);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
## Performance Considerations
|
|
899
|
+
|
|
900
|
+
1. **Connection Pooling** - o-node manages connection reuse automatically
|
|
901
|
+
2. **Stream Multiplexing** - Multiple requests over single connection
|
|
902
|
+
3. **DHT Caching** - Peer information is cached locally
|
|
903
|
+
4. **NAT Traversal** - Automatic hole-punching and relay fallback
|
|
904
|
+
5. **Concurrent Requests** - Handle multiple requests simultaneously
|
|
905
|
+
|
|
906
|
+
## Troubleshooting
|
|
907
|
+
|
|
908
|
+
### Connection Issues
|
|
909
|
+
|
|
910
|
+
```typescript
|
|
911
|
+
// Enable debug logging
|
|
912
|
+
import debug from 'debug';
|
|
913
|
+
|
|
914
|
+
debug.enable('libp2p:*');
|
|
915
|
+
debug.enable('o-protocol:*');
|
|
916
|
+
|
|
917
|
+
const agent = new oServerNode(config);
|
|
918
|
+
await agent.start();
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
### "Can not dial self" Error
|
|
922
|
+
|
|
923
|
+
```typescript
|
|
924
|
+
// This means you're trying to connect to your own address
|
|
925
|
+
// Make sure leader/parent addresses have the correct transports
|
|
926
|
+
|
|
927
|
+
// ❌ Wrong
|
|
928
|
+
const agent = new oServerNode({
|
|
929
|
+
address: new oNodeAddress('o://agent'),
|
|
930
|
+
leader: new oNodeAddress('o://leader') // Missing transports!
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
// ✅ Correct
|
|
934
|
+
const agent = new oServerNode({
|
|
935
|
+
address: new oNodeAddress('o://agent'),
|
|
936
|
+
leader: new oNodeAddress('o://leader', leaderTransports)
|
|
937
|
+
});
|
|
938
|
+
```
|
|
939
|
+
|
|
940
|
+
### Peer Discovery Issues
|
|
941
|
+
|
|
942
|
+
```typescript
|
|
943
|
+
// Add bootstrap nodes for better discovery
|
|
944
|
+
const agent = new oServerNode({
|
|
945
|
+
address: new oNodeAddress('o://agent'),
|
|
946
|
+
leader: leaderAddress,
|
|
947
|
+
network: {
|
|
948
|
+
peerDiscovery: [
|
|
949
|
+
bootstrap({
|
|
950
|
+
list: [
|
|
951
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
|
952
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa'
|
|
953
|
+
]
|
|
954
|
+
})
|
|
955
|
+
]
|
|
956
|
+
}
|
|
957
|
+
});
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
## Testing
|
|
961
|
+
|
|
962
|
+
```bash
|
|
963
|
+
# Run tests
|
|
964
|
+
npm test
|
|
965
|
+
|
|
966
|
+
# Run tests in Node.js
|
|
967
|
+
npm run test:node
|
|
968
|
+
|
|
969
|
+
# Run tests in browser
|
|
970
|
+
npm run test:browser
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
## Development
|
|
974
|
+
|
|
975
|
+
```bash
|
|
976
|
+
# Install dependencies
|
|
977
|
+
npm install
|
|
978
|
+
|
|
979
|
+
# Build the package
|
|
980
|
+
npm run build
|
|
981
|
+
|
|
982
|
+
# Run in development mode with debug output
|
|
983
|
+
npm run dev
|
|
984
|
+
|
|
985
|
+
# Update o-core dependency
|
|
986
|
+
npm run update:lib
|
|
987
|
+
|
|
988
|
+
# Lint the code
|
|
989
|
+
npm run lint
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
## Related Packages
|
|
993
|
+
|
|
994
|
+
- `@olane/o-core` - Abstract agent runtime (this implements it)
|
|
995
|
+
- `@olane/o-config` - libp2p configuration and utilities
|
|
996
|
+
- `@olane/o-protocol` - Protocol definitions and types
|
|
997
|
+
- `@olane/o-tool` - Tool system for agent capabilities
|
|
998
|
+
- `@olane/o-network-cli` - CLI for managing agent networks
|
|
999
|
+
|
|
1000
|
+
## Documentation
|
|
1001
|
+
|
|
1002
|
+
- [o-core Documentation](../o-core/README.md) - Understand the abstract runtime
|
|
1003
|
+
- [o-core Router System](../o-core/src/router/README.md) - Deep dive into routing
|
|
1004
|
+
- [o-core Connection System](../o-core/src/connection/README.md) - IPC layer details
|
|
1005
|
+
- [Full Documentation](https://olane.com/docs)
|
|
1006
|
+
- [libp2p Documentation](https://docs.libp2p.io/)
|
|
1007
|
+
|
|
1008
|
+
## Support
|
|
1009
|
+
|
|
1010
|
+
- [GitHub Issues](https://github.com/olane-labs/olane/issues)
|
|
1011
|
+
- [Community Forum](https://olane.com/community)
|
|
1012
|
+
- [Email Support](mailto:support@olane.com)
|
|
1013
|
+
|
|
1014
|
+
## Contributing
|
|
1015
|
+
|
|
1016
|
+
We welcome contributions! Please see our [Contributing Guide](../../CONTRIBUTING.md) for details.
|
|
1017
|
+
|
|
1018
|
+
## License
|
|
1019
|
+
|
|
1020
|
+
ISC © Olane Inc.
|
|
1021
|
+
|
|
1022
|
+
---
|
|
1023
|
+
|
|
1024
|
+
**Part of the Olane OS ecosystem** - The production distribution layer where you build tool nodes that AI agents use. An agentic operating system where AI agents are the users, tool nodes are the applications, and Olane provides the runtime.
|