Update README with capabilities negotiation flow

- Add capabilities negotiation to Features list
- Document connection flow (5 steps)
- Add capabilities_response message format
- Add request_capabilities message format
- Update JavaScript example with capabilities handling
- Update Python example with capabilities handling
This commit is contained in:
root
2026-03-31 21:43:06 +02:00
parent 1421f9d645
commit 0d226d608b

113
README.md
View File

@@ -14,6 +14,7 @@ Custom WebSocket-based messaging channel plugin for OpenClaw. Enables custom mes
- Reactions
- Threads
- Typing indicators
- 🔄 **Capabilities Negotiation** - Clients report their capabilities on connect
- 🛡️ **DM Security** - Three policies: `allowlist`, `open`, `closed`
- 🔗 **Threading** - Full support for threaded conversations
- 🤝 **Pairing Flow** - Text-based pairing with code exchange
@@ -87,9 +88,41 @@ const ws = new WebSocket('ws://localhost:8765/ws', {
});
```
### Connection Flow
1. **Client connects** → Server authenticates via API key
2. **Server sends handshake** → Server capabilities (maximum allowed)
3. **Server requests capabilities** → Asks client what it supports
4. **Client responds** → Client capabilities + metadata
5. **Effective capabilities** → Server uses intersection of both
6. **Messaging begins** → Only supported message types allowed
### Message Format
**Client → Server:**
#### Client → Server
**Capabilities Response (required after handshake):**
```json
{
"type": "capabilities_response",
"capabilities": {
"text": true,
"images": true,
"files": false,
"voice": false,
"reactions": false,
"threads": true,
"typing": true
},
"metadata": {
"clientName": "My App",
"version": "1.0.0",
"platform": "custom"
}
}
```
**Text Message:**
```json
{
"type": "message",
@@ -101,7 +134,9 @@ const ws = new WebSocket('ws://localhost:8765/ws', {
}
```
**Server → Client (Handshake):**
#### Server → Client
**Handshake:**
```json
{
"type": "handshake",
@@ -109,19 +144,27 @@ const ws = new WebSocket('ws://localhost:8765/ws', {
"capabilities": {
"text": true,
"images": true,
"files": false,
"voice": false,
"files": true,
"voice": true,
"reactions": false,
"threads": true,
"typing": true
},
"metadata": {
"serverName": "My WebSocket Server"
}
},
"timestamp": 1703275200000
}
```
**Server → Client (Message):**
**Capabilities Request:**
```json
{
"type": "request_capabilities"
}
```
**Message:**
```json
{
"type": "message",
@@ -146,12 +189,39 @@ const ws = new WebSocket('ws://localhost:8765/ws?key=YOUR_API_KEY');
ws.on('message', (data) => {
const msg = JSON.parse(data.toString());
if (msg.type === 'message') {
console.log('Bot:', msg.content.text);
switch (msg.type) {
case 'handshake':
console.log('Server capabilities:', msg.capabilities);
break;
case 'request_capabilities':
// Send client capabilities
ws.send(JSON.stringify({
type: 'capabilities_response',
capabilities: {
text: true,
images: true,
files: false,
voice: false,
reactions: false,
threads: true,
typing: true
},
metadata: {
clientName: 'My App',
version: '1.0.0'
}
}));
break;
case 'message':
console.log('Bot:', msg.content.text);
break;
}
});
// Send message
// Send message (after capabilities_response)
ws.send(JSON.stringify({
type: 'message',
from: 'user-123',
@@ -167,7 +237,30 @@ import json
def on_message(ws, message):
data = json.loads(message)
if data['type'] == 'message':
if data['type'] == 'handshake':
print(f"Server capabilities: {data['capabilities']}")
elif data['type'] == 'request_capabilities':
# Send client capabilities
ws.send(json.dumps({
"type": "capabilities_response",
"capabilities": {
"text": True,
"images": True,
"files": False,
"voice": False,
"reactions": False,
"threads": True,
"typing": True
},
"metadata": {
"clientName": "My Python App",
"version": "1.0.0"
}
}))
elif data['type'] == 'message':
print(f"Bot: {data['content']['text']}")
ws = websocket.WebSocketApp(