Commit 81cab59
Add WebSocket transport implementation for real-time communication (#36)
* Add WebSocket transport implementation for real-time communication
Implements comprehensive WebSocket transport following UTCP architecture:
## Core Features
- Real-time bidirectional communication via WebSocket protocol
- Tool discovery through WebSocket handshake using UTCP messages
- Streaming tool execution with proper error handling
- Connection management with keep-alive and reconnection support
## Architecture Compliance
- Dependency injection pattern with constructor injection
- Implements ClientTransportInterface contract
- Composition over inheritance design
- Clear separation of data and business logic
- Thread-safe and scalable implementation
## Authentication & Security
- Full authentication support (API Key, Basic Auth, OAuth2)
- Security enforcement (WSS required, localhost exception)
- Custom headers and protocol specification support
## Testing & Quality
- Unit tests covering all functionality (80%+ coverage)
- Mock WebSocket server for development/testing
- Integration with existing UTCP test patterns
- Comprehensive error handling and edge cases
## Protocol Implementation
- Discovery: {"type": "discover", "request_id": "id"}
- Tool calls: {"type": "call_tool", "tool_name": "name", "arguments": {...}}
- Responses: {"type": "tool_response|tool_error", "result": {...}}
## Documentation
- Complete example with interactive client/server demo
- Updated README removing "work in progress" status
- Protocol specification and usage examples
Addresses the "No wrapper tax" principle by enabling direct WebSocket
communication without requiring changes to existing WebSocket services.
Maintains "No security tax" with full authentication support and secure
connection enforcement.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Address PR feedback: individual tool providers and flexible message format
- Each tool now gets its own WebSocketProvider instance (addresses h3xxit feedback)
- Added message_format field for custom WebSocket message formatting
- Maintains backward compatibility with default UTCP format
- Allows integration with existing WebSocket services without modification
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix WebSocket transport per reviewer feedback
- Tools now come with their own tool_provider instead of manually creating providers
- Response data for /utcp endpoint properly parsed as UtcpManual
- Maintains backward compatibility while following official UDP patterns
- All tests passing (145 passed, 1 skipped)
Addresses @h3xxit's review comments on PR #36
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add WebSocket plugin tests and update main README
- Created comprehensive test suite for WebSocketCallTemplate
- All 8 tests passing with 100% coverage of call template functionality
- Added WebSocket plugin to main README protocol plugins table
- Plugin marked as ✅ Stable and production-ready
Tests cover:
- Basic call template creation and defaults
- Localhost URL validation
- Security enforcement (rejects insecure ws:// URLs)
- Authentication (API Key, Basic, OAuth2)
- Text format with templates
- Serialization/deserialization
- Custom headers and header fields
- Legacy message format support
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Address WebSocket flexibility feedback and add plugin to main README
This commit addresses reviewer @h3xxit's feedback that the WebSocket implementation was "too restrictive" by implementing maximum flexibility to work with ANY WebSocket endpoint.
Key Changes:
- **Flexible Message Templating**: Added `message` field (Union[str, Dict[str, Any]]) with ${arg_name} placeholder support
- Dict templates: Support structured messages like JSON-RPC, chat protocols
- String templates: Support text-based protocols like IoT commands
- No template (default): Sends arguments as-is in JSON for maximum compatibility
- **Flexible Response Handling**: Added `response_format` field (Optional["json", "text", "raw"])
- No format (default): Returns raw response without processing
- Works with any WebSocket response structure
- **Removed Restrictive Fields**:
- Removed `request_data_format`, `request_data_template`, `message_format`
- No longer enforces specific request/response structure
- **Implementation**:
- Added `_substitute_placeholders()` method for recursive template substitution
- Updated `_format_tool_call_message()` to use template or send args as-is
- Updated `call_tool()` to return raw responses by default
- **Testing**: Updated all 9 tests to reflect new flexibility approach
- **Documentation**:
- Updated README to emphasize "maximum flexibility" principle
- Added examples showing no template, dict template, and string template usage
- Added WebSocket entry to main README plugin table
Philosophy: "Talk to as many WebSocket endpoints as possible" - UTCP should adapt to existing endpoints, not require endpoints to adapt to UTCP.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix placeholder format: change from dollar-brace to UTCP_ARG format
Addresses @h3xxit critical feedback that dollar-brace syntax is reserved
for secret variable replacement from .env files and cannot be used for
argument placeholders.
Changes:
- WebSocketCallTemplate: message field now uses UTCP_ARG_arg_name_UTCP_ARG format
- _substitute_placeholders(): replaces UTCP_ARG_arg_name_UTCP_ARG placeholders
- Updated all 9 tests to use correct UTCP_ARG format
- Updated README.md: all template examples now show UTCP_ARG format
- Preserved dollar-brace in auth examples (correct for env variables)
All tests passing (9/9).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Update example/src/websocket_example/websocket_server.py
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* Update example/src/websocket_example/websocket_server.py
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* Update example/src/websocket_example/websocket_client.py
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* Update plugins/communication_protocols/websocket/README.md
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* Update example/src/websocket_example/websocket_client.py
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* Update src/utcp/client/transport_interfaces/websocket_transport.py
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* Complete remaining cubic-dev-ai fixes
Addresses the last three cubic-dev-ai suggestions that weren't auto-fixed:
1. Fix peername guard in websocket_server.py:
- Check if peername exists and has length before indexing
- Prevents crash when transport lacks peer data
2. Fix CLAUDE.md test paths:
- Update from non-existent tests/client paths
- Point to actual plugin test directories
3. Fix JSON-RPC example in README.md:
- Update example to show actual output (stringified params)
- Add note explaining the behavior
All WebSocket tests passing (9/9).
Ready for PR merge.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>1 parent fcc7856 commit 81cab59
File tree
15 files changed
+2587
-0
lines changed- example/src/websocket_example
- plugins/communication_protocols/websocket
- src/utcp_websocket
- tests
- src/utcp/client/transport_interfaces
15 files changed
+2587
-0
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
86 | 86 | | |
87 | 87 | | |
88 | 88 | | |
| 89 | + | |
89 | 90 | | |
90 | 91 | | |
91 | 92 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
0 commit comments