Skip to content

feat: emit ovos.skill.loaded with derived capabilities - #623

Merged
JarbasAl merged 1 commit into
devfrom
feat/ovos-skill-loaded
Sep 9, 2026
Merged

feat: emit ovos.skill.loaded with derived capabilities#623
JarbasAl merged 1 commit into
devfrom
feat/ovos-skill-loaded

Conversation

@JarbasAl

@JarbasAl JarbasAl commented Sep 9, 2026

Copy link
Copy Markdown
Member

🤖 Auto-generated by Claude Sonnet 5 via Claude Code — NOT human-reviewed. Verify before acting.

This adds the ovos.skill.loaded announcement from OVOS-INTENT-4 §8.6 to ovos_workshop/skill_launcher.py and ovos_workshop/skills/ovos.py, without touching the legacy mycroft.skills.loaded payload. The reader's decision is whether the capability-derivation rules below match intent, since they had to be adapted from the brief that requested this PR.

ovos.skill.loaded: { "skill_id": "...", "capabilities": ["converse", "fallback"] }, session-keyed by context.session.session_id... Capability vocabulary: fallback, common_query, converse; unknown names ignored.

The load-status handler now emits ovos.skill.loaded through the loaded instance's own bus, right beside the untouched legacy emission, so context.skill_id rides along and the bus client's own emit() fills in context.session. OVOSSkill.on_ready_status re-emits the same announcement, so a skill process that survives a core restart re-announces its capabilities without a full reload.

Capabilities are read off the class, never guessed, in a new ovos_workshop/skills/capabilities.py::get_skill_capabilities() helper: fallback from isinstance(instance, FallbackSkill); common_query from the _cq_handler a @common_query-decorated method sets on the instance at bind time (there is no common-query base class in this repo to isinstance against — the mechanism here is a decorator, not inheritance); converse from whether the instance defines a converse method at all (OVOSSkill itself has none, so its presence already means a mixin like ConversationalSkill or an ad hoc override supplied one — there is no OVOSSkill.converse to compare identity against, since the base class never defines it).

Verified against origin/dev of this repo: the mycroft.skills.loaded emission site (skill_launcher.py, _communicate_load_status), the absence of OVOSSkill.converse and of any common-query base class (both confirmed by grep across ovos_workshop/), and that MessageBusClient.emit auto-populates context["session"] when absent (checked in the installed ovos_bus_client package). Not independently verified: any downstream consumer's exact expectations, since this PR only emits the message and does not add a listener.

9 tests in test/unittests/test_ovos_skill_loaded.py assert the capability values, not just that a message fired: a plain skill gets [], a FallbackSkill gets ["fallback"], a common-query skill gets ["common_query"], a converse-overriding skill gets ["converse"], the legacy payload is unchanged, and on_ready_status re-announces. Confirmed red before the fix (collection fails with ModuleNotFoundError for the missing capabilities helper) and green after (9 passed). Full suite: 727 passed, no regressions.

Summary by CodeRabbit

  • New Features

    • Skill loading now announces each skill’s ID and supported capabilities.
    • Capability information includes fallback, common-query, and conversational support where applicable.
    • Skill readiness announcements preserve capability information after a core restart.
  • Bug Fixes

    • Improved recovery of skill capabilities when rebuilding manifests without fully reloading skills.

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 1ab23f4b-b5d1-4971-a450-91e7d5ba6ec0

📥 Commits

Reviewing files that changed from the base of the PR and between 102c711 and dc3fcff.

📒 Files selected for processing (4)
  • ovos_workshop/skill_launcher.py
  • ovos_workshop/skills/capabilities.py
  • ovos_workshop/skills/ovos.py
  • test/unittests/test_ovos_skill_loaded.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change derives capabilities from skill instances and emits them in ovos.skill.loaded messages during skill loading and readiness callbacks. Tests cover capability detection, message payloads, context, and preservation of the legacy announcement.

Changes

Skill capability announcements

Layer / File(s) Summary
Capability derivation
ovos_workshop/skills/capabilities.py, test/unittests/test_ovos_skill_loaded.py
Adds get_skill_capabilities for fallback, common_query, and converse. Tests cover supported skill types and exclude ConversationalGameSkill from converse.
Load and readiness announcements
ovos_workshop/skill_launcher.py, ovos_workshop/skills/ovos.py, test/unittests/test_ovos_skill_loaded.py
Emits ovos.skill.loaded with the skill ID and capabilities during loading and readiness. Tests verify message context and preserve the legacy mycroft.skills.loaded payload.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to dc3fc

Skills now announce their declared capabilities when loaded and after readiness recovery, while retaining the existing load event unchanged. The covered behavior has no identified merge-blocking risk.

Sequence Diagram(s)

