HotPlex Worker Go Client

May 22, 2026 · View on GitHub

Go client SDK for HotPlex Worker Gateway — AEP v1 WebSocket protocol

Go Reference

Installation

go get github.com/hrygo/hotplex/client

Quick Start

package 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)
}

API

Options

Functional options pattern, passed to New:

client.URL("ws://localhost:8888")           // required
client.WorkerType("claude_code")            // required
client.BotID("bot-123")                     // Bot ID for multi-bot setups
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

Connection

// New session
ack, err := c.Connect(ctx)                  // returns *InitAckData

// Resume existing session
ack, err := c.Resume(ctx, "sess_xxx")       // returns *InitAckData

Sending

// 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

Events

// 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 { /* ... */ }
}

Lifecycle

c.SessionID()     // current session ID
c.State()         // current SessionState
c.Close()         // graceful shutdown

Event Kinds

ConstantDescription
EventMessageStartStreaming message begins
EventMessageDeltaStreaming content chunk
EventMessageEndStreaming message ends
EventToolCallWorker requests tool execution
EventToolResultTool execution result
EventPermissionRequestWorker asks for permission
EventStateSession state changed
EventDoneSession completed
EventErrorError occurred
EventControlControl event
EventPingHeartbeat probe
EventPongHeartbeat response
EventInitAckConnection established
EventRawPassthrough agent data
EventReasoningAgent "thinking" tokens
EventStepHigher-level task step
EventQuestionRequestWorker asks a question
EventElicitationRequestMCP elicitation request

Data Types

InitAckData

type InitAckData struct {
    SessionID  string
    State      SessionState
    ServerCaps ServerCaps
    Error      string
}

ServerCaps

type ServerCaps struct {
    ProtocolVersion string
    WorkerType      string
    SupportsResume  bool
    SupportsDelta   bool
    SupportsTool    bool
    SupportsPing    bool
    MaxFrameSize    int
    MaxTurns        int
    Tools           []string
}

Session States

StateCreated    // session initialized
StateRunning    // worker active
StateIdle       // waiting for input
StateTerminated // worker exited
StateDeleted    // GC'd

Bot ID (Multi-Bot Setup)

c, err := client.New(ctx,
    client.URL("ws://localhost:8888"),
    client.WorkerType("claude_code"),
    client.APIKey("ak-xxx"),
    client.BotID("bot-123"),   // specify target Bot ID
)

Examples

FileDescription
examples/quickstart.goMinimal connect & chat
examples/complete.goFull features: permissions, stats, resume

Run an example:

cd client
HOTPLEX_API_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/