thalovant

package module
v0.3.12 Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2026 License: MIT Imports: 28 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.25 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.

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 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). 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.
_, err = control.ReleaseRuntimeGroup(ctx, groupID, thalovant.ReleaseOptions{Channel: "stable"})
_, err = control.ReleaseHub(ctx, hubID, thalovant.ReleaseOptions{Channel: "stable"})

Creating a hub is idempotent. CreateHub always sends an Idempotency-Key header, so a call retried after a timeout returns the hub that was already created instead of making a second one. Set HubCreateOptions.IdempotencyKey to control the key; leave it empty and the SDK generates one.

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 or missing value with HTTP 412 without changing anything:

hub, err := control.GetHub(ctx, hubID)
hub, err = control.UpdateHub(ctx, hubID, map[string]any{"active": false}, hub["etag"].(string))
err = control.DeleteHub(ctx, hubID, hub["etag"].(string))

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()

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.

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

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.
  • 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 and used, and 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 response body in the message. The SDK does not retry automatically: Retry-After is authoritative, so honor it before resending. Per-plan limits are listed in the dashboard and at 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)

Development

go test ./...

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
)
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 DefaultConfigFilename = "config.yaml"
View Source
const Version = "0.3.12"

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}

Functions

func DecryptBinary added in v0.2.5

func DecryptBinary(key string, payload []byte) ([]byte, error)

func DecryptFromJSON

func DecryptFromJSON(key string, raw string) (string, error)

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 EncryptAsBinary added in v0.2.5

func EncryptAsBinary(key string, plaintext []byte) ([]byte, error)

func EncryptAsJSON

func EncryptAsJSON(key string, plaintext string) (string, 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 NewRequestID

func NewRequestID() string

func NewSessionID

func NewSessionID() string

func RequestIDFromContext

func RequestIDFromContext(context Context) string

func RichMediaFromData

func RichMediaFromData(data Data) map[string]any

func RuntimeCryptoKey

func RuntimeCryptoKey(raw string) []byte

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

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

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

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.

The request is idempotent: an Idempotency-Key header is always sent, using HubCreateOptions.IdempotencyKey when set and a generated key otherwise, so a create retried after a timeout returns the first hub instead of making a second one.

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 or empty value fails with HTTP 412.

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 or empty value fails with HTTP 412 and changes nothing; re-read the hub with GetHub and retry with the new etag.

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 HTTPTransport

type HTTPTransport struct {
	Identity     Identity
	UserAgent    string
	PollInterval time.Duration
	HTTPClient   *http.Client
	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) 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

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) SendHiveMessage added in v0.2.15

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

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

type Identity struct {
	AccessKey          string                 `json:"access_key"`
	Password           string                 `json:"password"`
	CryptoKey          string                 `json:"crypto_key,omitempty"`
	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, Password, and CryptoKey (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 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
	// 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) 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) SendHiveMessage added in v0.2.15

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

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 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 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
	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) SendHiveMessage added in v0.2.15

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

Jump to

Keyboard shortcuts

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