sequenceDiagram
  participant PluginSkillLoader
  participant LoaderBus
  participant SkillInstanceBus
  PluginSkillLoader->>LoaderBus: emit mycroft.skills.loaded
  PluginSkillLoader->>SkillInstanceBus: emit ovos.skill.loaded with skill_id and capabilities
  PluginSkillLoader->>SkillInstanceBus: on_ready_status emits ovos.skill.loaded with capabilities
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.74% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 23 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: emitting ovos.skill.loaded messages with derived capabilities.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ovos-skill-loaded

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 Sep 9, 2026

Copy link
Copy Markdown
Contributor

Your PR has been successfully processed by the OVOS bot. 📥

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

🔍 Lint

The automated results are now available for your perusal. 📂

ruff: issues found — see job log

⚖️ License Check

Scanning for any non-commercial-only restrictions. 💰

✅ No license violations found.

Policy: Apache 2.0 (universal donor). StrongCopyleft / NetworkCopyleft / WeakCopyleft / Other / Error categories fail. MPL allowed.

🔒 Security (pip-audit)

Scanning for any potential denial-of-service vectors. 🚫

✅ No known vulnerabilities found (72 packages scanned).

📡 Channel Compat — stable

Checking if we've met all our check criteria. ✅

🚧 Channel unresolvable with this checkout — the repo's dependency floors exceed what the channel pins (fleet finding; see the install log).

Constraints: https://raw.githubusercontent.com/OpenVoiceOS/OpenVoiceOS/main/constraints-stable.txt
Resolved stack: channel-compat-stable artifact (constraints + pip freeze).

📋 Repo Health

Scanning for any signs of 'merge conflict' stress. 😫

✅ All required files present.

Latest Version: 9.7.4a1

ovos_workshop/version.py — Version file
README.md — README
LICENSE — License file
pyproject.toml — pyproject.toml
⚠️ setup.py — setup.py
CHANGELOG.md — Changelog
ovos_workshop/version.py has valid version block markers

📡 Channel Compat — testing

The results are fresh out of the pipeline. 🏗️

🚧 Channel unresolvable with this checkout — the repo's dependency floors exceed what the channel pins (fleet finding; see the install log).

Constraints: https://raw.githubusercontent.com/OpenVoiceOS/OpenVoiceOS/main/constraints-testing.txt
Resolved stack: channel-compat-testing artifact (constraints + pip freeze).

🔨 Build Tests

I've checked the welds on your new features. 👨‍🏭

✅ All versions pass

Python Build Install Tests
3.10
3.11
3.12
3.13
3.14

Crafting a better voice assistant, one commit at a time 🎙️

OVOS-INTENT-4 §8.6 fixes `ovos.skill.loaded`: `{"skill_id": "...",
"capabilities": ["converse", "fallback"]}`, session-keyed via
context.session.session_id, capability vocabulary limited to
fallback/common_query/converse.

skill_launcher.py's load-status announcement kept the legacy
`mycroft.skills.loaded` payload unchanged and, beside it, now emits
`ovos.skill.loaded` through the loaded instance's own bus so
context.skill_id rides along and the bus auto-fills context.session.
OVOSSkill.on_ready_status re-emits the same announcement, covering
cold-start recovery when a skill process outlives a core restart.

Capabilities are read off the instance, never guessed: fallback via
isinstance(FallbackSkill), common_query via the _cq_handler a
@common_query-decorated method sets at bind time, converse via
isinstance(ConversationalSkill) -- the only base that wires the
CONVERSE-1 §4 surface (ovos.converse.ping, <skill_id>.converse.ping/
.request). A callable-attribute check was rejected: OVOSGameSkill and
ConversationalGameSkill define their own converse() outside
ConversationalSkill's MRO, and that surface never binds for them, so
"has a converse method" would announce a capability the skill cannot
answer on. The helper lives in ovos_workshop/skills/capabilities.py so
tests can assert its return value directly.

10 tests in test/unittests/test_ovos_skill_loaded.py assert the
capability values (not just that a message fired) for a plain skill
([]), a FallbackSkill (["fallback"]), a common-query skill
(["common_query"]), a ConversationalSkill (["converse"]), and a game
skill that defines converse() outside ConversationalSkill's MRO ([],
proving the callable-attribute check was rejected), plus the unchanged
legacy payload and the readiness re-announcement. Full suite 728
passed, no regressions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@JarbasAl
JarbasAl force-pushed the feat/ovos-skill-loaded branch from 4b6ffcb to dc3fcff Compare September 9, 2026 02:10
@openvoiceos-bot

Copy link
Copy Markdown

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@github-actions github-actions Bot added feature and removed feature labels Sep 9, 2026
@JarbasAl
JarbasAl marked this pull request as ready for review September 9, 2026 16:15
@JarbasAl
JarbasAl merged commit 6c01f5c into dev Sep 9, 2026
14 checks passed
@JarbasAl
JarbasAl deleted the feat/ovos-skill-loaded branch September 9, 2026 16:15
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.

2 participants