Go client SDK for HotPlex Worker Gateway — AEP v1 WebSocket protocol
go get github.com/hrygo/hotplex/clientpackage main
import (
"context"
"fmt"
"log"
"os"
client "github.com/hrygo/hotplex/client"
)
func main() {
ctx := context.Background()
c, err := client.New(ctx,
client.URL("ws://localhost:8888"),
client.WorkerType("claude_code"),
client.APIKey(os.Getenv("HOTPLEX_API_KEY")),
)
if err != nil {
log.Fatal(err)
}
defer c.Close()
// 1. Connect
ack, err := c.Connect(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Connected | Session: %s\n", ack.SessionID)
// 2. Listen for streaming deltas in background
go func() {
for evt := range c.Events() {
if evt.Type == client.EventMessageDelta {
if d, ok := evt.AsMessageDeltaData(); ok {
fmt.Print(d.Content)
}
}
}
}()
// 3. Send input and wait for completion (async task)
done, err := c.SendInputAsync(ctx, "What is 2+2?")
if err != nil {
log.Fatal(err)
}
fmt.Printf("\n--- done (success: %v) ---\n", done.Success)
}Functional options pattern, passed to New:
client.URL("ws://localhost:8888") // required
client.WorkerType("claude_code") // required
client.AuthToken("jwt-token") // JWT bearer token
client.APIKey("sk-xxx") // API key header
client.PingInterval(30 * time.Second) // heartbeat (default 54s)
client.ClientSessionID("my-session-001") // client-managed session ID (UUIDv5 mapped)
client.AutoReconnect(true) // enable automatic reconnection
client.Logger(slog.Default()) // custom logger
client.Metadata(map[string]any{"p": "v"}) // init handshake metadata// New session
ack, err := c.Connect(ctx) // returns *InitAckData
// Resume existing session
ack, err := c.Resume(ctx, "sess_xxx") // returns *InitAckData// Fire and forget
c.SendInput(ctx, "your message", metadata) // user input + opt. metadata
// Send and wait for completion
done, err := c.SendInputAsync(ctx, "your message") // returns *DoneData
c.SendPermissionResponse(ctx, "id", true, "approved") // approve tool
c.SendQuestionResponse(ctx, "id", answers) // answer question
c.SendElicitationResponse(ctx, "id", "accept", content) // respond to elicit
c.SendControl(ctx, "terminate") // terminate session
c.SendReset(ctx, "user_requested") // clear context, restart worker
c.SendGC(ctx, "user_idle") // archive session, terminate worker// Subscribe to all subsequent events
events := c.Events()
// Unsubscribe to stop receiving and free resources
defer c.Unsubscribe(events)
for evt := range events {
// evt.Type — event type string (see constants below)
// evt.Seq — monotonic sequence number
// evt.Session — session ID
// evt.Data — event payload (use helpers below)
if done, ok := evt.AsDoneData(); ok { /* ... */ }
if err, ok := evt.AsErrorData(); ok { /* ... */ }
if tc, ok := evt.AsToolCallData(); ok { /* ... */ }
}c.SessionID() // current session ID
c.State() // current SessionState
c.Close() // graceful shutdown| Constant | Description |
|---|---|
EventMessageStart |
Streaming message begins |
EventMessageDelta |
Streaming content chunk |
EventMessageEnd |
Streaming message ends |
EventToolCall |
Worker requests tool execution |
EventToolResult |
Tool execution result |
EventPermissionRequest |
Worker asks for permission |
EventState |
Session state changed |
EventDone |
Session completed |
EventError |
Error occurred |
EventControl |
Control event |
EventPing |
Heartbeat probe |
EventPong |
Heartbeat response |
EventInitAck |
Connection established |
EventRaw |
Passthrough agent data |
EventReasoning |
Agent "thinking" tokens |
EventStep |
Higher-level task step |
EventQuestionRequest |
Worker asks a question |
EventElicitationRequest |
MCP elicitation request |
type InitAckData struct {
SessionID string
State SessionState
ServerCaps ServerCaps
Error string
}type ServerCaps struct {
ProtocolVersion string
WorkerType string
SupportsResume bool
SupportsDelta bool
SupportsTool bool
SupportsPing bool
MaxFrameSize int
MaxTurns int
Tools []string
}StateCreated // session initialized
StateRunning // worker active
StateIdle // waiting for input
StateTerminated // worker exited
StateDeleted // GC'dgen, err := client.NewTokenGenerator(signingKey)
if err != nil { /* ... */ }
// Key formats: PEM file path, 64-char hex, or 44-char base64
token, err := gen.Generate("user-id", []string{"read", "write"}, 1*time.Hour)
// Custom audience (default "gateway")
gen.WithAudience("custom-aud")| File | Description |
|---|---|
examples/quickstart.go |
Minimal connect & chat |
examples/complete.go |
Full features: permissions, stats, resume |
scripts/gen-token/main.go |
JWT token generator CLI |
Run an example:
cd client
HOTPLEX_SIGNING_KEY=<key> go run examples/quickstart.go- Protocol Spec:
docs/architecture/AEP-v1-Protocol.md - Python Client:
examples/python-client/ - TypeScript Client:
examples/typescript-client/ - Java Client:
examples/java-client/