Skip to content

Conversation

alimoradi296
Copy link

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

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 <[email protected]>
Copy link
Member

@h3xxit h3xxit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good job. Left some comments. I'll ping you again, once I have a reference implementation for the socket like communication.

Could you change the PR to be in another branch. A feature/websockets branch. So I can also make some changes on it, before we merge it into dev

inputs=ToolInputOutputSchema(**tool_data.get("inputs", {})),
outputs=ToolInputOutputSchema(**tool_data.get("outputs", {})),
tags=tool_data.get("tags", []),
tool_provider=manual_provider
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each tool should have their own tool_provider, as a HTTP manual can have tools that are called with Websockets, grpc, cli and so on. So following the same logic, a WS manual can have tools that are not accessible via the same websocket, or via a different transport.

Comment on lines +213 to +246
async def call_tool(self, tool_name: str, arguments: Dict[str, Any], tool_provider: Provider) -> Any:
"""
Call a tool via WebSocket.

Sends a JSON message:
{"type": "call_tool", "request_id": "unique_id", "tool_name": "tool", "arguments": {...}}

Expected response:
{"type": "tool_response", "request_id": "unique_id", "result": {...}}
or
{"type": "tool_error", "request_id": "unique_id", "error": "error message"}
"""
if not isinstance(tool_provider, WebSocketProvider):
raise ValueError("WebSocketClientTransport can only be used with WebSocketProvider")

ws = await self._get_connection(tool_provider)

# Prepare tool call request
request_id = f"call_{tool_name}_{id(arguments)}"
call_request = {
"type": "call_tool",
"request_id": request_id,
"tool_name": tool_name,
"arguments": arguments
}

# Add any header fields to the request
if tool_provider.header_fields and arguments:
headers = {}
for field in tool_provider.header_fields:
if field in arguments:
headers[field] = arguments[field]
if headers:
call_request["headers"] = headers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This enforces a strict format for the data transmitted via the socket. Unfortunately websockets don't enforce a well-known standard for the information format (unlike REST where the format is always sent as part of the headers).

Because the goal of UTCP is to enable even agents to transmit information to existing endpoints, just like humans would, without needing change in the endpoints, we need a more flexible format for the sent data. I will be working today on the UDP implementation, and once that's done I can ping you to adapt it accordingly.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback @h3xxit!

I've addressed your comments and moved to the feature/websockets branch as requested. Continuing the work in #36 .

Changes made:
✅ Individual tool providers
✅ Flexible message format
✅ New branch structure

Closing this PR and continuing in the new one.

@alimoradi296
Copy link
Author

Closing this PR in favor of a new one using the feature/websockets branch as requested by @h3xxit.

Changes made based on review feedback:

  • ✅ Each tool now gets its own WebSocketProvider instance
  • ✅ Added flexible message format support via message_format field
  • ✅ Created new feature/websockets branch

New PR: #36

Thanks for the feedback @h3xxit! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants