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:
111
README.md
111
README.md
@@ -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') {
|
||||
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user