Bus Service
A Message Bus is mechanism for independent systems to communicate with each other using a set of messages for common commands or notifiers.
In the OVOS ecosystem, the Messagebus is a websocket and the messages contain a message type with an optional JSON data packet.
Some messages trigger actions and have side effects; some are simple notifiers of actions that either have occurred or are about to occur.
The Messagebus connects the ovos-core
processes and the Skills, and can also be joined by outside systems such as HiveMind.
Messages can be sent from the producers and acted upon by Skills or other consumers within OVOS.
You can think of the bus service as OVOS's nervous system
The messagebus is considered an internal and private websocket, external clients should not connect directly to it.
Configuration
The messagebus has a dedicated section in mycroft.conf
"websocket": {
"host": "127.0.0.1",
"port": 8181,
"route": "/core",
"shared_connection": true
}
Security
in mycroft-core all skills share a bus connection, this allows malicious skills to manipulate it and affect other skills
you can see a demonstration of this problem with BusBrickerSkill
"shared_connection": false
ensures each skill gets its own websocket connection and avoids this problem
It is recommended you DO NOT change "host": "127.0.0.1"
, this will ensure no outside world connections are allowed
Exposing the bus
Please do not expose the messagebus to the outside world!
Anything connected to the bus can fully control OVOS, and OVOS usually has full control over the whole system!
You can read more about the security issues over at Nhoya/MycroftAI-RCE
If you need to connect to the bus from the outside world please check the companion project HiveMind
Lots of guides for mycroft tell you to expose the websocket, please (re)read the info and links above, think 10 times before following steps blindly
Messages
A Message
consists of a json payload, it contains a type
, some data
and a context
.
The context
is considered to be metadata and might be changed at any time in transit, the context
can contain anything depending on where the message came from, and often is completely empty.
You can think of the message context
as a sort of session data for a individual interaction, in general messages down the chain keep the context
from the original message, most listeners (eg, skills) will only care about type
and data
.
An index of all bus messages emitted or listened too by all the OVOS repositories can be found at https://openvoiceos.github.io/message_spec
Session
NEW in ovos-core
version 0.0.8
The message.context
may contain anything, but a special key is the "session"
A Session contains per-request preferences and state data, external clients such as voice satellites have their own session
the Session can be used to select user preferences or resume previous conversations by restoring skill state
ovos-core
always uses the reserved "session_id": "default"
, and will fully manage the state of the default Session, individual clients are supposed to manage their own session and might ignore updates coming from ovos-core
Things included in a Session:
- list of active skills (able to converse)
- list of intent contexts (follow up questions)
- utterance state (get_response vs regular utterance)
- language
- location
- tts / stt preferences (eg, voice)
- intent pipeline to be used
- site_id
By default these values are populated from mycroft.conf
, skills have some "magic variables" that also reflect the session, such as self.lang
and self.location
.
NOTE Voice satellites will send a subset of their own
mycroft.conf
via their Session
Transformers may modify the Session, for example to inject intent context
It is up to individual skills to manage session, see the Session Aware Skills docs for details
WARNING skills that are not session aware may keep a shared state may behave weirdly with voice satellites
Message Targeting
ovos-core uses the message context
to add metadata about the messages themselves, where do they come from and what are they intended for.
the Message
object provides the following methods:
message.forward
method, keeps previous context.- message continues going to same
destination
- message continues going to same
message.reply
method swaps"source"
with"destination"
- message goes back to
source
- message goes back to
The context destination
parameter in the original message can be set to a list with any number of intended targets:
bus.emit(Message('recognizer_loop:utterance', data,
context={'destination': ['audio', 'kde'],
'source': "remote_service"))
Internal routing
- intent service will
.reply
to the original utterance message - all skill/intent service messages are
.forward
(from previous intent service.reply
) - WARNING skills sending their own messages might not respect this
NOTE: HiveMind depends on the
"source"
and"destination"
keys to route responses back to their respective satellites
Sources
OVOS injects the context when it emits an utterance, usually when spoken via STT service
STT will identify itself as audio
mycroft.conf
contains a native_sources
section you can configure to change how the audio service processes external requests
"Audio": {
"native_sources": ["debug_cli", "audio"]
}
Destinations
TTS checks the message context if it's the intended target for the message and will only speak in the following conditions:
- Explicitly targeted i.e. the
destination
is"audio"
destination
is set toNone
destination
is missing completely
The idea is that for example when the android app is used to access OpenVoiceOS the device at home shouldn't start to speak.
TTS will be executed when "audio"
is the destination
(configurable in "native_sources"
)
A missing destination
or if the destination
is set to None
is interpreted as a multicast and should trigger all output capable processes (be it the audio service, a web-interface, the KDE plasmoid or maybe the android app)