This release is a pre-release and may not be stable for production use.
ubo-app assistant
A standalone subprocess that runs the device's Pipecat conversational
pipeline. It is the only place in ubo-app where STT, LLM, TTS and image
generation providers are instantiated: the core 090-assistant service owns the
state (which providers are selected, which models are downloaded, which keys
exist), and this process turns that state into a running pipeline.
It talks to ubo-app exclusively over the gRPC store API (ubo_bindings) on
localhost:50051 — it never imports ubo_app.
Why it is a separate process
- Dependency weight and isolation.
pipecat-aiwith its provider extras, plusvosk,piper-tts, Kokoro and Moonshine, is a large and version-touchy dependency tree. It lives in its own virtualenv so it cannot constrain the core's. - A wider Python range. The core pins
>=3.11,<3.12; this package builds against>=3.11,<3.14. - Crash isolation. A provider blowing up takes down a restartable subprocess, not the store.
Because it cannot import the core store package, a few values are mirrored as
bare strings in constants.py — LIVE_PIPELINE_SOURCE_ID ('pipecat') and
REQUEST_PIPELINE_SOURCE_ID ('assistant_request') must stay in sync with
ubo_app.store.services.assistant. A mismatch silently breaks chat routing
rather than raising.
The two pipelines
┌─────────────── ubo-app core (gRPC :50051) ────────────────┐
│ state.assistant (selected providers, models, prompts) │
└────────▲─────────────────────────────────────┬───────────┘
│ AssistantReportAction │ autorun / events
│ (source_id tags the producer) │
┌────────┴─────────────────────────────────────▼───────────┐
│ assistant subprocess (this package) │
│ │
│ LIVE 'pipecat' │ REQUEST 'assistant_request'│
│ ────────────────────── │ ────────────────────────── │
│ one long-lived pipeline │ one short-lived pipeline │
│ UboInputTransport │ per AssistantRunPipelineEvent│
│ → STT → LLM → TTS │ a contiguous STT/LLM/TTS │
│ → UboOutputTransport │ sub-chain, output collected │
│ barge-in, end-of-turn, │ by GRPCTerminalCollector │
│ stop-talking, VAD │ │
└───────────────────────────────────────────────────────────┘
Live (main.py) is the conversation the user hears: a ParallelPipeline
driven by a WorkerRunner, with audio arriving through UboInputTransport and
leaving through UboOutputTransport, wrapped in the turn-taking processors
described below.
Request (request_handler.py) serves external clients. It subscribes once
to AssistantRunPipelineEvent and builds an isolated, short-lived pipeline per
event via pipeline_builder.build_request_pipeline, reporting frames back
through grpc_collector. Tool-calling is deliberately not wired here yet — the
context aggregator is placed around the LLM so the structure is ready, but the
live draw_image/get_image tools need the live transports.
The client-facing contract for both — actions, events, result frames, enums — is documented in the service README, not here.
Module map
| Area | Modules |
|---|---|
| Entry point | main.py (ubo-assistant script) |
| Provider adapters | ubo_stt.py, ubo_llm.py, ubo_tts.py, ubo_image_generator.py, switch.py |
| Local engines | vosk.py, piper.py, kokoro.py, moonshine.py, moonshine_cache.py, segmented_googlestt.py |
| Provider one-offs | venice_stt.py, venice_tts.py |
| Transports | ubo_input_transport.py, ubo_output_transport.py, grpc_collector.py, file_source.py |
| Turn-taking | barge_in.py, end_of_turn.py, stop_talking.py, stop_listening_on_bot_speech.py, silence_user_turn_stop.py |
| Requests | request_handler.py, request_providers.py, pipeline_builder.py |
| Watchers | system_prompt_watcher.py, policy_watcher.py |
| Support | constants.py, logging.py, error_notification.py, image_frame.py, tools.py, tts_voice.py, pipecat_debug.py |
Audio chunking (the one non-obvious constraint)
MAX_AUDIO_CHUNK_BYTES (8 KB) caps every emitted AudioSample. Pipecat hands
out ~0.5 s frames — roughly 48 KB at 48 kHz/16-bit — which overflow the heap of
memory-constrained clients; the ESP32 LVGL client has about 50 KB free, so
nanopb's decode realloc fails and TTS goes silent.
It is enforced shared, not per-transport, because every path that emits TTS
audio has to honour it. It previously lived in ubo_output_transport alone, so
the grpc_collector path — screen reader and one-shot requests — shipped whole
frames and satellites lost most of the utterance.
Configuration
Provider credentials, model selections and defaults are injected as environment
variables by the service's ubo_handle.py::binary_env_provider, which resolves
them from the core's secrets store. This process reads os.environ; it never
reads the secrets file itself.
| Variable | Meaning | Default |
|---|---|---|
UBO_ASSISTANT_LOG_LEVEL |
log level | INFO (invalid values warn and fall back) |
UBO_ASSISTANT_LOG_PATH |
log file path | ubo-assistant.log |
UBO_DATA_PATH |
model/data directory | platform user-data dir |
Boundaries
- Source of truth is the store. Selections, downloads and credentials live
in
state.assistant; this process projects them into a pipeline. - No
ubo_appimports. Onlyubo_bindings. See theubo_bindingsimport rule in.claude/rules/coding-style.md. - MCP is not managed here. Tools come from the separate MCP gateway; this process is one of its clients.
Tests
tests/ runs under the sub-project's own venv:
poe --directory=ubo_app/services/090-assistant/ubo-service test # fast, no network
It covers turn-taking
(test_barge_in, test_end_of_turn, test_stop_talking,
test_silence_user_turn_stop, test_stop_listening_on_bot_speech), engines
(test_vosk, test_piper_tts, test_moonshine, test_lazy_local_tts),
request orchestration (test_request_orchestration, test_provider_*_roundtrip)
and support behaviour (test_logging, test_error_notification,
test_system_prompt_watcher, test_policy_watcher).
tests/provider_harness.py backs the providers-marked tests — real TTS/STT/LLM
round-trips against whatever the secrets file configures. They are excluded from
test because they cost network and money; run them with
poe … test:providers, which CI does on the Pi pods.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ubo_app_assistant-2.0.1.dev260819103102489955.tar.gz.
File metadata
- Download URL: ubo_app_assistant-2.0.1.dev260819103102489955.tar.gz
- Upload date:
- Size: 93.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62a8cec7e546f1a3b948687d932e07dcbfda64853c1be48904de67b953798e10
|
|
| MD5 |
ccf627a0dd8ca7038ff7209237ca00ab
|
|
| BLAKE2b-256 |
9f72602da7f90828e3ab9518905a8f5f5c8ac467fc7e6d82f596ae46368fb17e
|
Provenance
The following attestation bundles were made for ubo_app_assistant-2.0.1.dev260819103102489955.tar.gz:
Publisher:
integration_delivery.yml on ubopod/ubo_app
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ubo_app_assistant-2.0.1.dev260819103102489955.tar.gz -
Subject digest:
62a8cec7e546f1a3b948687d932e07dcbfda64853c1be48904de67b953798e10 - Sigstore transparency entry: 2523816657
- Sigstore integration time:
-
Permalink:
ubopod/ubo_app@f0c7c85b31c012524bfe66f6b01cc09ffed7e1de -
Branch / Tag:
refs/heads/development - Owner: https://github.com/ubopod
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
integration_delivery.yml@f0c7c85b31c012524bfe66f6b01cc09ffed7e1de -
Trigger Event:
push
-
Statement type:
File details
Details for the file ubo_app_assistant-2.0.1.dev260819103102489955-py3-none-any.whl.
File metadata
- Download URL: ubo_app_assistant-2.0.1.dev260819103102489955-py3-none-any.whl
- Upload date:
- Size: 114.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5edb177f0d409a631381e508c64eab6844921312882bc3c2d4757886953fa192
|
|
| MD5 |
c8f97df00585d4c492fd4ebce1c4fb0e
|
|
| BLAKE2b-256 |
ecf5c7b65822a6967cd5ceadd89fd1d2eeaa046092dc6db5dc48545936f9a3b8
|
Provenance
The following attestation bundles were made for ubo_app_assistant-2.0.1.dev260819103102489955-py3-none-any.whl:
Publisher:
integration_delivery.yml on ubopod/ubo_app
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ubo_app_assistant-2.0.1.dev260819103102489955-py3-none-any.whl -
Subject digest:
5edb177f0d409a631381e508c64eab6844921312882bc3c2d4757886953fa192 - Sigstore transparency entry: 2523818805
- Sigstore integration time:
-
Permalink:
ubopod/ubo_app@f0c7c85b31c012524bfe66f6b01cc09ffed7e1de -
Branch / Tag:
refs/heads/development - Owner: https://github.com/ubopod
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
integration_delivery.yml@f0c7c85b31c012524bfe66f6b01cc09ffed7e1de -
Trigger Event:
push
-
Statement type: