Documentation
¶
Index ¶
- Constants
- Variables
- func Alive(client HubSessionClient) bool
- func AnswerHomeRequests(link HomeLink, handler HomeHandler, opts HomeAnswerOptions) (stop func())
- func AsSentence(text, lang string) string
- func BinaryKindName(wireNumber int) string
- func BuildLocation(opts LocationOptions) map[string]any
- func CarryConversation(previous, session map[string]any) map[string]any
- func ChallengeFor(verifier string) string
- func ClosestLanguage(target string, available []string) (string, bool)
- func CommonAffix(names []string) (kind, token string)
- func CompareNames(left, right string) int
- func DecodeReferences(text string) string
- func DefaultConfigPath() (string, error)
- func EncodeHiveBinaryFrame(message HiveMessage) ([]byte, error)
- func EndpointFromDomain(domain string, protocol HubProtocol) string
- func EventMatchesContext(event Event, expected Context) bool
- func ForgetCachedPSK(dir, nodeID string) error
- func ForgetNoisePin(dir, nodeID string) error
- func FriendlyTitle(id string) string
- func HomeAssistantScopes() []string
- func HomeErrorCodes() []string
- func HomeResponseTypes() []string
- func HubDisplayName(hub map[string]any) string
- func HubHostname(master string) string
- func Humanize(name string) string
- func IdentityHost(identityPath string) string
- func InventoryCacheKey(mode, identityPath string) string
- func IsThalovantURL(raw string) bool
- func LanguagesPresent(i Inventory) []string
- func LoadCachedPSK(dir, nodeID string) []byte
- func LoadNoisePin(dir, nodeID string) (string, error)
- func LoadOrCreateNoiseKey(dir string) (noise.DHKey, error)
- func NewRequestID() string
- func NewSessionID() string
- func NewVerifier() (string, error)
- func NoiseStateDir() (string, error)
- func PlainSpeech(text string) string
- func RequestIDFromContext(context Context) string
- func RichMediaFromData(data Data) map[string]any
- func SameLanguage(a, b string) bool
- func SaveCachedPSK(dir, nodeID string, psk []byte) error
- func SaveNoisePin(dir, nodeID, publicKey string) error
- func SessionIDFromContext(context Context) string
- func Speakable(pattern string, slots map[string]string) string
- func SpeakableWithLanguage(pattern string, slots map[string]string, lang string) string
- func StripAffix(name, kind, token string) string
- func StripSSML(text string) string
- func UsualForm(tag string) (string, bool)
- type APIError
- type APIToken
- type ActionOptions
- type AdmissionFailedError
- type AdmissionOptions
- type AdmissionTimeoutError
- type AnalyticsOverviewOptions
- type AskOptions
- type BootstrapIdentityOptions
- type BootstrapIdentityResult
- type Client
- func (c *Client) Ask(ctx context.Context, text string, opts RequestOptions) (Reply, error)
- func (c *Client) AskWithOptions(ctx context.Context, text string, opts AskOptions) (Reply, error)
- func (c *Client) Broadcast(ctx context.Context, eventType string, data Data, eventContext Context) error
- func (c *Client) Close(ctx context.Context) error
- func (c *Client) ClosedRefused() bool
- func (c *Client) Connect(ctx context.Context) error
- func (c *Client) ConnectWithInfo(ctx context.Context) (TransportConnectionInfo, error)
- func (c *Client) ConnectionInfo() TransportConnectionInfo
- func (c *Client) Conversation(opts ConversationOptions) Conversation
- func (c *Client) DescribeIntent(ctx context.Context, skillID, intentName, lang string, opts ...IntentOptions) ([]IntentDefinition, error)
- func (c *Client) Emit(ctx context.Context, eventType string, data Data, eventContext Context) error
- func (c *Client) Escalate(ctx context.Context, eventType string, data Data, eventContext Context) error
- func (c *Client) Healthcheck() TransportHealth
- func (c *Client) Intents(ctx context.Context, languages []string, opts ...IntentOptions) (HubIntentInventory, error)
- func (c *Client) IntentsWithCapabilities(ctx context.Context, languages []string, opts ...IntentOptions) (HubIntentCapabilities, error)
- func (c *Client) ListFallbacks(ctx context.Context, timeout time.Duration) ([]HubFallback, error)
- func (c *Client) ListIntents(ctx context.Context, lang string, opts ...IntentOptions) ([]IntentRegistration, error)
- func (c *Client) Listen(ctx context.Context, eventName string, options ListenOptions) (*Subscription[Event], error)
- func (c *Client) ListenBinary(ctx context.Context, options ListenOptions) (*Subscription[ThalovantBinary], error)
- func (c *Client) ListenHive(ctx context.Context, kind string, options ListenOptions) (*Subscription[HiveMessage], error)
- func (c *Client) Propagate(ctx context.Context, eventType string, data Data, eventContext Context) error
- func (c *Client) Query(ctx context.Context, text string, opts QueryOptions) (Reply, error)
- func (c *Client) Reply(ctx context.Context, event Event, msgType string, data Data, ...) error
- func (c *Client) SendAction(ctx context.Context, payload string, opts ActionOptions) error
- func (c *Client) SendCode(ctx context.Context, value string, opts CodeOptions) error
- func (c *Client) SendUtterance(ctx context.Context, text string, opts RequestOptions) error
- func (c *Client) SubscribeEvents(capacity int) *Subscription[Event]
- func (c *Client) WaitForEvent(ctx context.Context, eventName string, options EventOptions) (Event, error)
- type ClientContextOptions
- type ClientKeyRejectedError
- type ClientOptions
- type CodeOptions
- type Context
- func BuildClientContext(base Context, opts ClientContextOptions) Context
- func ContextWithCorrelation(raw Context, sessionID, siteID, lang, requestID string) Context
- func MergeContext(base, extra Context) Context
- func ReplyContext(eventContext Context) Context
- func RequestContext(base Context, opts RequestContextOptions) Context
- type ControlPlane
- func (c *ControlPlane) BeginDeviceLogin(ctx context.Context, scopes []string, clientName string) (*DeviceAuthorization, error)
- func (c *ControlPlane) BeginDeviceLoginWithOptions(ctx context.Context, opts DeviceLoginOptions) (*DeviceAuthorization, error)
- func (c *ControlPlane) ClearHubRating(ctx context.Context, hubID string) (map[string]any, error)
- func (c *ControlPlane) CompleteNativeSignIn(ctx context.Context, code string, verifier string, clientID string, ...) (map[string]any, error)
- func (c *ControlPlane) CreateClient(ctx context.Context, payload map[string]any, idempotencyKey string) (map[string]any, error)
- func (c *ControlPlane) CreateClientIdentity(ctx context.Context, hub map[string]any, opts BootstrapIdentityOptions) (BootstrapIdentityResult, error)
- func (c *ControlPlane) CreateClientIdentityForHubID(ctx context.Context, hubID string, opts BootstrapIdentityOptions) (BootstrapIdentityResult, error)
- func (c *ControlPlane) CreateHub(ctx context.Context, payload map[string]any, opts HubCreateOptions) (map[string]any, error)
- func (c *ControlPlane) CreateMemoryItem(ctx context.Context, payload map[string]any) (map[string]any, error)
- func (c *ControlPlane) CreateRuntimeGroup(ctx context.Context, payload map[string]any) (map[string]any, error)
- func (c *ControlPlane) DeleteClient(ctx context.Context, clientID string, etag string) error
- func (c *ControlPlane) DeleteHub(ctx context.Context, hubID string, etag string) error
- func (c *ControlPlane) DeleteMemoryItem(ctx context.Context, memoryID string) error
- func (c *ControlPlane) DeleteRuntimeGroup(ctx context.Context, runtimeGroupID string) error
- func (c *ControlPlane) DescribeDeviceLogin(ctx context.Context, userCode string) (*DeviceLoginRequest, error)
- func (c *ControlPlane) GetAnalyticsOverview(ctx context.Context, opts AnalyticsOverviewOptions) (map[string]any, error)
- func (c *ControlPlane) GetClient(ctx context.Context, clientID string) (map[string]any, error)
- func (c *ControlPlane) GetHub(ctx context.Context, hubID string) (map[string]any, error)
- func (c *ControlPlane) GetHubRuntimeCapabilities(ctx context.Context, hubID string) (map[string]any, error)
- func (c *ControlPlane) GetMemoryItem(ctx context.Context, memoryID string) (map[string]any, error)
- func (c *ControlPlane) GetMemorySummary(ctx context.Context, ownerID string) (map[string]any, error)
- func (c *ControlPlane) GetOperation(ctx context.Context, operationID string) (OperationResource, error)
- func (c *ControlPlane) GetPublicHub(ctx context.Context, hubRef string) (map[string]any, error)
- func (c *ControlPlane) GetRuntimeGroup(ctx context.Context, runtimeGroupID string) (map[string]any, error)
- func (c *ControlPlane) GetRuntimeGroupConfig(ctx context.Context, runtimeGroupID string) (map[string]any, error)
- func (c *ControlPlane) InstallHubSkill(ctx context.Context, hubID, skill, version string, opts HubSkillWaitOptions) (map[string]any, error)
- func (c *ControlPlane) InstallRuntimeGroupSkill(ctx context.Context, runtimeGroupID string, skillID string, ...) (map[string]any, error)
- func (c *ControlPlane) ListHubSkillHistory(ctx context.Context, hubID string, limit int) (map[string]any, error)
- func (c *ControlPlane) ListHubSkills(ctx context.Context, hubID string) (map[string]any, error)
- func (c *ControlPlane) ListHubs(ctx context.Context, limit int, cursor string, ownerID string) (map[string]any, error)
- func (c *ControlPlane) ListMarketplaceSkills(ctx context.Context, opts MarketplaceSkillListOptions) (map[string]any, error)
- func (c *ControlPlane) ListMemoryItems(ctx context.Context, opts MemoryListOptions) (map[string]any, error)
- func (c *ControlPlane) ListPublicHubs(ctx context.Context, limit int, cursor string) (map[string]any, error)
- func (c *ControlPlane) ListRuntimeGroupInventory(ctx context.Context, runtimeGroupID string, opts RuntimeGroupInventoryOptions) (map[string]any, error)
- func (c *ControlPlane) ListRuntimeGroupMarketplace(ctx context.Context, runtimeGroupID string, ...) (map[string]any, error)
- func (c *ControlPlane) ListRuntimeGroups(ctx context.Context, ownerID string) (map[string]any, error)
- func (c *ControlPlane) Login(ctx context.Context, email string, password string, scope string) (map[string]any, error)
- func (c *ControlPlane) LoginWithBrowser(ctx context.Context, opts DeviceLoginOptions) (map[string]any, error)
- func (c *ControlPlane) LoginWithOptions(ctx context.Context, email string, password string, opts LoginOptions) (map[string]any, error)
- func (c *ControlPlane) PollDeviceLogin(ctx context.Context, authorization *DeviceAuthorization) (*APIToken, error)
- func (c *ControlPlane) ReleaseHub(ctx context.Context, hubID string, opts ReleaseOptions) (map[string]any, error)
- func (c *ControlPlane) ReleaseRuntimeGroup(ctx context.Context, runtimeGroupID string, opts ReleaseOptions) (map[string]any, error)
- func (c *ControlPlane) RemoveHubSkill(ctx context.Context, hubID, skill string, opts HubSkillWaitOptions) (map[string]any, error)
- func (c *ControlPlane) ReplaceRuntimeGroupConfig(ctx context.Context, runtimeGroupID string, config map[string]any, ...) (map[string]any, error)
- func (c *ControlPlane) RequireRuntimeProtocol(result BootstrapIdentityResult, protocol HubProtocol) (*SelectedHubEndpoint, error)
- func (c *ControlPlane) RevokeAPIToken(ctx context.Context, tokenID string) error
- func (c *ControlPlane) SetHubRating(ctx context.Context, hubID string, rating int) (map[string]any, error)
- func (c ControlPlane) String() string
- func (c *ControlPlane) UninstallRuntimeGroupSkill(ctx context.Context, runtimeGroupID string, skillID string) error
- func (c *ControlPlane) UpdateHub(ctx context.Context, hubID string, payload map[string]any, etag string) (map[string]any, error)
- func (c *ControlPlane) UpdateHubSkill(ctx context.Context, hubID, skill, version string, opts HubSkillWaitOptions) (map[string]any, error)
- func (c *ControlPlane) UpdateMemoryItem(ctx context.Context, memoryID string, payload map[string]any) (map[string]any, error)
- func (c *ControlPlane) UpdateRuntimeGroup(ctx context.Context, runtimeGroupID string, payload map[string]any) (map[string]any, error)
- func (c *ControlPlane) UpdateRuntimeGroupConfig(ctx context.Context, runtimeGroupID string, config map[string]any, ...) (map[string]any, error)
- func (c *ControlPlane) WaitForAdmission(ctx context.Context, operation *OperationResource, opts AdmissionOptions) error
- func (c *ControlPlane) WaitForHubSkillOperation(ctx context.Context, accepted map[string]any, opts HubSkillWaitOptions) (map[string]any, error)
- type Conversation
- func (c Conversation) Ask(ctx context.Context, text string, opts RequestOptions) (Reply, error)
- func (c Conversation) Query(ctx context.Context, text string, opts QueryOptions) (Reply, error)
- func (c Conversation) SendAction(ctx context.Context, payload string, opts ActionOptions) error
- func (c Conversation) SendCode(ctx context.Context, value string, opts CodeOptions) error
- func (c Conversation) SendUtterance(ctx context.Context, text string, opts RequestOptions) error
- type ConversationOptions
- type Data
- type DeviceAuthorization
- type DeviceLoginDeniedError
- type DeviceLoginExpiredError
- type DeviceLoginOptions
- type DeviceLoginPendingError
- type DeviceLoginRequest
- type DisplayItem
- type Event
- func (e Event) AudioBytes() ([]byte, error)
- func (e Event) AudioBytesWithLimit(maxBytes int) ([]byte, error)
- func (e Event) DisplayItems(maxTextChars int) []DisplayItem
- func (e Event) DisplayText() string
- func (e Event) HasAudio() bool
- func (e Event) IsAudio() bool
- func (e Event) IsFailure() bool
- func (e Event) Lang() string
- func (e Event) RequestID() string
- func (e Event) RichMedia() map[string]any
- func (e Event) SessionID() string
- func (e Event) Text() string
- func (e Event) Utterances() []string
- type EventOptions
- type EventSubscriber
- type HTTPTransport
- func (t *HTTPTransport) Authorization() string
- func (t *HTTPTransport) BaseURL() string
- func (t *HTTPTransport) ClosedRefused() bool
- func (t *HTTPTransport) Connect(ctx context.Context) error
- func (t *HTTPTransport) ConnectionInfo() TransportConnectionInfo
- func (t *HTTPTransport) Disconnect(ctx context.Context) error
- func (t *HTTPTransport) EmitBus(ctx context.Context, eventType string, data Data, eventContext Context) error
- func (t *HTTPTransport) Events() <-chan Event
- func (t *HTTPTransport) Healthcheck() TransportHealth
- func (t *HTTPTransport) HiveMessages() <-chan HiveMessage
- func (t *HTTPTransport) IsHandshakeComplete() bool
- func (t *HTTPTransport) PollOnce(ctx context.Context) error
- func (t *HTTPTransport) RemoteStaticKey() string
- func (t *HTTPTransport) SendHiveMessage(ctx context.Context, message HiveMessage, encrypt bool) error
- func (t *HTTPTransport) SubscribeEvents(capacity int) *Subscription[Event]
- func (t *HTTPTransport) SubscribeHiveMessages(capacity int) *Subscription[HiveMessage]
- type HiveMessage
- type HiveMessageSubscriber
- type HomeAnswer
- type HomeAnswerOptions
- type HomeHandler
- type HomeLink
- type HomeRequest
- type HubCreateOptions
- type HubDataPlaneEndpoints
- type HubFallback
- type HubIntent
- type HubIntentCapabilities
- type HubIntentInventory
- type HubProtocol
- type HubProtocolSettings
- type HubSession
- func (s *HubSession) Ask(ctx context.Context, text string, options AskOptions) (reply Reply, err error)
- func (s *HubSession) Close(ctx context.Context) error
- func (s *HubSession) Connect(ctx context.Context) error
- func (s *HubSession) Connected() bool
- func (s *HubSession) Emit(ctx context.Context, eventType string, data Data, eventContext Context) error
- func (s *HubSession) Held() bool
- func (s *HubSession) On(eventType string, handler func(Event)) (unsubscribe func())
- func (s *HubSession) OnStateChange(notify func(up bool)) (unsubscribe func())
- func (s *HubSession) Probe(ctx context.Context) error
- func (s *HubSession) ProbeDelay() time.Duration
- func (s *HubSession) Reply(ctx context.Context, event Event, msgType string, data Data, ...) error
- func (s *HubSession) RetryAt() time.Time
- func (s *HubSession) RetryWait() time.Duration
- func (s *HubSession) Run(ctx context.Context) error
- func (s *HubSession) SubscribeEvents(capacity int) *Subscription[Event]
- func (s *HubSession) Warm(ctx context.Context) bool
- type HubSessionClient
- type HubSessionOption
- type HubSessionPolicy
- type HubSkillIntents
- type HubSkillWaitOptions
- type Identity
- func (i Identity) EnabledProtocols() []HubProtocol
- func (i Identity) EndpointBase() string
- func (i Identity) EndpointFor(protocol HubProtocol) string
- func (i Identity) SourcePath() string
- func (i Identity) String() string
- func (i Identity) Summary() map[string]any
- func (i Identity) SupportsProtocol(protocol HubProtocol) bool
- type Intent
- type IntentDefinition
- type IntentExampleOptions
- type IntentOptions
- type IntentRegistration
- type Inventory
- type InventoryCache
- type LinkAction
- type LinkDecision
- type LinkOutcome
- type LinkSupervisor
- type ListenOptions
- type ListingData
- type ListingLanguage
- type ListingRules
- func (r *ListingRules) AsSentence(text, lang string) string
- func (r *ListingRules) Asks(text, lang string) (bool, error)
- func (r *ListingRules) Available() bool
- func (r *ListingRules) Dangling(text, lang string) bool
- func (r *ListingRules) LanguageData(lang string) ListingLanguage
- func (r *ListingRules) Rank(phrases []string, lang string) []string
- func (r *ListingRules) Speakable(pattern string, slots map[string]string, lang string) string
- type LocationOptions
- type LoginOptions
- type MQTTTransport
- func (t *MQTTTransport) Connect(ctx context.Context) error
- func (t *MQTTTransport) ConnectionInfo() TransportConnectionInfo
- func (t *MQTTTransport) Disconnect(ctx context.Context) error
- func (t *MQTTTransport) EmitBus(ctx context.Context, eventType string, data Data, eventContext Context) error
- func (t *MQTTTransport) Events() <-chan Event
- func (t *MQTTTransport) Healthcheck() TransportHealth
- func (t *MQTTTransport) HiveMessages() <-chan HiveMessage
- func (t *MQTTTransport) IsHandshakeComplete() bool
- func (t *MQTTTransport) RemoteStaticKey() string
- func (t *MQTTTransport) SendHiveMessage(ctx context.Context, message HiveMessage, encrypt bool) error
- func (t *MQTTTransport) SubscribeEvents(capacity int) *Subscription[Event]
- func (t *MQTTTransport) SubscribeHiveMessages(capacity int) *Subscription[HiveMessage]
- type MarketplaceSkillListOptions
- type MemoryListOptions
- type MqttBrokerCredentials
- type MqttTopicSet
- type NativeSignIn
- type NativeSignInOptions
- type OperationResource
- type OperationStatus
- type OriginAttempt
- type OriginPreference
- type PolicyDeniedError
- type QueryOptions
- type Quota
- type ReleaseOptions
- type Replier
- type Reply
- type RequestContextOptions
- type RequestOptions
- type RuntimeGroupConfigOptions
- type RuntimeGroupInventoryOptions
- type RuntimeGroupMarketplaceOptions
- type RuntimeGroupSkillInstallOptions
- type RuntimeTransport
- type SelectedHubEndpoint
- type Skill
- type Subscription
- type ThalovantBinary
- type TransportConnectionInfo
- type TransportConnectionPhase
- type TransportHealth
- type UnansweredError
- type UnsupportedConnectionTypeError
- type WSSTransport
- func (t *WSSTransport) Authorization() string
- func (t *WSSTransport) ClosedRefused() bool
- func (t *WSSTransport) Connect(ctx context.Context) error
- func (t *WSSTransport) ConnectionInfo() TransportConnectionInfo
- func (t *WSSTransport) Disconnect(_ context.Context) error
- func (t *WSSTransport) EmitBus(ctx context.Context, eventType string, data Data, eventContext Context) error
- func (t *WSSTransport) Events() <-chan Event
- func (t *WSSTransport) Healthcheck() TransportHealth
- func (t *WSSTransport) HiveMessages() <-chan HiveMessage
- func (t *WSSTransport) IsHandshakeComplete() bool
- func (t *WSSTransport) RemoteStaticKey() string
- func (t *WSSTransport) SendHiveMessage(ctx context.Context, message HiveMessage, encrypt bool) error
- func (t *WSSTransport) SubscribeEvents(capacity int) *Subscription[Event]
- func (t *WSSTransport) SubscribeHiveMessages(capacity int) *Subscription[HiveMessage]
Constants ¶
const ( ConnectionTypeVoiceSatellite = "voice_satellite" ConnectionTypeWebChat = "web_chat" ConnectionTypeDeveloper = "developer" ConnectionTypeEmbedded = "embedded" // ConnectionTypeHomeAssistant is a hub's Home Assistant link. A hub holds // at most one: a second is refused with ErrAlreadyLinked. ConnectionTypeHomeAssistant = "home_assistant" )
The kinds of connection the API knows, sent as spec.connection_type. The kind decides what a connection may send and receive; the API may learn more of them, so the field is a plain string.
const ( // DefaultAdmissionTimeout bounds WaitForAdmission. A hub admits a new // connection about ninety seconds after it is created. DefaultAdmissionTimeout = 180 * time.Second // DefaultOperationPollInterval is how often WaitForAdmission reads the // operation. DefaultOperationPollInterval = 2 * time.Second )
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" )
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 )
const ( // PolicyCodeACL is an allow-list refusal: ask whoever manages the // connection to allow the type; Allowed lists what it may send. PolicyCodeACL = "acl_disallowed_type" // PolicyCodeQuotaExceeded is a spent allowance: wait, or raise the // limit; Quota carries the numbers. PolicyCodeQuotaExceeded = "intent_quota_exceeded" // nothing the caller does will fix. PolicyCodeBackendUnavailable = "backend_unavailable" )
The hub's codes for the three kinds of refusal that arrive as hive.policy.denied, each needing something different said about it.
const ( // HomeRequestEvent is what a hub sends a Home Assistant link. HomeRequestEvent = "thalovant.home.request" // HomeResponseEvent is the one answer every request gets. HomeResponseEvent = "thalovant.home.response" // HomeRequestTimeout is how long the hub waits for an answer before it // treats the silence as a timeout. HomeRequestTimeout = 10 * time.Second // DefaultHomeHandlerTimeout is how long a handler has by default: a // second inside the hub's bound, so the SDK's own timeout answer still // lands before the hub gives up. DefaultHomeHandlerTimeout = HomeRequestTimeout - time.Second )
const ( HomeActionDone = "action_done" HomeQueryAnswer = "query_answer" HomeError = "error" )
The response types a home answer may carry.
const ( HomeErrorNoIntentMatch = "no_intent_match" HomeErrorNoValidTargets = "no_valid_targets" HomeErrorFailedToHandle = "failed_to_handle" HomeErrorUnknown = "unknown" HomeErrorTimeout = "timeout" )
The error codes an error answer may name.
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 )
const DefaultConfigFilename = "config.yaml"
const DefaultDashboardURL = "https://dash.thalovant.com"
DefaultDashboardURL is where a person approves the request.
const DefaultHubRefusalGrace = 600 * time.Second
DefaultHubRefusalGrace is how long Run treats a hub refusing the credentials as "not admitted yet" before returning the refusal. A new connection is refused until its hub admits it, about ninety seconds.
const DefaultHubSettle = 750 * time.Millisecond
DefaultHubSettle is how long a link opened by Connect or Run must stay up before it counts. A hub that does not know a client's static key says so only by closing right after the handshake.
const EventAudioQueue = "mycroft.audio.queue"
const EventFallbackList = "ovos.skills.fallback.list"
const EventFallbackListResponse = "ovos.skills.fallback.list.response"
const HomeAssistantClientID = "thalovant-home-assistant"
HomeAssistantClientID is the registered app id Home Assistant signs in as: DeviceLoginOptions.ClientID of its device login. The approval screen then shows the platform's own name for the app as verified, and approving it again replaces the token the last approval gave it instead of counting a second one against the plan.
const HubSource = "hub"
const InventoryCacheTTL = time.Hour
const InventoryCacheVersion = 1
const MaxAudioClipBytes = 4 * 1024 * 1024
const MaxReplyMediaBytes = 16 * 1024 * 1024
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.
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.
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.
const Version = "0.12.0"
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 ¶
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") // ErrDeviceLoginPending reports that nobody has approved a device // sign-in yet. PollDeviceLogin returns it as a *DeviceLoginPendingError, // whose Interval says when to ask again. ErrDeviceLoginPending = errors.New("thalovant device sign-in pending") // ErrAuth matches an *APIError that signing in again is the way out of: // HTTP 401 (a token unknown, expired or revoked), 423 (a locked account), // or 403 whose detail is "Insufficient scopes". ErrAuth = errors.New("thalovant authentication refused") // ErrPlan matches an *APIError the account's plan refused: HTTP 402, or // 403 with code "plan_limit". Problem carries the plan's numbers. ErrPlan = errors.New("thalovant plan refused") // ErrAlreadyLinked matches an *APIError saying the hub already holds the // one link of its kind: HTTP 409 with code "home_assistant_already_linked". // LinkedClientID names the connection that holds it. ErrAlreadyLinked = errors.New("thalovant hub already linked") // ErrUnsupportedConnectionType matches an *UnsupportedConnectionTypeError: // the API could not make a connection of the kind asked for. ErrUnsupportedConnectionType = errors.New("thalovant unsupported connection type") // ErrHubRefused reports that a hub turned the connection's credentials // away. It always travels with ErrConnection. A new connection is refused // until its hub admits it, so a HubSession's Run treats it as "not yet" // for a grace period before returning it. ErrHubRefused = errors.New("thalovant hub refused the credentials") // ErrHubKeyChanged reports that a hub's Noise static key is not the one // pinned for it: the hub was replaced or reinstalled, or another machine // answers at its address. It always travels with ErrConnection. It is not // a refusal, and retrying cannot change it; the pin is never replaced // automatically (see ForgetNoisePin). ErrHubKeyChanged = errors.New("thalovant hub key changed") // ErrClientKeyRejected reports that a hub refused this client's own Noise // static key: it pinned a different one for the connection. It is a // refusal -- errors.Is(err, ErrHubRefused) holds too, and it travels with // ErrConnection -- but no handshake can recover from it, so a HubSession's // Run returns it at once. errors.As reaches the *ClientKeyRejectedError, // which names the key folders. ErrClientKeyRejected = fmt.Errorf("%w: the hub refused this client's Noise key", ErrHubRefused) // ErrAPIUnreachable reports a control-plane request that never got an // answer: DNS, the connection, TLS, a proxy. It always travels with ErrAPI // and ErrConnection, and it says nothing about what the API would have // answered. ErrAPIUnreachable = errors.New("thalovant api unreachable") )
var BinaryPayloadKinds = map[int]string{
1: "raw_audio",
2: "numpy_image",
3: "file",
4: "stt_transcribe",
5: "stt_handle",
6: "tts_audio",
}
BinaryPayloadKinds name the payload types a BINARY frame can carry, by their wire number.
A hub answers speak:synth by rendering the utterance and sending one of these back, so a client with no synthesiser of its own can still speak; a file arrives the same way. The wire numbers the type, this names it.
var ConversationSessionFields = []string{
"converse_handlers",
"active_handlers",
"active_skills",
"context",
"utterance_states",
"response_mode",
}
ConversationSessionFields are the session fields a client carries from one turn of a conversation to the next.
A hub keeps nothing for a named session: OVOS-SESSION-2 §2.2 makes the orchestrator stateless for those, so the carrier a client sends is the whole snapshot and whatever the last turn activated is discarded the moment it ends. Without converse_handlers the converse pipeline has no skill to poll and every follow-up reaches the fallback instead of the skill that just answered.
An allow-list, not a deny-list. Deliberately absent: the caller's own per-turn settings (lang, pipeline, site_id), because a client that decides the language per utterance would otherwise be pinned to whichever one the conversation opened in; and the live device flags, which describe a moment that has passed by the time the next turn is sent.
var DefaultNativeScopes = []string{"hubs:read", "clients:read", "clients:write"}
DefaultNativeScopes are the three a phone needs; also the three a free plan may mint.
var DefaultProtocolPreference = []HubProtocol{ProtocolWSS, ProtocolHTTPS, ProtocolMQTT}
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.
var HiveKinds = []string{"broadcast", "propagate", "escalate", "intercom", "rendezvous"}
HiveKinds are the hive's own frame kinds, which a client may subscribe to.
query and cascade are deliberately absent: they are this client's own request/response traffic and Ask already owns them, so subscribing to one would quietly compete for the same replies.
Functions ¶
func Alive ¶ added in v0.9.0
func Alive(client HubSessionClient) bool
func AnswerHomeRequests ¶ added in v0.11.0
func AnswerHomeRequests(link HomeLink, handler HomeHandler, opts HomeAnswerOptions) (stop func())
AnswerHomeRequests answers every thalovant.home.request that reaches link, each on a goroutine of its own so a slow one does not hold up the next, and returns a function that stops it. Stopping cancels the contexts of the answers still running; those send nothing.
With a HubSession, requests keep arriving across reconnects while the session's Run keeps the link up:
session, _ := thalovant.NewHubSession(connect, thalovant.DefaultHubSessionPolicy())
stop := thalovant.AnswerHomeRequests(session, handler, thalovant.HomeAnswerOptions{})
defer stop()
go session.Run(ctx)
func AsSentence ¶ added in v0.8.0
AsSentence uses the bundled canonical locale data.
func BinaryKindName ¶ added in v0.10.0
BinaryKindName names a payload type. One nobody has named still arrives, under its number, rather than being dropped.
func BuildLocation ¶ added in v0.7.0
func BuildLocation(opts LocationOptions) map[string]any
func CarryConversation ¶ added in v0.10.0
CarryConversation fills the conversation fields of session from the hub's last reply.
This turn's own values win: a field the caller set is never overwritten, only one it left out is taken from the turn before.
func ChallengeFor ¶ added in v0.9.2
ChallengeFor returns the S256 challenge for a verifier.
func ClosestLanguage ¶ added in v0.8.0
func CommonAffix ¶ added in v0.9.0
func CompareNames ¶ added in v0.9.0
CompareNames gives a deterministic natural order without integer overflow.
func DecodeReferences ¶ added in v0.11.0
DecodeReferences decodes the portable set of character references once, left to right: numeric references (H, H, H) and the five XML entities plus . A numeric reference to no character -- 0, a surrogate, anything past U+10FFFF -- and every other named reference (é, ©) are left as written, since the libraries SDKs would otherwise use disagree about them.
func DefaultConfigPath ¶ added in v0.2.11
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 ForgetCachedPSK ¶ added in v0.4.2
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
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 FriendlyTitle ¶ added in v0.9.0
func HomeAssistantScopes ¶ added in v0.11.0
func HomeAssistantScopes() []string
HomeAssistantScopes are the scopes a Home Assistant link signs in with: enough to find the account's hubs and to create, read and delete the one connection it holds. They are also everything a Free plan can approve. Each call returns a fresh slice.
func HomeErrorCodes ¶ added in v0.11.0
func HomeErrorCodes() []string
HomeErrorCodes lists every error code the contract allows, in its order. Each call returns a fresh slice.
func HomeResponseTypes ¶ added in v0.11.0
func HomeResponseTypes() []string
HomeResponseTypes lists every response type the contract allows, in its order. Each call returns a fresh slice.
func HubDisplayName ¶ added in v0.9.2
HubDisplayName returns what to call a hub on a screen somebody is reading.
Every control-plane read in this SDK returns raw JSON, so each caller picks its own fields -- and on 2026-09-15 a phone offered somebody a list of rooms called "ops-copilot", "daily-desk", "news-stream". Those are slugs. The app was not careless: it read name and preferred it over slug, and on that deployment name holds the slug. The name a person was shown when the hub was made lives in spec.catalog.title.
One place to get that wrong is better than one per app.
func HubHostname ¶ added in v0.9.0
func IdentityHost ¶ added in v0.9.0
func InventoryCacheKey ¶ added in v0.9.0
func IsThalovantURL ¶ added in v0.9.2
IsThalovantURL reports whether a URL belongs to Thalovant, for a caller that wants to show where it is about to send somebody. Scheme and host only: a display check, not an authorization one.
func LanguagesPresent ¶ added in v0.9.0
func LoadCachedPSK ¶ added in v0.4.2
LoadCachedPSK returns the stored pre-shared key for a hub, or nil when there is none.
func LoadNoisePin ¶ added in v0.4.0
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
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 NewVerifier ¶ added in v0.9.2
NewVerifier returns a PKCE verifier: 64 random bytes, base64url, no padding.
func NoiseStateDir ¶ added in v0.4.0
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 PlainSpeech ¶ added in v0.11.0
PlainSpeech is speech a device can say as it is, made in this order, the same in every SDK (home-link-vectors.json):
- markup removed, with StripSSML: only real tags, comments and processing instructions, so "5 < 6 and 7 > 3" stays whole;
- character references decoded once, left to right, with DecodeReferences: numeric ones, the five XML entities and , nothing else;
- every run of Unicode White_Space collapsed to one space, and the ends trimmed of it.
Nothing comes from html.UnescapeString: its table of named references is not the one other SDKs decode.
func RequestIDFromContext ¶
func RichMediaFromData ¶
func SameLanguage ¶ added in v0.3.13
SameLanguage reports whether two language tags name the same language: "fr-fr" and "fr_FR" do.
func SaveCachedPSK ¶ added in v0.4.2
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
SaveNoisePin records the server static key for a node id on first contact.
func SessionIDFromContext ¶
func Speakable ¶ added in v0.7.0
Speakable renders one sentence, removing optional parts without inventing slot values.
func SpeakableWithLanguage ¶ added in v0.8.0
SpeakableWithLanguage uses bundled locale examples without changing the original two-argument Speakable function's calling convention.
func StripAffix ¶ added in v0.9.0
func StripSSML ¶
StripSSML removes SSML and XML markup from display text: tags, comments and processing instructions. Only real markup goes, so "5 < 6 and 7 > 3" survives whole, and an unclosed "<b" is text. Entities are left as they are; PlainSpeech decodes the portable set.
func UsualForm ¶ added in v0.10.3
ClosestLanguage returns the nearest OVOS-compatible registration (maximum distance ten). Equal distances preserve the caller's registration order. UsualForm is the form a language is usually written in, when that differs from tag: "en-CA" and "en-AT" both to "en-us", "fr-BE" to "fr-fr", "pt-AO" to "pt-br", from CLDR's likely subtags. The second return is false when there is nothing different to try, so a caller can tell "already the usual form" from "no idea".
Listing and asking do not agree about languages, and this closes the gap. A hub matches an utterance to the closest language it knows, so a phone set to "en-CA" is understood by skills registered under "en-US"; its manifest is keyed by exact tag, so the same hub lists nothing for "en-CA".
Lower case, because that is how skills register and how the manifest is keyed: an exact lookup with BCP47's "en-US" finds nothing.
Types ¶
type APIError ¶ added in v0.7.0
type APIError struct {
// StatusCode is the HTTP status the API answered with.
StatusCode int
// Detail is the single line Error() prints: the body's own message
// fields joined, whitespace-collapsed and cut at 256 runes, or a stand-in
// such as "(no response body)" or "(server error response omitted)". It
// never carries a value the body echoed back from the request.
Detail string
// Code is the body's machine-readable code, such as
// "platform_image_required" or "plan_limit", exactly as sent; "" when the
// body has none. It is read from the body's "code" member, or from inside
// a "detail" member that is itself an object (FastAPI's own envelope), and
// a code that is not a string or is only whitespace is no code.
Code string
// ProblemDetail is the API's whole sentence, exactly as sent: never
// trimmed, collapsed or shortened, unlike Detail. It is read the same way
// as Code, from the body's "detail" member; "" when the body has none.
ProblemDetail string
// Problem is the whole error body decoded, when it is a JSON object: the
// Problem+JSON document every API refusal is. A structured field is
// reachable here without a new SDK release: refused_images,
// allowed_images and allowed_repositories on platform_image_required;
// resource, limit, used and plan on plan_limit. Numbers are float64, as
// everywhere encoding/json decodes into map[string]any. nil for a body
// that is empty, not JSON, or JSON that is not an object. It can hold
// values the body echoed back from the request, which is why Error()
// never prints it.
Problem map[string]any
// RetryAfter is how long the API asked the caller to wait before trying
// again, when it said; 0 otherwise. It is read from the body's
// retry_after_seconds (at the top, or inside a detail object), else from
// the Retry-After header in seconds, else from RateLimit-Reset: the API's
// own rate limiter answers a 429 in plain text with only that header.
RetryAfter time.Duration
}
APIError is a control-plane request the API answered with an error status. It preserves the HTTP status while continuing to match ErrAPI.
Error() prints one bounded line for display, and that line can be shortened, so it is never where to read what the API said. That rides beside it: Code to branch on, ProblemDetail for the API's whole sentence, and Problem for every structured field of the body.
var apiErr *thalovant.APIError
if errors.As(err, &apiErr) && apiErr.Code == "platform_image_required" {
fmt.Println(apiErr.ProblemDetail)
fmt.Println(apiErr.Problem["allowed_images"])
}
An APIError built as a literal with only StatusCode and Detail reads and prints exactly as it always did, with the other fields empty.
func (*APIError) GoString ¶ added in v0.12.0
GoString keeps %#v from printing Problem, which can hold values the body echoed back from the request: a validation error's input is the request as sent. It shows the status, the code and the display line, which never carries an echoed value; read Problem itself when you need it.
func (*APIError) Is ¶ added in v0.11.0
Is reports whether the refusal is one a caller can branch on: ErrAuth, ErrPlan or ErrAlreadyLinked. They are read from the status and the body, so every control-plane call answers them the same way, and the error stays an *APIError with every field it carried:
var apiErr *thalovant.APIError
switch {
case errors.Is(err, thalovant.ErrAlreadyLinked) && errors.As(err, &apiErr):
fmt.Println("linked by", apiErr.LinkedClientID())
case errors.Is(err, thalovant.ErrPlan):
fmt.Println("upgrade the plan")
case errors.Is(err, thalovant.ErrAuth):
fmt.Println("sign in again")
}
func (*APIError) LinkedClientID ¶ added in v0.11.0
LinkedClientID is the connection that already holds a hub's link, named by an ErrAlreadyLinked refusal; "" when the answer names none. It is read from the body's client_id (or existing_client_id, or connection_id), at the top or inside a detail that is itself an object.
type APIToken ¶ added in v0.11.0
type APIToken struct {
AccessToken string
TokenType string
Scopes []string
// ExpiresAt is when the token stops working; zero when the API did not say.
ExpiresAt time.Time
// TokenID names the token for RevokeAPIToken; "" when the API did not say.
TokenID string
}
APIToken is an API token a device sign-in minted: the credential and what it may do. There is no refresh token; a device-login token lives 365 days. Keep TokenID to revoke it with RevokeAPIToken. String() redacts AccessToken.
type ActionOptions ¶
type AdmissionFailedError ¶ added in v0.11.0
type AdmissionFailedError struct {
// OperationID is the operation that was followed.
OperationID string
// Status is the operation's final status, when it reached one.
Status OperationStatus
// ErrorCode is the operation's own code, such as "gitops_push_rejected";
// "" when it had none, and always "" when the API refused the wait (its
// code is on the *APIError in Err).
ErrorCode string
// ErrorMessage is the operation's own explanation, when it gave one.
ErrorMessage string
// Err is the API's refusal of the wait, when that is what ended it.
Err error
}
AdmissionFailedError reports that the hub could not admit a new connection: the operation carrying it ended failed or timed_out on the platform, or the API refused the wait itself (for any reason but authentication, which WaitForAdmission returns as the *APIError it is). It matches ErrConnection; when the API refused the wait, errors.As also reaches its *APIError, with the status, code and detail it answered.
func (*AdmissionFailedError) Error ¶ added in v0.11.0
func (e *AdmissionFailedError) Error() string
func (*AdmissionFailedError) Unwrap ¶ added in v0.11.0
func (e *AdmissionFailedError) Unwrap() []error
Unwrap makes an AdmissionFailedError match ErrConnection, and whatever the API answered when that is what ended the wait.
type AdmissionOptions ¶ added in v0.11.0
type AdmissionOptions struct {
// Timeout is how long to wait; DefaultAdmissionTimeout when zero.
Timeout time.Duration
// PollInterval is how often to read the operation;
// DefaultOperationPollInterval when zero.
PollInterval time.Duration
}
AdmissionOptions bounds WaitForAdmission. Zero values take the defaults.
type AdmissionTimeoutError ¶ added in v0.11.0
type AdmissionTimeoutError struct {
// Wait is how long the wait lasted.
Wait time.Duration
// OperationID is the operation that was followed.
OperationID string
}
AdmissionTimeoutError reports that a new connection was not admitted by its hub within the wait. It is a connection error and a timeout at once -- errors.Is matches both ErrConnection and ErrTimeout, and Timeout reports true -- because the connection may still be admitted after it.
func (*AdmissionTimeoutError) Error ¶ added in v0.11.0
func (e *AdmissionTimeoutError) Error() string
func (*AdmissionTimeoutError) Timeout ¶ added in v0.11.0
func (e *AdmissionTimeoutError) Timeout() bool
Timeout reports true, the way a net.Error that timed out does.
func (*AdmissionTimeoutError) Unwrap ¶ added in v0.11.0
func (e *AdmissionTimeoutError) Unwrap() []error
Unwrap makes an AdmissionTimeoutError match ErrConnection and ErrTimeout.
type AnalyticsOverviewOptions ¶ added in v0.2.13
type AskOptions ¶ added in v0.5.0
type AskOptions struct {
STTLang string
Pipeline []string
Location map[string]any
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
// ConnectionType is the kind of connection to create, such as
// ConnectionTypeHomeAssistant, sent as spec.connection_type; "" leaves the
// API's default. The API must say the connection is of that kind: when it
// does not, CreateClientIdentity deletes what it made and returns an
// *UnsupportedConnectionTypeError.
ConnectionType string
}
type BootstrapIdentityResult ¶ added in v0.2.2
type BootstrapIdentityResult struct {
Identity Identity
Hub map[string]any
Client map[string]any
Endpoint *SelectedHubEndpoint
// Operation tracks the hub admitting the new connection, about ninety
// seconds; WaitForAdmission follows it. nil when the API sent none.
Operation *OperationResource
}
func (BootstrapIdentityResult) ClientID ¶ added in v0.11.0
func (r BootstrapIdentityResult) ClientID() string
ClientID is the id of the connection that was created; "" when the answer carried none.
func (BootstrapIdentityResult) ConnectionType ¶ added in v0.11.0
func (r BootstrapIdentityResult) ConnectionType() string
ConnectionType is the kind of connection the API says it created, from the answer's spec.connection_type; "" when it named none.
func (BootstrapIdentityResult) SelectedProtocol ¶ added in v0.2.2
func (r BootstrapIdentityResult) SelectedProtocol() HubProtocol
type Client ¶
type Client struct {
Identity Identity
Transport RuntimeTransport
ConnectTimeout time.Duration
// contains filtered or unexported fields
}
func NewClientFromConfig ¶ added in v0.2.11
func NewClientFromEnv ¶
func NewClientFromFile ¶
func NewClientWithOptions ¶ added in v0.2.2
func NewClientWithOptions(identity Identity, opts ClientOptions) (*Client, error)
func (*Client) AskWithOptions ¶ added in v0.5.0
func (*Client) Broadcast ¶ added in v0.10.0
func (c *Client) Broadcast(ctx context.Context, eventType string, data Data, eventContext Context) error
Broadcast sends an event down to every child of this hub. Admin only.
A hub requires admin standing and the can_broadcast grant, and a client that sends one without them is not answered with an error -- it is disconnected for misbehaviour. Nothing here can check first: a hub's HELLO carries its public key, peer name and node id, and nothing about what this client may do, so a refusal arrives as a closed connection on the next read.
func (*Client) ClosedRefused ¶ added in v0.11.0
ClosedRefused reports whether the hub closed this client's last connection the way it refuses credentials: a close with no status, 1000, 1005 or 1008. It is only a verdict on the credentials when the close came right after the handshake -- a hub that does not know a client's static key says so only by closing then, and a hub shutting down later closes with 1000 too -- which is how HubSession's settle window reads it. It is false for a transport that cannot tell.
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) Escalate ¶ added in v0.10.0
func (c *Client) Escalate(ctx context.Context, eventType string, data Data, eventContext Context) error
Escalate sends an event up to the parent node.
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
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) ListenBinary ¶ added in v0.10.0
func (c *Client) ListenBinary(ctx context.Context, options ListenOptions) (*Subscription[ThalovantBinary], error)
ListenBinary connects and returns an independent stream of binary frames: rendered speech, and files.
This is what a hub sends back for speak:synth -- the audio itself, so a client with no synthesiser can still speak -- and how it hands over a file. Delivered as a stream and not on a reply, because a binary frame carries no request id: it cannot be attributed to one Ask. Its Utterance is the only thread back to a turn.
func (*Client) ListenHive ¶ added in v0.10.0
func (c *Client) ListenHive(ctx context.Context, kind string, options ListenOptions) (*Subscription[HiveMessage], error)
ListenHive connects and returns an independent stream of one hive frame kind.
A hub relays more than this client's conversation: broadcast is aimed down at every child, propagate walks the whole hive, escalate goes up to the parent, intercom is addressed node to node, and rendezvous is the mailbox peers use to find each other through NAT. See HiveKinds.
Range over C and inspect Err afterward; call Close when done.
func (*Client) Propagate ¶ added in v0.10.0
func (c *Client) Propagate(ctx context.Context, eventType string, data Data, eventContext Context) error
Propagate sends an event across the hive; every node sees it once.
func (*Client) Reply ¶ added in v0.11.0
func (c *Client) Reply(ctx context.Context, event Event, msgType string, data Data, eventContext Context) error
Reply answers an event the hub sent, back along the route it came (OVOS-MSG-1 §5.2). The reply carries a deep copy of the event's context as the hub sent it -- its session, its request id, everything a skill waiting on the answer matches -- with the routing turned round by ReplyContext. eventContext entries, when given, are laid over the copy before the turn. Like Emit, a reply is never replayed.
func (*Client) SendAction ¶
func (*Client) SendUtterance ¶
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 ClientKeyRejectedError ¶ added in v0.12.0
ClientKeyRejectedError is a hub refusing this client's own Noise static key.
A hub pins the first static key a connection presents and refuses any other for good, closing the link the moment the XX handshake that showed it ends. Two programs that read the same identity but keep their keys in different folders -- a satellite and a command-line tool run by another user, say -- each present their own key, and whichever came second is locked out.
KeyFolder is the folder this client's key is in; OtherKeyFolder, when there is a likely one, where another program reading the same identity keeps its key. The fix is to pair again (a new connection pins afresh), or to share the key folder: point every program that reads this identity at the folder holding the key the hub trusts (the transports' NoiseStateDir). It matches ErrClientKeyRejected, ErrHubRefused and ErrConnection.
func (*ClientKeyRejectedError) Error ¶ added in v0.12.0
func (e *ClientKeyRejectedError) Error() string
func (*ClientKeyRejectedError) Unwrap ¶ added in v0.12.0
func (e *ClientKeyRejectedError) Unwrap() []error
Unwrap makes a ClientKeyRejectedError match ErrClientKeyRejected, and through it ErrHubRefused, and ErrConnection.
type ClientOptions ¶ added in v0.2.2
type ClientOptions struct {
Protocol HubProtocol
ConnectTimeout time.Duration
}
type CodeOptions ¶
type Context ¶
func BuildClientContext ¶
func BuildClientContext(base Context, opts ClientContextOptions) Context
func ContextWithCorrelation ¶
func MergeContext ¶
func ReplyContext ¶ added in v0.11.0
ReplyContext is the context of a reply to a message that carried eventContext (OVOS-MSG-1 §5.2): a deep copy, so the reply keeps the request's session and everything else it said, with the routing turned round. The reply goes to whoever sent the request ("destination" becomes the old "source") and comes from whoever it was sent to ("source" becomes the old "destination", its first entry when that is a list). A request with a destination and no source gets a reply with no destination: keeping the old one would address the reply to its own sender. A hub uses this to route the answer back to the peer that asked, across bridges and NAT. Otherwise a key that is absent or null stays as it was.
func RequestContext ¶ added in v0.7.0
func RequestContext(base Context, opts RequestContextOptions) Context
RequestContext copies the context and its session before applying nonempty hints.
type ControlPlane ¶ added in v0.2.2
type ControlPlane struct {
APIURL string
AccessToken string
UserAgent string
HTTPClient *http.Client
// TokenID names the API token in AccessToken when the sign-in that stored
// it said which one (a device login does), for RevokeAPIToken; "" otherwise.
// Every sign-in sets it from its own answer.
TokenID string
// contains filtered or unexported fields
}
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) BeginDeviceLogin ¶ added in v0.11.0
func (c *ControlPlane) BeginDeviceLogin(ctx context.Context, scopes []string, clientName string) (*DeviceAuthorization, error)
BeginDeviceLogin starts a device sign-in: a code for a person to approve in a browser, and the interval to poll at. It is LoginWithBrowser one step at a time, for a caller that runs its own loop -- a setup screen that shows the code and polls on its own schedule -- and it prints and opens nothing.
scopes are what the token will carry; nil or empty lets the API choose its default (hubs:read and clients:write) -- the API refuses an empty list, so one is never sent. HomeAssistantScopes is what a Home Assistant link asks for. clientName, when set, names the device on the approval page.
A verification URL that is not HTTP(S), has no host, or carries credentials is refused: it is about to be opened in a browser.
func (*ControlPlane) BeginDeviceLoginWithOptions ¶ added in v0.12.0
func (c *ControlPlane) BeginDeviceLoginWithOptions(ctx context.Context, opts DeviceLoginOptions) (*DeviceAuthorization, error)
BeginDeviceLoginWithOptions is BeginDeviceLogin with the options LoginWithBrowser takes; it reads Scopes, ClientName and ClientID, and ignores the rest.
ClientID signs in as a registered app, such as HomeAssistantClientID: the approval screen shows the platform's name for the app as verified (ClientName becomes the device's own label beside it), and approving the app again replaces the token it already holds. Such an app may ask only for its own scopes, and an id the API does not know is refused with a 400 unknown_client *APIError. "" leaves the field out.
func (*ControlPlane) ClearHubRating ¶ added in v0.3.6
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) CompleteNativeSignIn ¶ added in v0.9.2
func (c *ControlPlane) CompleteNativeSignIn(ctx context.Context, code string, verifier string, clientID string, redirectURI string) (map[string]any, error)
CompleteNativeSignIn exchanges an authorization code for a scoped access token and stores it.
The verifier is sent here and nowhere else; it never entered the browser, which is what makes an intercepted code useless to whoever intercepted it.
A code presented twice revokes the token the first exchange minted (RFC 9700), so retrying a failed exchange with the same code destroys the token it is trying to obtain. Start again from BeginNativeSignIn.
func (*ControlPlane) CreateClient ¶ added in v0.2.2
func (*ControlPlane) CreateClientIdentity ¶ added in v0.2.2
func (c *ControlPlane) CreateClientIdentity(ctx context.Context, hub map[string]any, opts BootstrapIdentityOptions) (BootstrapIdentityResult, error)
CreateClientIdentity provisions a connection to a hub and returns the identity to connect with. The secrets are generated here and sent to the API once; the usable identity is in the result.
With opts.ConnectionType set, the connection is of that kind, and the refusals a caller can branch on come back as errors to test with errors.Is: ErrUnsupportedConnectionType (an *UnsupportedConnectionTypeError: the API does not know the kind, or made an ordinary connection instead, which is deleted), ErrPlan (the plan does not allow it), ErrAlreadyLinked (the hub already holds the one link of its kind; APIError.LinkedClientID names it) and ErrAuth (sign in again). Each still carries the *APIError the API answered with.
The result's Operation tracks the hub admitting the connection, about ninety seconds; WaitForAdmission waits for it.
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 (*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) DeleteClient ¶ added in v0.11.0
DeleteClient deletes a connection.
The API wants the connection's current etag as If-Match. With etag "" this reads it first; if another writer changed the connection in between (HTTP 412) it reads it once more and retries once. A connection that is already gone (HTTP 404 on either request) counts as deleted.
func (*ControlPlane) DeleteHub ¶ added in v0.3.6
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) DescribeDeviceLogin ¶ added in v0.12.0
func (c *ControlPlane) DescribeDeviceLogin(ctx context.Context, userCode string) (*DeviceLoginRequest, error)
DescribeDeviceLogin reads a pending device sign-in by its user code, as its approver sees it: GET /v1/auth/device/codes/{userCode}, signed in as the person who would approve it. It says which app asked and whether the platform vouches for its name (ClientVerified). A code that is unknown, expired or already answered is a 404 *APIError.
func (*ControlPlane) GetAnalyticsOverview ¶ added in v0.2.13
func (c *ControlPlane) GetAnalyticsOverview(ctx context.Context, opts AnalyticsOverviewOptions) (map[string]any, error)
func (*ControlPlane) GetClient ¶ added in v0.11.0
GetClient reads one connection (a client of a hub), with the etag a change to it needs.
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 (*ControlPlane) GetMemorySummary ¶ added in v0.2.13
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 (*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) InstallHubSkill ¶ added in v0.6.0
func (c *ControlPlane) InstallHubSkill(ctx context.Context, hubID, skill, version string, opts HubSkillWaitOptions) (map[string]any, error)
InstallHubSkill installs on the shared runtime; every hub using it is affected. Use version "latest" or an exact version. Requires hubs:write and a paid plan.
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) ListHubSkillHistory ¶ added in v0.6.0
func (c *ControlPlane) ListHubSkillHistory(ctx context.Context, hubID string, limit int) (map[string]any, error)
ListHubSkillHistory reads newest-first events and operations. Limit is 1–200.
func (*ControlPlane) ListHubSkills ¶ added in v0.6.0
ListHubSkills reads the skills of the hub's shared runtime group.
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 (*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) 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, with its token_id on ControlPlane.TokenID. Denial, expiry, and timeout are reported as ErrDeviceAccessDenied (a *DeviceLoginDeniedError), ErrDeviceCodeExpired (a *DeviceLoginExpiredError), and ErrTimeout respectively. BeginDeviceLogin and PollDeviceLogin are the same flow one step at a time.
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) PollDeviceLogin ¶ added in v0.11.0
func (c *ControlPlane) PollDeviceLogin(ctx context.Context, authorization *DeviceAuthorization) (*APIToken, error)
PollDeviceLogin asks once whether a device sign-in was approved.
On approval it returns the token and keeps it on this ControlPlane (AccessToken and TokenID), exactly like Login. Otherwise it returns:
- *DeviceLoginPendingError (errors.Is ErrDeviceLoginPending): nobody has approved yet; poll again after its Interval. A slow_down answer lengthens authorization.Interval by five seconds, for good, as RFC 8628 §3.5 asks, so keep polling with the same authorization;
- *DeviceLoginExpiredError (errors.Is ErrDeviceCodeExpired): start again;
- *DeviceLoginDeniedError (errors.Is ErrDeviceAccessDenied);
- any other refusal as an *APIError carrying what the API said.
All of them match ErrAPI. Neither the device code nor the token ever appears in an 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) RemoveHubSkill ¶ added in v0.6.0
func (c *ControlPlane) RemoveHubSkill(ctx context.Context, hubID, skill string, opts HubSkillWaitOptions) (map[string]any, error)
RemoveHubSkill removes the shared runtime attachment, affecting every served hub.
func (*ControlPlane) ReplaceRuntimeGroupConfig ¶ added in v0.7.0
func (c *ControlPlane) ReplaceRuntimeGroupConfig(ctx context.Context, runtimeGroupID string, config map[string]any, opts RuntimeGroupConfigOptions) (map[string]any, error)
ReplaceRuntimeGroupConfig explicitly replaces configuration via unconditional PATCH. Personas are replaced only when non-nil. Requires paid hubs:write.
func (*ControlPlane) RequireRuntimeProtocol ¶ added in v0.2.2
func (c *ControlPlane) RequireRuntimeProtocol(result BootstrapIdentityResult, protocol HubProtocol) (*SelectedHubEndpoint, error)
func (*ControlPlane) RevokeAPIToken ¶ added in v0.11.0
func (c *ControlPlane) RevokeAPIToken(ctx context.Context, tokenID string) error
RevokeAPIToken revokes an API token; with tokenID "" the one this ControlPlane signed in with (TokenID). A token may always revoke itself, whatever its scopes. Revoking the token in use forgets it here too, so a later call fails locally rather than with an HTTP 401.
Revoking the token in use is idempotent. A token already revoked, or expired, cannot authenticate its own revoke, so the API answers 401; the token is dead either way, so that counts as revoked and the token is forgotten. Revoking it again then sends nothing and returns nil, until the next sign-in. Revoking another token by id is not idempotent: the API's own answer, such as a 404 for a token it does not know, is returned as usual.
A sign-in that finishes on another goroutine while the revoke is on its way keeps its token: the revoke forgets only the token it revoked, checked and cleared under the same lock a sign-in stores its token and id under. The lock is never held across the request.
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) UpdateHubSkill ¶ added in v0.6.0
func (c *ControlPlane) UpdateHubSkill(ctx context.Context, hubID, skill, version string, opts HubSkillWaitOptions) (map[string]any, error)
UpdateHubSkill moves a skill to an exact version or "latest" on the shared runtime.
func (*ControlPlane) UpdateMemoryItem ¶ added in v0.2.13
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 deep-merges with a revision precondition and at most three attempts. Only 412 conflicts trigger a fresh read and merge. Older APIs fail before writing. Requires hubs:read and paid hubs:write.
func (*ControlPlane) WaitForAdmission ¶ added in v0.11.0
func (c *ControlPlane) WaitForAdmission(ctx context.Context, operation *OperationResource, opts AdmissionOptions) error
WaitForAdmission waits until the hub has admitted a new connection, about ninety seconds after CreateClientIdentity returned it. Pass the result's Operation.
It follows the operation, reading GET /v1/operations/{id}:
- ready: admitted, and it returns nil;
- failed or timed_out: *AdmissionFailedError, with the operation's ErrorCode;
- requested, committed, applied: it keeps reading;
- no operation at all (nil), or HTTP 404 (the API no longer tracks it): admitted at once;
- HTTP 429: the next read waits what the API asks (APIError.RetryAfter: the body's retry_after_seconds, else Retry-After, else RateLimit-Reset), or the poll interval when that is longer; asking for longer than the time left is the timeout at once;
- HTTP 5xx: ridden out;
- HTTP 401 or 403: the *APIError itself, since the token rather than the connection is the trouble (errors.Is ErrAuth for a revoked token or a missing scope);
- any other refusal of the wait: *AdmissionFailedError, whose Err is the *APIError with the status, code and detail the API answered;
- a request that did not reach the API: returned as it is (errors.Is ErrAPIUnreachable), since losing the API says nothing about the hub.
When opts.Timeout passes first it returns *AdmissionTimeoutError, which matches both ErrConnection and ErrTimeout: the connection may still be admitted later. Cancelling ctx ends the wait with ErrTimeout and the context's error. A hub that refuses the new credentials inside this window is not admitting them yet, not refusing them.
An operation whose links.self points at another origin than the API's is refused and never fetched: the token goes to the API and nowhere else.
func (*ControlPlane) WaitForHubSkillOperation ¶ added in v0.6.0
func (c *ControlPlane) WaitForHubSkillOperation(ctx context.Context, accepted map[string]any, opts HubSkillWaitOptions) (map[string]any, error)
WaitForHubSkillOperation resumes an accepted write without repeating it. On failure the accepted response is also returned so its operation_id survives.
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 Data ¶
func AnswerHomeRequest ¶ added in v0.11.0
func AnswerHomeRequest(ctx context.Context, replier Replier, event Event, handler HomeHandler, opts HomeAnswerOptions) (Data, error)
AnswerHomeRequest answers one request: it runs handler, then replies with whatever happened, and returns the payload it sent.
Everything happens inside the hub's bound (opts.HubTimeout, HomeRequestTimeout by default), counted from the call: the hub gives up on a request after that, and an answer it has given up on only confuses the next one. The handler gets opts.Timeout (DefaultHomeHandlerTimeout by default) or what is left of the bound, whichever is less, under a context derived from ctx; the reply gets whatever the handler left. When the handler fails the answer is failed_to_handle, and when it is still running at its deadline the answer is timeout, sent at once: a handler that ignores its context is left to finish on its own goroutine, and what it returns then is dropped.
A reply is never started after the bound, and one still waiting to be sent when it passes is withdrawn; a frame already being written is finished, since half of one would break the Noise stream. When there was no time to answer, AnswerHomeRequest returns a nil payload and a nil error. When ctx itself ends first, nothing is sent and ctx's error is returned: the link is going away.
func HomeResponse ¶ added in v0.11.0
func HomeResponse(request HomeRequest, answer HomeAnswer) Data
HomeResponse is the thalovant.home.response payload for answer, held to the contract: an unknown response type or error code becomes HomeError with HomeErrorUnknown, keeping the speech.
func UtterancePayload ¶
type DeviceAuthorization ¶ added in v0.11.0
type DeviceAuthorization struct {
DeviceCode string
UserCode string
VerificationURI string
// VerificationURIComplete is the verification URL with the code in it, or
// "" when the API sent none.
VerificationURIComplete string
// Interval is how long to wait between two polls. A slow_down answer
// lengthens it on the authorization that was polled.
Interval time.Duration
// ExpiresIn is how long the code stays valid from when it was issued.
ExpiresIn time.Duration
}
DeviceAuthorization is a started device sign-in (RFC 8628): what to show a person, and what to poll with. Show VerificationURI and UserCode, or open VerificationURIComplete, which carries the code; then call PollDeviceLogin every Interval.
DeviceCode is the secret half and never needs showing; String() redacts it. Keep the whole value to resume polling later, in this process or another.
func (DeviceAuthorization) GoString ¶ added in v0.11.0
func (a DeviceAuthorization) GoString() string
GoString keeps %#v from printing the device code.
func (DeviceAuthorization) String ¶ added in v0.11.0
func (a DeviceAuthorization) String() string
String renders the authorization with its device code redacted.
type DeviceLoginDeniedError ¶ added in v0.11.0
type DeviceLoginDeniedError struct {
APIError *APIError
}
DeviceLoginDeniedError is a device sign-in the person refused in the browser. It matches ErrDeviceAccessDenied, and errors.As reaches the *APIError the API answered with.
func (*DeviceLoginDeniedError) Error ¶ added in v0.11.0
func (e *DeviceLoginDeniedError) Error() string
func (*DeviceLoginDeniedError) Unwrap ¶ added in v0.11.0
func (e *DeviceLoginDeniedError) Unwrap() []error
Unwrap makes a DeviceLoginDeniedError match ErrDeviceAccessDenied and ErrAPI.
type DeviceLoginExpiredError ¶ added in v0.11.0
type DeviceLoginExpiredError struct {
APIError *APIError
}
DeviceLoginExpiredError is a device sign-in code that expired before anyone approved it; start a new sign-in for a new code. It matches ErrDeviceCodeExpired, and errors.As reaches the *APIError the API answered with.
func (*DeviceLoginExpiredError) Error ¶ added in v0.11.0
func (e *DeviceLoginExpiredError) Error() string
func (*DeviceLoginExpiredError) Unwrap ¶ added in v0.11.0
func (e *DeviceLoginExpiredError) Unwrap() []error
Unwrap makes a DeviceLoginExpiredError match ErrDeviceCodeExpired and ErrAPI.
type DeviceLoginOptions ¶ added in v0.3.3
type DeviceLoginOptions struct {
Scopes []string
ClientName string
// ClientID signs in as a registered app, such as HomeAssistantClientID;
// "" leaves it out. See BeginDeviceLoginWithOptions.
ClientID 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 (an empty Scopes is left out, as the API refuses one); 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 DeviceLoginPendingError ¶ added in v0.11.0
type DeviceLoginPendingError struct {
// Interval is how long to wait before the next poll.
Interval time.Duration
// APIError is what the API answered.
APIError *APIError
}
DeviceLoginPendingError is a device sign-in nobody has approved yet: poll again after Interval. A slow_down answer has already lengthened it, for good, on the DeviceAuthorization that was polled. It matches ErrDeviceLoginPending, and errors.As reaches the *APIError the API answered with (HTTP 400).
func (*DeviceLoginPendingError) Error ¶ added in v0.11.0
func (e *DeviceLoginPendingError) Error() string
func (*DeviceLoginPendingError) Unwrap ¶ added in v0.11.0
func (e *DeviceLoginPendingError) Unwrap() []error
Unwrap makes a DeviceLoginPendingError match ErrDeviceLoginPending and ErrAPI.
type DeviceLoginRequest ¶ added in v0.12.0
type DeviceLoginRequest struct {
Scopes []string
ClientName string
// ExpiresAt is when the code stops being approvable; zero when the API did
// not say.
ExpiresAt time.Time
ClientID string
ClientVerified bool
DeviceName string
}
DeviceLoginRequest is a pending device sign-in as the person approving it sees it; see DescribeDeviceLogin.
ClientVerified is true only when a registered app asked (it named its ClientID): ClientName is then the platform's own name for that app, and DeviceName whatever the device called itself, which nothing checks. Otherwise ClientName is the device's own claim.
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 ¶
func (Event) AudioBytes ¶ added in v0.7.0
AudioBytes decodes embedded hex only. It never fetches a skill path or URL.
func (Event) AudioBytesWithLimit ¶ added in v0.7.0
func (Event) DisplayItems ¶
func (e Event) DisplayItems(maxTextChars int) []DisplayItem
func (Event) DisplayText ¶
func (Event) Utterances ¶
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.
// Empty uses the directory of the file the identity was read from
// (Identity.SourcePath), else NoiseStateDir().
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) ClosedRefused ¶ added in v0.12.0
func (t *HTTPTransport) ClosedRefused() bool
ClosedRefused reports whether the hub refused this connection's credentials the last time it ended: a request answered 401 or 403 before the hub had sent anything that decrypted under the session's keys. A hub that has spoken accepted the credentials, so a refusal after that is not read as one. A new connection attempt clears it.
func (*HTTPTransport) Connect ¶
func (t *HTTPTransport) Connect(ctx context.Context) error
Connect opens the HTTP session and completes the v3 Noise handshake. A KK handshake the hub refuses, or whose answer does not authenticate, is followed at once by one XX handshake inside this connect, since only XX tells a changed password (ErrHubRefused) from a changed hub key (ErrHubKeyChanged); the XX attempt's outcome is the connect's.
A request answered 401 or 403 while this client sends the last frames of an XX handshake it completed is the hub refusing this client's own key: a *ClientKeyRejectedError.
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) 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) 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"`
// Binary is set only on a BINARY frame, whose payload is bytes, not JSON.
Binary *ThalovantBinary `json:"-"`
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 HomeAnswer ¶ added in v0.11.0
type HomeAnswer struct {
Speech string
ResponseType string
ErrorCode string
ContinueConversation bool
ConversationID string
}
HomeAnswer is what a handler says back. Speech may carry markup; it is sent as plain text. An empty ResponseType is HomeActionDone. ErrorCode is sent only with HomeError. ConversationID, when empty, echoes the request's.
type HomeAnswerOptions ¶ added in v0.11.0
type HomeAnswerOptions struct {
// Timeout is how long each handler has at most; DefaultHomeHandlerTimeout
// when zero.
Timeout time.Duration
// HubTimeout is the hub's bound on a request, counted from its arrival,
// which the handler and the reply share; HomeRequestTimeout when zero.
HubTimeout time.Duration
// OnReplyError, when set, hears about an answer that could not be sent.
// An answer there was no time left to send is not an error.
OnReplyError func(request HomeRequest, err error)
}
HomeAnswerOptions tunes AnswerHomeRequest and AnswerHomeRequests.
type HomeHandler ¶ added in v0.11.0
type HomeHandler func(ctx context.Context, request HomeRequest) (HomeAnswer, error)
HomeHandler answers one request. It runs on its own goroutine under a context that ends when the handler's time is up; an error, a panic or running out of time is answered for it (failed_to_handle, failed_to_handle, timeout).
type HomeLink ¶ added in v0.11.0
HomeLink is a connection a hub's requests arrive on: somewhere to register a handler for one event type, and to reply. HubSession is one.
type HomeRequest ¶ added in v0.11.0
type HomeRequest struct {
RequestID string
Utterance string
Lang string
ConversationID string
// Event is what the request arrived as; the answer is a reply to it.
Event Event
}
HomeRequest is one thalovant.home.request: what was said, in which language. Absent fields are "".
func HomeRequestFromEvent ¶ added in v0.11.0
func HomeRequestFromEvent(event Event) HomeRequest
HomeRequestFromEvent reads a request out of the event it arrived as. Only a non-empty string counts as a value.
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 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
Examples returns complete phrases before prefixes and slots, preferring fuller wording up to eight words. A non-positive limit returns all results.
func (HubIntent) ExamplesWithOptions ¶ added in v0.7.0
func (i HubIntent) ExamplesWithOptions(lang string, limit int, opts IntentExampleOptions) []string
func (HubIntent) ID ¶ added in v0.3.13
ID is the intent's "<skill_id>:<name>" name, as the engines' manifests spell it.
func (HubIntent) PhrasesFor ¶ added in v0.3.13
PhrasesFor returns the closest OVOS-compatible language registration.
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"`
// ListedIn is the tag the hub actually listed each requested language
// under, in Languages order. Equal to Languages unless a listing came
// back empty and the language's usual form answered instead, which is the
// only way the two differ. Callers rendering sentences must read them
// from the tag that answered.
ListedIn []string `json:"listed_in"`
}
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 HubSession ¶ added in v0.9.0
type HubSession struct {
// contains filtered or unexported fields
}
HubSession owns one connection. Either call Run in a goroutine, which keeps the link up by policy until the session closes, or call Probe at ProbeDelay intervals yourself. Warm is asynchronous; foreground calls bypass the unattended retry ladder. No admitted Ask or Emit is replayed after an ambiguous transport failure.
func NewHubSession ¶ added in v0.9.0
func NewHubSession(connect func(context.Context) (HubSessionClient, error), policy HubSessionPolicy, options ...HubSessionOption) (*HubSession, error)
func (*HubSession) Ask ¶ added in v0.9.0
func (s *HubSession) Ask(ctx context.Context, text string, options AskOptions) (reply Reply, err error)
func (*HubSession) Close ¶ added in v0.9.0
func (s *HubSession) Close(ctx context.Context) error
Close retires the session permanently, stops Run, and waits for its admitted call.
func (*HubSession) Connect ¶ added in v0.11.0
func (s *HubSession) Connect(ctx context.Context) error
Connect makes one attempt: it returns with a live link, or says why there is none. A link the session already holds is kept. A new one must stay up for the settle window (WithSettle); a hub that closes it inside the window with no status, 1000, 1005 or 1008 has refused the credentials, which is ErrHubRefused (always with ErrConnection). Any other failure is ErrConnection or ErrTimeout.
func (*HubSession) Connected ¶ added in v0.11.0
func (s *HubSession) Connected() bool
Connected reports whether the session holds a client whose link is up.
func (*HubSession) Held ¶ added in v0.9.0
func (s *HubSession) Held() bool
func (*HubSession) On ¶ added in v0.11.0
func (s *HubSession) On(eventType string, handler func(Event)) (unsubscribe func())
On calls handler for every event named eventType the session receives, on the client it holds now and on every client it builds after a reconnect, until the returned function is called; once it has returned, no delivery calls handler again. Handlers run one at a time, in order, on the session's delivery goroutine, so a handler that does slow work starts a goroutine of its own. Events and their maps are read-only.
func (*HubSession) OnStateChange ¶ added in v0.11.0
func (s *HubSession) OnStateChange(notify func(up bool)) (unsubscribe func())
OnStateChange calls notify with true when the link comes up and false when it goes down, until the returned function is called. It runs on the goroutine that changed the state while that goroutine holds the session, so it must return promptly and must not call Ask, Emit, Reply, Connect or Close itself; start a goroutine for that.
func (*HubSession) ProbeDelay ¶ added in v0.9.0
func (s *HubSession) ProbeDelay() time.Duration
func (*HubSession) Reply ¶ added in v0.11.0
func (s *HubSession) Reply(ctx context.Context, event Event, msgType string, data Data, eventContext Context) error
Reply answers an event the hub sent, back along the route it came (OVOS-MSG-1 §5.2): see Client.Reply. Like Emit, it is never replayed.
func (*HubSession) RetryAt ¶ added in v0.9.0
func (s *HubSession) RetryAt() time.Time
func (*HubSession) RetryWait ¶ added in v0.9.0
func (s *HubSession) RetryWait() time.Duration
func (*HubSession) Run ¶ added in v0.11.0
func (s *HubSession) Run(ctx context.Context) error
Run keeps the link up until the session closes or ctx ends; start it in a goroutine of its own. It makes the first attempt at once, and after every attempt does what a LinkSupervisor decides: a link that drops is dialled again at once; a failed attempt waits the retry ladder (Retry, doubling up to RetryCeiling); a hub that refuses the credentials is retried the same way until the refusals have lasted the refusal grace (WithRefusalGrace), since a new connection is refused until its hub admits it, and then Run returns the refusal (ErrHubRefused); a hub whose key changed ends Run at once with that error (ErrHubKeyChanged), since retrying cannot change it, and so does a hub that refused this client's own key (ErrClientKeyRejected). A held link is looked at continually. Run returns nil once the session is closed, and ctx's error when ctx ends first.
func (*HubSession) SubscribeEvents ¶ added in v0.9.0
func (s *HubSession) SubscribeEvents(capacity int) *Subscription[Event]
type HubSessionClient ¶ added in v0.9.0
type HubSessionOption ¶ added in v0.11.0
type HubSessionOption func(*HubSession)
HubSessionOption adjusts a HubSession built by NewHubSession.
func WithRefusalGrace ¶ added in v0.11.0
func WithRefusalGrace(grace time.Duration) HubSessionOption
WithRefusalGrace sets how long Run keeps retrying a hub that refuses the credentials before it returns the refusal (DefaultHubRefusalGrace). Nonpositive values are ignored.
func WithSettle ¶ added in v0.11.0
func WithSettle(window time.Duration) HubSessionOption
WithSettle sets how long a link opened by Connect or Run must stay up before it counts (DefaultHubSettle); 0 turns the check off. A close inside the window with no status, 1000, 1005 or 1008 is the hub refusing the credentials (ErrHubRefused); any other is a drop. Negative values are ignored.
type HubSessionPolicy ¶ added in v0.9.0
func DefaultHubSessionPolicy ¶ added in v0.9.0
func DefaultHubSessionPolicy() HubSessionPolicy
func (HubSessionPolicy) NextWait ¶ added in v0.9.0
func (p HubSessionPolicy) NextWait(current time.Duration) time.Duration
func (HubSessionPolicy) Validate ¶ added in v0.9.0
func (p HubSessionPolicy) Validate() error
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 HubSkillWaitOptions ¶ added in v0.6.0
HubSkillWaitOptions controls optional polling after one accepted write. Zero durations use a 120-second timeout and two-second polling interval. Cancellation or polling failure never retries the accepted mutation.
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"`
// contains filtered or unexported fields
}
func IdentityFromConfig ¶ added in v0.2.11
func IdentityFromEnv ¶
func IdentityFromFile ¶
func (Identity) EnabledProtocols ¶ added in v0.2.1
func (i Identity) EnabledProtocols() []HubProtocol
func (Identity) EndpointBase ¶
func (Identity) EndpointFor ¶ added in v0.2.1
func (i Identity) EndpointFor(protocol HubProtocol) string
func (Identity) SourcePath ¶ added in v0.12.0
SourcePath is the file this identity was read from (IdentityFromFile, IdentityFromConfig), as an absolute path, or "" when it came from anywhere else. With no NoiseStateDir named, a transport keeps this identity's Noise key and hub pins in that file's directory, so every program that reads the same file presents the same key to the hub. It is not identity material: never serialized.
func (Identity) String ¶ added in v0.3.7
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) SupportsProtocol ¶ added in v0.2.1
func (i Identity) SupportsProtocol(protocol HubProtocol) bool
type Intent ¶ added in v0.9.0
type Intent struct {
// Languages preserves phrase-map order when no requested language is supplied.
Languages []string `json:"languages"`
ID string `json:"id"`
Name string `json:"name"`
SkillID string `json:"skill_id"`
Engine string `json:"engine"`
Phrases map[string][]string `json:"phrases"`
}
func (Intent) MarshalJSON ¶ added in v0.9.0
func (*Intent) UnmarshalJSON ¶ added in v0.9.0
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 IntentExampleOptions ¶ added in v0.7.0
type IntentExampleOptions struct {
Speakable bool
Sentence bool
Slots map[string]string
Listing *ListingRules
}
IntentExampleOptions controls locale-aware illustrative rendering.
type IntentOptions ¶ added in v0.3.13
type IntentOptions struct {
Timeout time.Duration
Describe *bool
Fallback *bool
IncludeDefinitions bool
// Nearest retries an empty listing once in the language's usual form.
// Nil means on: a listing that returns nothing from a hub which
// demonstrably answers in that language is a fault, not a preference.
// See UsualForm.
Nearest *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 Inventory ¶ added in v0.9.0
type Inventory struct {
CacheVersion int `json:"cache_version"`
HubID string `json:"hub_id"`
HubName string `json:"hub_name"`
Source string `json:"source"`
GeneratedAt string `json:"generated_at"`
Notes []string `json:"notes"`
Skills []Skill `json:"skills"`
}
func InventoryFromJSON ¶ added in v0.9.0
func (Inventory) HasPhrases ¶ added in v0.9.0
func (Inventory) MarshalJSON ¶ added in v0.9.0
type InventoryCache ¶ added in v0.9.0
func NewInventoryCache ¶ added in v0.9.0
func NewInventoryCache(directory string) *InventoryCache
func (*InventoryCache) Load ¶ added in v0.9.0
func (c *InventoryCache) Load(key string) *Inventory
func (*InventoryCache) Path ¶ added in v0.9.0
func (c *InventoryCache) Path(key string) (string, error)
func (*InventoryCache) Store ¶ added in v0.9.0
func (c *InventoryCache) Store(key string, inventory Inventory)
type LinkAction ¶ added in v0.11.0
type LinkAction string
LinkAction is what to do after an attempt.
const ( // LinkHold keeps the link that is up. LinkHold LinkAction = "hold" // LinkRetry dials again after LinkDecision.Wait. LinkRetry LinkAction = "retry" // LinkGiveUp stops; LinkDecision.Reason says why. LinkGiveUp LinkAction = "give_up" )
The actions a LinkSupervisor decides.
type LinkDecision ¶ added in v0.11.0
type LinkDecision struct {
Action LinkAction
// Wait is how long to wait before dialling again, for LinkRetry.
Wait time.Duration
// Reason is the outcome that ended the link, for LinkGiveUp:
// LinkRefused, LinkKeyChanged or LinkClientKeyRejected.
Reason LinkOutcome
}
LinkDecision is a LinkSupervisor's answer to one outcome.
type LinkOutcome ¶ added in v0.11.0
type LinkOutcome string
LinkOutcome is what one attempt to hold a link came to.
const ( // LinkUp: the link is up. LinkUp LinkOutcome = "up" // LinkDropped: an established link went down. LinkDropped LinkOutcome = "dropped" // LinkFailed: the hub or the network could not be reached. LinkFailed LinkOutcome = "failed" // LinkRefused: the hub turned the credentials away (ErrHubRefused). LinkRefused LinkOutcome = "refused" // LinkKeyChanged: the hub's key is not the pinned one (ErrHubKeyChanged). LinkKeyChanged LinkOutcome = "key_changed" // LinkClientKeyRejected: the hub refused this client's own key, having // pinned another one for the connection (ErrClientKeyRejected). LinkClientKeyRejected LinkOutcome = "client_key_rejected" )
The outcomes a LinkSupervisor decides on.
type LinkSupervisor ¶ added in v0.11.0
type LinkSupervisor struct {
// contains filtered or unexported fields
}
LinkSupervisor decides how a long-lived link is kept up, as a pure function of what happened and when; HubSession's Run asks it after every attempt, and every SDK follows the same rules (link-keeping-vectors.json):
- LinkUp: hold, and start the ladder and the refusal clock afresh;
- LinkDropped: dial again at once;
- LinkFailed: wait the ladder's step -- the policy's Retry, doubling to RetryCeiling -- and stop counting refusals;
- LinkRefused: wait the ladder's step the same way, until the refusals have lasted the refusal grace since the first of them (inclusive), then give up;
- LinkKeyChanged: give up at once, since retrying cannot change it;
- LinkClientKeyRejected: give up at once too: no handshake can make the hub accept a key it did not pin.
A LinkSupervisor is not safe for concurrent use.
func NewLinkSupervisor ¶ added in v0.11.0
func NewLinkSupervisor(policy HubSessionPolicy, refusalGrace time.Duration) *LinkSupervisor
NewLinkSupervisor is a supervisor for policy that gives refusals refusalGrace (DefaultHubRefusalGrace when nonpositive).
func (*LinkSupervisor) After ¶ added in v0.11.0
func (l *LinkSupervisor) After(outcome LinkOutcome, now time.Time) LinkDecision
After is the decision after outcome, observed at now; only the differences between the times it is given matter.
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 ListingData ¶ added in v0.8.0
type ListingData struct {
SentenceEnds string `json:"sentence_ends"`
Languages map[string]ListingLanguage `json:"languages"`
}
ListingData is a complete language data tree, rather than an overlay.
type ListingLanguage ¶ added in v0.8.0
type ListingLanguage struct {
TrailingWords []string `json:"trailing_words,omitempty"`
QuestionOpeners []string `json:"question_openers,omitempty"`
QuestionWordsAnywhere []string `json:"question_words_anywhere,omitempty"`
QuestionPatterns []string `json:"question_patterns,omitempty"`
WrittenForms map[string]string `json:"written_forms,omitempty"`
SlotExamples map[string]string `json:"slot_examples,omitempty"`
}
ListingLanguage contains optional canonical thalovant-languages listing rules.
type ListingRules ¶ added in v0.8.0
type ListingRules struct {
// contains filtered or unexported fields
}
ListingRules snapshots language rules; its methods may be used concurrently. Construct with nil for bare rendering without language data.
func DefaultListing ¶ added in v0.8.0
func DefaultListing() *ListingRules
DefaultListing returns the immutable bundled language rules.
func NewListingRules ¶ added in v0.8.0
func NewListingRules(data *ListingData) (*ListingRules, error)
NewListingRules validates patterns before publishing an immutable snapshot. Invalid patterns return an error. Runtime backtracking is bounded by a 100ms per-pattern deadline and a 65536-entry stack; Asks reports matching failures.
func (*ListingRules) AsSentence ¶ added in v0.8.0
func (r *ListingRules) AsSentence(text, lang string) string
AsSentence capitalizes and punctuates a phrase using known locale rules. Unknown rules, dangling prefixes and regex failures leave a bare line.
func (*ListingRules) Asks ¶ added in v0.8.0
func (r *ListingRules) Asks(text, lang string) (bool, error)
Asks recognizes questions and reports bounded regex failures to the caller.
func (*ListingRules) Available ¶ added in v0.8.0
func (r *ListingRules) Available() bool
Available reports whether this snapshot contains language data.
func (*ListingRules) Dangling ¶ added in v0.8.0
func (r *ListingRules) Dangling(text, lang string) bool
Dangling reports a locale's trailing prefix waiting for an entity.
func (*ListingRules) LanguageData ¶ added in v0.8.0
func (r *ListingRules) LanguageData(lang string) ListingLanguage
LanguageData returns a copy of the closest locale's rules.
type LocationOptions ¶ added in v0.7.0
LocationOptions accepts numeric or string coordinates. A city is required.
type LoginOptions ¶ added in v0.3.2
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.
// Empty uses the directory of the file the identity was read from
// (Identity.SourcePath), else NoiseStateDir().
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) error
Connect opens the broker session and completes the v3 Noise handshake. A KK handshake whose answer does not authenticate is followed at once by one XX handshake inside this connect, since only XX tells a changed password (ErrHubRefused) from a changed hub key (ErrHubKeyChanged); the XX attempt's outcome is the connect's.
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) 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
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 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
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 NativeSignIn ¶ added in v0.9.2
type NativeSignIn struct {
// AuthorizationURL is opened in a browser.
AuthorizationURL string
// State proves the redirect answers this attempt and not a replayed one.
State string
// Verifier is never sent to the browser. Exchanged with the code, once.
Verifier string
// RedirectURI is what this attempt asked the callback to arrive at. One
// that lands anywhere else is not this attempt's, however good its state.
RedirectURI string
}
NativeSignIn is one sign-in attempt in progress. Keep it until the browser comes back; it holds the two secrets that make the round trip safe.
func BeginNativeSignIn ¶ added in v0.9.2
func BeginNativeSignIn(opts NativeSignInOptions) (NativeSignIn, error)
BeginNativeSignIn starts a sign-in, returning the URL to open and the secrets to keep.
func (NativeSignIn) CodeFrom ¶ added in v0.9.2
func (s NativeSignIn) CodeFrom(redirect string) (code string, ok bool)
CodeFrom returns the authorization code out of the redirect the browser came back with. ok is false when it is not an answer to this attempt.
A bool rather than an error on a state mismatch, a missing code, or an error= response -- including one that also carries a code: all of those mean "do not continue", and a caller that handles them alike cannot accidentally treat one of them as success.
type NativeSignInOptions ¶ added in v0.9.2
type NativeSignInOptions struct {
ClientID string
RedirectURI string
Scopes []string
DashboardURL string
}
NativeSignInOptions carries the inputs for BeginNativeSignIn. RedirectURI must be one the API has registered for ClientID; the authorization endpoint matches it exactly and refuses anything else, so it cannot be turned into an open redirect.
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 OriginAttempt ¶ added in v0.9.0
OriginAttempt leaves the URL host, certificate validation and SNI unchanged. The factory owns a transport-local dial override and cleans up failed attempts.
type OriginPreference ¶ added in v0.9.0
type OriginPreference struct {
Address string
HandshakeTimeout, Cooldown time.Duration
// contains filtered or unexported fields
}
func (*OriginPreference) Connect ¶ added in v0.9.0
func (o *OriginPreference) Connect(ctx context.Context, build func(context.Context, OriginAttempt) (HubSessionClient, error), options OriginAttempt) (HubSessionClient, error)
func (*OriginPreference) CoolingDown ¶ added in v0.9.0
func (o *OriginPreference) CoolingDown() bool
type PolicyDeniedError ¶ added in v0.3.13
type PolicyDeniedError struct {
// DeniedType is the message type the hub refused, such as
// "recognizer_loop:utterance".
DeniedType string
// Code is the hub's refusal code: PolicyCodeACL,
// PolicyCodeQuotaExceeded or PolicyCodeBackendUnavailable.
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
// Quota carries the numbers behind a spent allowance; nil for any other
// refusal.
Quota *Quota
}
PolicyDeniedError reports that the hub refused a message, the instant it did. The hub sends hive.policy.denied as soon as it refuses; returning this saves the caller a timeout and says which kind of refusal it was.
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) && denied.Quota != nil {
fmt.Println(denied.Quota.Used, "of", denied.Quota.Limit)
}
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 Quota ¶ added in v0.10.1
type Quota struct {
Period string
Limit int64
Used int64
// ResetAfter is seconds until the counter resets, or 0 when the hub did
// not say.
ResetAfter int64
}
Quota is the numbers behind a refusal that is a spent allowance, not a policy. The intent-quota policy sends which counter ran out ("daily", "monthly"), what it allows, how much was used, and how many seconds until it resets. Without them a caller can only say "refused", which is what an app showed somebody who had simply used up the day.
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.
Unless the caller is a platform administrator, each image must be one the platform releases for its key: a catalog pin of the stable or alpha channel, the resource's current, recommended or release-policy image, or the platform's default image. A runtime group's "core" and a hub's "listener" also accept any tag or digest of the platform's own repository (ghcr.io/thalovant/ovos-core, ghcr.io/thalovant/hivemind-listener); "bus" and "preview_bridge" take only the listed images. The API refuses anything else with HTTP 403 "platform_image_required": an *APIError whose Code says so, whose ProblemDetail names what each refused key may be instead, and whose Problem carries refused_images, allowed_images and allowed_repositories.
type Replier ¶ added in v0.11.0
type Replier interface {
Reply(ctx context.Context, event Event, msgType string, data Data, eventContext Context) error
}
Replier sends a reply to an event, back along the route it came. Client and HubSession are Repliers.
type Reply ¶
type Reply struct {
DroppedMedia int
Text string
Utterances []string
Handled bool
OK bool
SessionID string
RequestID string
Events []Event
FailureEvent *Event
}
func (Reply) Claimed ¶ added in v0.9.1
Claimed is advisory: an OK reply from any non-fallback stage is claimed. An older hub without stage stamps retains its existing OK behavior.
func (Reply) DisplayItems ¶
func (r Reply) DisplayItems(maxTextChars int) []DisplayItem
func (Reply) DisplayText ¶
func (Reply) MediaEvents ¶ added in v0.7.0
func (Reply) PipelineIDs ¶ added in v0.9.1
PipelineIDs reports nonempty string stage stamps in first-seen order.
type RequestContextOptions ¶ added in v0.7.0
RequestContextOptions carries per-request hints read by OVOS.
type RequestOptions ¶
type RuntimeGroupConfigOptions ¶ added in v0.3.6
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 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 Skill ¶ added in v0.9.0
type Skill struct {
ID string `json:"id"`
Title string `json:"title"`
Locales []string `json:"locales"`
Intents []Intent `json:"intents"`
}
func (Skill) DeclaresLocales ¶ added in v0.9.0
func (Skill) MarshalJSON ¶ added in v0.9.0
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 ThalovantBinary ¶ added in v0.10.0
type ThalovantBinary struct {
// Kind is tts_audio, file, ... or binary:<wire number> for an unnamed type.
Kind string
// Data is the payload itself. Never parsed, never decompressed.
Data []byte
// Metadata is what the hub sent beside it.
Metadata map[string]any
// Utterance is what was said, when this is rendered speech.
Utterance string
// Lang is the language it was said in.
Lang string
// FileName is the name a file arrived under. An empty name is no name.
FileName string
}
ThalovantBinary is a binary frame: the bytes a hub sent, and what it said about them.
func BinaryFrame ¶ added in v0.10.0
func BinaryFrame(kind string, data []byte, metadata map[string]any) *ThalovantBinary
BinaryFrame reads a hub's metadata into the shape above. A value the hub did not send and one it sent empty both read as empty: rendering "" as a filename would put a blank name in front of somebody as though the hub had chosen it.
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 UnansweredError ¶ added in v0.10.1
type UnansweredError struct {
// Said is the hub's own words, when it sent any.
Said string
}
UnansweredError reports that the hub understood a question and has nothing for it. ovos.intent.unmatched (complete_intent_failure from older hubs) is neither a refusal nor a fault; as a bare runtime error a caller could only report that something failed. It wraps ErrRuntime.
func (*UnansweredError) Error ¶ added in v0.10.1
func (e *UnansweredError) Error() string
func (*UnansweredError) Unwrap ¶ added in v0.10.1
func (e *UnansweredError) Unwrap() error
Unwrap makes an UnansweredError match ErrRuntime under errors.Is.
type UnsupportedConnectionTypeError ¶ added in v0.11.0
type UnsupportedConnectionTypeError struct {
// ConnectionType is the kind asked for.
ConnectionType string
// Answered is the kind the API made instead; "" when it named none.
Answered string
// ClientID is the connection the API made instead, when it made one.
ClientID string
// Deleted reports that the connection the API made instead is gone.
Deleted bool
// DeleteErr is why deleting it failed, when it did; remove it in the
// dashboard.
DeleteErr error
// APIError is the API's refusal, when it refused.
APIError *APIError
}
UnsupportedConnectionTypeError reports that the API could not make a connection of the kind asked for. Either it refused the kind (HTTP 422 about spec.connection_type; APIError carries the answer), or it made an ordinary connection instead, which the SDK then deleted (APIError is nil; ClientID and Deleted say what happened to it). It matches ErrUnsupportedConnectionType and ErrAPI.
func (*UnsupportedConnectionTypeError) Error ¶ added in v0.11.0
func (e *UnsupportedConnectionTypeError) Error() string
func (*UnsupportedConnectionTypeError) Unwrap ¶ added in v0.11.0
func (e *UnsupportedConnectionTypeError) Unwrap() []error
Unwrap makes an UnsupportedConnectionTypeError match ErrUnsupportedConnectionType, and ErrAPI through the API's own answer when there is one.
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 of the file the identity was
// read from (Identity.SourcePath), else the directory holding the SDK
// config file (NoiseStateDir()).
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) ClosedRefused ¶ added in v0.11.0
func (t *WSSTransport) ClosedRefused() bool
ClosedRefused reports whether the hub refused this connection's credentials the last time it ended: a handshake message that did not authenticate (a wrong password), or a close with no status, 1000, 1005 or 1008 during the handshake or within DefaultHubSettle after it. A hub that does not know a client's static key says so only by closing then; the same codes later are a hub going away, which is a drop. A new connection attempt clears it.
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) 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]
Source Files
¶
- client.go
- connections.go
- constants.go
- context.go
- context_mutex.go
- control.go
- device_login.go
- errors.go
- events.go
- fallbacks.go
- hive.go
- home.go
- hub_skills.go
- hubs.go
- identity.go
- intents.go
- inventory.go
- language_matching.go
- listen.go
- listing.go
- mqtt_topics.go
- native_auth.go
- noise.go
- noise_folder.go
- noise_store.go
- noise_store_file.go
- protocols.go
- rich.go
- session.go
- subscriptions.go
- transport.go
- transport_mqtt.go
- transport_noise.go
- transport_wss.go
- version.go
- wire.go