Skip to content

feat: land GUI adapter/template rework (session_id-only); fix B1-B9 (supersedes #100) - #112

Draft
JarbasAl wants to merge 7 commits into
devfrom
feat/gui-rework-landing
Draft

feat: land GUI adapter/template rework (session_id-only); fix B1-B9 (supersedes #100)#112
JarbasAl wants to merge 7 commits into
devfrom
feat/gui-rework-landing

Conversation

@JarbasAl

@JarbasAl JarbasAl commented Jun 20, 2026

Copy link
Copy Markdown
Member

GUI rework landing — adapter/template architecture (supersedes #100)

Lands the template/adapter rework on top of current origin/dev as a clean,
reviewable diff, and fixes the release-blocking bugs from the Phase-0 audit
(REVIEW_2026-06-20.md, B1–B9). Routing is session_id onlysite_id is
dropped entirely; a shared/multi-room screen is expressed by clients sharing a
session_id.

ovos-gui becomes a pure state/dispatch hub: it runs no WebSocket server and
renders nothing. It loads every installed opm.gui_adapter plugin via
OVOSGUIAdapterFactory.create_all(bus, config) and fans each SYSTEM_* template
event out to all of them. A headless device with zero adapters degrades to no-op
dispatch — it never crashes.

Bugs fixed

  • B1service.py now calls the real OVOSGUIAdapterFactory.create_all (no
    hasattr fallback); zero adapters logs + continues instead of raising
    RuntimeError.
  • B2pyproject.toml has no file:// pins; declares
    ovos-plugin-manager>=2.1.0,<3.0.0, ovos-bus-client>=1.0.0,<3.0.0 (allows
    2.x), an optional gui extra for ovos-legacy-mycroft-gui-plugin, and a
    test extra. The package builds an sdist/wheel cleanly.
  • B3 — removed the dead duplicate first copies of _safe_call /
    forward_to_gui / handle_clear_namespace / _parse_persistence in
    namespace.py.
  • B4 — removed the dead GuiPage model and the page-delete handlers that
    referenced the non-existent namespace.pages / remove_pages; gui.page.delete*
    no longer raises AttributeError.
  • B5GUI_DESIGN.md + new docs/adapter-development/CONTRACT.md &
    architecture.md match the session_id-only hook signatures; stale
    routing-key/site_id text removed.
  • B6/B7/B8 — dropped site_id and the 3-case routing logic; the routing key
    is the session_id. Emit context (gui.namespace.removed/displayed) carries
    session_id only.
  • B9 — removed the silent TypeError-retry in _safe_call; signature errors
    are logged/surfaced.

Tests

116 passing locally. test/end2end uses a concrete RecordingGUIPlugin
(subclass of AbstractGUIPlugin) instead of Mock() so handler/hook arity is
enforced. Coverage: real factory loading (B1), default + UUID session_id,
two clients sharing one session_id getting the same dispatch, multi-adapter
fan-out + failure isolation, and the removed page-delete path.

CI / unreleased deps

The reusable build-tests/coverage workflows install the unreleased loader and
adapter from git until they publish to PyPI:

git+https://github.com/OpenVoiceOS/ovos-plugin-manager@gui
git+https://github.com/OpenVoiceOS/ovos-legacy-mycroft-gui-plugin@dev

These pins revert to PyPI versions once the deps release.

Dependency: CI installs ovos-plugin-manager from the @gui branch
(#377), which carries OVOSGUIAdapterFactory + the session_id-only
AbstractGUIPlugin. Reverts to the released version once that lands and OPM
publishes.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5a02d05c-b303-41ca-888f-eac7fc89a48e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/gui-rework-landing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown

Back again! I've just finished another round of automated checks. 🔄

I've aggregated the results of the automated checks for this PR below.

🔨 Build Tests

Ensuring the code is correctly packaged and ready. 📦

✅ All versions pass

Python Build Install Tests
3.10
3.11
3.12
3.13
3.14

The bits and bytes are looking good today. 💾

JarbasAl and others added 6 commits July 4, 2026 01:29
Replace the uninstallable file:// pins with version specs:
- ovos-plugin-manager>=2.1.0,<3.0.0 (carries OVOSGUIAdapterFactory)
- ovos-bus-client>=1.0.0,<3.0.0 (allows 2.x), reconciled as the single source
- optional 'gui' extra for ovos-legacy-mycroft-gui-plugin (display backend)
- 'test' extra for the test deps

Drop the now-unused tornado dependency (the WS server moved to the legacy
adapter) and the stale res/**/* package-data (QML resources removed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ovos-gui becomes a pure state/dispatch hub: it runs no WebSocket server and
renders nothing itself. GUIService.\_load_adapter_plugins calls the published
OVOSGUIAdapterFactory.create_all(bus, config) directly (no hasattr fallback).
A headless device with zero adapters installed logs and continues with no-op
dispatch instead of raising RuntimeError.

Remove the in-process Tornado WS server (bus.py), the GUIExtension/homescreen
machinery (extensions.py, homescreen.py, constants.py) and the bundled QML
resources — these now live in the adapter plugins. Add message_types.py
documenting the GUI bus protocol.

BREAKING CHANGE: ovos-gui no longer starts a WebSocket server or loads QML;
install an opm.gui_adapter plugin to render.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collapse routing to a single key: session_id (shared screens share a
session_id). Drop site_id from every adapter call and internal helper and
remove the 3-case routing-key logic; \_session_id(message) reads
context['session']['session_id'] (default 'default').

- B3: drop the dead duplicate first copies of \_safe_call/forward_to_gui/
  handle_clear_namespace/\_parse_persistence; keep the live block.
- B7/B8: emit gui.namespace.removed/displayed context with session_id only.
- B9: remove the silent TypeError-retry-with-fewer-args in \_safe_call; log
  and surface signature errors.

Adapters are now called as dispatch_template(template, skill_id, data,
session_id), on_namespace_activated/deactivated(skill_id, session_id),
on_session_update(skill_id, data, session_id), on_status_event(event, data,
session_id) — matching the AbstractGUIPlugin contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…B4/B5)

- B5: rewrite GUI_DESIGN.md routing/hook sections and add canonical
  docs/adapter-development/CONTRACT.md + architecture.md to the session_id-only
  hook signatures (name, session_id) / (msg_type, data, session_id). Drop the
  3-case routing-key/site_id text and the stale OVOSGuiFactory.create signature.
- B4: remove the dead GuiPage model (ovos_gui/page.py); the page-delete handlers
  that referenced the non-existent namespace.pages/remove_pages are gone, so
  gui.page.delete* no longer raises AttributeError. The template-only Namespace
  has no per-page model.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the Mock() adapters in test/end2end with a concrete RecordingGUIPlugin
subclassing AbstractGUIPlugin (enforces handler/hook arity). Cover: real
factory loading on a headless device (B1), default + UUID session_id routing,
two clients sharing one session_id getting the same dispatch, multi-adapter
fan-out with per-adapter failure isolation, and that the removed page-delete
path no longer crashes (B4).

Update unit tests to the session_id-only API: drop GuiPage/site_id, assert the
real adapter call signatures, add a B1 headless-no-raise regression for the
service, and derive the expected version from the constants instead of a
hard-coded string.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drive a real GUIInterface (show_weather/show_text) through NamespaceManager to
a spec-conformant adapter, proving the skill-side wire format matches what
ovos-gui parses and dispatches (incl. multi-adapter fanout). Adds the api-client
as a test dep (git-installed in CI until released).
@JarbasAl
JarbasAl force-pushed the feat/gui-rework-landing branch from b896fd0 to 299ce38 Compare July 4, 2026 00:35
The opm.gui_adapter loader (OVOSGUIAdapterFactory) is not yet on PyPI; it
lives on the ovos-plugin-manager gui branch. Install it from git before the
editable install, mirroring the pre_install_pip used by build_tests, so the
resolver keeps the branch instead of substituting the PyPI release.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant