thalovant

package module
v0.5.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2026 License: MIT Imports: 36 Imported by: 0

README

Thalovant Go SDK

Go SDK for connecting services, CLIs, devices, and agents to Thalovant hubs.

The control API is used to discover hubs and provision a client identity. After that, the SDK talks directly to the hub data plane over HTTPS, WSS, or MQTTS.

Full docs: https://docs.thalovant.com/developers/sdks/go/

What You Need

  • A Thalovant account with API access for authenticated control-plane actions.
  • A hub id or slug.
  • A client identity for that hub. You can create one through the API or use one downloaded from the dashboard.

Install

Use Go 1.26 or newer so the SDK receives supported upstream networking security fixes.

go get github.com/thalovant/thalovant-go-sdk

Quick Start

package main

import (
	"context"
	"fmt"

	thalovant "github.com/thalovant/thalovant-go-sdk"
)

func main() {
	ctx := context.Background()
	control := thalovant.NewDefaultControlPlane("")

	// Public hub discovery does not require auth.
	publicHubs, err := control.ListPublicHubs(ctx, 12, "")
	if err != nil {
		panic(err)
	}
	for _, raw := range publicHubs["data"].([]any) {
		hub := raw.(map[string]any)
		fmt.Println(hub["id"], hub["slug"], hub["title"])
	}

	// Auth is required when creating a client identity.
	if _, err := control.Login(ctx, "you@example.com", "password", ""); err != nil {
		panic(err)
	}

	result, err := control.CreateClientIdentityForHubID(ctx, "hub-id", thalovant.BootstrapIdentityOptions{
		Name:               "go-demo-client",
		PreferredProtocols: []thalovant.HubProtocol{thalovant.ProtocolWSS, thalovant.ProtocolHTTPS, thalovant.ProtocolMQTT},
	})
	if err != nil {
		panic(err)
	}

	client, err := thalovant.NewClientWithOptions(result.Identity, thalovant.ClientOptions{
		Protocol: thalovant.ProtocolWSS,
	})
	if err != nil {
		panic(err)
	}
	defer client.Close(ctx)

	info, err := client.ConnectWithInfo(ctx)
	if err != nil {
		panic(err)
	}
	fmt.Println("connected in", info.ConnectMS, "ms")

	reply, err := client.Ask(ctx, "Tell me a short clean joke.", thalovant.RequestOptions{})
	if err != nil {
		panic(err)
	}
	fmt.Println(reply.Text)
}

NewDefaultControlPlane uses https://api.thalovant.com. Use NewControlPlane only for local development or a self-hosted control plane. Credential-bearing control requests require HTTPS; HTTP is supported only for literal localhost, 127.0.0.1, and [::1] development endpoints. Control requests do not follow redirects, including when using an injected http.Client, so login passwords and bearer credentials remain bound to the chosen endpoint.

Login With MFA

Accounts with multi-factor authentication enabled are rejected with HTTP 401 {"code": "mfa_required"} by a plain Login call. Use LoginWithOptions to pass a TOTP code, or a recovery code when the authenticator is unavailable:

control := thalovant.NewDefaultControlPlane("")

// With a TOTP code from an authenticator app.
_, err := control.LoginWithOptions(ctx, "you@example.com", "password", thalovant.LoginOptions{
	OTPCode: "123456",
})

// Or with a one-time recovery code.
_, err = control.LoginWithOptions(ctx, "you@example.com", "password", thalovant.LoginOptions{
	RecoveryCode: "your-recovery-code",
})

LoginOptions.Scope matches the scope argument of Login. Empty fields are omitted from the request body, so LoginWithOptions with a zero-value LoginOptions behaves exactly like Login without a scope.

Sign In With the Browser (Device Flow)

Accounts without a password (for example Google sign-in) use the device flow. LoginWithBrowser accepts only HTTP(S) verification URLs with a host and no embedded credentials. Browser launch uses direct arguments without a command shell. It prints a verification URL and a short user code, opens the browser on a best-effort basis, and polls until you approve the request:

control := thalovant.NewDefaultControlPlane("")

token, err := control.LoginWithBrowser(ctx, thalovant.DeviceLoginOptions{
	Scopes:     []string{"hubs:read", "clients:write"}, // optional
	ClientName: "my-cli",                               // optional label in the dashboard
})
if err != nil {
	panic(err)
}
fmt.Println("signed in, token id:", token["token_id"])

On approval the returned access_token is a durable scoped API token; it is stored on control.AccessToken exactly like Login, so subsequent control-plane calls are authenticated. The server may expand the echoed scopes during normalization.

Options:

  • OpenBrowser: *bool, defaults to true when nil. Set it to a false pointer on headless hosts; the plain verification URL and code are always shown.
  • Prompt: func(grant map[string]any) replaces the default stdout message. The grant carries verification_uri, user_code, and verification_uri_complete.
  • Timeout: total approval wait, 15 minutes when zero.

Failures are distinct sentinel errors: errors.Is(err, thalovant.ErrDeviceAccessDenied) when the request is denied in the browser, thalovant.ErrDeviceCodeExpired when the code expires unapproved (call LoginWithBrowser again for a new code), and thalovant.ErrTimeout when the wait elapses. Context cancellation is honored between polls.

CI: Direct API Token Auth

Non-interactive environments should skip login entirely and construct the control plane with a pre-provisioned API token, such as one issued by LoginWithBrowser on a workstation:

control := thalovant.NewDefaultControlPlane(os.Getenv("THALOVANT_API_TOKEN"))

page, err := control.ListHubs(ctx, 50, "", "")

ControlPlane.AccessToken is an exported field, so an existing instance can also be pointed at a token directly: control.AccessToken = token.

Keep result.Identity secret: it holds the client's data-plane credentials. result.Summary(false) — the default — is safe to log: it redacts the secret fields of the identity and of the raw hub/client maps (the initial_identify access key/password/crypto key/MQTT password, the initial_identify_token, and the echoed spec apiKey/password/cryptoKey). The crypto key is no longer issued, but the redaction still names it so an older stored payload that carries one cannot be logged. result.Summary(true) returns every one of those secrets in the clear and must never be logged or written to an untrusted sink. The redaction covers human-facing formatting only; json.Marshal of the identity itself (for the identity file you persist with chmod 600) still contains the real secrets by design.

List Your Hubs

Authenticated accounts can list owned or visible hubs:

control := thalovant.NewDefaultControlPlane("")
_, _ = control.Login(ctx, "you@example.com", "password", "")

page, err := control.ListHubs(ctx, 50, "", "")
if err != nil {
	panic(err)
}
for _, raw := range page["data"].([]any) {
	hub := raw.(map[string]any)
	fmt.Println(hub["id"], hub["slug"], hub["title"])
}

Provision Hubs

Hubs, runtime groups, and skills can be created and managed from code. These routes need a paid plan and a token with the hubs:write scope ("Create and update your hubs" on the dashboard's API Tokens page). A free-plan token fails with HTTP 402 and API access requires a paid plan., and a token without the scope fails with HTTP 403 and Insufficient scopes.

control := thalovant.NewDefaultControlPlane(os.Getenv("THALOVANT_API_TOKEN"))

// 1. Discover what is installable before provisioning anything.
catalog, err := control.ListMarketplaceSkills(ctx, thalovant.MarketplaceSkillListOptions{})
if err != nil {
	panic(err)
}
for _, raw := range catalog["data"].([]any) {
	skill := raw.(map[string]any)
	fmt.Println(skill["skill_id"], skill["title"], skill["access_tier"])
}

// 2. Create a runtime group to run the skills.
group, err := control.CreateRuntimeGroup(ctx, map[string]any{
	"name":        "kiosks",
	"description": "Lobby kiosks",
})
if err != nil {
	panic(err)
}
groupID := group["id"].(string)

// 3. Create a hub attached to it.
hub, err := control.CreateHub(ctx, map[string]any{
	"name":             "joke-garden",
	"runtime_group_id": groupID,
	"spec":             map[string]any{"protocols": map[string]any{"wss": map[string]any{"enabled": true}}},
}, thalovant.HubCreateOptions{})
if err != nil {
	panic(err)
}
hubID := hub["id"].(string)

// 4. Install a skill from the marketplace catalog.
if _, err := control.InstallRuntimeGroupSkill(ctx, groupID, "skill-weather", thalovant.RuntimeGroupSkillInstallOptions{}); err != nil {
	panic(err)
}

// 5. Release: roll the runtime and the hub onto a release channel.
if _, err := control.ReleaseRuntimeGroup(ctx, groupID, thalovant.ReleaseOptions{Channel: "stable"}); err != nil {
	panic(err)
}
if _, err := control.ReleaseHub(ctx, hubID, thalovant.ReleaseOptions{Channel: "stable"}); err != nil {
	panic(err)
}

CreateHub always sends an Idempotency-Key. For safe caller retries, choose one HubCreateOptions.IdempotencyKey before the first attempt and reuse it after a timeout. Leaving it empty generates a fresh key for each call; retrying with empty options can create a second hub.

Updating and deleting a hub use optimistic locking, so etag is a required argument rather than an option. Pass the etag from the hub resource you read; the SDK sends it as If-Match, and the API rejects a stale value with HTTP 412 without changing anything. Empty or whitespace-only values fail locally with ErrAPI before a request is sent:

hub, err := control.GetHub(ctx, hubID)
if err != nil {
	panic(err)
}
etag, ok := hub["etag"].(string)
if !ok || etag == "" {
	panic("hub response has no etag")
}
hub, err = control.UpdateHub(ctx, hubID, map[string]any{"active": false}, etag)
if err != nil {
	panic(err)
}
etag, ok = hub["etag"].(string)
if !ok || etag == "" {
	panic("updated hub response has no etag")
}
if err := control.DeleteHub(ctx, hubID, etag); err != nil {
	panic(err)
}

Deleting a hub also deletes its clients and ACLs. Runtime groups have no If-Match requirement, but the API refuses to delete the workspace default group or a group that still has hubs attached (HTTP 409).

Payload maps take the API's snake_case keys; the camelCase spellings (runtimeGroupId, ownerId, capacityProfile, isLocked, cloneFromDefault) are accepted too and are renamed before the request is sent, so neither spelling is silently dropped.

Runtime configuration is merged, not replaced, and Personas is replaced only when set:

_, err = control.UpdateRuntimeGroupConfig(ctx, groupID, map[string]any{"lang": "en-us"}, thalovant.RuntimeGroupConfigOptions{})

config, err := control.GetRuntimeGroupConfig(ctx, groupID)
fmt.Println(config["config"])

Rating a public hub with SetHubRating and ClearHubRating needs the hubs:write scope but, unlike the routes above, no paid plan. Reading what a hub is actually running needs the hubs:inspect scope instead:

capabilities, err := control.GetHubRuntimeCapabilities(ctx, hubID)
fmt.Println(capabilities["counts"].(map[string]any)["total_intents"])

Discover Skills

The marketplace catalog is readable with the hubs:read scope and, unlike the provisioning routes above, is not paid-gated — a free-plan token can browse the whole catalog before upgrading, and only the install needs a paid plan.

catalog, err := control.ListMarketplaceSkills(ctx, thalovant.MarketplaceSkillListOptions{})
if err != nil {
	panic(err)
}
for _, raw := range catalog["data"].([]any) {
	skill := raw.(map[string]any)
	fmt.Println(skill["skill_id"], skill["category"], skill["access_tier"])
}

Each entry carries what an install needs (skill_id, source_type, source_ref, config_schema, secret_schema) next to presentation fields (title, summary, tags, verified). Admin tokens can additionally set OwnerID to read another tenant's catalog and IncludeInactive to see retired entries; both are silently ignored for non-admin callers, which are scoped to their own tenant and to active entries. ForceRefresh re-syncs the global catalog from source first, which is slower.

Two group-scoped reads need the hubs:inspect scope and are likewise not paid-gated. The first resolves the catalog against one runtime group, so each entry reports whether it is already desired, whether it was observed running, and whether the tenant plan allows installing it:

view, err := control.ListRuntimeGroupMarketplace(ctx, groupID, thalovant.RuntimeGroupMarketplaceOptions{})
if err != nil {
	panic(err)
}
for _, raw := range view["data"].([]any) {
	entry := raw.(map[string]any)
	if entry["installable"] == true && entry["active"] != true {
		fmt.Println("available:", entry["skill_id"])
	}
}

The second answers what the group is actually running right now, rather than what could be installed:

inventory, err := control.ListRuntimeGroupInventory(ctx, groupID, thalovant.RuntimeGroupInventoryOptions{Refresh: true})
if err != nil {
	panic(err)
}
fmt.Println(inventory["source"], len(inventory["data"].([]any)))

Both answer from a cached inventory snapshot by default; set RefreshInventory or Refresh to force a live read from the runtime operator. When nothing is reporting yet, ListRuntimeGroupInventory returns an empty data list with a pending source rather than failing — GetHubRuntimeCapabilities is the one that answers HTTP 409 in that case.

Workspace Analytics

Authenticated accounts can read the same overview used by the dashboard:

overview, err := control.GetAnalyticsOverview(ctx, thalovant.AnalyticsOverviewOptions{
	Range: "7d",
	HubID: "hub-id",
})
if err != nil {
	panic(err)
}
fmt.Println(overview["totals"])

Durable Memory

Private Daily Desk and workspace assistants can manage explicit opt-in memory:

memory, err := control.CreateMemoryItem(ctx, map[string]any{
	"scope":   "workspace",
	"kind":    "preference",
	"content": "Prefer America/Toronto for scheduling.",
	"tags":    []string{"timezone"},
})
if err != nil {
	panic(err)
}
fmt.Println(memory["id"])

items, err := control.ListMemoryItems(ctx, thalovant.MemoryListOptions{
	Scope: "workspace",
	Query: "timezone",
})
if err != nil {
	panic(err)
}
fmt.Println(items["data"])

Use An Existing Identity

For local development, store one or more identities in the protected SDK config:

mkdir -p ~/.config/thalovant
chmod 700 ~/.config/thalovant
$EDITOR ~/.config/thalovant/config.yaml
chmod 600 ~/.config/thalovant/config.yaml
profile: prod
profiles:
  prod:
    identity:
      access_key: ...
      password: ...
      site_id: demo-agent
      default_master: https://jokes.thalovant.io
      data_plane_endpoints:
        wss: wss://jokes.thalovant.io/public
        https: https://jokes.thalovant.io/public
        mqtt: mqtts://mqtt.thalovant.com:8883
      mqtt:
        endpoint: mqtts://mqtt.thalovant.com:8883
        username: ...
        password: ...
        topic_prefix: hubs/hub-id/clients/client-id
        tls: true
client, err := thalovant.NewClientFromConfig("", "prod")
if err != nil {
	panic(err)
}
defer client.Close(ctx)

reply, err := client.Ask(ctx, "What can this hub do?", thalovant.RequestOptions{})
if err != nil {
	panic(err)
}
fmt.Println(reply.Text)

SDKs reject config files that are readable or writable by other users on Linux and macOS. Keep this file out of git.

Raw identity files are supported too:

client, err := thalovant.NewClientFromFile("_identity.json")

Environment variables are supported too:

client, err := thalovant.NewClientFromEnv()
Runtime capabilities and concurrent replies

IntentsWithCapabilities adds optional fallback discovery without changing existing HubIntentInventory literals:

capabilities, err := client.IntentsWithCapabilities(ctx, []string{"en-us"}, thalovant.IntentOptions{})
if err != nil { return err }
fmt.Println(capabilities.Inventory.Source, capabilities.FallbacksKnown)
fmt.Println("may answer:", capabilities.MayAnswer("en-us"))

Fallbacks contains skill IDs and numeric priorities, sorted by priority and skill ID. The optional probe has a 1.5-second budget including connect, send and reply collection. Unsupported, silent, refused, malformed or explicitly failed listings remain unknown; an explicit empty list is known-empty. MayAnswer is a conservative capability hint, not a guarantee that the next request will succeed. Disabled intent phrases do not imply that the runtime can answer them. ListFallbacks(ctx, timeout) exposes the probe directly; nil means unknown.

Use client.SubscribeEvents(capacity) for an independent observer and call its Close method when finished. Its channel closes with ErrEventOverflow if the consumer falls behind. Treat delivered events and their maps as read-only. Transport SubscribeHiveMessages supports independent query/cascade observers. Legacy Events and HiveMessages channels remain available for compatibility; the bounded subscription API reports overflow explicitly.

WaitForEvent(ctx, name, EventOptions) waits for one named event with a default 12-second deadline including connection. Listen returns a filtered subscription:

stream, err := client.Listen(ctx, thalovant.EventSpeak, thalovant.ListenOptions{
    EventOptions: thalovant.EventOptions{Timeout: 30*time.Second, SessionID: "session-id"},
    MaxEvents: 10,
    Capacity: 128,
})
if err != nil { return err }
defer stream.Close()
for event := range stream.C { fmt.Println(event.Text()) }
if err := stream.Err(); err != nil { return err }

Both support Context, RequestID, SessionID, and a Predicate function. Matching request IDs take precedence over the hub-assigned session ID; ID-less legacy events retain session fallback. Listen has no lifetime/count cap when Timeout/MaxEvents are zero, so use a cancellable context or call Close. Buffers default to 256 events and are capped at 65536. Timeout, disconnect and slow-consumer overflow are explicit errors; reaching MaxEvents or calling Close succeeds. Cancellation removes the subscription even if a custom predicate is still pending; predicates should return promptly.

AskWithOptions adds ReplySettle (default 250ms) and EmptyReplyWait (default 5s) alongside embedded RequestOptions. The request deadline bounds connection, send and reply collection. First nonempty speech starts a fixed settlement window; first handled or soft intent-miss without speech starts a fixed empty wait. Later fragments do not reset settlement. Collected speech is returned when the total deadline clips a window, even if an admitted write is still retiring. Policy denial or explicit query timeout freezes the partial reply immediately; soft intent misses can recover. Query waits for hive.query.complete or a hard terminal event. Ask requires the matching request ID and accepts a runtime-replaced session ID; ambient events cannot satisfy it. Existing Ask calls use the same defaults. Cancellation does not replay an application request, and a retiring send retains transport ownership until its cleanup completes.

Connection callers share authenticated readiness. A canceled or timed-out caller cannot race a later connection against its unfinished cleanup. Close uses the client connection timeout by default (6s) and honors an earlier context deadline; ConnectWithInfo includes diagnostic collection in that same deadline, even for custom transports. HTTP cleanup continues after a timed-out caller until its old poll retires, and reconnect waits for that owned cleanup; a timeout means cleanup has not completed, so do not reuse that identity in a separate client. Do not copy a Client or built-in transport after first use.

Noise trust writes use atomic publication and an OS lock shared across processes. An interrupted writer cannot publish a partial static key or lose another hub's pin. A conflicting pin requires explicit verification and ForgetNoisePin. Saved pin values and new pins require exactly 64 hexadecimal characters (32 bytes) and a nonempty node ID. Invalid trust files, including null or empty pin values, fail before any rewrite; diagnose and repair that state explicitly. Hexadecimal case does not change key identity; idempotent checks preserve existing file bytes. Sharing a state directory does not permit simultaneous runtime sessions with the same identity: each active connection needs its own identity.

CI runs race-enabled tests on Linux, macOS and Windows, both minimum/current Go on Linux, reachable vulnerability analysis and a bounded frame-parser fuzz run. Tests use local TLS/Noise peers and cover process crashes, concurrent discovery, reconnect ownership, canceled writes and request correlation.

Protocols

Hubs may expose one or more public data-plane protocols:

  • wss: secure realtime WebSocket, the default public path and SDK preference.
  • https: request/response HTTP protocol exposed as HTTPS.
  • mqtt: broker-mediated MQTT over TLS. Requires per-client broker credentials.
Transport Security

wss, https, and mqtt connections perform the HiveMind v3 Noise handshake (Noise_XXpsk2_25519_ChaChaPoly_SHA256, or KKpsk0 once the hub's static key is pinned). It is the only key exchange a HiveMind-core 5.x hub accepts: there is no pre-shared crypto_key any more, no cleartext path, and a connection that cannot complete the handshake never becomes ready. A WebSocket hub refusal may close with code 1008.

Nothing extra has to be provisioned. The Noise pre-shared key is derived from the identity password with argon2id, salted with the hub's node id, so an identity that can authenticate can already handshake.

Two files persist beside the SDK config file (~/.config/thalovant unless XDG_CONFIG_HOME or %APPDATA% says otherwise), both 0600 on Unix. Windows inherits directory access controls; use an application-private directory accessible only to the intended user. The state filesystem must support atomic rename and hard links (for example ext4, APFS or NTFS); unsupported storage fails without replacing the existing identity. The files are:

  • noise_key — this client's static X25519 key. It has to persist: a hub pins it on first contact, so regenerating it makes the client look like a different peer and the hub refuses it.
  • noise_pins.json — the hub static keys this client has pinned.

Set NoiseStateDir on WSSTransport, HTTPTransport, or MQTTTransport to use another persistent directory. Reuse the same directory and identity when switching transports; do not regenerate a paired client's static key.

The first connection to a hub trusts the key it presents and records it. A later connection presenting a different key is refused, because the SDK cannot tell a reinstalled hub from another machine answering at the same address. If the hub really was replaced, clear the pin deliberately:

if err := thalovant.ForgetNoisePin("", nodeID); err != nil {
	panic(err)
}

The derivation costs 64 MiB and a few hundred milliseconds. WSS caches the result per hub; HTTP and MQTT derive from the current password on each fresh connection. All transports retain the hub pin after authentication failures.

An unconfirmed HTTP disconnect retains cleanup responsibility. A retry recognizes the hub's exact already-disconnected acknowledgment when its earlier success response was lost; arbitrary refusals and contradictory acknowledgments still fail. Pins and replica affinity remain intact.

HTTP reconnect first resets this transport object's previously admitted peer, so a failed poll can recover even while the hub still retains the old session. An initial connection does not disconnect a peer admitted by another process.

HTTP preserves the hub's replica affinity cookie and posts encrypted frames as Base64 form data with binary=1; encrypted replies arrive through /get_binary_messages. Non-success HTTP status codes and JSON error responses other than the exact idempotent disconnect acknowledgment invalidate the connection. MQTT carries the same Noise frames as raw binary payloads after its initial cleartext HELLO and Noise exchange. TLS remains required on HTTP and MQTT because the access key and broker credentials also need protection. MQTTTransport.TLSConfig can supply private CA roots.

MQTT uses an opaque random broker connection ID; the access key still appears in the protocol-required topic paths. Use a distinct identity per simultaneous client because the hub keys its Noise sessions by identity.

A broker disconnect invalidates MQTT readiness. Call Connect again to resubscribe and negotiate a fresh Noise session; Paho's automatic connection resumption is disabled because it would retain stale encryption counters. Concurrent sends serialize complete encrypted messages and their chunks. Passing encrypt=false to SendHiveMessage cannot bypass Noise.

For an explicit transport and persistent identity state:

transport := thalovant.NewHTTPTransport(identity)
transport.NoiseStateDir = "/var/lib/my-agent/thalovant"
if err := transport.Connect(ctx); err != nil {
    return err
}
defer transport.Disconnect(ctx)
// Connect returns only after the Noise exchange and encrypted HELLO succeed.
err := transport.EmitBus(ctx, "ovos.intent.list", thalovant.Data{},
    thalovant.Context{"request_id": thalovant.NewSessionID()})

HTTPTransport.RemoteStaticKey() and MQTTTransport.RemoteStaticKey() expose the authenticated hub key, as WSS already does. An interrupted or tampered session must reconnect before sending again.

Inspect what an identity supports:

identity := result.Identity

fmt.Println(identity.EnabledProtocols())
fmt.Println(identity.EndpointFor(thalovant.ProtocolWSS))
fmt.Println(identity.EndpointFor(thalovant.ProtocolHTTPS))
fmt.Println(identity.EndpointFor(thalovant.ProtocolMQTT))
if identity.MQTT != nil {
	fmt.Println(identity.MQTT.Endpoint)
}

Connect with a specific protocol:

for _, protocol := range []thalovant.HubProtocol{
	thalovant.ProtocolWSS,
	thalovant.ProtocolHTTPS,
	thalovant.ProtocolMQTT,
} {
	if !identity.SupportsProtocol(protocol) {
		continue
	}
	if protocol == thalovant.ProtocolMQTT && identity.MQTT == nil {
		continue
	}

	client, err := thalovant.NewClientWithOptions(identity, thalovant.ClientOptions{Protocol: protocol})
	if err != nil {
		panic(err)
	}
	reply, err := client.Ask(ctx, fmt.Sprintf("Reply over %s.", protocol), thalovant.RequestOptions{})
	_ = client.Close(ctx)
	if err != nil {
		panic(err)
	}
	fmt.Println(protocol, reply.Text)
}

Use client.ConnectWithInfo(ctx) when you need connection telemetry for benchmarks or health dashboards. The returned snapshot includes phase, socket/open time, handshake time, total connect time, and last error.

Use client.Query(ctx, ...) for the direct HiveMind query frame path when the hub supports it. It avoids broad bus fanout and is the preferred request/reply API for low-latency app integrations.

reply, err := client.Query(ctx, "What time is it in Toronto?", thalovant.QueryOptions{})

MQTT identities include a broker endpoint, username, password, TLS flag, and topic prefix. The broker credentials are scoped to that client and should be treated like a password. Public identities should use mqtts://; the SDK also honors an explicit tls: true flag from the identity.

Conversations

Use a conversation when related turns should share one session.

conversation := client.Conversation(thalovant.ConversationOptions{Lang: "en-us"})

first, err := conversation.Ask(ctx, "Remember that my favorite color is blue.", thalovant.RequestOptions{})
if err != nil {
	panic(err)
}
second, err := conversation.Ask(ctx, "What color did I mention?", thalovant.RequestOptions{})
if err != nil {
	panic(err)
}

fmt.Println(first.Text)
fmt.Println(second.Text)

Client Context

Context lets skills know which app, device, user, or channel made the request.

requestContext := thalovant.BuildClientContext(nil, thalovant.ClientContextOptions{
	UserID:       "user-42",
	UserName:     "Ada",
	AuthProvider: "oidc",
	Roles:        []string{"member"},
	Platform:     "kiosk",
	Source:       "checkout-kiosk",
	Channel:      "chat",
})

reply, err := client.Ask(ctx, "Show the next instruction.", thalovant.RequestOptions{
	Context: requestContext,
})

Actions And Exact Inputs

Use actions for button payloads and codes for exact typed or scanned values.

conversation := client.Conversation(thalovant.ConversationOptions{SessionID: "work-session"})

_ = conversation.SendAction(ctx, `/choose{"id":"42"}`, thalovant.ActionOptions{Title: "Choose item"})
_ = conversation.SendCode(ctx, "SN-001-XYZ", thalovant.CodeOptions{Kind: "qr", Label: "serial"})

Rich Responses

Replies can include text, choices, tables, images, or attachments.

items := reply.DisplayItems(600)
for _, item := range items {
	if item.Kind == "text" {
		fmt.Println(item.Text)
	}
}

What A Hub Can Be Asked

A connected client can ask its hub what can be said, over its own session and with no control-plane token. The hub runtime keeps an intent manifest: every intent each skill registered, per language, and for template intents the sentences the skill's locale files wrote, {slot} placeholders included.

inventory, err := client.Intents(ctx, []string{"en-us", "fr-fr"})
if err != nil {
	var denied *thalovant.PolicyDeniedError
	if errors.As(err, &denied) {
		// This connection may not publish denied.DeniedType; denied.Allowed
		// lists what it may.
	}
	panic(err)
}
for _, skill := range inventory.Skills {
	fmt.Println(skill.SkillID, skill.Languages())
	for _, intent := range skill.Intents {
		fmt.Println("  ", intent.ID(), intent.Engine, intent.Examples("en-us", 2))
	}
}

Each HubIntent carries Phrases keyed by language, PhrasesFor(lang) — tags compare case-insensitively with _ and - folded, so fr_FR finds fr-fr — and Examples(lang, limit), which prefers whole sentences to ones with a slot, shorter first. Engine is padatious for a template intent and adapt for a keyword one.

inventory.Source is intent-manifest when the sentences came from the manifest. A refused or silent ovos.intent.list query uses the engines' own manifests instead: the result then carries names only, Source is engine-manifests, the legacy Denied field names ovos.intent.list for either case (silence does not prove a policy refusal), and HasPhrases() is false. IntentOptions tunes the call — Timeout bounds each query the hub is sent (5 seconds when zero), Fallback set to a false pointer returns the original refusal or timeout instead of falling back, and Describe set to a false pointer skips the per-intent describes and returns names and engines only:

no := false
inventory, err := client.Intents(ctx, nil, thalovant.IntentOptions{
	Timeout:  3 * time.Second,
	Fallback: &no,
})

A nil or empty language list asks for en-us; tags are trimmed, and a language repeated under another spelling (en-us, en-US, en_us) is asked once, under the first spelling given. Built-in transports give concurrent Ask, Query, and inventory calls independent subscriptions. Custom transports should implement EventSubscriber and HiveMessageSubscriber for this behavior; legacy custom implementations sharing one channel must serialize reply collectors. The two underlying queries are exposed too:

// ovos.intent.list: one row per registration in one language.
rows, err := client.ListIntents(ctx, "en-us")

// ovos.intent.describe: the registrations behind one intent, sentences included.
definitions, err := client.DescribeIntent(ctx, rows[0].SkillID, rows[0].IntentName, "en-us")
fmt.Println(definitions[0].Samples)

The connection must be allowed to publish ovos.intent.list; ovos.intent.describe is needed only when the sentences are asked for, which is the default, so Describe set to a false pointer needs the listing alone. A hub that answers a listing {"ok": false} has failed the query rather than refused the type: Intents and ListIntents return an error wrapping ErrRuntime carrying the hub's own text, and the engines' manifests are not asked instead — a listing that failed is not a hub with no intents. The same answer to a describe is a real one, meaning the hub does not know that registration, so that intent simply carries no sentences.

When the runtime does not attach definitions to the listing, each intent is described individually; those requests go out thalovant.DescribeBatch (32) at a time so a hub with many intents cannot burst more replies than the transport's channel holds. An intent the hub does not describe in time simply carries no sentences.

json.Marshal(inventory) produces the same snake_case shape as the Python SDK's as_dict(), so the output can be handed to a satellite, an installer or an agent as is.

Common Issues

  • missing access token: call control.Login(...) or control.LoginWithBrowser(...) before private control-plane actions, or pass an access token to NewControlPlane.
  • HTTP 401 with "code": "mfa_required": the account has MFA enabled; use control.LoginWithOptions(...) with an OTPCode or RecoveryCode.
  • The account has no password (Google sign-in): use control.LoginWithBrowser(...), or mint a durable token once and pass it to NewDefaultControlPlane in CI.
  • API access requires a paid plan: upgrade the workspace before using the SDK control-plane API to provision private resources. Hub ratings and the marketplace catalog are readable without one.
  • HTTP 412 with "ETag mismatch": the etag passed to UpdateHub or DeleteHub is stale or empty. Re-read the hub with GetHub and retry with the etag it returns; nothing was changed.
  • unsupported protocol: the hub does not expose that protocol, or the identity was created before that protocol was enabled.
  • MQTT fails immediately: create or download a fresh client identity after MQTT is enabled. MQTT needs the per-client Identity.MQTT credentials.
  • the hub refused "ovos.intent.list": the connection's allow-list does not include the intent manifest queries. Connections the control plane provisions for SDK clients allow ovos.intent.list, ovos.intent.describe (needed only when definitions are asked for) and the two engine manifest reads by default; for an older client identity, allow them in the dashboard's connection settings or create a fresh identity. The error is a *thalovant.PolicyDeniedError (errors.As) that carries the refused type and the allowed list; by default client.Intents falls back to the engines' manifests and returns names only.
  • ovos.intent.list failed: ...: the hub accepted the query and could not answer it — the text after the colon is the hub's own. This is an error wrapping ErrRuntime, not a *PolicyDeniedError, and no fallback is attempted: the hub's intents are unknown, not absent. Retry, or check the runtime's logs.
  • A request times out: set RequestOptions{Timeout: ...}.
  • HTTP 429 with "code": "token_rate_limited": the API token exceeded its plan's per-minute request rate (60 requests per minute on the free plan). The response carries a Retry-After header and a matching retry_after_seconds; wait that long and resend.
  • HTTP 429 with "code": "token_quota_exceeded": the API token exhausted its plan's daily or monthly call quota. The body names which in quota (daily or monthly) alongside limit, used, and retry_after_seconds; Retry-After points at the next UTC day or month boundary.

Both 429s apply to token-authenticated control-plane calls and are returned as errors wrapping ErrAPI, with the status and selected error message fields. The SDK does not retry automatically and does not expose the HTTP headers or retry_after_seconds as structured metadata. When inspecting a direct API response, honor its authoritative Retry-After value before resending. Check the dashboard for per-plan limits and reset times. See also https://docs.thalovant.com/developers/sdks/go/.

API Shape

  • NewDefaultControlPlane(accessToken)
  • NewControlPlane(apiURL, accessToken) for local or self-hosted control planes
  • control.Login(ctx, email, password, scope)
  • control.LoginWithOptions(ctx, email, password, LoginOptions{Scope: ..., OTPCode: ..., RecoveryCode: ...})
  • control.LoginWithBrowser(ctx, DeviceLoginOptions{Scopes: ..., ClientName: ..., OpenBrowser: ..., Prompt: ..., Timeout: ...})
  • control.ListPublicHubs(ctx, limit, cursor)
  • control.GetPublicHub(ctx, hubRef)
  • control.ListHubs(ctx, limit, cursor, ownerID)
  • control.GetHub(ctx, hubID)
  • control.CreateHub(ctx, payload, HubCreateOptions{IdempotencyKey: ...})
  • control.UpdateHub(ctx, hubID, payload, etag)
  • control.DeleteHub(ctx, hubID, etag)
  • control.ReleaseHub(ctx, hubID, ReleaseOptions{Channel: ..., Mode: ..., Version: ..., Images: ..., Reason: ...})
  • control.SetHubRating(ctx, hubID, rating)
  • control.ClearHubRating(ctx, hubID)
  • control.GetHubRuntimeCapabilities(ctx, hubID)
  • control.ListRuntimeGroups(ctx, ownerID)
  • control.GetRuntimeGroup(ctx, runtimeGroupID)
  • control.CreateRuntimeGroup(ctx, payload)
  • control.UpdateRuntimeGroup(ctx, runtimeGroupID, payload)
  • control.GetRuntimeGroupConfig(ctx, runtimeGroupID)
  • control.UpdateRuntimeGroupConfig(ctx, runtimeGroupID, config, RuntimeGroupConfigOptions{Personas: ...})
  • control.ReleaseRuntimeGroup(ctx, runtimeGroupID, ReleaseOptions{...})
  • control.DeleteRuntimeGroup(ctx, runtimeGroupID)
  • control.InstallRuntimeGroupSkill(ctx, runtimeGroupID, skillID, RuntimeGroupSkillInstallOptions{MarketplaceSkillID: ..., SourceType: ..., SourceRef: ..., VersionPin: ..., Active: ...})
  • control.UninstallRuntimeGroupSkill(ctx, runtimeGroupID, skillID)
  • control.ListMarketplaceSkills(ctx, MarketplaceSkillListOptions{OwnerID: ..., IncludeInactive: ..., ForceRefresh: ...})
  • control.ListRuntimeGroupMarketplace(ctx, runtimeGroupID, RuntimeGroupMarketplaceOptions{RefreshInventory: ...})
  • control.ListRuntimeGroupInventory(ctx, runtimeGroupID, RuntimeGroupInventoryOptions{Refresh: ...})
  • control.GetOperation(ctx, operationID)
  • control.GetAnalyticsOverview(ctx, options)
  • control.ListMemoryItems(ctx, options)
  • control.GetMemorySummary(ctx, ownerID)
  • control.CreateMemoryItem(ctx, payload)
  • control.GetMemoryItem(ctx, memoryID)
  • control.UpdateMemoryItem(ctx, memoryID, payload)
  • control.DeleteMemoryItem(ctx, memoryID)
  • control.CreateClientIdentityForHubID(ctx, hubID, options)
  • IdentityFromConfig(path, profile)
  • IdentityFromFile(path)
  • NewClientFromConfig(path, profile)
  • NewClientFromFile(path)
  • NewClientFromEnv()
  • NewClientWithOptions(identity, ClientOptions{Protocol: ...})
  • client.ConnectWithInfo(ctx)
  • client.ConnectionInfo()
  • client.Query(ctx, text, options)
  • client.Ask(ctx, text, options)
  • client.SendUtterance(ctx, text, options)
  • client.SendAction(ctx, payload, options)
  • client.SendCode(ctx, value, options)
  • client.Conversation(options)
  • client.Intents(ctx, languages, IntentOptions{Timeout: ..., Describe: ..., Fallback: ...})
  • client.ListIntents(ctx, lang, IntentOptions{Timeout: ..., IncludeDefinitions: ...})
  • client.DescribeIntent(ctx, skillID, intentName, lang, IntentOptions{Timeout: ...})

Development

go test ./...

Concurrent Ask calls on one client must use distinct request IDs; concurrent Query calls must use distinct query IDs. An active duplicate fails locally with ErrRuntime before publication. Ask and Query use separate namespaces. Reservations end when their collectors are disposed; existing transport ownership still prevents reuse while an admitted write retires. Use a fresh ID for each later logical operation, including after cancellation; delayed remote replies can outlive a disposed collector. Reuse is appropriate only when an application deliberately correlates the same operation.

Documentation

Index

Constants

View Source
const (
	EventRecognizerLoopUtterance = "recognizer_loop:utterance"
	EventSpeak                   = "speak"
	EventOvosUtteranceSpeak      = "ovos.utterance.speak"
	EventUtteranceHandled        = "ovos.utterance.handled"
	// EventIntentUnmatched is the current OVOS bus event fired when an utterance
	// matches no intent. EventIntentFailure is the legacy Mycroft name for the
	// same signal; both are kept so old and new runtimes are recognised.
	EventIntentUnmatched = "ovos.intent.unmatched"
	EventIntentFailure   = "complete_intent_failure"
	EventPolicyDenied    = "hive.policy.denied"
	EventQueryTimeout    = "hive.query.timeout"
	DefaultUserAgent     = userAgent
	// The hub runtime's intent manifest (OVOS-INTENT-4 section 10) and the
	// engines' own manifests, read by Client.Intents, Client.ListIntents and
	// Client.DescribeIntent. See intents.go.
	EventIntentList             = "ovos.intent.list"
	EventIntentListResponse     = "ovos.intent.list.response"
	EventIntentDescribe         = "ovos.intent.describe"
	EventIntentDescribeResponse = "ovos.intent.describe.response"
	EventAdaptManifestGet       = "intent.service.adapt.manifest.get"
	EventAdaptManifest          = "intent.service.adapt.manifest"
	EventPadatiousManifestGet   = "intent.service.padatious.manifest.get"
	EventPadatiousManifest      = "intent.service.padatious.manifest"
)
View Source
const (
	DefaultControlAPIURL    = "https://api.thalovant.com"
	DefaultControlUserAgent = userAgent

	// DefaultDeviceLoginTimeout bounds how long LoginWithBrowser waits for the
	// user to approve the sign-in request in the browser.
	DefaultDeviceLoginTimeout = 15 * time.Minute
)
View Source
const (
	// IntentSourceManifest marks an inventory read from the hub runtime's
	// intent manifest: sentences per language.
	IntentSourceManifest = "intent-manifest"
	// IntentSourceEngines marks the names-only fallback read from the
	// engines' own manifests; the inventory's Denied then names the query
	// the hub refused.
	IntentSourceEngines = "engine-manifests"
	// DefaultIntentTimeout bounds each intent query when
	// IntentOptions.Timeout is zero.
	DefaultIntentTimeout = 5 * time.Second
	// DescribeBatch is how many describes go out together. A hub with 69
	// intents in two languages is 138 requests and, with every reply
	// delivered twice, 276 inbound events -- more than a transport's reply
	// channel holds, and a burst the hub never asked for. Batching also
	// bounds the deadline: a hub answering nothing fails after one batch
	// rather than holding every request open.
	DescribeBatch = 32
)
View Source
const DefaultConfigFilename = "config.yaml"
View Source
const EventFallbackList = "ovos.skills.fallback.list"
View Source
const EventFallbackListResponse = "ovos.skills.fallback.list.response"
View Source
const NoiseKeyFilename = "noise_key"

NoiseKeyFilename is the static X25519 private key used for every v3 handshake, hex encoded. It must persist: regenerating it on each start makes every connection look like a new peer and defeats pinning in both directions.

View Source
const NoisePinsFilename = "noise_pins.json"

NoisePinsFilename records the server static keys this client has pinned, as a JSON object keyed by the server node id.

View Source
const NoisePskFilename = "noise_psks.json"

NoisePskFilename caches derived pre-shared keys, as a JSON object keyed by the server node id.

The derivation is argon2id at 64 MiB and depends only on the password and the hub's node id, both constant for the life of the pairing, so it is the same answer every time. The in-memory cache on a transport only helps that one object; this survives reconnects, other transports in the same process, and restarts.

Only the key is stored. A fingerprint of the password would make rotation cheap to detect, but it would also put a fast hash of the password in the same file as the key it protects -- and a fast hash is exactly the offline oracle argon2id exists to deny. A rotated password is noticed when the handshake rejects the stale key, and ForgetCachedPSK drops it.

View Source
const Version = "0.5.4"

Version is the module release this package was built from, and the single source of truth for every user agent the SDK sends. The VERSION file at the repository root is the release pipeline's copy of the same number; TestVersionMatchesVersionFile keeps the two in step.

Never hard-code a version inside a user-agent literal anywhere else: TestNoSourceFileHardCodesAUserAgentVersion rejects it.

Variables

View Source
var (
	ErrIdentity   = errors.New("thalovant identity error")
	ErrConnection = errors.New("thalovant connection error")
	ErrTimeout    = errors.New("thalovant timeout")
	ErrRuntime    = errors.New("thalovant runtime error")
	ErrAPI        = errors.New("thalovant api error")
	ErrProtocol   = errors.New("thalovant unsupported protocol")

	// ErrDeviceAccessDenied reports that the browser device sign-in request
	// was denied by the user.
	ErrDeviceAccessDenied = errors.New("thalovant device sign-in denied")
	// ErrDeviceCodeExpired reports that the device sign-in code expired
	// before it was approved.
	ErrDeviceCodeExpired = errors.New("thalovant device sign-in code expired")
)
View Source
var DefaultProtocolPreference = []HubProtocol{ProtocolWSS, ProtocolHTTPS, ProtocolMQTT}
View Source
var ErrEventOverflow = errors.New("runtime event subscription overflow")

ErrEventOverflow means a subscriber did not keep up. The subscription is closed instead of silently losing replies or blocking the Noise reader.

Functions

func DefaultConfigPath added in v0.2.11

func DefaultConfigPath() (string, error)

func EncodeHiveBinaryFrame added in v0.2.5

func EncodeHiveBinaryFrame(message HiveMessage) ([]byte, error)

func EndpointFromDomain added in v0.2.1

func EndpointFromDomain(domain string, protocol HubProtocol) string

func EventMatchesContext

func EventMatchesContext(event Event, expected Context) bool

func ForgetCachedPSK added in v0.4.2

func ForgetCachedPSK(dir, nodeID string) error

ForgetCachedPSK drops a stored key. The handshake calls this when the hub rejects one, which is how a rotated password is noticed: the next attempt derives again from the current one.

func ForgetNoisePin added in v0.4.0

func ForgetNoisePin(dir, nodeID string) error

ForgetNoisePin drops a pinned server key. Use it when a server was deliberately reinstalled or replaced; a pin that stops matching on its own is a failure to investigate, not one to clear.

func LoadCachedPSK added in v0.4.2

func LoadCachedPSK(dir, nodeID string) []byte

LoadCachedPSK returns the stored pre-shared key for a hub, or nil when there is none.

func LoadNoisePin added in v0.4.0

func LoadNoisePin(dir, nodeID string) (string, error)

LoadNoisePin returns the pinned server static key for a node id, or "" when this client has not seen that server before.

func LoadOrCreateNoiseKey added in v0.4.0

func LoadOrCreateNoiseKey(dir string) (noise.DHKey, error)

LoadOrCreateNoiseKey returns this client's persistent static X25519 keypair, generating and storing one on first use.

On Unix the key file is created 0600 and rejected if group/world-accessible. Windows inherits the protected state directory's access controls.

func NewRequestID

func NewRequestID() string

func NewSessionID

func NewSessionID() string

func NoiseStateDir added in v0.4.0

func NoiseStateDir() (string, error)

NoiseStateDir is the directory holding the static key and the pin file. It sits beside the SDK config file, so XDG_CONFIG_HOME and the Windows APPDATA location are honored the same way.

func RequestIDFromContext

func RequestIDFromContext(context Context) string

func RichMediaFromData

func RichMediaFromData(data Data) map[string]any

func SameLanguage added in v0.3.13

func SameLanguage(a, b string) bool

SameLanguage reports whether two language tags name the same language: "fr-fr" and "fr_FR" do.

func SaveCachedPSK added in v0.4.2

func SaveCachedPSK(dir, nodeID string, psk []byte) error

SaveCachedPSK records a derived key so the next connection to this hub skips argon2id. The cache is an optimisation, so callers treat a failure here as non-fatal.

func SaveNoisePin added in v0.4.0

func SaveNoisePin(dir, nodeID, publicKey string) error

SaveNoisePin records the server static key for a node id on first contact.

func SessionIDFromContext

func SessionIDFromContext(context Context) string

func StripSSML

func StripSSML(text string) string

Types

type ActionOptions

type ActionOptions struct {
	Title     string
	Lang      string
	Context   Context
	SessionID string
	RequestID string
}

type AnalyticsOverviewOptions added in v0.2.13

type AnalyticsOverviewOptions struct {
	Range     string
	Bucket    string
	HubID     string
	ClientID  string
	Country   string
	Message   string
	Utterance string
	Intent    string
	TimeStart string
	TimeEnd   string
	Weekday   *int
	Hour      *int
}

type AskOptions added in v0.5.0

type AskOptions struct {
	RequestOptions
	ReplySettle    time.Duration
	EmptyReplyWait time.Duration
}

AskOptions extends RequestOptions without changing existing keyed or unkeyed RequestOptions literals. Zero settlement values use the family defaults.

type BootstrapIdentityOptions added in v0.2.2

type BootstrapIdentityOptions struct {
	Name               string
	SiteID             string
	Spec               map[string]any
	OwnerID            string
	Active             *bool
	PreferredProtocols []HubProtocol
	IdempotencyKey     string
}

type BootstrapIdentityResult added in v0.2.2

type BootstrapIdentityResult struct {
	Identity Identity
	Hub      map[string]any
	Client   map[string]any
	Endpoint *SelectedHubEndpoint
}

func (BootstrapIdentityResult) SelectedProtocol added in v0.2.2

func (r BootstrapIdentityResult) SelectedProtocol() HubProtocol

func (BootstrapIdentityResult) Summary added in v0.2.2

func (r BootstrapIdentityResult) Summary(includeSecrets bool) map[string]any

type Client

type Client struct {
	Identity       Identity
	Transport      RuntimeTransport
	ConnectTimeout time.Duration
	// contains filtered or unexported fields
}

func NewClient

func NewClient(identity Identity) *Client

func NewClientFromConfig added in v0.2.11

func NewClientFromConfig(path string, profile string) (*Client, error)

func NewClientFromEnv

func NewClientFromEnv() (*Client, error)

func NewClientFromFile

func NewClientFromFile(path string) (*Client, error)

func NewClientWithOptions added in v0.2.2

func NewClientWithOptions(identity Identity, opts ClientOptions) (*Client, error)

func (*Client) Ask

func (c *Client) Ask(ctx context.Context, text string, opts RequestOptions) (Reply, error)

func (*Client) AskWithOptions added in v0.5.0

func (c *Client) AskWithOptions(ctx context.Context, text string, opts AskOptions) (Reply, error)

func (*Client) Close

func (c *Client) Close(ctx context.Context) error

func (*Client) Connect

func (c *Client) Connect(ctx context.Context) error

func (*Client) ConnectWithInfo added in v0.2.14

func (c *Client) ConnectWithInfo(ctx context.Context) (TransportConnectionInfo, error)

ConnectWithInfo includes diagnostic collection in the connection deadline. A timed-out custom getter retains operation ownership until it returns.

func (*Client) ConnectionInfo added in v0.2.14

func (c *Client) ConnectionInfo() TransportConnectionInfo

func (*Client) Conversation

func (c *Client) Conversation(opts ConversationOptions) Conversation

func (*Client) DescribeIntent added in v0.3.13

func (c *Client) DescribeIntent(ctx context.Context, skillID, intentName, lang string, opts ...IntentOptions) ([]IntentDefinition, error)

DescribeIntent returns every registration behind one intent in one language, keyword ones first, sentences included for a template intent. An empty lang asks for "en-us". A registration the hub does not know yields an empty list, not an error: ok: false is a real answer here, unlike on the listing, and means the intent has no sentences. Built-in transports support concurrent collectors through independent subscriptions. Legacy custom transports with one shared event channel must serialize collectors.

func (*Client) Emit

func (c *Client) Emit(ctx context.Context, eventType string, data Data, eventContext Context) error

func (*Client) Healthcheck

func (c *Client) Healthcheck() TransportHealth

func (*Client) Intents added in v0.3.13

func (c *Client) Intents(ctx context.Context, languages []string, opts ...IntentOptions) (HubIntentInventory, error)

Intents returns everything the hub can be asked, per language, grouped by skill.

It reads the runtime's intent manifest over this session, so no control-plane credential is involved. Each intent carries the sentences a person says to reach it, as the skill wrote them, "{slot}" placeholders included. A nil or empty languages asks for "en-us"; tags are trimmed and a language repeated under another spelling ("en-US", "en_us") is asked once, under the first spelling given.

The hub's queries are correlated by request id like Ask; a reply delivered more than once is taken once. Unless the runtime attached definitions to the listing, every template registration is described, DescribeBatch of them in flight at a time, and one the hub does not describe in time carries no sentences.

A hub that refuses ovos.intent.list is asked for the engines' own manifests instead, unless IntentOptions.Fallback is false: the result then carries names only, Source set to IntentSourceEngines and Denied naming the refused query. A hub refusing those too, or any refusal with the fallback off, returns a *PolicyDeniedError; a hub that stays silent returns an error wrapping ErrTimeout. A hub that answers the listing ok: false has failed the query rather than refused the type: that returns an error wrapping ErrRuntime, and the engines are not asked instead.

Built-in transports give each call its own bounded event subscription. Hubs that omit request IDs still require one same-type query at a time.

func (*Client) IntentsWithCapabilities added in v0.5.0

func (c *Client) IntentsWithCapabilities(ctx context.Context, languages []string, opts ...IntentOptions) (HubIntentCapabilities, error)

IntentsWithCapabilities adds the optional fallback-handler probe, bounded to 1.5 seconds. Existing Intents remains available for callers that only need the manifest and its established return type.

func (*Client) ListFallbacks added in v0.5.0

func (c *Client) ListFallbacks(ctx context.Context, timeout time.Duration) ([]HubFallback, error)

ListFallbacks returns nil for unsupported, refused, silent or malformed discovery; a non-nil empty slice means the hub reported no handlers. Caller cancellation and transport errors still propagate.

func (*Client) ListIntents added in v0.3.13

func (c *Client) ListIntents(ctx context.Context, lang string, opts ...IntentOptions) ([]IntentRegistration, error)

ListIntents returns the hub's intent manifest for one language, one row per registration. An empty lang asks for "en-us". With IntentOptions.IncludeDefinitions the runtime is asked to attach each row's definition; a runtime that honours it fills IntentRegistration.Definition. A hub that answers ok: false returns an error wrapping ErrRuntime carrying the hub's own text: a listing that failed is not a hub with no intents. Built-in transports give each call its own bounded event subscription. Hubs that omit request IDs still require one same-type query at a time.

func (*Client) Listen added in v0.5.0

func (c *Client) Listen(ctx context.Context, eventName string, options ListenOptions) (*Subscription[Event], error)

Listen connects and returns an independent filtered stream. Range over C and inspect Err afterward; reaching MaxEvents or calling Close is successful. Timeout, caller cancellation, disconnect and overflow close the stream with an explicit error. Legacy custom transports need EventSubscriber for isolation.

func (*Client) Query added in v0.2.15

func (c *Client) Query(ctx context.Context, text string, opts QueryOptions) (Reply, error)

func (*Client) SendAction

func (c *Client) SendAction(ctx context.Context, payload string, opts ActionOptions) error

func (*Client) SendCode

func (c *Client) SendCode(ctx context.Context, value string, opts CodeOptions) error

func (*Client) SendUtterance

func (c *Client) SendUtterance(ctx context.Context, text string, opts RequestOptions) error

func (*Client) SubscribeEvents added in v0.5.0

func (c *Client) SubscribeEvents(capacity int) *Subscription[Event]

func (*Client) WaitForEvent added in v0.5.0

func (c *Client) WaitForEvent(ctx context.Context, eventName string, options EventOptions) (Event, error)

WaitForEvent connects and waits for one matching event within one deadline. The default deadline is 12 seconds, including connection establishment.

type ClientContextOptions

type ClientContextOptions struct {
	UserID       string
	UserName     string
	AuthToken    string
	AuthProvider string
	AuthClaims   map[string]any
	Roles        []string
	Platform     string
	Source       string
	Destination  string
	Channel      string
	DeviceID     string
	Locale       string
	Metadata     map[string]any
	SessionID    string
}

type ClientOptions added in v0.2.2

type ClientOptions struct {
	Protocol       HubProtocol
	ConnectTimeout time.Duration
}

type CodeOptions

type CodeOptions struct {
	Kind      string
	Label     string
	Lang      string
	Context   Context
	SessionID string
	RequestID string
}

type Context

type Context map[string]any

func BuildClientContext

func BuildClientContext(base Context, opts ClientContextOptions) Context

func ContextWithCorrelation

func ContextWithCorrelation(raw Context, sessionID, siteID, lang, requestID string) Context

func MergeContext

func MergeContext(base, extra Context) Context

type ControlPlane added in v0.2.2

type ControlPlane struct {
	APIURL      string
	AccessToken string
	UserAgent   string
	HTTPClient  *http.Client
}

func NewControlPlane added in v0.2.2

func NewControlPlane(apiURL string, accessToken string) *ControlPlane

func NewDefaultControlPlane added in v0.2.8

func NewDefaultControlPlane(accessToken string) *ControlPlane

func (*ControlPlane) ClearHubRating added in v0.3.6

func (c *ControlPlane) ClearHubRating(ctx context.Context, hubID string) (map[string]any, error)

ClearHubRating removes the caller's rating from a public hub and returns the updated hub.

Requires a token with the hubs:write scope; it is not paid-gated.

func (*ControlPlane) CreateClient added in v0.2.2

func (c *ControlPlane) CreateClient(ctx context.Context, payload map[string]any, idempotencyKey string) (map[string]any, error)

func (*ControlPlane) CreateClientIdentity added in v0.2.2

func (c *ControlPlane) CreateClientIdentity(ctx context.Context, hub map[string]any, opts BootstrapIdentityOptions) (BootstrapIdentityResult, error)

func (*ControlPlane) CreateClientIdentityForHubID added in v0.2.2

func (c *ControlPlane) CreateClientIdentityForHubID(ctx context.Context, hubID string, opts BootstrapIdentityOptions) (BootstrapIdentityResult, error)

func (*ControlPlane) CreateHub added in v0.3.6

func (c *ControlPlane) CreateHub(ctx context.Context, payload map[string]any, opts HubCreateOptions) (map[string]any, error)

CreateHub creates a hub.

payload mirrors the API's hub create body: "name" and "spec" are required, and "slug", "namespace", "runtime_group_id", "domain", "active", "visibility", "capacity_profile", and "owner_id" are optional. camelCase keys are accepted and sent as snake_case.

An Idempotency-Key header is always sent. To retry safely after a timeout, reuse the same explicit HubCreateOptions.IdempotencyKey for every attempt. An empty option generates a new key for this call only; repeating such a call can create another hub.

Requires a paid plan and a token with the hubs:write scope. A free-plan token fails with HTTP 402.

func (*ControlPlane) CreateMemoryItem added in v0.2.13

func (c *ControlPlane) CreateMemoryItem(ctx context.Context, payload map[string]any) (map[string]any, error)

func (*ControlPlane) CreateRuntimeGroup added in v0.3.6

func (c *ControlPlane) CreateRuntimeGroup(ctx context.Context, payload map[string]any) (map[string]any, error)

CreateRuntimeGroup creates a runtime group.

payload takes the API's create body: "name" is required, and "description", "environment", "owner_id", and "clone_from_default" are optional. camelCase keys are accepted and sent as snake_case.

Requires a paid plan and a token with the hubs:write scope.

func (*ControlPlane) DeleteHub added in v0.3.6

func (c *ControlPlane) DeleteHub(ctx context.Context, hubID string, etag string) error

DeleteHub deletes a hub and its dependent clients and ACLs.

Like UpdateHub this route requires the hub's current etag, sent as If-Match; a stale value fails with HTTP 412. Empty or whitespace-only etags fail locally with ErrAPI before sending a request.

Requires a paid plan and a token with the hubs:write scope.

func (*ControlPlane) DeleteMemoryItem added in v0.2.13

func (c *ControlPlane) DeleteMemoryItem(ctx context.Context, memoryID string) error

func (*ControlPlane) DeleteRuntimeGroup added in v0.3.6

func (c *ControlPlane) DeleteRuntimeGroup(ctx context.Context, runtimeGroupID string) error

DeleteRuntimeGroup deletes a runtime group.

The API answers HTTP 409 for the workspace default group and for a group that still has hubs attached.

Requires a paid plan and a token with the hubs:write scope.

func (*ControlPlane) GetAnalyticsOverview added in v0.2.13

func (c *ControlPlane) GetAnalyticsOverview(ctx context.Context, opts AnalyticsOverviewOptions) (map[string]any, error)

func (*ControlPlane) GetHub added in v0.2.2

func (c *ControlPlane) GetHub(ctx context.Context, hubID string) (map[string]any, error)

func (*ControlPlane) GetHubRuntimeCapabilities added in v0.3.6

func (c *ControlPlane) GetHubRuntimeCapabilities(ctx context.Context, hubID string) (map[string]any, error)

GetHubRuntimeCapabilities reads the live skill and intent inventory a hub runtime exposes.

Requires a token with the hubs:inspect scope. The API answers HTTP 409 when the hub has no connected client that can report inventory and no runtime group snapshot to fall back on. ListRuntimeGroupInventory is the read that reports a pending source instead of failing.

func (*ControlPlane) GetMemoryItem added in v0.2.13

func (c *ControlPlane) GetMemoryItem(ctx context.Context, memoryID string) (map[string]any, error)

func (*ControlPlane) GetMemorySummary added in v0.2.13

func (c *ControlPlane) GetMemorySummary(ctx context.Context, ownerID string) (map[string]any, error)

func (*ControlPlane) GetOperation added in v0.2.16

func (c *ControlPlane) GetOperation(ctx context.Context, operationID string) (OperationResource, error)

func (*ControlPlane) GetPublicHub added in v0.2.6

func (c *ControlPlane) GetPublicHub(ctx context.Context, hubRef string) (map[string]any, error)

func (*ControlPlane) GetRuntimeGroup added in v0.3.6

func (c *ControlPlane) GetRuntimeGroup(ctx context.Context, runtimeGroupID string) (map[string]any, error)

GetRuntimeGroup fetches one runtime group.

Requires a token with the hubs:read scope.

func (*ControlPlane) GetRuntimeGroupConfig added in v0.3.6

func (c *ControlPlane) GetRuntimeGroupConfig(ctx context.Context, runtimeGroupID string) (map[string]any, error)

GetRuntimeGroupConfig reads a runtime group's runtime configuration and personas.

Requires a token with the hubs:read scope.

func (*ControlPlane) InstallRuntimeGroupSkill added in v0.3.6

func (c *ControlPlane) InstallRuntimeGroupSkill(ctx context.Context, runtimeGroupID string, skillID string, opts RuntimeGroupSkillInstallOptions) (map[string]any, error)

InstallRuntimeGroupSkill installs, or re-installs, a skill in a runtime group.

The default source type of "catalog" installs a marketplace skill and requires the skill to exist in the catalog; a "git" install needs RuntimeGroupSkillInstallOptions.SourceRef. Installing a skill that is already present updates the existing entry.

Requires a paid plan and a token with the hubs:write scope. Paid marketplace skills also need marketplace access on the tenant plan.

func (*ControlPlane) ListHubs added in v0.2.2

func (c *ControlPlane) ListHubs(ctx context.Context, limit int, cursor string, ownerID string) (map[string]any, error)

func (*ControlPlane) ListMarketplaceSkills added in v0.3.6

func (c *ControlPlane) ListMarketplaceSkills(ctx context.Context, opts MarketplaceSkillListOptions) (map[string]any, error)

ListMarketplaceSkills lists the marketplace skill catalog visible to the authenticated user.

The returned "data" entries carry the catalog fields an install needs -- "skill_id", "source_type", "source_ref", "package_name", "version" compatibility, "config_schema" and "secret_schema" -- alongside presentation and access fields such as "category", "tags", "verified", "access_tier" and "billing_sku". Global catalog entries and the caller's own tenant entries are both included.

Requires a token with the hubs:read scope. Unlike the provisioning routes this catalog is not paid-gated, so free-plan callers can browse the marketplace before upgrading; only the install itself needs a paid plan.

func (*ControlPlane) ListMemoryItems added in v0.2.13

func (c *ControlPlane) ListMemoryItems(ctx context.Context, opts MemoryListOptions) (map[string]any, error)

func (*ControlPlane) ListPublicHubs added in v0.2.6

func (c *ControlPlane) ListPublicHubs(ctx context.Context, limit int, cursor string) (map[string]any, error)

func (*ControlPlane) ListRuntimeGroupInventory added in v0.3.6

func (c *ControlPlane) ListRuntimeGroupInventory(ctx context.Context, runtimeGroupID string, opts RuntimeGroupInventoryOptions) (map[string]any, error)

ListRuntimeGroupInventory lists the skills a runtime group is actually observed running.

Where ListRuntimeGroupMarketplace answers "what could be installed here", this answers "what is loaded right now": each entry carries "skill_id", "version", "source", "active", "adapt_intents", "padatious_intents", "total_intents" and "observed_at". The envelope reports the observation's provenance in "source" -- "ovos-runtime-operator", "runtime-group-cache" or "ovos-runtime-operator-pending" -- plus "operator_phase" and "operator_message".

Unlike GetHubRuntimeCapabilities this route does not answer HTTP 409 when nothing is reporting: it returns an empty "data" list with a pending "source" instead.

Requires a token with the hubs:inspect scope; no paid plan is needed.

func (*ControlPlane) ListRuntimeGroupMarketplace added in v0.3.6

func (c *ControlPlane) ListRuntimeGroupMarketplace(ctx context.Context, runtimeGroupID string, opts RuntimeGroupMarketplaceOptions) (map[string]any, error)

ListRuntimeGroupMarketplace lists the marketplace catalog resolved against one runtime group.

This is the discovery view to use before installing: every catalog entry is returned with the group's own state folded in -- whether the skill is desired ("active", "version_pin", "source_type"), whether it was observed running ("observed_source", "observed_at", intent counts), operator status fields, and the access verdict for the tenant plan ("purchase_required", "installable", "access_message"). The envelope also carries "runtime_group_id", "observed_at", "source", "operator_phase" and "operator_message".

Requires a token with the hubs:inspect scope; no paid plan is needed to browse. The API answers HTTP 404 for an unknown group and HTTP 403 when the caller does not own it.

func (*ControlPlane) ListRuntimeGroups added in v0.3.6

func (c *ControlPlane) ListRuntimeGroups(ctx context.Context, ownerID string) (map[string]any, error)

ListRuntimeGroups lists the runtime groups visible to the authenticated user. An empty ownerID is omitted from the query.

Requires a token with the hubs:read scope.

func (*ControlPlane) Login added in v0.2.2

func (c *ControlPlane) Login(ctx context.Context, email string, password string, scope string) (map[string]any, error)

func (*ControlPlane) LoginWithBrowser added in v0.3.3

func (c *ControlPlane) LoginWithBrowser(ctx context.Context, opts DeviceLoginOptions) (map[string]any, error)

LoginWithBrowser signs in through the browser device flow and stores the returned API token. This is the sign-in path for accounts without a password (for example Google sign-in). It requests a device authorization, tells the user to visit verification_uri and enter the short user_code (set DeviceLoginOptions.Prompt to present it yourself), opens the browser at verification_uri_complete on a best-effort basis unless DeviceLoginOptions.OpenBrowser is false, and polls until the request is approved, denied, expired, the timeout elapses, or ctx is cancelled.

On approval the returned access_token is a durable scoped API token and is stored on ControlPlane.AccessToken exactly like Login. Denial, expiry, and timeout are reported as ErrDeviceAccessDenied, ErrDeviceCodeExpired, and ErrTimeout respectively.

func (*ControlPlane) LoginWithOptions added in v0.3.2

func (c *ControlPlane) LoginWithOptions(ctx context.Context, email string, password string, opts LoginOptions) (map[string]any, error)

func (*ControlPlane) ReleaseHub added in v0.3.6

func (c *ControlPlane) ReleaseHub(ctx context.Context, hubID string, opts ReleaseOptions) (map[string]any, error)

ReleaseHub applies a hub release policy and returns the updated hub.

Requires a paid plan and a token with the hubs:write scope.

func (*ControlPlane) ReleaseRuntimeGroup added in v0.3.6

func (c *ControlPlane) ReleaseRuntimeGroup(ctx context.Context, runtimeGroupID string, opts ReleaseOptions) (map[string]any, error)

ReleaseRuntimeGroup applies a runtime image policy and returns the updated runtime group. Options behave like ReleaseHub.

Requires a paid plan and a token with the hubs:write scope.

func (*ControlPlane) RequireRuntimeProtocol added in v0.2.2

func (c *ControlPlane) RequireRuntimeProtocol(result BootstrapIdentityResult, protocol HubProtocol) (*SelectedHubEndpoint, error)

func (*ControlPlane) SetHubRating added in v0.3.6

func (c *ControlPlane) SetHubRating(ctx context.Context, hubID string, rating int) (map[string]any, error)

SetHubRating rates a public hub from 1 to 5 and returns the updated hub.

Only public hubs can be rated, and owners cannot rate their own hubs. Requires a token with the hubs:write scope; unlike the provisioning routes this one is not paid-gated.

func (ControlPlane) String added in v0.3.7

func (c ControlPlane) String() string

String implements fmt.Stringer so the %v, %s, and %+v verbs render a ControlPlane with its AccessToken (a bearer API token) redacted. The receiver is a value so a dereferenced *ControlPlane printed with %v is redacted too. This is a human-facing formatting guard only; it does not affect json.Marshal.

func (*ControlPlane) UninstallRuntimeGroupSkill added in v0.3.6

func (c *ControlPlane) UninstallRuntimeGroupSkill(ctx context.Context, runtimeGroupID string, skillID string) error

UninstallRuntimeGroupSkill removes a skill from a runtime group.

Requires a paid plan and a token with the hubs:write scope.

func (*ControlPlane) UpdateHub added in v0.3.6

func (c *ControlPlane) UpdateHub(ctx context.Context, hubID string, payload map[string]any, etag string) (map[string]any, error)

UpdateHub partially updates a hub.

The API enforces optimistic locking on this route, so etag is required: pass the "etag" of the hub resource you read and the SDK sends it as If-Match. A stale value fails with HTTP 412 and changes nothing; re-read the hub with GetHub and retry with the new etag. Empty or whitespace-only etags fail locally with ErrAPI before sending a request.

Requires a paid plan and a token with the hubs:write scope.

func (*ControlPlane) UpdateMemoryItem added in v0.2.13

func (c *ControlPlane) UpdateMemoryItem(ctx context.Context, memoryID string, payload map[string]any) (map[string]any, error)

func (*ControlPlane) UpdateRuntimeGroup added in v0.3.6

func (c *ControlPlane) UpdateRuntimeGroup(ctx context.Context, runtimeGroupID string, payload map[string]any) (map[string]any, error)

UpdateRuntimeGroup updates a runtime group's "name", "description", or "spec". "spec" patches "replicas" and container "resources". Unlike the hub routes this one reads no If-Match header.

Requires a paid plan and a token with the hubs:write scope.

func (*ControlPlane) UpdateRuntimeGroupConfig added in v0.3.6

func (c *ControlPlane) UpdateRuntimeGroupConfig(ctx context.Context, runtimeGroupID string, config map[string]any, opts RuntimeGroupConfigOptions) (map[string]any, error)

UpdateRuntimeGroupConfig merges runtime configuration into a runtime group.

The API merges config into the stored configuration rather than replacing it, and marks the group pending so the runtime operator reconciles the change. RuntimeGroupConfigOptions.Personas is replaced only when non-nil.

Requires a paid plan and a token with the hubs:write scope.

type Conversation

type Conversation struct {
	Client  *Client
	Options ConversationOptions
}

func (Conversation) Ask

func (c Conversation) Ask(ctx context.Context, text string, opts RequestOptions) (Reply, error)

func (Conversation) Query added in v0.2.15

func (c Conversation) Query(ctx context.Context, text string, opts QueryOptions) (Reply, error)

func (Conversation) SendAction

func (c Conversation) SendAction(ctx context.Context, payload string, opts ActionOptions) error

func (Conversation) SendCode

func (c Conversation) SendCode(ctx context.Context, value string, opts CodeOptions) error

func (Conversation) SendUtterance

func (c Conversation) SendUtterance(ctx context.Context, text string, opts RequestOptions) error

type ConversationOptions

type ConversationOptions struct {
	SessionID string
	Lang      string
	Context   Context
}

type Data

type Data map[string]any

func UtterancePayload

func UtterancePayload(text, lang string) Data

type DeviceLoginOptions added in v0.3.3

type DeviceLoginOptions struct {
	Scopes      []string
	ClientName  string
	OpenBrowser *bool
	Prompt      func(grant map[string]any)
	Timeout     time.Duration
}

DeviceLoginOptions carries optional device-flow sign-in inputs for LoginWithBrowser. Scopes and ClientName are forwarded to the device authorization request when set; the server may expand the echoed scopes during normalization. OpenBrowser defaults to true when nil. Prompt, when set, receives the device authorization payload instead of the default message printed to stdout. Timeout bounds the whole approval wait and defaults to DefaultDeviceLoginTimeout when zero.

type DisplayItem

type DisplayItem struct {
	Kind    string
	Text    string
	Data    any
	Title   string
	Payload string
	URL     string
	Silent  bool
}

func DisplayItemsFromEventData

func DisplayItemsFromEventData(data Data, eventName string, maxTextChars int) []DisplayItem

type Event

type Event struct {
	Name    string
	Data    Data
	Context Context
	Raw     any
}

func (Event) DisplayItems

func (e Event) DisplayItems(maxTextChars int) []DisplayItem

func (Event) DisplayText

func (e Event) DisplayText() string

func (Event) IsFailure

func (e Event) IsFailure() bool

func (Event) RequestID

func (e Event) RequestID() string

func (Event) RichMedia

func (e Event) RichMedia() map[string]any

func (Event) SessionID

func (e Event) SessionID() string

func (Event) Text

func (e Event) Text() string

func (Event) Utterances

func (e Event) Utterances() []string

type EventOptions added in v0.5.0

type EventOptions struct {
	Timeout   time.Duration
	Context   Context
	SessionID string
	RequestID string
	Predicate func(Event) bool
}

EventOptions scopes an event waiter or listener. A matching request ID takes precedence over a hub-assigned session ID; ID-less replies retain the shared legacy session fallback. Predicate runs after event-name and context filtering.

type EventSubscriber added in v0.5.0

type EventSubscriber interface {
	SubscribeEvents(capacity int) *Subscription[Event]
}

EventSubscriber is optional for custom transports, preserving RuntimeTransport. Built-in transports implement it. Custom transports should implement it when concurrent calls or independent passive subscribers are required.

type HTTPTransport

type HTTPTransport struct {
	Identity     Identity
	UserAgent    string
	PollInterval time.Duration
	HTTPClient   *http.Client
	// NoiseStateDir selects the persistent client key and hub pin directory.
	NoiseStateDir string

	BusEvents  chan Event
	HiveEvents chan HiveMessage
	// contains filtered or unexported fields
}

func NewHTTPTransport

func NewHTTPTransport(identity Identity) *HTTPTransport

func (*HTTPTransport) Authorization

func (t *HTTPTransport) Authorization() string

func (*HTTPTransport) BaseURL

func (t *HTTPTransport) BaseURL() string

func (*HTTPTransport) Connect

func (t *HTTPTransport) Connect(ctx context.Context) (err error)

func (*HTTPTransport) ConnectionInfo added in v0.2.14

func (t *HTTPTransport) ConnectionInfo() TransportConnectionInfo

func (*HTTPTransport) Disconnect

func (t *HTTPTransport) Disconnect(ctx context.Context) error

Disconnect bounds the caller while retaining teardown ownership until old readers retire. Only an acknowledged remote reset clears admission.

func (*HTTPTransport) EmitBus

func (t *HTTPTransport) EmitBus(ctx context.Context, eventType string, data Data, eventContext Context) error

func (*HTTPTransport) Events added in v0.2.4

func (t *HTTPTransport) Events() <-chan Event

func (*HTTPTransport) Healthcheck

func (t *HTTPTransport) Healthcheck() TransportHealth

func (*HTTPTransport) HiveMessages added in v0.2.15

func (t *HTTPTransport) HiveMessages() <-chan HiveMessage

func (*HTTPTransport) IsHandshakeComplete

func (t *HTTPTransport) IsHandshakeComplete() bool

func (*HTTPTransport) PollOnce

func (t *HTTPTransport) PollOnce(ctx context.Context) error

func (*HTTPTransport) RemoteStaticKey added in v0.4.4

func (t *HTTPTransport) RemoteStaticKey() string

RemoteStaticKey returns the authenticated peer key, empty outside a session.

func (*HTTPTransport) SendHiveMessage added in v0.2.15

func (t *HTTPTransport) SendHiveMessage(ctx context.Context, message HiveMessage, encrypt bool) error

func (*HTTPTransport) SubscribeEvents added in v0.5.0

func (t *HTTPTransport) SubscribeEvents(capacity int) *Subscription[Event]

func (*HTTPTransport) SubscribeHiveMessages added in v0.5.0

func (t *HTTPTransport) SubscribeHiveMessages(capacity int) *Subscription[HiveMessage]

type HiveMessage

type HiveMessage struct {
	MsgType      string         `json:"msg_type"`
	Payload      map[string]any `json:"payload"`
	Metadata     map[string]any `json:"metadata"`
	Route        []any          `json:"route"`
	Node         any            `json:"node"`
	TargetSiteID any            `json:"target_site_id"`
	TargetPubKey any            `json:"target_pubkey"`
	SourcePeer   any            `json:"source_peer"`
}

func DecodeHiveBinaryFrame added in v0.2.5

func DecodeHiveBinaryFrame(payload []byte) (HiveMessage, error)

type HiveMessageSubscriber added in v0.5.0

type HiveMessageSubscriber interface {
	SubscribeHiveMessages(capacity int) *Subscription[HiveMessage]
}

type HubCreateOptions added in v0.3.6

type HubCreateOptions struct {
	IdempotencyKey string
}

HubCreateOptions carries the optional inputs of CreateHub. IdempotencyKey overrides the key the SDK generates for the Idempotency-Key header; leave it empty to let CreateHub mint one.

type HubDataPlaneEndpoints added in v0.2.1

type HubDataPlaneEndpoints struct {
	HTTPS string `json:"https,omitempty"`
	WSS   string `json:"wss,omitempty"`
	MQTT  string `json:"mqtt,omitempty"`
}

func DataPlaneEndpointsFromHub added in v0.2.1

func DataPlaneEndpointsFromHub(hub map[string]any) HubDataPlaneEndpoints

func DataPlaneEndpointsFromMap added in v0.2.1

func DataPlaneEndpointsFromMap(values map[string]any) HubDataPlaneEndpoints

func (HubDataPlaneEndpoints) EndpointFor added in v0.2.1

func (e HubDataPlaneEndpoints) EndpointFor(protocol HubProtocol) string

func (HubDataPlaneEndpoints) HTTPBase added in v0.2.1

func (e HubDataPlaneEndpoints) HTTPBase(fallbackMaster string, fallbackPort int, fallbackPath string) string

func (HubDataPlaneEndpoints) Map added in v0.2.1

func (e HubDataPlaneEndpoints) Map(redactCredentials bool) map[string]string

Map renders the data-plane endpoints as a plain map. Polarity note: the boolean is redactCredentials, where true STRIPS any embedded userinfo credentials from each endpoint URL and false returns them verbatim. This is the OPPOSITE polarity of MqttBrokerCredentials.Map(includeSecrets bool) in identity.go, which reveals when its boolean is true — keep the two straight at call sites.

type HubFallback added in v0.5.0

type HubFallback struct {
	SkillID  string `json:"skill_id"`
	Priority int64  `json:"priority"`
}

type HubIntent added in v0.3.13

type HubIntent struct {
	SkillID   string              `json:"skill_id"`
	Name      string              `json:"name"`
	Engine    string              `json:"engine"`
	Enabled   bool                `json:"enabled"`
	Languages []string            `json:"languages"`
	Phrases   map[string][]string `json:"phrases"`
}

HubIntent is one thing a hub can be asked, with the sentences that ask it, per language. Phrases is keyed by the language tag the inventory was asked for; Languages lists those keys in the order they were asked. A names-only inventory carries neither.

func (HubIntent) Examples added in v0.3.13

func (i HubIntent) Examples(lang string, limit int) []string

Examples returns a few sentences worth showing: whole ones before ones with a slot, shorter ones first. An empty lang means the first language the intent has; a limit of zero or less returns the whole pool.

func (HubIntent) ID added in v0.3.13

func (i HubIntent) ID() string

ID is the intent's "<skill_id>:<name>" name, as the engines' manifests spell it.

func (HubIntent) PhrasesFor added in v0.3.13

func (i HubIntent) PhrasesFor(lang string) []string

PhrasesFor returns the sentences that reach the intent in one language, matched with SameLanguage, or nil when the hub registered none.

type HubIntentCapabilities added in v0.5.0

type HubIntentCapabilities struct {
	Inventory      HubIntentInventory `json:"inventory"`
	Fallbacks      []HubFallback      `json:"fallbacks"`
	FallbacksKnown bool               `json:"fallbacks_known"`
}

HubIntentCapabilities enriches the existing inventory without changing HubIntentInventory struct literals. Unknown fallbacks do not mean none.

func (HubIntentCapabilities) MayAnswer added in v0.5.0

func (c HubIntentCapabilities) MayAnswer(lang string) bool

MayAnswer conservatively avoids declaring a language unsupported just because no registered intent has phrases. It is not a language guarantee.

type HubIntentInventory added in v0.3.13

type HubIntentInventory struct {
	Languages []string          `json:"languages"`
	Skills    []HubSkillIntents `json:"skills"`
	Source    string            `json:"source"`
	Denied    []string          `json:"denied"`
}

HubIntentInventory is everything a hub can be asked, grouped by skill.

Source says how it was read: IntentSourceManifest carries sentences per language; IntentSourceEngines is the names-only fallback, and Denied then names the query the hub refused.

func (HubIntentInventory) HasPhrases added in v0.3.13

func (inv HubIntentInventory) HasPhrases() bool

HasPhrases reports whether any intent carries a sentence, which a names-only inventory never does.

func (HubIntentInventory) Intents added in v0.3.13

func (inv HubIntentInventory) Intents() []HubIntent

Intents flattens the inventory: every skill's intents, skills in order.

type HubProtocol added in v0.2.1

type HubProtocol string
const (
	ProtocolWSS   HubProtocol = "wss"
	ProtocolHTTPS HubProtocol = "https"
	ProtocolMQTT  HubProtocol = "mqtt"
)

type HubProtocolSettings added in v0.2.1

type HubProtocolSettings struct {
	WSS  bool `json:"wss"`
	HTTP bool `json:"http"`
	MQTT bool `json:"mqtt"`
}

func DefaultHubProtocolSettings added in v0.2.1

func DefaultHubProtocolSettings() HubProtocolSettings

func ProtocolSettingsFromMap added in v0.2.1

func ProtocolSettingsFromMap(values map[string]any) HubProtocolSettings

func (HubProtocolSettings) EnabledProtocols added in v0.2.1

func (s HubProtocolSettings) EnabledProtocols() []HubProtocol

func (HubProtocolSettings) IsEnabled added in v0.2.1

func (s HubProtocolSettings) IsEnabled(protocol HubProtocol) bool

func (HubProtocolSettings) SpecMap added in v0.2.1

func (s HubProtocolSettings) SpecMap() map[string]any

type HubSkillIntents added in v0.3.13

type HubSkillIntents struct {
	SkillID string      `json:"skill_id"`
	Intents []HubIntent `json:"intents"`
}

HubSkillIntents groups the intents one skill registered.

func (HubSkillIntents) Languages added in v0.3.13

func (s HubSkillIntents) Languages() []string

Languages lists every language one of the skill's intents has, in the order they were asked.

type Identity

type Identity struct {
	AccessKey          string                 `json:"access_key"`
	Password           string                 `json:"password"`
	SiteID             string                 `json:"site_id"`
	DefaultMaster      string                 `json:"default_master"`
	DefaultPort        int                    `json:"default_port"`
	DefaultPath        string                 `json:"default_path,omitempty"`
	PublicKey          string                 `json:"public_key,omitempty"`
	Metadata           map[string]any         `json:"metadata,omitempty"`
	DataPlaneEndpoints HubDataPlaneEndpoints  `json:"data_plane_endpoints,omitempty"`
	Protocols          HubProtocolSettings    `json:"protocols,omitempty"`
	MQTT               *MqttBrokerCredentials `json:"mqtt,omitempty"`
}

func IdentityFromConfig added in v0.2.11

func IdentityFromConfig(path string, profile string) (Identity, error)

func IdentityFromEnv

func IdentityFromEnv(prefix string) (Identity, error)

func IdentityFromFile

func IdentityFromFile(path string) (Identity, error)

func IdentityFromMap

func IdentityFromMap(values map[string]any) (Identity, error)

func (Identity) EnabledProtocols added in v0.2.1

func (i Identity) EnabledProtocols() []HubProtocol

func (Identity) EndpointBase

func (i Identity) EndpointBase() string

func (Identity) EndpointFor added in v0.2.1

func (i Identity) EndpointFor(protocol HubProtocol) string

func (Identity) String added in v0.3.7

func (i Identity) String() string

String implements fmt.Stringer so the %v, %s, and %+v verbs render an Identity with its AccessKey and Password (and the nested MQTT credentials) redacted. Without it, %+v would print the client's data-plane secrets into any log line or error string. This affects human-facing formatting ONLY: json.Marshal does not consult String(), so the wire protocol and the identity file on disk still round-trip the real secret values.

func (Identity) Summary

func (i Identity) Summary() map[string]any

func (Identity) SupportsProtocol added in v0.2.1

func (i Identity) SupportsProtocol(protocol HubProtocol) bool

type IntentDefinition added in v0.3.13

type IntentDefinition struct {
	SkillID    string         `json:"skill_id"`
	IntentName string         `json:"intent_name"`
	Lang       string         `json:"lang"`
	Method     string         `json:"method"`
	Samples    []string       `json:"samples"`
	Raw        map[string]any `json:"raw"`
}

IntentDefinition is a registration as the skill made it, from ovos.intent.describe. Samples are the sentences a template intent answers to, slots in braces; Raw is the whole definition as the hub sent it.

func (IntentDefinition) Engine added in v0.3.13

func (d IntentDefinition) Engine() string

Engine names the intent engine behind the definition: "padatious" for a template intent, "adapt" for a keyword one.

type IntentOptions added in v0.3.13

type IntentOptions struct {
	Timeout            time.Duration
	Describe           *bool
	Fallback           *bool
	IncludeDefinitions bool
}

IntentOptions tunes Client.Intents, Client.ListIntents and Client.DescribeIntent. Timeout bounds each query the hub is sent and defaults to DefaultIntentTimeout when zero. Describe, when nil or true, has Client.Intents fetch every template intent's sentences; false leaves the inventory with names and engines only. Fallback, when nil or true, has Client.Intents read the engines' own manifests when the hub refuses ovos.intent.list; false returns the *PolicyDeniedError instead. IncludeDefinitions asks the runtime to attach each row's definition to the ovos.intent.list reply in Client.ListIntents; Client.Intents sets it itself whenever it describes.

type IntentRegistration added in v0.3.13

type IntentRegistration struct {
	SkillID    string         `json:"skill_id"`
	IntentName string         `json:"intent_name"`
	Lang       string         `json:"lang"`
	Method     string         `json:"method"`
	Enabled    bool           `json:"enabled"`
	SessionID  string         `json:"session_id"`
	Definition map[string]any `json:"definition,omitempty"`
}

IntentRegistration is one row of the hub's intent manifest. Definition is set only when the runtime attached it to the listing.

func (IntentRegistration) Engine added in v0.3.13

func (r IntentRegistration) Engine() string

Engine names the intent engine behind the registration: "padatious" for a template intent, "adapt" for a keyword one.

type ListenOptions added in v0.5.0

type ListenOptions struct {
	EventOptions
	MaxEvents int
	Capacity  int
}

ListenOptions bounds a listener's duration, event count and buffered backlog. Zero Timeout and MaxEvents leave lifetime/count to the caller's context and Close. Capacity defaults to 256 and is capped at 65536. Predicates should return promptly; cancellation unsubscribes immediately even if a predicate is pending.

type LoginOptions added in v0.3.2

type LoginOptions struct {
	Scope        string
	OTPCode      string
	RecoveryCode string
}

LoginOptions carries optional login inputs. Scope overrides the default token scopes. OTPCode and RecoveryCode satisfy an MFA challenge; the API rejects MFA-enabled accounts with HTTP 401 {"code": "mfa_required"} when neither is provided.

type MQTTTransport added in v0.2.4

type MQTTTransport struct {
	Identity   Identity
	UserAgent  string
	Topics     MqttTopicSet
	BusEvents  chan Event
	HiveEvents chan HiveMessage

	// NoiseStateDir selects the persistent client key and hub pin directory.
	NoiseStateDir string
	// TLSConfig optionally supplies broker trust roots or a client certificate.
	TLSConfig *tls.Config
	// contains filtered or unexported fields
}

func NewMQTTTransport added in v0.2.4

func NewMQTTTransport(identity Identity) (*MQTTTransport, error)

func (*MQTTTransport) Connect added in v0.2.4

func (t *MQTTTransport) Connect(ctx context.Context) (err error)

func (*MQTTTransport) ConnectionInfo added in v0.2.14

func (t *MQTTTransport) ConnectionInfo() TransportConnectionInfo

func (*MQTTTransport) Disconnect added in v0.2.4

func (t *MQTTTransport) Disconnect(ctx context.Context) error

func (*MQTTTransport) EmitBus added in v0.2.4

func (t *MQTTTransport) EmitBus(ctx context.Context, eventType string, data Data, eventContext Context) error

func (*MQTTTransport) Events added in v0.2.4

func (t *MQTTTransport) Events() <-chan Event

func (*MQTTTransport) Healthcheck added in v0.2.4

func (t *MQTTTransport) Healthcheck() TransportHealth

func (*MQTTTransport) HiveMessages added in v0.2.15

func (t *MQTTTransport) HiveMessages() <-chan HiveMessage

func (*MQTTTransport) IsHandshakeComplete added in v0.2.4

func (t *MQTTTransport) IsHandshakeComplete() bool

func (*MQTTTransport) RemoteStaticKey added in v0.4.4

func (t *MQTTTransport) RemoteStaticKey() string

RemoteStaticKey returns the authenticated hub key, empty outside a session.

func (*MQTTTransport) SendHiveMessage added in v0.2.15

func (t *MQTTTransport) SendHiveMessage(ctx context.Context, message HiveMessage, encrypt bool) error

func (*MQTTTransport) SubscribeEvents added in v0.5.0

func (t *MQTTTransport) SubscribeEvents(capacity int) *Subscription[Event]

func (*MQTTTransport) SubscribeHiveMessages added in v0.5.0

func (t *MQTTTransport) SubscribeHiveMessages(capacity int) *Subscription[HiveMessage]

type MarketplaceSkillListOptions added in v0.3.6

type MarketplaceSkillListOptions struct {
	OwnerID         string
	IncludeInactive bool
	ForceRefresh    bool
}

MarketplaceSkillListOptions carries the optional inputs of ListMarketplaceSkills. OwnerID and IncludeInactive are honored for admin tokens only; the API silently scopes a non-admin caller to their own tenant and to active entries instead of failing. ForceRefresh re-syncs the global catalog from its source before answering, which is slower.

type MemoryListOptions added in v0.2.13

type MemoryListOptions struct {
	Scope          string
	Kind           string
	OwnerID        string
	HubID          string
	Query          string
	IncludeDeleted bool
	IncludeExpired bool
	Limit          int
	Offset         int
}

type MqttBrokerCredentials added in v0.2.3

type MqttBrokerCredentials struct {
	Endpoint    string `json:"endpoint"`
	Username    string `json:"username"`
	Password    string `json:"password"`
	TopicPrefix string `json:"topic_prefix,omitempty"`
	QOS         byte   `json:"qos,omitempty"`
	TLS         bool   `json:"tls"`
}

func MqttBrokerCredentialsFromMap added in v0.2.3

func MqttBrokerCredentialsFromMap(raw any) *MqttBrokerCredentials

func (MqttBrokerCredentials) Map added in v0.2.3

func (m MqttBrokerCredentials) Map(includeSecrets bool) map[string]any

Map renders the broker credentials as a plain map. Polarity note: the boolean is includeSecrets, where true REVEALS the username, password, and topic details and false returns only the non-sensitive endpoint and tls fields. This is the OPPOSITE polarity of HubDataPlaneEndpoints.Map(redactCredentials bool) in protocols.go, which redacts when its boolean is true — keep the two straight at call sites.

func (MqttBrokerCredentials) String added in v0.3.7

func (m MqttBrokerCredentials) String() string

String implements fmt.Stringer so the %v, %s, and %+v verbs render the broker credentials with the Username and Password redacted, mirroring how Map(false) omits them. Like Identity.String this is a formatting-only guard and does not affect json.Marshal, which still serializes the real values.

type MqttTopicSet added in v0.2.4

type MqttTopicSet struct {
	Inbound  string
	Outbound string
	Status   string
}

func MQTTTopicsForIdentity added in v0.2.4

func MQTTTopicsForIdentity(identity Identity) (MqttTopicSet, error)

MQTTTopicsForIdentity derives the data-plane topic set from the identity's MQTT credentials. TopicPrefix is the full base -- hivemind/<hub-id>/<access-key> -- and the channels append a fixed suffix to it: publish requests go to <prefix>/in, subscribe replies arrive on <prefix>/out, and the retained presence/LWT lives on <prefix>/status.

type OperationResource added in v0.2.16

type OperationResource struct {
	ID            string             `json:"id"`
	Kind          string             `json:"kind"`
	AggregateType string             `json:"aggregate_type"`
	AggregateID   *string            `json:"aggregate_id"`
	Status        OperationStatus    `json:"status"`
	Details       map[string]any     `json:"details"`
	GitCommitSHA  *string            `json:"git_commit_sha"`
	ErrorCode     *string            `json:"error_code"`
	ErrorMessage  *string            `json:"error_message"`
	CreatedAt     string             `json:"created_at"`
	UpdatedAt     string             `json:"updated_at"`
	CommittedAt   *string            `json:"committed_at"`
	AppliedAt     *string            `json:"applied_at"`
	ReadyAt       *string            `json:"ready_at"`
	TerminalAt    *string            `json:"terminal_at"`
	Links         map[string]*string `json:"links"`
}

type OperationStatus added in v0.2.16

type OperationStatus string
const (
	OperationRequested OperationStatus = "requested"
	OperationCommitted OperationStatus = "committed"
	OperationApplied   OperationStatus = "applied"
	OperationReady     OperationStatus = "ready"
	OperationFailed    OperationStatus = "failed"
	OperationTimedOut  OperationStatus = "timed_out"
)

type PolicyDeniedError added in v0.3.13

type PolicyDeniedError struct {
	// DeniedType is the message type the hub refused, such as
	// "ovos.intent.list".
	DeniedType string
	// Code is the hub's refusal code, "acl_disallowed_type" for a type outside
	// the connection's allow-list.
	Code string
	// Reason is the hub's human-readable explanation, when it gave one.
	Reason string
	// Allowed lists the message types the connection may publish, when the
	// hub said.
	Allowed []string
}

PolicyDeniedError reports that the hub refused a message type this connection may not publish. The hub answers hive.policy.denied at once, naming the type and the list it does allow; returning this error saves the caller a timeout and tells the operator exactly what to add to the connection's allow-list.

It wraps ErrRuntime, so errors.Is(err, ErrRuntime) holds, and it is retrieved with errors.As:

var denied *thalovant.PolicyDeniedError
if errors.As(err, &denied) {
	fmt.Println(denied.DeniedType, denied.Allowed)
}

func (*PolicyDeniedError) Error added in v0.3.13

func (e *PolicyDeniedError) Error() string

func (*PolicyDeniedError) Unwrap added in v0.3.13

func (e *PolicyDeniedError) Unwrap() error

Unwrap makes a PolicyDeniedError match ErrRuntime under errors.Is, the same way the hub's other refusals do.

type QueryOptions added in v0.2.15

type QueryOptions struct {
	Timeout   time.Duration
	Lang      string
	Context   Context
	SessionID string
	RequestID string
	QueryID   string
}

type ReleaseOptions added in v0.3.6

type ReleaseOptions struct {
	Channel string
	Mode    string
	Version string
	Images  map[string]string
	Reason  string
}

ReleaseOptions carries the release policy ReleaseHub and ReleaseRuntimeGroup apply. Every field is optional and an unset field is omitted from the request body, so the API falls back to the workspace release policy for it. Setting Images switches the target to "custom" mode unless Mode is also set.

type Reply

type Reply struct {
	Text         string
	Utterances   []string
	Handled      bool
	OK           bool
	SessionID    string
	RequestID    string
	Events       []Event
	FailureEvent *Event
}

func (Reply) DisplayItems

func (r Reply) DisplayItems(maxTextChars int) []DisplayItem

func (Reply) DisplayText

func (r Reply) DisplayText() string

type RequestOptions

type RequestOptions struct {
	Timeout   time.Duration
	Lang      string
	Context   Context
	SessionID string
	RequestID string
}

type RuntimeGroupConfigOptions added in v0.3.6

type RuntimeGroupConfigOptions struct {
	Personas map[string]any
}

RuntimeGroupConfigOptions carries the optional inputs of UpdateRuntimeGroupConfig. Personas replaces the stored personas when non-nil and is omitted from the request body when nil.

type RuntimeGroupInventoryOptions added in v0.3.6

type RuntimeGroupInventoryOptions struct {
	Refresh bool
}

RuntimeGroupInventoryOptions carries the optional inputs of ListRuntimeGroupInventory. Refresh forces a live read from the runtime operator; the API also refreshes on its own when it holds no cached snapshot.

type RuntimeGroupMarketplaceOptions added in v0.3.6

type RuntimeGroupMarketplaceOptions struct {
	RefreshInventory bool
}

RuntimeGroupMarketplaceOptions carries the optional inputs of ListRuntimeGroupMarketplace. RefreshInventory forces a live read from the runtime operator instead of answering from the cached inventory snapshot.

type RuntimeGroupSkillInstallOptions added in v0.3.6

type RuntimeGroupSkillInstallOptions struct {
	MarketplaceSkillID string
	SourceType         string
	SourceRef          string
	VersionPin         string
	Active             *bool
}

RuntimeGroupSkillInstallOptions carries the optional inputs of InstallRuntimeGroupSkill. The zero value installs an active skill from the marketplace catalog: SourceType defaults to "catalog" when empty and Active defaults to true when nil. A "git" install needs SourceRef set to the repository URL.

type RuntimeTransport added in v0.2.4

type RuntimeTransport interface {
	Connect(ctx context.Context) error
	Disconnect(ctx context.Context) error
	Healthcheck() TransportHealth
	ConnectionInfo() TransportConnectionInfo
	EmitBus(ctx context.Context, eventType string, data Data, eventContext Context) error
	Events() <-chan Event
}

type SelectedHubEndpoint added in v0.2.2

type SelectedHubEndpoint struct {
	Protocol HubProtocol `json:"protocol"`
	Endpoint string      `json:"endpoint"`
}

func SelectDataPlaneEndpoint added in v0.2.2

func SelectDataPlaneEndpoint(endpoints HubDataPlaneEndpoints, protocols HubProtocolSettings, preferred []HubProtocol) *SelectedHubEndpoint

type Subscription added in v0.5.0

type Subscription[T any] struct {
	C <-chan T
	// contains filtered or unexported fields
}

Subscription owns an independent, bounded stream. Read until C closes, then inspect Err; call Close when done. Events and their maps are read-only.

func (*Subscription[T]) Close added in v0.5.0

func (s *Subscription[T]) Close()

func (*Subscription[T]) Err added in v0.5.0

func (s *Subscription[T]) Err() error

type TransportConnectionInfo added in v0.2.14

type TransportConnectionInfo struct {
	Phase           TransportConnectionPhase `json:"phase"`
	StartedAt       time.Time                `json:"started_at,omitempty"`
	ConnectedAt     time.Time                `json:"connected_at,omitempty"`
	TransportOpenMS float64                  `json:"transport_open_ms,omitempty"`
	SocketOpenMS    float64                  `json:"socket_open_ms,omitempty"`
	HandshakeMS     float64                  `json:"handshake_ms,omitempty"`
	ConnectMS       float64                  `json:"connect_ms,omitempty"`
	LastError       string                   `json:"last_error,omitempty"`
}

type TransportConnectionPhase added in v0.2.14

type TransportConnectionPhase string
const (
	ConnectionIdle       TransportConnectionPhase = "idle"
	ConnectionConnecting TransportConnectionPhase = "connecting"
	ConnectionHandshake  TransportConnectionPhase = "handshake"
	ConnectionReady      TransportConnectionPhase = "ready"
	ConnectionClosed     TransportConnectionPhase = "closed"
	ConnectionError      TransportConnectionPhase = "error"
)

type TransportHealth

type TransportHealth struct {
	Connected         bool
	HandshakeComplete bool
	TransportAlive    bool
	LastError         string
	Connection        TransportConnectionInfo
}

type WSSTransport added in v0.2.4

type WSSTransport struct {
	Identity  Identity
	UserAgent string

	// NoiseStateDir overrides where the persistent static key and the server
	// pin file live. Empty uses the directory holding the SDK config file.
	NoiseStateDir string

	BusEvents  chan Event
	HiveEvents chan HiveMessage
	// contains filtered or unexported fields
}

func NewWSSTransport added in v0.2.4

func NewWSSTransport(identity Identity) *WSSTransport

func (*WSSTransport) Authorization added in v0.2.4

func (t *WSSTransport) Authorization() string

func (*WSSTransport) Connect added in v0.2.4

func (t *WSSTransport) Connect(ctx context.Context) error

func (*WSSTransport) ConnectionInfo added in v0.2.14

func (t *WSSTransport) ConnectionInfo() TransportConnectionInfo

func (*WSSTransport) Disconnect added in v0.2.4

func (t *WSSTransport) Disconnect(_ context.Context) error

func (*WSSTransport) EmitBus added in v0.2.4

func (t *WSSTransport) EmitBus(ctx context.Context, eventType string, data Data, eventContext Context) error

func (*WSSTransport) Events added in v0.2.4

func (t *WSSTransport) Events() <-chan Event

func (*WSSTransport) Healthcheck added in v0.2.4

func (t *WSSTransport) Healthcheck() TransportHealth

func (*WSSTransport) HiveMessages added in v0.2.15

func (t *WSSTransport) HiveMessages() <-chan HiveMessage

func (*WSSTransport) IsHandshakeComplete added in v0.2.4

func (t *WSSTransport) IsHandshakeComplete() bool

func (*WSSTransport) RemoteStaticKey added in v0.4.0

func (t *WSSTransport) RemoteStaticKey() string

RemoteStaticKey is the server's Noise static public key for the current session, hex encoded. Empty before the handshake completes.

func (*WSSTransport) SendHiveMessage added in v0.2.15

func (t *WSSTransport) SendHiveMessage(ctx context.Context, message HiveMessage, encrypt bool) error

func (*WSSTransport) SubscribeEvents added in v0.5.0

func (t *WSSTransport) SubscribeEvents(capacity int) *Subscription[Event]

func (*WSSTransport) SubscribeHiveMessages added in v0.5.0

func (t *WSSTransport) SubscribeHiveMessages(capacity int) *Subscription[HiveMessage]

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL