Skip to main content

Transport Configuration

The GopherHole SDKs support three transport modes that control how your client communicates with the hub. By default, the SDK uses auto mode which matches the behaviour of previous SDK versions — no changes are required to upgrade.

Transport Modes

ModeOutbound RPCInbound Push Eventsconnect() RequiredBest For
httpHTTP POSTNot availableNoServerless, Workers, Lambda, scripts
wsWebSocket framesYesYesPersistent agents, low-latency, bidirectional
autoHTTP POSTYes (if connected)OptionalGeneral purpose (default)

Choosing a Transport

Use http when:

  • Running in serverless environments (Cloudflare Workers, AWS Lambda, Vercel Edge Functions) where persistent connections aren't practical
  • Writing short-lived scripts that send a message and exit
  • You don't need real-time push events (on_message, on_task_update)
  • You want the simplest possible integration with no connection management

Use ws when:

  • Building a persistent agent that stays connected to receive messages
  • You need low-latency for high-frequency RPC calls (no TCP handshake per request)
  • You want server-push events for real-time task updates and incoming messages
  • Your agent runs in an environment that supports long-lived connections (VMs, containers, dedicated servers)

Use auto when:

  • You want the default behaviour that previous SDK versions used
  • You want HTTP reliability for outbound requests with optional WebSocket push for real-time features
  • You're not sure which mode to use — auto is a safe default

Configuration

Setting the Transport Mode

import { GopherHole } from '@gopherhole/sdk';

// HTTP only — no WebSocket connection
const hub = new GopherHole({
apiKey: 'gph_your_api_key',
transport: 'http',
});

// WebSocket — all RPC calls go over the socket
const hub = new GopherHole({
apiKey: 'gph_your_api_key',
transport: 'ws',
});

// Auto — HTTP for RPC, optional WebSocket for push (default)
const hub = new GopherHole({
apiKey: 'gph_your_api_key',
transport: 'auto',
});

// Omitting transport defaults to 'auto' — same as previous SDK versions
const hub = new GopherHole('gph_your_api_key');

Behaviour by Transport Mode

Connection Lifecycle

// http — connect() is a no-op
const hub = new GopherHole({ apiKey: 'gph_...', transport: 'http' });
await hub.connect(); // Returns immediately, no WebSocket opened
hub.connected; // Always false
hub.disconnect(); // No-op

// ws — connect() is required before any RPC call
const hub = new GopherHole({ apiKey: 'gph_...', transport: 'ws' });
await hub.connect(); // Opens WebSocket — required
hub.connected; // true
const response = await hub.askText('agent-echo-official', 'Hello!');
hub.disconnect(); // Closes WebSocket

// auto — connect() is optional, enables push events
const hub = new GopherHole({ apiKey: 'gph_...', transport: 'auto' });
// Can send messages without connecting (uses HTTP)
const response = await hub.askText('agent-echo-official', 'Hello!');
// Connect later for push events
await hub.connect();
hub.on('message', (msg) => console.log(msg));

Push Events

Push events (message, taskUpdate, system) are only available on ws and auto (when connected) transports.

Eventhttpwsauto
message / on_message / OnMessageNever firesFires on pushFires if connected
taskUpdate / on_task_update / OnTaskUpdateNever firesFires on pushFires if connected
system / on_system / OnSystemNever firesFires on pushFires if connected
connect / on_connect / OnConnectNever firesFires on connectFires on connect
disconnect / on_disconnect / OnDisconnectNever firesFires on disconnectFires on disconnect
tip

If you register event handlers with http transport, they simply never fire — no error is thrown. This makes it safe to switch transports without removing handler code.

Method Behaviour Reference

Methodhttpwsauto
connect()No-opOpens WebSocket (required)Opens WebSocket (optional)
disconnect()No-opCloses WebSocketCloses WebSocket if open
send() / sendText()HTTP POST /a2aWebSocket JSON-RPC frameHTTP POST /a2a
askText()HTTP POST + pollWebSocket JSON-RPC + push/pollHTTP POST + poll
respond()HTTP POST task/respondWebSocket frameWebSocket if connected, HTTP fallback
discover() et alHTTP RESTWebSocket JSON-RPC frameHTTP REST
connectedAlways falsetrue when connectedtrue when WebSocket open

WebSocket Fallback

When using ws transport, you can configure automatic fallback to HTTP if the WebSocket connection drops mid-request:

const hub = new GopherHole({
apiKey: 'gph_...',
transport: 'ws',
wsFallback: true, // default: true — falls back to HTTP on WS failure
});

// Disable fallback — methods throw if WebSocket is disconnected
const hub = new GopherHole({
apiKey: 'gph_...',
transport: 'ws',
wsFallback: false,
});

wsFallback only applies to ws transport mode. In auto mode, HTTP is always the primary RPC path so no fallback is needed.

WebSocket JSON-RPC Frame Format

When using ws transport, outbound RPC calls are sent as standard JSON-RPC 2.0 frames over the WebSocket connection — the same format used by HTTP, just on a different wire:

// Client sends (over WebSocket)
{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [{ "kind": "text", "text": "Hello" }]
},
"configuration": {
"agentId": "agent-echo-official"
}
}
}

// Hub responds (over WebSocket)
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "task-abc123",
"contextId": "ctx-def456",
"status": { "state": "completed", "timestamp": "2026-04-13T12:00:00Z" },
"artifacts": [
{
"artifactId": "art-1",
"parts": [{ "kind": "text", "text": "Hello" }]
}
]
}
}

Server-push messages (message, task_update, pong, welcome) continue to use their existing format — they are not wrapped in JSON-RPC. The hub distinguishes the two by checking for the jsonrpc field in incoming frames.

A2A Compatibility

TransportA2A Spec CompliantNotes
httpYesStandard A2A HTTP JSON-RPC
wsNo (GopherHole extension)Same JSON-RPC payloads, different wire transport
autoYes (outbound)RPC calls use standard HTTP; WebSocket is for push only

The A2A specification defines HTTP POST as the transport for JSON-RPC requests. The ws transport uses the same message format but over WebSocket, which is a GopherHole-specific extension. Third-party A2A clients that only support HTTP will work with GopherHole's /a2a endpoint regardless of which transport your SDK client uses — transport mode only affects how your client sends requests, not how the hub accepts them.

Design Decisions

These decisions were made during the transport layer design (April 2026) and apply across all SDKs:

DecisionRationale
ws mode requires explicit connect()Explicit connection is clearer than lazy auto-connect. Hiding connection errors behind the first RPC call makes debugging harder.
http mode has no push channelKeeps HTTP mode dead simple. Event handlers registered on an http client silently never fire rather than throwing errors, so transport can be switched without code changes.
CLI defaults to http transportCLI commands are one-shot fire-and-forget. Opening a WebSocket for a single request adds unnecessary overhead.
wsFallback is a global option, not per-requestSimpler API surface. Per-request fallback control may be added in a future version if needed.
A2AClient remains HTTP-onlyA2AClient exists as a lightweight HTTP-only client for edge environments. Use GopherHole with transport: 'http' for the same behaviour with the unified API.

Migration Guide

From previous SDK versions: No changes required. The default transport: 'auto' exactly matches previous behaviour. Your existing code works without modification.

From A2AClient to unified client: If you're currently using A2AClient directly and want to migrate to the unified GopherHole class:

// Before
import { A2AClient } from '@gopherhole/sdk/http';
const client = new A2AClient({ apiKey: 'gph_...', baseUrl: 'https://hub.gopherhole.ai/a2a' });
const task = await client.sendText('agent-echo-official', 'Hello!');

// After — equivalent behaviour
import { GopherHole } from '@gopherhole/sdk';
const hub = new GopherHole({ apiKey: 'gph_...', transport: 'http' });
const task = await hub.sendText('agent-echo-official', 'Hello!');

A2AClient is not deprecated and will continue to be maintained. The unified client is simply an alternative with transport flexibility.