Aelio
PlatformsGo

Go

Implement the Aelio SDK in Go using the wire protocol — community guide.

Status: No official Go SDK yet. The wire protocol enum includes 'go' as a planned language. This guide shows how to implement the SDK yourself (~300 lines).

Go backends can connect to Aelio by implementing the JSON-over-WebSocket wire protocol directly. The Python SDK (sdk/python/sdk.py, ~330 lines) is the best reference implementation.

Wire protocol overview

Your Go backend                    Aelio Server
     │                                  │
     │── WebSocket /sdk ──────────────▶│  Authorization: Bearer secret
     │── register frame ──────────────▶│  (functions, states, persona)
     │                                  │
     │◀── invoke frame ────────────────│  (LLM wants a tool)
     │── result frame ────────────────▶│  (handler return value)
     │                                  │
     │◀── ping ───────────────────────│  (every 30s)
     │── pong ──────────────────────▶│

Step 1: Connect

package aelio

import (
    "net/http"
    "github.com/gorilla/websocket"
)

func Connect(secret, serverURL string) (*websocket.Conn, error) {
    header := http.Header{}
    header.Set("Authorization", "Bearer "+secret)

    url := serverURL + "/sdk"
    conn, _, err := websocket.DefaultDialer.Dial(url, header)
    return conn, err
}

Step 2: Register tools

Send immediately after connecting:

type FunctionDef struct {
    Name        string                 `json:"name"`
    Description string                 `json:"description"`
    Params      map[string]interface{} `json:"params"`
    Safety      string                 `json:"safety"`
}

type RegisterMessage struct {
    Type      string        `json:"type"`
    Functions []FunctionDef `json:"functions"`
    Language  string        `json:"language"`
    SDKVersion string       `json:"sdkVersion"`
}

func Register(conn *websocket.Conn, functions []FunctionDef) error {
    msg := RegisterMessage{
        Type:       "register",
        Functions:  functions,
        Language:   "go",
        SDKVersion: "0.1.0",
    }
    return conn.WriteJSON(msg)
}

Step 3: Handle invocations

type InvokeMessage struct {
    Type     string                 `json:"type"`
    ID       string                 `json:"id"`
    Function string                 `json:"function"`
    Args     map[string]interface{} `json:"args"`
    Context  map[string]interface{} `json:"context"`
}

type ResultMessage struct {
    Type   string      `json:"type"`
    ID     string      `json:"id"`
    OK     bool        `json:"ok"`
    Data   interface{} `json:"data,omitempty"`
    Error  *ErrorBody  `json:"error,omitempty"`
}

type ErrorBody struct {
    Code      string `json:"code"`
    Message   string `json:"message"`
    Retryable bool   `json:"retryable"`
}

type Handler func(args map[string]interface{}, ctx map[string]interface{}) (interface{}, error)

func Listen(conn *websocket.Conn, handlers map[string]Handler) {
    for {
        var raw map[string]interface{}
        if err := conn.ReadJSON(&raw); err != nil {
            // reconnect with exponential backoff
            break
        }

        msgType, _ := raw["type"].(string)

        switch msgType {
        case "invoke":
            id, _ := raw["id"].(string)
            fn, _ := raw["function"].(string)
            args, _ := raw["args"].(map[string]interface{})
            ctx, _ := raw["context"].(map[string]interface{})

            handler, ok := handlers[fn]
            if !ok {
                conn.WriteJSON(ResultMessage{
                    Type: id, ID: id, OK: false,
                    Error: &ErrorBody{Code: "FUNCTION_NOT_FOUND", Message: fn},
                })
                continue
            }

            result, err := handler(args, ctx)
            if err != nil {
                conn.WriteJSON(ResultMessage{
                    Type: "result", ID: id, OK: false,
                    Error: &ErrorBody{Code: "HANDLER_ERROR", Message: err.Error()},
                })
            } else {
                conn.WriteJSON(ResultMessage{
                    Type: "result", ID: id, OK: true, Data: result,
                })
            }

        case "ping":
            conn.WriteJSON(map[string]string{"type": "pong"})

        case "send":
            // Handle outbound message delivery (BYO channel)
        }
    }
}

Step 4: Full example

package main

import (
    "log"
    "os"
)

func main() {
    secret := os.Getenv("AELIO_SDK_SECRET")
    url := os.Getenv("AELIO_SERVER_URL")

    conn, err := Connect(secret, url)
    if err != nil {
        log.Fatal(err)
    }

    functions := []FunctionDef{
        {
            Name:        "getOrderStatus",
            Description: "Get the status of a customer order",
            Params:      map[string]interface{}{"orderId": map[string]string{"type": "string"}},
            Safety:      "read",
        },
    }

    if err := Register(conn, functions); err != nil {
        log.Fatal(err)
    }

    handlers := map[string]Handler{
        "getOrderStatus": func(args, ctx map[string]interface{}) (interface{}, error) {
            return map[string]interface{}{
                "orderId":    args["orderId"],
                "customerId": ctx["customerId"],
                "status":     "shipped",
            }, nil
        },
    }

    log.Println("Aelio SDK connected (Go)")
    Listen(conn, handlers)
}

Step 5: Run

AELIO_SDK_SECRET=change-me-in-production \
AELIO_SERVER_URL=ws://127.0.0.1:3010 \
go run main.go

Protocol reference

DetailValue
WebSocket path/sdk
Auth headerAuthorization: Bearer <secret>
Register timeout15 seconds
Heartbeat interval30 seconds
Heartbeat timeout60 seconds
Max frame size64 KB
Max connections32
Reconnect backoffExponential, max 30s

Message types

Client → Server: register, result, pong, ingest, set_state, set_flow_progress

Server → Client: invoke, send, ping, error, ack

See the full SDK Wire Protocol reference.

Reference implementations

  • Python SDK: sdk/python/sdk.py (~330 lines) — best minimal reference
  • Node SDK: sdk/node/src/index.ts — full-featured reference
  • Protocol types: packages/protocol/src/index.ts — Zod schemas
  • Server validation: server/src/routes/sdk.ts — what the server expects

On this page