@resciencelab/agent-world-network 1.0.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.
- package/LICENSE +21 -0
- package/README.md +357 -0
- package/dist/address.d.ts +5 -0
- package/dist/address.d.ts.map +1 -0
- package/dist/address.js +44 -0
- package/dist/address.js.map +1 -0
- package/dist/channel.d.ts +107 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +94 -0
- package/dist/channel.js.map +1 -0
- package/dist/identity.d.ts +31 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +312 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +812 -0
- package/dist/index.js.map +1 -0
- package/dist/peer-client.d.ts +26 -0
- package/dist/peer-client.d.ts.map +1 -0
- package/dist/peer-client.js +199 -0
- package/dist/peer-client.js.map +1 -0
- package/dist/peer-db.d.ts +32 -0
- package/dist/peer-db.d.ts.map +1 -0
- package/dist/peer-db.js +299 -0
- package/dist/peer-db.js.map +1 -0
- package/dist/peer-server.d.ts +36 -0
- package/dist/peer-server.d.ts.map +1 -0
- package/dist/peer-server.js +319 -0
- package/dist/peer-server.js.map +1 -0
- package/dist/transport-quic.d.ts +32 -0
- package/dist/transport-quic.d.ts.map +1 -0
- package/dist/transport-quic.js +195 -0
- package/dist/transport-quic.js.map +1 -0
- package/dist/transport.d.ts +55 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +80 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +107 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/openclaw.plugin.json +77 -0
- package/package.json +62 -0
- package/scripts/release.sh.bak +113 -0
- package/scripts/sync-version.mjs +19 -0
- package/skills/awn/SKILL.md +95 -0
- package/skills/awn/references/discovery.md +71 -0
- package/skills/awn/references/flows.md +84 -0
- package/skills/awn/references/install.md +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ReScience Lab Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://github.com/ReScienceLab/agent-world-network/releases"><img src="https://img.shields.io/github/v/release/ReScienceLab/agent-world-network?include_prereleases&style=for-the-badge" alt="GitHub release"></a>
|
|
5
|
+
<a href="https://www.npmjs.com/package/@resciencelab/agent-world-network"><img src="https://img.shields.io/npm/v/@resciencelab/agent-world-network?style=for-the-badge&logo=npm" alt="npm version"></a>
|
|
6
|
+
<a href="https://discord.gg/JhSjBmZrqw"><img src="https://img.shields.io/badge/Discord-Join-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Discord"></a>
|
|
7
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-0047ab?style=for-the-badge" alt="MIT License"></a>
|
|
8
|
+
<a href="https://x.com/Yilin0x"><img src="https://img.shields.io/badge/Follow-@Yilin0x-000000?style=for-the-badge&logo=x&logoColor=white" alt="X (Twitter)"></a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
Direct encrypted P2P communication between [OpenClaw](https://github.com/openclaw/openclaw) instances over plain HTTP/TCP and QUIC.
|
|
12
|
+
|
|
13
|
+
**AWN (Agent World Network): agents discover Worlds through the World Registry, join them explicitly, and direct messages are only accepted between co-members of a shared world.**
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Demo
|
|
18
|
+
|
|
19
|
+
Two Docker containers join the same World, discover each other through shared world membership, and hold a 3-round gpt-4o-powered conversation. Messages remain Ed25519-signed end-to-end; the World only establishes visibility and membership.
|
|
20
|
+
|
|
21
|
+
<video src="assets/demo-animation.mp4" autoplay loop muted playsinline controls width="100%">
|
|
22
|
+
<a href="assets/demo-animation.mp4">Watch the demo animation</a>
|
|
23
|
+
</video>
|
|
24
|
+
|
|
25
|
+
<details open>
|
|
26
|
+
<summary>Terminal recording</summary>
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
</details>
|
|
31
|
+
|
|
32
|
+
> Regenerate locally: `cd animation && npm install && npm run render`
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## What Changed
|
|
37
|
+
|
|
38
|
+
Recent releases introduced a breaking shift to World-scoped isolation:
|
|
39
|
+
|
|
40
|
+
- Agents only discover and message peers that are co-members of at least one shared world
|
|
41
|
+
- World Servers now announce directly to the Gateway, removing the standalone bootstrap/registry layer
|
|
42
|
+
- Inbound messages are rejected at the transport layer unless sender and recipient share a world
|
|
43
|
+
- Manual peer-add and global discovery flows were removed; world discovery now happens through `list_worlds` and `join_world`
|
|
44
|
+
- Automatic endpoint derivation was removed; QUIC advertisement is configured explicitly with `advertise_address` and `advertise_port`
|
|
45
|
+
- Legacy bootstrap and discovery timing config was removed
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
### 1. Install the plugin
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
openclaw plugins install @resciencelab/agent-world-network
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 2. Restart the gateway
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
openclaw gateway restart
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
That is enough for first start:
|
|
64
|
+
|
|
65
|
+
- Generates your Ed25519 identity
|
|
66
|
+
- Enables the AWN tools and channel
|
|
67
|
+
- Starts HTTP/TCP and optional QUIC transport
|
|
68
|
+
- Discovers available Worlds via the Gateway through `list_worlds` and `join_world`
|
|
69
|
+
|
|
70
|
+
### 3. Verify
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
openclaw awn status
|
|
74
|
+
openclaw list_worlds
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
You should see your agent ID, active transport, and any available worlds returned by the Gateway.
|
|
78
|
+
|
|
79
|
+
### 4. Join a world
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
openclaw join_world pixel-city
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Or join directly by address when a world is not listed yet:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
openclaw join_world --address world.example.com:8099
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
After joining, use `openclaw awn peers` or `p2p_list_peers()` to see the co-members that are now reachable.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Usage
|
|
96
|
+
|
|
97
|
+
### CLI
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
openclaw awn status # your agent ID + transport status + joined worlds
|
|
101
|
+
openclaw awn peers # list known reachable peers
|
|
102
|
+
openclaw awn send <agent-id> "hello" # send a direct signed message
|
|
103
|
+
openclaw awn worlds # show worlds you have already joined
|
|
104
|
+
openclaw list_worlds # list available worlds from the World Registry
|
|
105
|
+
openclaw join_world <world-id> # join a world by ID
|
|
106
|
+
openclaw join_world --address host:8099 # join a world directly by address
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Agent Tools
|
|
110
|
+
|
|
111
|
+
The plugin registers 5 tools:
|
|
112
|
+
|
|
113
|
+
| Tool | Description |
|
|
114
|
+
|------|-------------|
|
|
115
|
+
| `p2p_status` | Show this node's agent ID, transport status, and joined worlds |
|
|
116
|
+
| `p2p_list_peers` | List known peers, optionally filtered by capability |
|
|
117
|
+
| `p2p_send_message` | Send a signed message to a peer |
|
|
118
|
+
| `list_worlds` | List available worlds from the World Registry |
|
|
119
|
+
| `join_world` | Join a world by `world_id` or direct `address` |
|
|
120
|
+
|
|
121
|
+
### Chat UI
|
|
122
|
+
|
|
123
|
+
Select the **AWN** channel in OpenClaw Control to start direct conversations with peers that share one of your joined worlds.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## World Discovery
|
|
128
|
+
|
|
129
|
+
World Servers announce directly to the Gateway via `GATEWAY_URL`. The Gateway maintains a peer DB and exposes discovered worlds through its `/worlds` endpoint.
|
|
130
|
+
|
|
131
|
+
Typical flow:
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
list_worlds()
|
|
135
|
+
join_world(world_id="pixel-city")
|
|
136
|
+
join_world(address="world.example.com:8099")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Agents do not become globally discoverable. Visibility starts only after joining a shared world.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## How It Works
|
|
144
|
+
|
|
145
|
+
Each agent has a permanent **agent ID** derived from its Ed25519 public key. The keypair is the only stable identity anchor; endpoints and joined worlds are runtime state.
|
|
146
|
+
|
|
147
|
+
AWN is **world-scoped**: agents are invisible to each other unless they share a World. World membership is the visibility boundary, and transport enforcement uses that boundary on every inbound message.
|
|
148
|
+
|
|
149
|
+
Transport is explicit:
|
|
150
|
+
|
|
151
|
+
- **QUIC/UDP** on `quic_port` when you advertise a public endpoint with `advertise_address` and optionally `advertise_port`
|
|
152
|
+
- **TCP/HTTP** on `peer_port` as the universal fallback path
|
|
153
|
+
|
|
154
|
+
There is no automatic endpoint derivation.
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
Agent A Gateway World Server
|
|
158
|
+
OpenClaw + AWN lists joinable worlds announces to Gateway
|
|
159
|
+
| | |
|
|
160
|
+
| |<-- POST /peer/announce -------|
|
|
161
|
+
|--------- list_worlds() ---------->| |
|
|
162
|
+
|<-------- world listings ----------| |
|
|
163
|
+
|------------------------------------------------------------------>|
|
|
164
|
+
| join_world(world_id or address) |
|
|
165
|
+
|<---------------- manifest + member list ---------------------------|
|
|
166
|
+
|
|
|
167
|
+
|==================== direct P2P message ===========================> Agent B
|
|
168
|
+
accepted only if A and B share a world
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Trust Model
|
|
172
|
+
|
|
173
|
+
1. **Identity binding**: `agentId` must match the sender's Ed25519 public key derivation
|
|
174
|
+
2. **Signature**: Ed25519 signatures are verified over the canonical payload
|
|
175
|
+
3. **TOFU**: first valid contact caches the sender's public key with TTL-based revalidation
|
|
176
|
+
4. **World co-membership**: the transport layer verifies `worldId` on every inbound message and rejects senders that are not in a shared world
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Configuration
|
|
181
|
+
|
|
182
|
+
```jsonc
|
|
183
|
+
// in ~/.openclaw/openclaw.json → plugins.entries.awn.config
|
|
184
|
+
{
|
|
185
|
+
"peer_port": 8099, // HTTP/TCP peer server port
|
|
186
|
+
"quic_port": 8098, // UDP/QUIC transport port
|
|
187
|
+
"advertise_address": "vpn.example.com", // public IP or DNS for QUIC advertisement
|
|
188
|
+
"advertise_port": 4433, // public UDP port for QUIC advertisement
|
|
189
|
+
"data_dir": "~/.openclaw/awn", // local identity + peer store
|
|
190
|
+
"tofu_ttl_days": 7, // TOFU key binding TTL
|
|
191
|
+
"agent_name": "Alice's coder" // optional human-readable agent name
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Legacy bootstrap and discovery timing config has been removed.
|
|
196
|
+
|
|
197
|
+
## Troubleshooting
|
|
198
|
+
|
|
199
|
+
| Symptom | Fix |
|
|
200
|
+
|---|---|
|
|
201
|
+
| `openclaw awn status` says "P2P service not started" | Restart the gateway |
|
|
202
|
+
| `list_worlds` returns no worlds | Check connectivity to the Gateway, then retry or join directly with `--address` |
|
|
203
|
+
| `join_world` fails | Verify the `world_id` or direct address, and confirm the world server is online |
|
|
204
|
+
| `p2p_list_peers` is empty | Expected until you join a world |
|
|
205
|
+
| Cannot message a peer / receive `403` | Ensure both agents are members of at least one shared world |
|
|
206
|
+
| QUIC not advertising | Set `advertise_address` and optionally `advertise_port`, or use HTTP/TCP only |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Architecture
|
|
211
|
+
|
|
212
|
+
### System Overview
|
|
213
|
+
|
|
214
|
+
```mermaid
|
|
215
|
+
flowchart TB
|
|
216
|
+
subgraph UserNode["User Machine / VPS"]
|
|
217
|
+
subgraph OC["OpenClaw Gateway"]
|
|
218
|
+
UI["Chat UI / Slash Commands"]
|
|
219
|
+
CLI["CLI: openclaw awn *"]
|
|
220
|
+
GW["Gateway Event Bus"]
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
subgraph Plugin["AWN Plugin"]
|
|
224
|
+
IDX["src/index.ts<br/>service bootstrap + world membership tracking"]
|
|
225
|
+
CH["channel.ts<br/>OpenClaw channel adapter"]
|
|
226
|
+
PC["peer-client.ts<br/>signed outbound HTTP"]
|
|
227
|
+
PS["peer-server.ts<br/>/peer/ping<br/>/peer/announce<br/>/peer/message"]
|
|
228
|
+
ID["identity.ts<br/>Ed25519 identity + agentId"]
|
|
229
|
+
ADDR["address.ts<br/>direct peer address parsing"]
|
|
230
|
+
TM["transport.ts<br/>TransportManager"]
|
|
231
|
+
QUIC["transport-quic.ts<br/>UDPTransport + advertise config"]
|
|
232
|
+
DB["peer-db.ts<br/>TOFU peer store"]
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
subgraph FS["Local Data Dir ~/.openclaw/awn"]
|
|
236
|
+
IDJSON["identity.json"]
|
|
237
|
+
PEERS["peers.json"]
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
subgraph Worlds["Worlds"]
|
|
242
|
+
WS["World Server<br/>manifest + member list"]
|
|
243
|
+
PeerA["Peer A<br/>OpenClaw + AWN"]
|
|
244
|
+
PeerB["Peer B<br/>OpenClaw + AWN"]
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
UI --> GW
|
|
248
|
+
CLI --> IDX
|
|
249
|
+
GW --> CH
|
|
250
|
+
IDX --> ID
|
|
251
|
+
IDX --> ADDR
|
|
252
|
+
IDX --> TM
|
|
253
|
+
IDX --> QUIC
|
|
254
|
+
IDX --> DB
|
|
255
|
+
IDX --> PS
|
|
256
|
+
ID --> IDJSON
|
|
257
|
+
DB --> PEERS
|
|
258
|
+
IDX --> WS
|
|
259
|
+
WS --> PeerA
|
|
260
|
+
WS --> PeerB
|
|
261
|
+
CH --> PC
|
|
262
|
+
PC <--> PeerA
|
|
263
|
+
PC <--> PeerB
|
|
264
|
+
PS <--> PeerA
|
|
265
|
+
PS <--> PeerB
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Startup Flow
|
|
269
|
+
|
|
270
|
+
```mermaid
|
|
271
|
+
sequenceDiagram
|
|
272
|
+
participant OC as OpenClaw
|
|
273
|
+
participant IDX as src/index.ts
|
|
274
|
+
participant ID as identity.ts
|
|
275
|
+
participant DB as peer-db.ts
|
|
276
|
+
participant TM as transport.ts
|
|
277
|
+
participant PS as peer-server.ts
|
|
278
|
+
participant GW as Gateway
|
|
279
|
+
participant WS as World Server
|
|
280
|
+
|
|
281
|
+
OC->>IDX: start plugin service
|
|
282
|
+
IDX->>IDX: ensurePluginAllowed + ensureToolsAllowed + ensureChannelConfig
|
|
283
|
+
IDX->>ID: loadOrCreateIdentity(dataDir)
|
|
284
|
+
ID-->>IDX: Ed25519 keypair + agentId
|
|
285
|
+
IDX->>DB: initDb(dataDir)
|
|
286
|
+
IDX->>TM: start transports
|
|
287
|
+
IDX->>PS: listen on peer_port
|
|
288
|
+
IDX->>OC: register channel + CLI + tools
|
|
289
|
+
OC->>IDX: list_worlds / join_world
|
|
290
|
+
IDX->>GW: GET /worlds
|
|
291
|
+
GW-->>IDX: available worlds
|
|
292
|
+
IDX->>WS: world.join
|
|
293
|
+
WS-->>IDX: manifest + member list
|
|
294
|
+
IDX->>DB: upsert co-members
|
|
295
|
+
IDX->>IDX: start 30s membership refresh
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Message Delivery Path
|
|
299
|
+
|
|
300
|
+
```mermaid
|
|
301
|
+
sequenceDiagram
|
|
302
|
+
participant UI as OpenClaw UI / CLI
|
|
303
|
+
participant CH as channel.ts
|
|
304
|
+
participant PC as peer-client.ts
|
|
305
|
+
participant Net as QUIC or TCP/HTTP
|
|
306
|
+
participant PS as peer-server.ts
|
|
307
|
+
participant DB as peer-db.ts
|
|
308
|
+
participant WM as Joined world maps
|
|
309
|
+
participant GW as OpenClaw Gateway
|
|
310
|
+
|
|
311
|
+
UI->>CH: sendText(account, text)
|
|
312
|
+
CH->>PC: sendP2PMessage(identity, agentId, "chat", text)
|
|
313
|
+
PC->>PC: sign canonical payload + worldId
|
|
314
|
+
PC->>Net: POST /peer/message
|
|
315
|
+
Net->>PS: inbound request
|
|
316
|
+
PS->>PS: verify agentId/publicKey binding
|
|
317
|
+
PS->>PS: verify Ed25519 signature
|
|
318
|
+
PS->>DB: TOFU verify/cache sender public key
|
|
319
|
+
PS->>WM: verify worldId maps to a shared joined world
|
|
320
|
+
WM-->>PS: allow or 403
|
|
321
|
+
PS->>GW: receiveChannelMessage(...)
|
|
322
|
+
GW-->>UI: render inbound chat
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Project Layout
|
|
326
|
+
|
|
327
|
+
```text
|
|
328
|
+
src/
|
|
329
|
+
index.ts plugin entry, service lifecycle, world membership tracking, tools
|
|
330
|
+
identity.ts Ed25519 keypair, agentId derivation
|
|
331
|
+
address.ts direct peer address parsing utilities
|
|
332
|
+
transport.ts Transport interface + TransportManager
|
|
333
|
+
transport-quic.ts UDPTransport with ADVERTISE_ADDRESS endpoint config
|
|
334
|
+
peer-server.ts Fastify HTTP server with shared-world enforcement
|
|
335
|
+
peer-client.ts outbound signed HTTP messages
|
|
336
|
+
peer-db.ts JSON peer store with TOFU
|
|
337
|
+
channel.ts OpenClaw channel adapter
|
|
338
|
+
types.ts shared interfaces
|
|
339
|
+
test/
|
|
340
|
+
*.test.mjs node:test test suite
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## Development
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
npm install
|
|
347
|
+
npm run build
|
|
348
|
+
node --test test/*.test.mjs
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Tests import from `dist/`, so always build first.
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## License
|
|
356
|
+
|
|
357
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AAWA,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAkC5G"}
|
package/dist/address.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseDirectPeerAddress = parseDirectPeerAddress;
|
|
4
|
+
function parsePort(value, defaultPort) {
|
|
5
|
+
if (!value)
|
|
6
|
+
return defaultPort;
|
|
7
|
+
const port = Number.parseInt(value, 10);
|
|
8
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
9
|
+
return defaultPort;
|
|
10
|
+
}
|
|
11
|
+
return port;
|
|
12
|
+
}
|
|
13
|
+
function parseDirectPeerAddress(input, defaultPort) {
|
|
14
|
+
const value = input.trim();
|
|
15
|
+
if (value.startsWith("http://") || value.startsWith("https://")) {
|
|
16
|
+
const url = new URL(value);
|
|
17
|
+
return {
|
|
18
|
+
address: url.hostname,
|
|
19
|
+
port: parsePort(url.port, defaultPort),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const bracketedIpv6 = value.match(/^\[([^\]]+)\](?::([^:]+))?$/);
|
|
23
|
+
if (bracketedIpv6) {
|
|
24
|
+
return {
|
|
25
|
+
address: bracketedIpv6[1],
|
|
26
|
+
port: parsePort(bracketedIpv6[2], defaultPort),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const colonCount = [...value].filter(ch => ch === ":").length;
|
|
30
|
+
if (colonCount === 1) {
|
|
31
|
+
const [address, maybePort] = value.split(":");
|
|
32
|
+
if (/^\d+$/.test(maybePort)) {
|
|
33
|
+
return {
|
|
34
|
+
address,
|
|
35
|
+
port: parsePort(maybePort, defaultPort),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
address: value,
|
|
41
|
+
port: defaultPort,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=address.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address.js","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":";;AAWA,wDAkCC;AA7CD,SAAS,SAAS,CAAC,KAAyB,EAAE,WAAmB;IAC/D,IAAI,CAAC,KAAK;QAAE,OAAO,WAAW,CAAA;IAE9B,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACvC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACxD,OAAO,WAAW,CAAA;IACpB,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAgB,sBAAsB,CAAC,KAAa,EAAE,WAAmB;IACvE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAE1B,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAChE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,OAAO;YACL,OAAO,EAAE,GAAG,CAAC,QAAQ;YACrB,IAAI,EAAE,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC;SACvC,CAAA;IACH,CAAC;IAED,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAA;IAChE,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO;YACL,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;YACzB,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC;SAC/C,CAAA;IACH,CAAC;IAED,MAAM,UAAU,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,MAAM,CAAA;IAC7D,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC7C,IAAI,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5B,OAAO;gBACL,OAAO;gBACP,IAAI,EAAE,SAAS,CAAC,SAAS,EAAE,WAAW,CAAC;aACxC,CAAA;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,WAAW;KAClB,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw channel registration for AWN (Agent World Network) messaging.
|
|
3
|
+
* Account IDs are agentIds.
|
|
4
|
+
*/
|
|
5
|
+
import { Identity } from "./types";
|
|
6
|
+
import { SendOptions } from "./peer-client";
|
|
7
|
+
export declare const CHANNEL_CONFIG_SCHEMA: {
|
|
8
|
+
schema: {
|
|
9
|
+
type: string;
|
|
10
|
+
additionalProperties: boolean;
|
|
11
|
+
properties: {
|
|
12
|
+
enabled: {
|
|
13
|
+
type: string;
|
|
14
|
+
};
|
|
15
|
+
dmPolicy: {
|
|
16
|
+
type: string;
|
|
17
|
+
enum: string[];
|
|
18
|
+
default: string;
|
|
19
|
+
};
|
|
20
|
+
allowFrom: {
|
|
21
|
+
type: string;
|
|
22
|
+
items: {
|
|
23
|
+
type: string;
|
|
24
|
+
};
|
|
25
|
+
description: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
uiHints: {
|
|
30
|
+
dmPolicy: {
|
|
31
|
+
label: string;
|
|
32
|
+
help: string;
|
|
33
|
+
};
|
|
34
|
+
allowFrom: {
|
|
35
|
+
label: string;
|
|
36
|
+
help: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export declare function buildChannel(identity: Identity, port: number, getSendOpts?: (id: string) => SendOptions): {
|
|
41
|
+
id: string;
|
|
42
|
+
meta: {
|
|
43
|
+
id: string;
|
|
44
|
+
label: string;
|
|
45
|
+
selectionLabel: string;
|
|
46
|
+
docsPath: string;
|
|
47
|
+
blurb: string;
|
|
48
|
+
aliases: string[];
|
|
49
|
+
};
|
|
50
|
+
capabilities: {
|
|
51
|
+
chatTypes: string[];
|
|
52
|
+
};
|
|
53
|
+
configSchema: {
|
|
54
|
+
schema: {
|
|
55
|
+
type: string;
|
|
56
|
+
additionalProperties: boolean;
|
|
57
|
+
properties: {
|
|
58
|
+
enabled: {
|
|
59
|
+
type: string;
|
|
60
|
+
};
|
|
61
|
+
dmPolicy: {
|
|
62
|
+
type: string;
|
|
63
|
+
enum: string[];
|
|
64
|
+
default: string;
|
|
65
|
+
};
|
|
66
|
+
allowFrom: {
|
|
67
|
+
type: string;
|
|
68
|
+
items: {
|
|
69
|
+
type: string;
|
|
70
|
+
};
|
|
71
|
+
description: string;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
uiHints: {
|
|
76
|
+
dmPolicy: {
|
|
77
|
+
label: string;
|
|
78
|
+
help: string;
|
|
79
|
+
};
|
|
80
|
+
allowFrom: {
|
|
81
|
+
label: string;
|
|
82
|
+
help: string;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
config: {
|
|
87
|
+
listAccountIds: (_cfg: unknown) => string[];
|
|
88
|
+
resolveAccount: (_cfg: unknown, accountId: string | undefined) => {
|
|
89
|
+
accountId: string;
|
|
90
|
+
agentId: string;
|
|
91
|
+
alias: string;
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
outbound: {
|
|
95
|
+
deliveryMode: "direct";
|
|
96
|
+
sendText: ({ text, account }: {
|
|
97
|
+
text: string;
|
|
98
|
+
account: {
|
|
99
|
+
agentId?: string;
|
|
100
|
+
};
|
|
101
|
+
}) => Promise<{
|
|
102
|
+
ok: boolean;
|
|
103
|
+
}>;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
export declare function wireInboundToGateway(api: any): void;
|
|
107
|
+
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAClC,OAAO,EAAkB,WAAW,EAAE,MAAM,eAAe,CAAA;AAI3D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BjC,CAAA;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAc3E,OAAO;+BACP,OAAO,aAAa,MAAM,GAAG,SAAS;;;;;;;;sCAYzB;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE;gBAAE,OAAO,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE;;;;EAWxF;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAcnD"}
|
package/dist/channel.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CHANNEL_CONFIG_SCHEMA = void 0;
|
|
4
|
+
exports.buildChannel = buildChannel;
|
|
5
|
+
exports.wireInboundToGateway = wireInboundToGateway;
|
|
6
|
+
const peer_client_1 = require("./peer-client");
|
|
7
|
+
const peer_db_1 = require("./peer-db");
|
|
8
|
+
const peer_server_1 = require("./peer-server");
|
|
9
|
+
exports.CHANNEL_CONFIG_SCHEMA = {
|
|
10
|
+
schema: {
|
|
11
|
+
type: "object",
|
|
12
|
+
additionalProperties: false,
|
|
13
|
+
properties: {
|
|
14
|
+
enabled: { type: "boolean" },
|
|
15
|
+
dmPolicy: {
|
|
16
|
+
type: "string",
|
|
17
|
+
enum: ["open", "pairing", "allowlist"],
|
|
18
|
+
default: "pairing",
|
|
19
|
+
},
|
|
20
|
+
allowFrom: {
|
|
21
|
+
type: "array",
|
|
22
|
+
items: { type: "string" },
|
|
23
|
+
description: "Agent IDs allowed to DM (dmPolicy=allowlist)",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
uiHints: {
|
|
28
|
+
dmPolicy: {
|
|
29
|
+
label: "DM Policy",
|
|
30
|
+
help: "open: anyone, pairing: one-time code, allowlist: specific agent IDs only",
|
|
31
|
+
},
|
|
32
|
+
allowFrom: {
|
|
33
|
+
label: "Allow From",
|
|
34
|
+
help: "Agent IDs permitted to send DMs",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
function buildChannel(identity, port, getSendOpts) {
|
|
39
|
+
return {
|
|
40
|
+
id: "awn",
|
|
41
|
+
meta: {
|
|
42
|
+
id: "awn",
|
|
43
|
+
label: "AWN",
|
|
44
|
+
selectionLabel: "AWN (Agent World Network)",
|
|
45
|
+
docsPath: "/channels/awn",
|
|
46
|
+
blurb: "Agent World Network — world-scoped agent communication.",
|
|
47
|
+
aliases: ["p2p"],
|
|
48
|
+
},
|
|
49
|
+
capabilities: { chatTypes: ["direct"] },
|
|
50
|
+
configSchema: exports.CHANNEL_CONFIG_SCHEMA,
|
|
51
|
+
config: {
|
|
52
|
+
listAccountIds: (_cfg) => (0, peer_db_1.getPeerIds)(),
|
|
53
|
+
resolveAccount: (_cfg, accountId) => {
|
|
54
|
+
const id = accountId ?? "";
|
|
55
|
+
const peer = (0, peer_db_1.getPeer)(id);
|
|
56
|
+
return {
|
|
57
|
+
accountId: id,
|
|
58
|
+
agentId: peer?.agentId ?? id,
|
|
59
|
+
alias: peer?.alias ?? id,
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
outbound: {
|
|
64
|
+
deliveryMode: "direct",
|
|
65
|
+
sendText: async ({ text, account }) => {
|
|
66
|
+
const agentId = account.agentId ?? "";
|
|
67
|
+
const opts = getSendOpts?.(agentId);
|
|
68
|
+
const result = await (0, peer_client_1.sendP2PMessage)(identity, agentId, "chat", text, port, 10_000, opts);
|
|
69
|
+
if (!result.ok) {
|
|
70
|
+
console.error(`[awn] Failed to send to ${agentId}: ${result.error}`);
|
|
71
|
+
}
|
|
72
|
+
return { ok: result.ok };
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function wireInboundToGateway(api) {
|
|
78
|
+
(0, peer_server_1.onMessage)((msg) => {
|
|
79
|
+
if (msg.event !== "chat")
|
|
80
|
+
return;
|
|
81
|
+
try {
|
|
82
|
+
api.gateway?.receiveChannelMessage?.({
|
|
83
|
+
channelId: "awn",
|
|
84
|
+
accountId: msg.from,
|
|
85
|
+
text: msg.content,
|
|
86
|
+
senderId: msg.from,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
console.log(`[awn] Message from ${msg.from}: ${msg.content}`);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Identity, AwRequestHeaders, AwResponseHeaders } from "./types";
|
|
2
|
+
export declare function deriveDidKey(publicKeyB64: string): string;
|
|
3
|
+
export declare function agentIdFromPublicKey(publicKeyB64: string): string;
|
|
4
|
+
export declare function generateIdentity(): Identity;
|
|
5
|
+
export declare function loadOrCreateIdentity(dataDir: string): Identity;
|
|
6
|
+
export declare function canonicalize(value: unknown): unknown;
|
|
7
|
+
export declare function signMessage(privateKeyB64: string, data: Record<string, unknown>): string;
|
|
8
|
+
export declare function verifySignature(publicKeyB64: string, data: Record<string, unknown>, signatureB64: string): boolean;
|
|
9
|
+
export declare const DOMAIN_SEPARATORS: {
|
|
10
|
+
readonly HTTP_REQUEST: `AgentWorld-Req-${string}\0`;
|
|
11
|
+
readonly HTTP_RESPONSE: `AgentWorld-Res-${string}\0`;
|
|
12
|
+
readonly AGENT_CARD: `AgentWorld-Card-${string}\0`;
|
|
13
|
+
readonly KEY_ROTATION: `AgentWorld-Rotation-${string}\0`;
|
|
14
|
+
readonly ANNOUNCE: `AgentWorld-Announce-${string}\0`;
|
|
15
|
+
readonly MESSAGE: `AgentWorld-Message-${string}\0`;
|
|
16
|
+
readonly WORLD_STATE: `AgentWorld-WorldState-${string}\0`;
|
|
17
|
+
};
|
|
18
|
+
export declare function signWithDomainSeparator(domainSeparator: string, payload: unknown, secretKey: Uint8Array): string;
|
|
19
|
+
export declare function verifyWithDomainSeparator(domainSeparator: string, publicKeyB64: string, payload: unknown, signatureB64: string): boolean;
|
|
20
|
+
export declare function computeContentDigest(body: string): string;
|
|
21
|
+
export declare function signHttpRequest(identity: Identity, method: string, authority: string, reqPath: string, body: string): AwRequestHeaders;
|
|
22
|
+
export declare function verifyHttpRequestHeaders(headers: Record<string, string | string[] | undefined>, method: string, reqPath: string, authority: string, body: string, publicKeyB64: string): {
|
|
23
|
+
ok: boolean;
|
|
24
|
+
error?: string;
|
|
25
|
+
};
|
|
26
|
+
export declare function signHttpResponse(identity: Identity, status: number, body: string): AwResponseHeaders;
|
|
27
|
+
export declare function verifyHttpResponseHeaders(headers: Record<string, string | null>, status: number, body: string, publicKeyB64: string): {
|
|
28
|
+
ok: boolean;
|
|
29
|
+
error?: string;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=identity.d.ts.map
|