Repository navigation
Conversation
Walkthrough
Pre-merge checks:
|
Greetings, human! The automated checks are complete. 👾I've aggregated the results of the automated checks for this PR below. 📋 Repo HealthI've checked the repo's social skills (aka issue response time). 🗣️ ✅ All required files present. Latest Version: ✅ ⚖️ License CheckI've verified the license compliance for your changes. ✅ ✅ No license violations found. Policy: Apache 2.0 (universal donor). StrongCopyleft / NetworkCopyleft / WeakCopyleft / Other / Error categories fail. MPL allowed. 🔍 LintEverything looks good so far! ✅ ❌ ruff: issues found in 117 file(s) — see job log 🔒 Security (pip-audit)Scanning for any potential privilege escalations. 🪜
🔨 Build TestsEnsuring the scaffolding is removed and the build is clean. 🧹 ✅ All versions pass
📡 Channel Compat — testingThe data is in, and it's looking interesting! 🧐 🚧 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 📡 Channel Compat — stableAnother day, another successful automated run. 🌅 🚧 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 Keeping the OVOS ecosystem thriving 🌿 |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ovos_workshop/skills/ovos.py (1)
739-763:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDon't mask the original startup failure when
statusis still unset.If
_init_settings()orbind()throws beforeself.statusis assigned, theexceptpath raises a secondAttributeErrorhere and hides the real cause. That's exactly what the current CI failures are showing.💡 Suggested fix
except Exception as e: - self.status.set_error(str(e)) + if hasattr(self, "status"): + self.status.set_error(str(e)) + else: + LOG.exception("Skill startup failed before ProcessStatus initialization") # If an exception occurs, attempt to clean up the skill try: self.default_shutdown()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ovos_workshop/skills/ovos.py` around lines 739 - 763, The except block can raise AttributeError when self.status was never set (e.g., if _init_settings() or bind() failed); update the exception handler to avoid masking the original error by guarding access to self.status and default_shutdown: check hasattr(self, "status") and self.status is not None before calling self.status.set_error(str(e)) or self.status.* methods, and protect default_shutdown call similarly (or call it only if it exists), then re-raise the original exception; reference symbols: self.status, _init_settings, bind, default_shutdown, self.status.set_error.
🧹 Nitpick comments (1)
ovos_workshop/skills/util.py (1)
30-50: ⚡ Quick winCache locale JSON resolution to avoid repeated filesystem I/O.
_load_workshop_jsoncurrently rescans locale dirs and re-reads JSON on each call;join_word_listcan hit this path frequently.💡 Suggested refactor
+from functools import lru_cache import json import os from os.path import dirname, isdir, isfile, join @@ +@lru_cache(maxsize=1) +def _available_locale_dirs() -> Dict[str, str]: + return {lang: str(path) for lang, path in iter_locale_dirs(_LOCALE_ROOT)} + +@lru_cache(maxsize=64) def _load_workshop_json(name: str, lang: str) -> Optional[Dict]: @@ - available = dict(iter_locale_dirs(_LOCALE_ROOT)) # {lang_norm: Path} + available = _available_locale_dirs() # {lang_norm: path} @@ - path = join(str(available[best]), f"{name}.json") + path = join(available[best], f"{name}.json")🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ovos_workshop/skills/util.py` around lines 30 - 50, The function _load_workshop_json repeatedly rescans locale dirs and reloads JSON on every call (used frequently by join_word_list); cache results to avoid filesystem I/O by memoizing the available locale mapping and parsed JSON per (name, lang) pair. Specifically, keep a module-level cache (or use functools.lru_cache) for iter_locale_dirs(_LOCALE_ROOT) output (used in available = dict(iter_locale_dirs(...))) and for loaded JSON results of json.load(path) keyed by (name, best) so subsequent calls return the cached dict instead of re-reading the file; ensure cache is invalidated/refreshable if needed (e.g., provide a clear/reset helper) and preserve current behavior when files are missing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ovos_workshop/app.py`:
- Line 4: The module removed the join import but settings_path still uses join,
causing runtime/lint failures; re-add join to the import list so settings_path
can use it—specifically update the top-level import that currently reads "from
ovos_spec_tools import find_lang_dir, standardize_lang" to also import join so
the function/settings_path and any uses of join resolve correctly.
In `@ovos_workshop/skills/_legacy_resources.py`:
- Around line 59-69: The _legacy_skill_resources method currently snapshots
self.lang into SkillResources and never updates; change it to use
self._resource_lang when constructing SkillResources and add logic to
invalidate/rebuild the cached self._skill_resources_compat whenever
self._resource_lang changes (store the last used lang or compare current
self._resource_lang to the lang on the cached SkillResources), so callers like
resources, dialog_renderer and find_resource get a SkillResources instance
matching the current _resource_lang; update the same pattern in the other
shim(s) referenced (lines 127-147) to ensure cache is refreshed on language
change.
In `@ovos_workshop/skills/ovos.py`:
- Around line 744-748: Startup now calls private implementations
(_load_data_files, _register_skill_json, _register_decorated,
_register_app_launcher, _register_resting_screen) which bypasses subclass
overrides; change calls so public methods (load_data_files,
register_skill_json/register_decorated if present, register_homescreen_app,
register_resting_screen) are invoked first and fall back to their underscored
counterparts if the public method is not overridden. Update _startup,
_register_app_launcher, and any other locations (e.g., around lines 791-793 and
2403-2439) to call the public shim methods like load_data_files and
register_homescreen_app instead of directly calling
_load_data_files/_register_app_launcher, preserving subclass override
compatibility while keeping private implementations as fallbacks.
In `@ovos_workshop/skills/util.py`:
- Around line 49-50: The locale JSON loader opens files using the system default
encoding; change the open call in ovos_workshop/skills/util.py to explicitly use
UTF-8 by passing encoding='utf-8' (e.g., in the with open(path, ...) statement
that wraps json.load), so that parsing localized content works correctly across
environments.
In `@test/end2end/test_regex_skill.py`:
- Around line 72-75: The on_speak handler currently sets speak_event for every
speak message which can unblock the test prematurely; change on_speak (and the
test wiring around seen_speaks/speak_event) to only set speak_event when the
utterance matches the expected output (e.g., compare
msg.data.get("utterance","") against the expected string/regex or check
substring) and still append seen_speaks as needed, so the wait only wakes for
the regex handler's emission.
In `@test/unittests/skills/test_legacy_skill_omnibus.py`:
- Around line 184-185: The tearDownClass currently swallows all exceptions from
cls.skill.default_shutdown() with "except Exception: pass"; change this to catch
Exception as e and handle it instead of silencing—either re-raise after logging
or call a test logger/assertFail to surface the error; specifically update the
tearDownClass method to wrap cls.skill.default_shutdown() in try/except
Exception as e and call something like logging.exception or raise to ensure
failures are reported rather than ignored.
---
Outside diff comments:
In `@ovos_workshop/skills/ovos.py`:
- Around line 739-763: The except block can raise AttributeError when
self.status was never set (e.g., if _init_settings() or bind() failed); update
the exception handler to avoid masking the original error by guarding access to
self.status and default_shutdown: check hasattr(self, "status") and self.status
is not None before calling self.status.set_error(str(e)) or self.status.*
methods, and protect default_shutdown call similarly (or call it only if it
exists), then re-raise the original exception; reference symbols: self.status,
_init_settings, bind, default_shutdown, self.status.set_error.
---
Nitpick comments:
In `@ovos_workshop/skills/util.py`:
- Around line 30-50: The function _load_workshop_json repeatedly rescans locale
dirs and reloads JSON on every call (used frequently by join_word_list); cache
results to avoid filesystem I/O by memoizing the available locale mapping and
parsed JSON per (name, lang) pair. Specifically, keep a module-level cache (or
use functools.lru_cache) for iter_locale_dirs(_LOCALE_ROOT) output (used in
available = dict(iter_locale_dirs(...))) and for loaded JSON results of
json.load(path) keyed by (name, best) so subsequent calls return the cached dict
instead of re-reading the file; ensure cache is invalidated/refreshable if
needed (e.g., provide a clear/reset helper) and preserve current behavior when
files are missing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: cbb8676b-dfdc-4473-8eae-926b41640555
📒 Files selected for processing (32)
.gitignoreovos_workshop/app.pyovos_workshop/decorators/__init__.pyovos_workshop/resource_files.pyovos_workshop/skills/_legacy_resources.pyovos_workshop/skills/auto_translatable.pyovos_workshop/skills/converse.pyovos_workshop/skills/ovos.pyovos_workshop/skills/util.pypyproject.tomltest/end2end/__init__.pytest/end2end/locale/en-US/drink.entitytest/end2end/locale/en-US/greet.dialogtest/end2end/locale/en-US/play.rxtest/end2end/locale/en-US/salutation.voctest/end2end/locale/en-US/wave.intenttest/end2end/locale/en-US/yes.voctest/end2end/test_padacioso_entity_file.pytest/end2end/test_padacioso_intent_file.pytest/end2end/test_regex_skill.pytest/end2end/test_speak_dialog.pytest/end2end/test_universal_skill.pytest/end2end/test_voc_match.pytest/end2end/universal_locale/locale/en-US/affirmative.voctest/end2end/universal_locale/locale/en-US/echo.dialogtest/end2end/universal_locale/locale/en-US/fact.intenttest/end2end/universal_locale/locale/pt-PT/fact.intenttest/unittests/skills/test_base.pytest/unittests/skills/test_legacy_resources.pytest/unittests/skills/test_legacy_skill_omnibus.pytest/unittests/skills/test_ovos.pytest/unittests/skills/test_regex_loading.py
| def on_speak(msg): | ||
| seen_speaks.append(msg.data.get("utterance", "")) | ||
| speak_event.set() | ||
|
|
There was a problem hiding this comment.
Gate the wait event on the expected utterance to prevent flakiness.
on_speak sets the event for every speak message. If unrelated speech arrives first, the wait can unblock before the regex handler emits its output.
Suggested fix
def on_speak(msg):
- seen_speaks.append(msg.data.get("utterance", ""))
- speak_event.set()
+ utt = msg.data.get("utterance", "")
+ seen_speaks.append(utt)
+ if "playing music" in utt:
+ speak_event.set()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/end2end/test_regex_skill.py` around lines 72 - 75, The on_speak handler
currently sets speak_event for every speak message which can unblock the test
prematurely; change on_speak (and the test wiring around
seen_speaks/speak_event) to only set speak_event when the utterance matches the
expected output (e.g., compare msg.data.get("utterance","") against the expected
string/regex or check substring) and still append seen_speaks as needed, so the
wait only wakes for the regex handler's emission.
| except Exception: | ||
| pass |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether silent broad-exception swallowing exists in this test module
rg -nP 'except\s+Exception:\s*\n\s*pass' test/unittests/skills/test_legacy_skill_omnibus.pyRepository: OpenVoiceOS/ovos-workshop
Length of output: 51
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="test/unittests/skills/test_legacy_skill_omnibus.py"
# Print the claimed area with line numbers
nl -ba "$file" | sed -n '165,205p'Repository: OpenVoiceOS/ovos-workshop
Length of output: 112
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="test/unittests/skills/test_legacy_skill_omnibus.py"
awk 'NR>=165 && NR<=205 { printf "%d:%s\n", NR, $0 }' "$file"Repository: OpenVoiceOS/ovos-workshop
Length of output: 2046
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="test/unittests/skills/test_legacy_skill_omnibus.py"
# Show the import section and any warnings usage
rg -n '^\s*(import|from)\s+warnings|warnings\.' "$file" || true
head -n 60 "$file"Repository: OpenVoiceOS/ovos-workshop
Length of output: 2616
Avoid silently swallowing teardown exceptions in tearDownClass.
In test/unittests/skills/test_legacy_skill_omnibus.py lines 184–185, except Exception: pass hides failures from cls.skill.default_shutdown().
Proposed fix
- except Exception:
- pass
+ except Exception as e:
+ warnings.warn(
+ f"default_shutdown failed during teardown: {e!r}",
+ RuntimeWarning
+ )🧰 Tools
🪛 Ruff (0.15.14)
[error] 184-185: try-except-pass detected, consider logging the exception
(S110)
[warning] 184-184: Do not catch blind exception: Exception
(BLE001)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/unittests/skills/test_legacy_skill_omnibus.py` around lines 184 - 185,
The tearDownClass currently swallows all exceptions from
cls.skill.default_shutdown() with "except Exception: pass"; change this to catch
Exception as e and handle it instead of silencing—either re-raise after logging
or call a test logger/assertFail to surface the error; specifically update the
tearDownClass method to wrap cls.skill.default_shutdown() in try/except
Exception as e and call something like logging.exception or raise to ensure
failures are reported rather than ignored.
e842cb2 to
9f7efc7
Compare
da27ca2 to
9f4883f
Compare
83d8792 to
1022f3c
Compare
84b281b to
a0ab65c
Compare
OVOSSkill and the rest of ovos_workshop read skill resources through ovos_spec_tools.LocaleResources and use nothing else. Dialogs render with ovos_spec_tools.render, vocabularies and blacklists load from LocaleResources, and .intent and .entity files resolve with LocaleResources.find. The first load for a language also registers every shipped .entity file for it, once per resource root and language. A missing dialog raises DialogNotFound, a subclass of FileNotFoundError. The message names the dialog, the language and the directories searched. OVOS-INTENT-2 section 2: "a missing `.dialog` leaves the handler with nothing to speak for that response in that language". A dialog the specification rejects as a whole renders the phrases that are valid for the given data and logs one warning; when no phrase renders it raises DialogNotFound with the file and the reason. get_response, ask_yesno and ask_selection keep their documented form of a dialog resource or a string. A resource that is empty or malformed is reported once and skipped where it is read, so it no longer aborts skill start or a handler. When two files share a base name, the shallowest file is used and a tie goes to the last path in sorted order; one warning names both paths. The legacy dialog/, vocab/ and regex/ layouts are not supported; OVOS-INTENT-2 defines locale/<lang>/ only. ovos_workshop.resource_files stays importable for outside callers, and its public functions and classes emit a DeprecationWarning. load_lang returns a LocaleResources that also answers the SkillResources methods, with a deprecation warning. The other legacy OVOSSkill members (resources, dialog_renderer, find_resource, load_dialog_files, voc_match_cache, runtime_requirements, network_requirements) live on _LegacyResourcesMixin. The shims raise DialogNotFound for a missing dialog too. skill.json is found through find_lang_dir, so a lowercase language folder works. register_regex leaves the group-name prefix to register_adapt_regex. OVOSAbstractApplication.get_language_dir resolves through ovos_spec_tools.find_lang_dir. UniversalSkill sets _resource_lang to its internal language. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
a0ab65c to
1f9c26b
Compare
The .required keywords from dev load through LocaleResources.load_required_keywords, like the blacklist beside them, so the skill still builds no legacy resource object. The ovos-spec-tools floor moves to 1.16.0a1, the first release with that method. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Take #737: the workshop's own dialogs in every locale, and skill.error renamed to skill_error. The error handler renders skill_error. The test for a language with no error dialog uses zu-ZA, because de-DE ships one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LocaleResources.vocabulary_keywords walks the core locale too, so every skill registered the workshop's cancel.voc as an adapt keyword. Nothing requires that keyword: get_response reads cancel.voc through voc_match. Skip a .voc that resolves into the workshop locale. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove _locale_resources, which only returned load_lang(). Inline _ships_dialog and _pick_duplicate into their one caller. Move the deprecated methods into _LegacyResourcesMixin: load_regex_files, register_homescreen_app, register_resting_screen and the @homescreen_app scan. A resource that shares its base name with another file in one language tree is malformed (OVOS-INTENT-2 §2). It is reported once and skipped. The workshop no longer picks the shallowest file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…self.lang OVOSSkill looks up dialogs, vocabulary and adapt registrations in self.lang. render_dialog takes a lang argument, like voc_list, register_vocabulary and register_regex. UniversalSkill overrides these four methods to default to internal_language, so the base class needs no language hook. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Supersedes #413 (closed during squash). Part of the OVOS migration onto ovos-spec-tools (architecture#7).
OVOSSkilland the rest ofovos_workshoproute resource access throughovos_spec_tools.LocaleResources. The legacyovos_workshop.resource_files.SkillResourcesis not used internally. It stays shipped and stays available on everyOVOSSkillthrough a deprecation mixin.Needs from the reviewer: a merge. The dialogs the workshop speaks itself (
skill_error, the four game dialogs andno_media_available) ship in all 47 locales through #737, so a game skill and the media player have a dialog in every language. This is a prerelease, so it targets alpha skills only; released skills pin a stable workshop. The change keeps the legacy entry points.Compatibility with current skills
Measured with the same harness on
devand on this branch over 85 current skill trees: startup messages, every intent and entity registration, every dialog over 40 seeds, andvoc_listandvoc_matchfor each vocabulary. The results are identical. The harness does not cover the behaviour changes in the next section.A live MiniCroft run with the real classes of date-time (de-DE) and hello-world (gl-ES) answers every utterance tried, as
devdoes.Behaviour changes ruled by the owner
These are rulings of the repository owner. They are not back-compatible and the title does not claim it.
speak_dialog,render_dialog,SkillResources.render_dialogand the legacydialog_renderer.renderraiseovos_workshop.exceptions.DialogNotFound, a subclass ofFileNotFoundError, when no dialog file exists for the name in the current language. The message names the dialog, the language and the directories searched.devspoke the dialog name with dots read as spaces. OVOS-INTENT-2 §2: "a missing.dialogleaves the handler with nothing to speak for that response in that language". An exception in a handler takes the normal error path: the error dialog is spoken andmycroft.skill.handler.erroris emitted.OVOSSkilland every other module resolve resources throughovos_spec_tools.LocaleResourcesonly.ovos_workshop.resource_files,self.resources,self.dialog_renderer,find_resourceand the objectload_lang()returns keep working for outside callers as deprecated shims. A source-level test fails if a module outside the shims imports them.DialogNotFoundis raised with the file and the reason. A dialog with different slots in different phrases, such as date-time de-DEtime.current.dialog, speaks the valid phrases.get_response,ask_yesno,ask_selectionand the first-run intro message document their prompt as "a dialog resource or string". A skill builds such a prompt at runtime, so no dialog file can exist for it. With no dialog file of that name the text is spoken. A dialog that exists but cannot render still raises.Specification
Slot names are lowercase ASCII letters, digits and underscores (OVOS-INTENT-1 §3.4). A dialog with
{DOWN},{ digits }or an accented slot name is malformed and raises. This branch does not change that.A repeated slot in one phrase, and two consecutive slots, are allowed in a
.dialogby the owner's ruling.ovos-spec-toolstakes that change in OpenVoiceOS/ovos-spec-tools#188. Until it is released, a dialog with a repeated slot raisesDialogNotFound, and this branch does not work around it.Duplicate files
OVOS-INTENT-2 §2 makes a skill malformed when two files of one extension share a base name in one language tree. The workshop does not pick one of them: the resource is reported once with a WARNING and skipped. A duplicate
.intent,.entityor.vocis not registered, and a duplicate.dialograisesDialogNotFound.Not supported
The legacy
dialog/<lang>/,vocab/<lang>/andregex/<lang>/layouts, and flat layouts without a language folder, are not supported. OVOS-INTENT-2 §2 defines one layout,locale/<lang>/.Back-compat surface
All legacy entry points stay on
OVOSSkillthrough_LegacyResourcesMixin. Each emits aDeprecationWarningand uses one cachedSkillResourcesper resource root and language. The removal version is computed fromVERSION_MAJOR.self.resourcesSkillResources.load_dialog_file,render_dialog,load_vocabulary_file,load_list_file,.value,.template,.wordand.jsonkeep working.speak_dialog,voc_match, ...) orovos_spec_tools.LocaleResources.self.load_lang(...)LocaleResourcesthat also answers everySkillResourcesmethod (load_dialog_file,render_dialog,load_vocabulary_file,dialog_renderer, ...) with a deprecation warning.LocaleResourcesmethods.self.dialog_rendererMustacheDialogRenderer, loading.dialogfiles from subfolders too.OVOSSkill.render_dialog.self.find_resource(name, dirname=None, lang=None)ovos_workshop.resource_files.find_resource.LocaleResources.find.self.load_dialog_files(root=None)self.voc_match_cache_voc_cachegetter. The setter warns and accepts a dict.voc_matchandvoc_listcache internally.runtime_requirements,network_requirementsclasspropertyshims. Subclass overrides are honoured.load_lang(...).vocabularies()without a language still returns theSkillResourcesmap, andload_vocabulary_filekeeps the written order of each expansion. The shims read dialogs from subfolders as before.What changes inside
.dialogLocaleResources.load_dialog, thenovos_spec_tools.render, withvocabularies()for<voc>references. See the behaviour changes above for a missing, empty, duplicated or rejected dialog..vocLocaleResources.vocabularies()for keyword registration.voc_list(lowercased, as before) forvoc_matchandremove_voc..intent,.entityLocaleResources.findthroughOVOSSkill._locate_lang_file..blacklistLocaleResources.load_blacklist: the intent's own file, a<slot>.blacklistfor each declared slot, and<entity>.blacklistfor each entity file (OVOS-INTENT-2 §4.3). The registration payload is unchanged.skill.jsonfind_lang_dir, solocale/en-us/servesen-US..rxload_regex_filesin_LegacyResourcesMixin, self-contained and deprecated.register_regexpasses the pattern toregister_adapt_regex, which prefixes the group names once.OVOSAbstractApplication.get_language_dircallsovos_spec_tools.find_lang_dir.A malformed or duplicate resource is logged once and skipped where it is read:
register_intent_file,register_entity_file,render_dialog,voc_list, the blacklists and the vocabularies. It no longer aborts skill start or a handler.load_langreturns one object per resource root and language. Each object holds a snapshot of the skill's locale tree, so a caller that passes a language, such asovos-good-manners-pipeline-pluginfor each language, adds one snapshot per language. The first load for a language also registers every shipped.entityfile for it, once per resource root and language, andskills.auto_register_entity_filesstill turns that off.OVOSSkilllooks up resources inself.lang, andrender_dialogtakes alangargument.UniversalSkilloverridesrender_dialog,voc_list,register_vocabularyandregister_regexto default to its internal language. The deadUniversalSkill._load_langoverride is removed..requiredkeywords load throughLocaleResources.load_required_keywords, beside the.blacklist, and travel on the registration asrequired_keywords.Other changes in this branch
These go beyond the refactor.
@homescreen_appand@resting_screen_handlerwarn when applied;register_homescreen_appandregister_resting_screenare deprecated and live in_LegacyResourcesMixin.UniversalSkill.speakcallstranslate_utterancewith the target and source languages the right way round.UniversalSkillskips__tags__translation when the message has no__tags__.word_connectors.jsonandeuphony.jsonload throughiter_locale_dirsandclosest_lang.CoreResourcesis deprecated..vocline is the alphabetically first alternative.LocaleResources.vocabulary_keywords. A skill registers only its own.vocfiles; the workshop'scancel.vocservesvoc_matchinget_responseand is not an Adapt keyword.User overrides
A user override is read from
<xdg data>/resources/<skill_id>/<lang>/, the pathdevreads. OVOS-INTENT-2 §2.1 names<skill_id>/locale/<lang>/; the spec path is not read and this branch does not change that. A test shows that a user dialog at the supported path wins over the skill's own.Dependencies
ovos-spec-tools>=1.16.0a1, the first release withLocaleResources.load_required_keywords. The floors ofovos-utilsandovos_bus_clientondevalready provide the rest.Tests
pytest testpasses: 879 passed, 1 skipped (dev: 827 passed, 1 skipped, same venv).test/unittests/test_required_file.pyfromdevpasses, and fails 2 tests when the loader returns no keywords.test/unittests/test_stable_skill_shapes.pyhas 42 regression tests built from file shapes found in skills: duplicate intents and entities in nested folders and inintent/againstintents/, which are reported and skipped, a dialog that mixes lines with and without{time}, the speedtest, randomness and ip dialogs, empty.dialogand.vocfiles, a lowercaselocale/en-us/skill.json, theload_lang(...)calls ofovos-good-manners-pipeline-plugin, a single prefix onregister_regexgroups, one WARNING per malformed file, a user override, and theDialogNotFounderror and its message, the handler error path, mixed-slot dialogs, and a source-level check that only the shims touch the legacy path. They cover the literal-prompt fallback (a dialog of another language, or one that cannot render, raises) and the first-run intro. The rest guard behaviour that already held.🤖 Generated with Claude Code