SDKs
Diminuendo ships four official client SDKs that cover the full surface of the wire protocol — all 21 client message types and all 51 server event types — with no exceptions, no partial implementations, and no event silently dropped. Each SDK is a standalone library with zero gateway dependencies: it defines its own types from the wire protocol specification, connects over a standard WebSocket, and can be published and consumed independently. The SDKs are not generated from a shared schema; they are handcrafted in each language’s native idiom, because a Rust developer should not have to think in TypeScript abstractions, and a Swift developer should not encounter Python’s naming conventions.Design Principles
Full Protocol Parity
Every client message type and every server event type is represented in each SDK. No event is silently dropped. No message type is missing. The SDKs are functionally equivalent — anything one can do, all can do.
Zero Gateway Dependencies
The SDKs do not import gateway code, do not share types via monorepo packages, and do not require code generation. Each SDK defines its own types from the wire protocol specification. This ensures they can be published and used independently.
Native Idioms
TypeScript uses Promises and typed event handlers. Rust uses async channels and serde. Python uses asyncio and dataclasses. Swift uses async/await and Codable. Each SDK feels native to its language — no lowest-common-denominator abstraction.
Adversarial Test Suites
Every SDK has a comprehensive test suite that does not merely verify happy paths, but actively attempts to break the client with malformed data, concurrent operations, timeouts, and edge cases.
SDK Comparison
| Aspect | TypeScript | Rust | Python | Swift |
|---|---|---|---|---|
| Runtime | Node.js, Bun, Deno, browsers | tokio (async runtime) | asyncio + websockets | Swift Concurrency + URLSessionWebSocketTask |
| Dependencies | Zero runtime deps | tokio, serde, tokio-tungstenite, futures-util, thiserror, tracing | websockets | None (Foundation only) |
| Async Model | Promises + event callbacks | mpsc::UnboundedReceiver<ServerEvent> | async/await + event callbacks | async/await + AsyncStream<ServerEvent> |
| Type System | TypeScript interfaces (compile-time) | Rust enums with #[serde(tag = "type")] (compile + runtime) | Dataclasses with from_dict parsers | Codable enums/structs with CodingKeys |
| Event Delivery | .on(type, handler) with unsubscribe | Channel-based (events.recv().await) | .on(type, handler) with unsubscribe | AsyncStream consumption in a for await loop |
| Wildcard Events | .on("*", handler) | ServerEvent::Unknown catch-all | .on("*", handler) | .unknown catch-all case |
| Wire Mapping | camelCase (native) | #[serde(rename)] from snake_case | from_dict with explicit key mapping | CodingKeys with camelCase |
| Connection Management | Auto-reconnect, ping timer | Manual (application controls lifecycle) | Auto-reconnect, ping timer | Auto-reconnect, ping timer |
| Primary Use Case | Web apps, Node.js services | Tauri desktop apps, CLI tools | Scripts, testing, notebooks | macOS/iOS apps, SwiftUI clients |
| Test Count | 137 tests | 178 tests | 173 tests | 193 tests |
- TypeScript
- Rust
- Python
- Swift
TypeScript SDK
The TypeScript SDK is a zero-dependency WebSocket client that works in any JavaScript runtime with a standardWebSocket global — browsers, Node.js 21+, Bun, and Deno. It provides a Promise-based API for request-response operations and typed event handlers for streaming events.Installation
Quick Start
Connection Lifecycle
| Option | Type | Default | Description |
|---|---|---|---|
url | string | (required) | Gateway WebSocket URL |
token | string | "" | JWT or API key for authentication |
autoReconnect | boolean | true | Automatically reconnect on disconnect |
reconnectDelay | number | 1000 | Milliseconds between reconnection attempts |
pingInterval | number | 30000 | Keepalive ping interval in ms. Set to 0 to disable |
autoReconnect is enabled, the client automatically re-establishes the connection and re-authenticates using the original token. Listen for lifecycle events to track reconnection:Session Management
All session management methods return Promises and use request/response correlation — the SDK sends a typed message and waits for the corresponding server event.SessionMeta:Session Interaction
runTurn and stopTurn are fire-and-forget — they send the message immediately and return void. The response arrives as a stream of events (turn_started, text_delta, tool_call, turn_complete, etc.).Event Handling
The SDK provides a type-safe event subscription system. Theon() method accepts an event type string and a handler function, with TypeScript narrowing the event payload to the correct type.File Access
Error Handling
Errors arise in two contexts:- Connection errors —
connect()rejects if the WebSocket fails to open, authentication fails, or the 10-second timeout is reached. - Request errors — methods like
listSessions()orjoinSession()reject if the gateway returns anerrorevent, or if the 10-second request timeout is reached.
Error("WebSocket not connected").Complete Example
Protocol Coverage Matrix
Every client message and server event is implemented in all four SDKs. The following tables confirm full parity across the entire wire protocol surface.21 Client Messages
21 Client Messages
| Message Type | TypeScript | Rust | Python | Swift |
|---|---|---|---|---|
authenticate | Yes | Yes | Yes | Yes |
list_sessions | Yes | Yes | Yes | Yes |
create_session | Yes | Yes | Yes | Yes |
rename_session | Yes | Yes | Yes | Yes |
archive_session | Yes | Yes | Yes | Yes |
unarchive_session | Yes | Yes | Yes | Yes |
delete_session | Yes | Yes | Yes | Yes |
join_session | Yes | Yes | Yes | Yes |
leave_session | Yes | Yes | Yes | Yes |
run_turn | Yes | Yes | Yes | Yes |
stop_turn | Yes | Yes | Yes | Yes |
steer | Yes | Yes | Yes | Yes |
answer_question | Yes | Yes | Yes | Yes |
get_history | Yes | Yes | Yes | Yes |
get_events | Yes | Yes | Yes | Yes |
ping | Yes | Yes | Yes | Yes |
list_files | Yes | Yes | Yes | Yes |
read_file | Yes | Yes | Yes | Yes |
file_history | Yes | Yes | Yes | Yes |
file_at_iteration | Yes | Yes | Yes | Yes |
manage_members | Yes | Yes | Yes | Yes |
51 Server Events
51 Server Events
| Event Type | TypeScript | Rust | Python | Swift |
|---|---|---|---|---|
welcome | Yes | Yes | Yes | Yes |
connected | Yes | Yes | Yes | Yes |
authenticated | Yes | Yes | Yes | Yes |
heartbeat | Yes | Yes | Yes | Yes |
session_list | Yes | Yes | Yes | Yes |
session_created | Yes | Yes | Yes | Yes |
session_updated | Yes | Yes | Yes | Yes |
session_archived | Yes | Yes | Yes | Yes |
session_unarchived | Yes | Yes | Yes | Yes |
session_deleted | Yes | Yes | Yes | Yes |
session_state | Yes | Yes | Yes | Yes |
state_snapshot | Yes | Yes | Yes | Yes |
stream_snapshot | Yes | Yes | Yes | Yes |
turn_started | Yes | Yes | Yes | Yes |
text_delta | Yes | Yes | Yes | Yes |
turn_complete | Yes | Yes | Yes | Yes |
turn_error | Yes | Yes | Yes | Yes |
message.delta | Yes | Yes | Yes | Yes |
message.complete | Yes | Yes | Yes | Yes |
tool_call | Yes | Yes | Yes | Yes |
tool_result | Yes | Yes | Yes | Yes |
tool_call_start | Yes | Yes | Yes | Yes |
tool_call_delta | Yes | Yes | Yes | Yes |
tool_error | Yes | Yes | Yes | Yes |
question_requested | Yes | Yes | Yes | Yes |
permission_requested | Yes | Yes | Yes | Yes |
approval_resolved | Yes | Yes | Yes | Yes |
thinking_start | Yes | Yes | Yes | Yes |
thinking_progress | Yes | Yes | Yes | Yes |
thinking_complete | Yes | Yes | Yes | Yes |
terminal_stream | Yes | Yes | Yes | Yes |
terminal_complete | Yes | Yes | Yes | Yes |
sandbox_init | Yes | Yes | Yes | Yes |
sandbox_provisioning | Yes | Yes | Yes | Yes |
sandbox_ready | Yes | Yes | Yes | Yes |
sandbox_removed | Yes | Yes | Yes | Yes |
usage_update | Yes | Yes | Yes | Yes |
usage_context | Yes | Yes | Yes | Yes |
gap | Yes | Yes | Yes | Yes |
replay_complete | Yes | Yes | Yes | Yes |
file_list | Yes | Yes | Yes | Yes |
file_content | Yes | Yes | Yes | Yes |
file_history_result | Yes | Yes | Yes | Yes |
file_changed | Yes | Yes | Yes | Yes |
steer_sent | Yes | Yes | Yes | Yes |
stop_acknowledged | Yes | Yes | Yes | Yes |
server_shutdown | Yes | Yes | Yes | Yes |
history | Yes | Yes | Yes | Yes |
events | Yes | Yes | Yes | Yes |
member_list | Yes | Yes | Yes | Yes |
member_updated | Yes | Yes | Yes | Yes |
member_removed | Yes | Yes | Yes | Yes |
error | Yes | Yes | Yes | Yes |
pong | Yes | Yes | Yes | Yes |
Testing Methodology
The SDK test suites do not exist to demonstrate that the code works. They exist to demonstrate that aggressive, systematic attempts to break the code have failed. This distinction — between confirmation and refutation — is the foundation of the testing methodology. The approach draws from Karl Popper’s philosophy of science: a claim is only as credible as the severity of the tests it has survived. A test that passes trivially provides no evidence of correctness.Tests are Adversarial
Every test is written from the perspective of an attacker. What input would cause a crash? What timing would cause a race condition? What encoding would corrupt deserialization?
Claims are Falsifiable
“The client handles
text_delta events” is not falsifiable. “A text_delta event with a 1MB text field is delivered to the handler without truncation” is falsifiable — and tested.Mock Oracles, Not Mock Implementations
Each SDK test suite runs against a mock gateway that speaks the actual wire protocol. The mock is an oracle that validates conformance, not a stub returning canned responses.
No Confirmation Bias
Tests do not confirm expected behavior by feeding expected inputs. They probe boundaries: empty strings, null fields, maximum-size payloads, negative numbers, concurrent mutations.
Test Architecture per SDK
- TypeScript: Runs a real
Bun.serveWebSocket server implementing the full wire protocol. The mock gateway sendswelcome,connected, andauthenticatedon connection, responds to all 21 message types, and simulates streaming event sequences. - Rust: Relies on serde’s compile-time guarantees plus runtime JSON round-trip verification. Every variant of
ClientMessage(21) andServerEvent(51) is tested for exact wire format conformance with explicit camelCase field assertions. - Python: Uses
websockets.serveto run a mock gateway in the same asyncio event loop. Tests cover connection lifecycle, all session methods, dataclass parsing,ServerEventproperties, category predicates, and the event handler system. - Swift: Uses Swift Testing framework (
@Test,#expect) withCodableround-trip verification. All 51ServerEventand 21ClientMessagevariants are tested for exact wire format conformance viaCodingKeys.
Adversarial Patterns Tested
All four SDKs are tested against these adversarial scenarios:- Malformed server data: Invalid JSON, wrong field types, missing required fields, extra unknown fields
- Request timeouts: Server never responds; pending promises/futures must reject, not hang
- Large payloads: 1MB
textfields, deeply nested JSON in tool args, thousands of sessions in a list - Unicode edge cases: Emoji, CJK, RTL, combining characters, zero-width characters, surrogate pairs
- Numeric edge cases:
seq: 0,seq: -1,seq: 9007199254740991(JS MAX_SAFE_INTEGER),i64::MAX - Unknown event types: Forward-compatible handling via
Unknownvariant, wildcard handlers, or.unknowncase - Concurrent operations: Multiple in-flight requests resolve to correct responses without cross-contamination
Coverage Statistics
| SDK | Tests | Assertions | Message Types | Event Types | Error Types |
|---|---|---|---|---|---|
| TypeScript | 137 | ~600 | 21/21 | 51/51 | All |
| Rust | 178 | ~800 | 21/21 | 51/51 | All |
| Python | 173 | ~800 | 21/21 | 51/51 | All |
| Swift | 193 | ~900 | 21/21 | 51/51 | All |
| Total (SDKs) | 681 | ~3,100 | 21/21 | 51/51 | All |