Release 2.10.0a1 - #411
Open
github-actions[bot] wants to merge 55 commits into
Open
Conversation
* chore: move 3rd party code to own file for proper attribution and to make it easier to keep in sync with upstream * chore: docstr * chore: docstr * Rename AudioData to srAudioData in sr.py
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…355) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* refactor: deprecate solver plugins remove autotranslation, standardize api contract, simplify implementation, remove redundant methods, improve naming conventions to better convey expectations * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * plugin loaders * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * coderabbit * coderabbit * improve deprecation logs * fix import --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* fix: explicitly model streaming tokens vs sentences * Apply suggestion from @coderabbitai[bot] Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…systems (#376) * fix: docs, tests, typing, fix config * docs and unittests * 📝 Add docstrings to `tests_and_docs` Docstrings generation was requested by @JarbasAl. The following files were modified: * `ovos_plugin_manager/installation.py` * `ovos_plugin_manager/plugin_entry.py` * `ovos_plugin_manager/stt.py` * `ovos_plugin_manager/templates/gui.py` * `ovos_plugin_manager/templates/phal.py` * `ovos_plugin_manager/templates/stt.py` * `ovos_plugin_manager/templates/transformers.py` * `ovos_plugin_manager/templates/tts.py` * `ovos_plugin_manager/templates/vad.py` * `ovos_plugin_manager/tts.py` * `ovos_plugin_manager/utils/config.py` * `ovos_plugin_manager/wakewords.py` * `test/unittests/test_installation.py` * `test/unittests/test_pipeline.py` * `test/unittests/test_plugin_entry.py` * `test/unittests/test_solver.py` * `test/unittests/test_stt.py` * `test/unittests/test_transformers.py` * `test/unittests/test_utils.py` * `test/unittests/test_vad.py` These files were kept as they were: * `ovos_plugin_manager/templates/hotwords.py` * `test/unittests/test_g2p.py` * `test/unittests/test_language.py` * `test/unittests/test_phal.py` * `test/unittests/test_tts.py` * `test/unittests/test_wakewords.py` These file types are not supported: * `docs/api/agents.md` * `docs/api/language.md` * `docs/api/microphone.md` * `docs/api/phal.md` * `docs/api/pipeline.md` * `docs/api/stt.md` * `docs/api/transformers.md` * `docs/api/tts.md` * `docs/api/vad.md` * `docs/api/wake-word.md` * `docs/configuration.md` * `docs/index.md` * `docs/installation.md` * `docs/plugin-types.md` * `docs/writing-plugins.md` * docs and unittests * ci: modernize GitHub Actions workflows to use shared gh-automations@dev Replace legacy inline/individual workflow files with standard reusable callers from OpenVoiceOS/gh-automations@dev: - Removed: build_tests.yml, pipaudit.yml, license_tests.yml, conventional-label.yaml (old naming conventions / inline steps) - Added: build-tests.yml, pip_audit.yml, license_check.yml, conventional-label.yml (reusable callers, standardized naming) - Added: coverage.yml, lint.yml, release-preview.yml, repo-health.yml (previously missing, now added per OVOS workflow standards) All new workflows pass system_deps: 'swig libssl-dev' where package installation is needed. build-tests.yml covers Python 3.10–3.14. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * update * fix: resolve CI failures and address CodeRabbit inline review comments Test fixes (CI failures): - test_microphone.py: replace removed assertNotEquals with assertNotEqual (Python 3.12+) - test_pipeline.py: fix mock patch target to ovos_plugin_manager.pipeline.find_plugins - test_skills.py: fix mock patch target to ovos_plugin_manager.skills.find_plugins - test_plugin_entry.py: update assertions to expect list args for pip_install calls - test_solver.py: add assert_has_calls/call_count to test_auto_translate_decorator Source fixes (CodeRabbit): - installation.py: fix recursive budget passing, Union[str,List[str]] signature, guard proc.stdout/stderr - plugin_entry.py: pass package names and git urls as lists to pip_install - templates/tts.py: bare except -> except Exception - templates/vad.py: soften extract_speech docstring (may return None) - templates/stt.py: fix return type annotation to List[Tuple[Optional[str], float]] - utils/__init__.py: add GUI_ADAPTER to PluginConfigTypes for symmetry - utils/config.py: add 'or {}' guard on load_plugin_configs; fix dialect matching logic - wakewords.py: remove unreachable return after raise; wrap scan_wws in try/except NotImplementedError - gui.py: add find_gui_adapter_plugins() and load_gui_adapter_plugin() helpers Docs fixes (CodeRabbit): - docs/api/pipeline.md: fix example plugins (adapt/padatious, not converse/common-QA) - docs/api/tts.md: correct OVOSTTSFactory.create() failure modes documentation - docs/api/vad.md: fix AudioFrame.duration type from int to float - docs/configuration.md: correct dialect priority semantics - docs/plugin-types.md: add ovos.plugin.audio2ipa to deprecated entry points table - docs/writing-plugins.md: fix cls->self in @Property examples for STT and TTS Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: use correct constructor param in TestAutoTranslate setUp AbstractSolver uses `internal_lang` (not `default_lang`) to set the solver's default language. Passing `default_lang='en'` silently fell into **kwargs and was ignored, causing the solver to pick up the system locale (e.g. pt-PT) instead of English. This made test_auto_translate_decorator fail on any machine whose locale differs from English. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: correct 8 bugs and typing issues found in full audit - templates/tts.py: lstrip/rstrip used as substring removers (character-set bug) fixed with removeprefix/removesuffix; validate_ssml discarded the return value of format_speak_tags making all SSML wrapping a no-op - templates/vad.py: extract_speech annotated -> bytes but can return None; changed to -> Optional[bytes] - stt.py: bare assert for lang validation replaced with raise ValueError (assert is disabled under python -O flag) - utils/config.py: get_valid_plugin_configs used .append(list) instead of .extend(list), corrupting the config list structure; bare except fixed - tts.py: os.listdir() called without os.path.isdir() guard; crashes on first run before voice cache is populated - wakewords.py: same os.listdir() without isdir guard - templates/transformers.py: (list, dict) tuple-expression used as return annotation; fixed to Tuple[List[str], dict] and dict respectively - skills.py, ocp.py, installation.py, templates/solvers.py, templates/audio.py: bare except: → except Exception: - agents.py, embeddings.py, intent_transformers.py, triples.py, gui_adapter.py: Apache 2.0 headers, module docstrings, type(X) return annotations replaced with Optional[Type[X]], bare dict → Dict[str, Type[X]] Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: raise coverage from 58% to 86% Added 24 new test files and expanded 3 existing stubs, covering the highest-impact uncovered modules: New files: - test_embeddings_templates.py: EmbeddingsDB, TextEmbedder, ImageEmbedder, VoiceEmbedder, FaceEmbedder base class logic (was 28%) - test_tts_template_streaming.py: ConcatTTS and StreamingTTS threading paths - test_phal_template_extended.py: PHAL plugin base class coverage (was 57%) - test_thirdparty_sr.py: SpeechRecognition wrapper with mocked audio - test_media_templates.py: MediaBackend abstract base class methods - test_led_animations.py: all LED animation classes with mocked hardware - test_embeddings.py, test_embeddings_distance.py: distance metrics, vectors - test_agents.py, test_gui_module.py, test_gui_plugin_template.py, test_intent_transformers_triples_gui_adapter.py: plugin factory functions - test_audio_backend_template.py, test_g2p_template.py, test_coreference_legacy.py, test_tokenization_template.py, test_tts_template_extended.py, test_tts_cache.py, test_ocp_extended.py, test_sr_audiodata.py, test_thirdparty_solvers.py: gap-filling across template modules Expanded: - test_installation.py, test_pipeline.py, test_skills.py All test methods carry -> None annotations and docstrings per standards. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add full audit findings and repo documentation - AUDIT.md: complete file:line-cited findings — critical bugs (tts.py SSML no-op, vad.py None return, config.py list append, assert validation, bare excepts), performance issues (entry-point rescans, O(n) sets, scipy hot-path import), type annotation gaps, and code smells - SUGGESTIONS.md: architecture proposals (plugin discovery caching, distance() dispatch table, thirdparty/sr.py removal timeline, unify find_X/load_X boilerplate via factory) - FAQ.md: keyword-rich Q&A for common plugin manager questions - QUICK_FACTS.md: machine-readable package reference - MAINTENANCE_REPORT.md: AI-transparency log of all changes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: skip embeddings tests when numpy is not installed Use pytest.importorskip("numpy") so the test module is gracefully skipped in CI environments that do not have numpy, instead of causing a collection error that blocks all other tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: move GUI plugin changes to feat/gui-plugin branch Remove AbstractGUIPlugin, gui_adapter.py, GUI_ADAPTER enum and related tests — these belong in a separate PR (feat/gui-plugin branch). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: remove GUI_ADAPTER reference from test_plugin_types GUI_ADAPTER was moved to the feat/gui-plugin branch; remove it from the exclusion list so the test does not fail on AttributeError. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * update * chore: update documentation and maintenance report * fix: properly handle print_logs in pip_install When print_logs=True, output should go directly to console without piping. When print_logs=False, output should be piped to suppress it silently. Previously, the code always piped stdout/stderr and manually read and printed them when print_logs=True, which is inefficient and causes test failures. This fix: - Conditionally pipes output based on the print_logs flag - When print_logs=True, Popen is called without stdout/stderr pipes - When print_logs=False, Popen is called with PIPE to capture output silently Fixes: test_print_logs_true_no_pipe failure across all Python versions Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * feat: add tests for uncovered modules and fix SSML dangling tag handling Add comprehensive unit tests: - test_intent_transformers.py: 100% coverage for intent_transformers.py - test_triples.py: 100% coverage for triples.py and templates/triples.py - Enhanced test_keywords.py: Added factory method tests for OVOSKeywordExtractorFactory - Enhanced test_tts.py: Added test for dangling closing tag normalization Bug fix in templates/tts.py: - Fixed validate_ssml to detect both opening "<speak>" and closing "</speak>" tags - Previously, dangling closing tags like "hello</speak>" were not normalized - Now properly calls format_speak_tags for both opening and closing tags Test results: - 990 tests passing - 85% code coverage - All new tests passing Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * feat: add comprehensive tests for postag, segmentation, tokenization modules Add unit tests for plugin discovery functions: - test_postag.py: Complete test coverage for postag.py - test_segmentation.py: Complete test coverage for segmentation.py - test_tokenization.py: Complete test coverage for tokenization.py Tests follow the same pattern as other plugin discovery modules: - find_plugins tests - load_plugin tests - get_configs tests - get_module_configs tests - get_lang_configs tests - get_supported_langs tests Total tests: 21 new tests covering utility functions and template base classes Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * chore: deprecate dead code modules scheduled for removal in v3.0 Mark the following modules as deprecated with proper warnings and logging: 1. ovos_plugin_manager.installation - deprecated, will be removed in v3.0 - Added module-level deprecation log - Added @deprecated decorator to main functions: - search_pip() - pip_install() - Recommended: use modern package managers instead 2. ovos_plugin_manager.plugin_entry - deprecated, will be removed in v3.0 - Added module-level deprecation log - OpenVoiceOSPlugin class should no longer be used 3. ovos_plugin_manager.hardware - deprecated, will be removed in v3.0 - Module is being superseded by ovos-hardware-helpers package - Added deprecation log at module level - Affects: - ovos_plugin_manager.hardware.switches - ovos_plugin_manager.hardware.fan - ovos_plugin_manager.hardware.led Deprecation warnings include: - Deprecation version marker (3.0) - Clear guidance on what to use instead - Warning messages logged when modules are imported or functions called All existing tests pass. Deprecation warnings are properly logged via ovos_utils.log. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * refactor: use dynamic version for deprecation notices Update deprecation messages to dynamically calculate the next major version instead of hardcoding '3.0'. This ensures deprecation version stays accurate when the package version is updated. Changes: - installation.py: Use VERSION_MAJOR to determine deprecation version (3.0) - plugin_entry.py: Use VERSION_MAJOR to determine deprecation version (3.0) - hardware/__init__.py: Use VERSION_MAJOR to determine deprecation version (3.0) All deprecation notices now display as "removed in v3.0" dynamically calculated from VERSION_MAJOR (currently 2). When version is bumped to 3.x, deprecation version will automatically update to 4.0. Tests: All 990 tests passing Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * refactor: convert hardware modules to backwards-compatibility shims Convert ovos_plugin_manager.hardware modules to act as backwards-compatibility shims that re-export classes from ovos-hardware-helpers. This directs users to the new canonical package while maintaining API compatibility. Changes: - fan.py: import AbstractFan from ovos_hardware_helpers.fan with deprecation log - switches.py: import AbstractSwitches from ovos_hardware_helpers.switches with deprecation log - led/__init__.py: import AbstractLed from ovos_hardware_helpers.led, maintain Color enum for backwards compatibility - hardware/__init__.py: add re-exports of all hardware classes for backwards-compatible imports All modules emit deprecation warnings on import, guiding users to migrate to ovos_hardware_helpers package. Tests verify backwards-compatibility is maintained. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * refactor: make ovos-hardware-helpers an optional dependency with lazy imports Use module-level __getattr__ to implement lazy importing of ovos-hardware-helpers classes. This allows the shim modules to be imported without requiring ovos-hardware-helpers to be installed, while still providing helpful error messages if users try to access the hardware classes without the dependency. Deprecation warnings are still logged on module import to guide users toward the canonical ovos-hardware-helpers package. Only when a class is actually used does the import attempt happen. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * fix: add ovos-hardware-helpers as test dependency Include ovos-hardware-helpers in the test dependencies so that hardware module tests can properly import the shim classes from ovos_plugin_manager.hardware. This ensures CI tests pass when running pytest, as the lazy imports need the dependency available when accessing the hardware classes. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * fix: specify test extras for coverage workflow Ensure test dependencies (including ovos-hardware-helpers) are installed when running coverage tests by passing install_extras: '.[test]' to the gh-automations coverage workflow. This fixes CI failures where hardware tests couldn't import the required ovos_hardware_helpers module. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: tool plugins
* Update requirements/requirements.txt
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* discovery
* pydantic validation
* better output validation
* better input validation
* Update ovos_plugin_manager/templates/agent_tools.py
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* fix coderabbit mess
* fix: agent_tools bug fixes, Apache header, docs, and tests
- Add Apache 2.0 license header (fixes License CI)
- Fix discover_tools() result not stored in __init__ (tools dict was always empty after init)
- Add LOG.debug on discover failure instead of silent except: pass
- Remove unused `Field` import (pydantic)
- docs: add docs/api/agent-tools.md — ToolBox plugin API reference
- docs: update docs/index.md to link agent-tools.md
- test: add test/unittests/test_agent_tools.py — 21 tests covering init,
call_tool (dict/model/error paths), lazy refresh, bus handlers, json schema
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: move tool plugins to opm.agents namespace, add AgenticLoopEngine
- PluginTypes: add AGENT_TOOLBOX (opm.agents.toolbox) and AGENT_LOOP (opm.agents.loop)
- PluginTypes: remove PERSONA_TOOL (opm.persona.tool) — wrong namespace for tool plugins
- PluginConfigTypes: add AGENT_TOOLBOX and AGENT_LOOP config entries
- persona.py: find_toolbox_plugins() now uses AGENT_TOOLBOX
- agent_tools.py: update ToolBox docstring to reference correct entry point group
- templates/agents.py: add AgenticLoopEngine(ChatEngine) — opm.agents.loop entry point
- standard load_toolboxes(toolboxes) interface for persona-injected ToolBoxes
- presents as ChatEngine to all callers; loop internals are implementation details
- docs/api/agents.md: document AgenticLoopEngine and persona config toolboxes pattern
- docs/api/agent-tools.md: fix entry point to opm.agents.toolbox
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor: remove AgenticLoopEngine and AGENT_LOOP from OPM
AgenticLoopEngine is now implemented in the standalone ovos-agentic-loop
repo (Agent Plugins/ovos-agentic-loop) and registers under the existing
opm.agents.chat entry-point group — no new OPM type is needed.
Removed:
- PluginTypes.AGENT_LOOP ("opm.agents.loop")
- PluginConfigTypes.AGENT_LOOP ("opm.agents.loop.config")
- AgenticLoopEngine class from templates/agents.py
- AgenticLoopEngine section from docs/api/agents.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: address PR #340 CodeRabbit review comments
Addressed 6 critical issues from CodeRabbit review on tool plugins PR:
**pyproject.toml:**
- Added pydantic~=2.0 to test optional-dependencies
Reason: GitHub Actions installs with 'test' extras from pyproject.toml;
pytest was failing with ModuleNotFoundError for pydantic
**test/unittests/test_agent_tools.py:**
- Removed dead placeholder definition (line 48-49)
Was causing Ruff F821 (Undefined name) warning
**docs/index.md:**
- Fixed entry-point name from opm.persona.tool to opm.agents.toolbox
Matches actual implementation in ToolBox class definition
**ovos_plugin_manager/templates/agent_tools.py:**
1. handle_discover() (line 123): Call refresh_tools() before broadcasting
- Prevents stale cache if initial discover_tools() fails
- Ensures dynamic tool discovery works for bus-only clients
2. handle_call() (line 144): Use model_dump(mode='json') for consistency
- Matches model_json_schema() advertised in tool_json_list
- Prevents divergence for datetime, UUID, enum, or aliased fields
3. validate_input() (line 170): Remove raw tool_kwargs from error message
- Security fix: prevents echoing secrets/user content on bus
4. validate_output() (line 193): Remove raw result from error message
- Security fix: prevents echoing secrets/user content on bus
**Testing:**
- All 1011 unit tests pass
- All 21 agent_tools tests pass
- Python syntax verified
AI-Generated Change:
- Model: Claude Haiku 4.5
- Intent: Address CodeRabbit PR review comments for tool plugins feature
- Impact: 6 critical fixes for cache staleness, JSON serialization, security, and dependencies
- Verified via: uv run pytest test/unittests/ -v (1011 passed)
* docs: update FAQ and MAINTENANCE_REPORT for PR #340 fixes
- Added 3 new FAQ entries: Agent Tools API, dynamic discovery, JSON serialization
- Added comprehensive MAINTENANCE_REPORT entry documenting all 6 fixes:
* pyproject.toml dependency fix
* Test placeholder removal
* Documentation accuracy fix
* Cache staleness prevention
* JSON serialization consistency
* Security fixes for error messages
- Included AI transparency (model, actions, oversight notes)
- Linked to source file locations for future reference
AI-Generated Change:
- Model: Claude Haiku 4.5
- Intent: Document PR #340 fixes and new agent tools features for future maintainers
- Impact: Improved discoverability and traceability of changes
- Verified via: Manual verification of FAQ clarity and MAINTENANCE_REPORT completeness
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add OptionMatcherEngine plugin type for ask_selection slot resolution Introduces a dedicated engine class for matching free-form user utterances to predefined option slots — semantically distinct from ReRankerEngine (which ranks answers against a semantic query) and modelled after the existing YesNoEngine pattern. Changes: - templates/agents.py: add OptionMatcherEngine with abstract match_option() - utils/__init__.py: add AGENT_OPTION_MATCHER = "opm.agents.option_matcher" to both PluginTypes and PluginConfigTypes - agents.py: add find_option_matcher_plugins() and load_option_matcher_plugin() - test_agents.py: 4 new tests covering find, load, abstract enforcement, and concrete subclass instantiation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * 📝 Add docstrings to `feat/opt_matcher` Docstrings generation was requested by @JarbasAl. The following files were modified: * `ovos_plugin_manager/agents.py` * `ovos_plugin_manager/templates/agents.py` * `test/unittests/test_agents.py` * Update agents.py --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* refactor: migrate to ovos-spec-tools for language matching Replace langcodes.tag_distance with ovos_spec_tools.lang_distance and ovos_utils.lang.standardize_lang_tag with ovos_spec_tools.standardize_lang, the conformant reference implementation of the OVOS language specs. - swap langcodes dependency for ovos-spec-tools>=0.0.1a2 - utils/config.py: tag_distance -> lang_distance (same <10 threshold) - migrate all standardize_lang_tag callers to standardize_lang; the macro=True argument is dropped as standardize_lang already normalizes to the comparable base/macro form - ovos_utils.lang.phonemes / ovos_utils.lang.visimes kept (not part of ovos-spec-tools) Wave 2 of the OVOS migration. Refs OpenVoiceOS/architecture#7 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: depend on ovos-spec-tools[langcodes] `langcodes` is optional for ovos-spec-tools itself, but the OVOS ecosystem silently degrades without it (region-stripping in standardize_lang_tag). Dropping the direct langcodes dependency left it absent in CI — language tags came back bare (`en` instead of `en-US`). Pull it back in via the ovos-spec-tools langcodes extra. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2.x only removed the bundled hivemind agent protocol + messagebus solver (ovos-bus-client#207); no API break (#215). Widening keeps 1.x as default while permitting 2.x, unblocking the HiveMind stack's 2.x adoption.
#395) - Add TestWakeWordVerifier with 5 tests covering find_wake_word_verifier_plugins, load_wake_word_verifier_plugin, and HotWordVerifier base class behaviour - Add AGENT_TOOLBOX / opm.agents.toolbox / ToolBox row to docs/plugin-types.md
* feat: add voice-clone plugin family (opm.vc) Introduces VoiceClonePlugin — an audio-to-audio ABC for converting source speech to a reference voice. Text input is explicitly out of scope for this family; zero-shot TTS-with-speaker-ref belongs in TTS plugins. - ovos_plugin_manager/templates/vc.py: VoiceClonePlugin ABC with a single abstract method clone_voice(audio, reference_voice, out_path) → str - ovos_plugin_manager/vc.py: find_voice_clone_plugins, load_voice_clone_plugin, get_voice_clone_config, OVOSVoiceClonerFactory - PluginTypes.VOICE_CLONE = "opm.vc", PluginConfigTypes.VOICE_CLONE = "opm.vc.config" - 21 unit tests covering template, enum, discovery, factory, and ABC enforcement - docs/plugin-types.md: add VOICE_CLONE row - docs/voice-clone.md: scope note, contract table, registration guide First implementation: vconnx (forward-looking mention). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: keep voice-clone docs implementation-agnostic --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ools, was test-only) (#399) * fix: declare pydantic as a core dependency (runtime import in agent_tools, was test-only) * chore: drop stale requirements/ (pyproject is the sole dependency source)
DEPRECATED_ENTRYPOINTS mapped the deprecated VAD group to 'opm.vad', but PluginTypes.VAD (and find_vad_plugins) use 'opm.VAD'. The case mismatch meant a VAD plugin still declaring 'ovos.plugin.VAD' aliased to a group the finder never queries, so it was never discovered.
* feat: first-class tool calls in the agent message/chat contract Make tool turns representable in a conversation so a tool loop can be threaded through history, persisted by memory plugins, and use providers' native function-calling: - MessageRole.TOOL and a ToolCall dataclass (id, name, arguments) - AgentMessage gains optional tool_calls / tool_call_id / name (trailing, default None — backward compatible; MultimodalAgentMessage inherits them) - ChatEngine.supports_tools class flag (default False) and an optional trailing tools= kwarg on continue_chat (existing 4-arg overrides keep satisfying the ABC) - ToolBox.tools_to_openai_spec staticmethod + openai_tools property: convert tool_json_list to the neutral OpenAI tools/function spec Additive and non-breaking. The orchestration loop lives in ovos-agentic-loop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: accept ToolBox objects directly in the tools argument Add ToolBox.normalize_tools (staticmethod) coercing a ToolBox, an OpenAI tool dict, or a list mixing either (or None) into the OpenAI spec list, and broaden ChatEngine.continue_chat's tools type so callers can pass toolbox objects directly rather than pre-serialized dicts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat: add MediaProvider plugin type (opm.media.provider)
Introduce a media catalog/search plugin type to replace OCP search skills.
MediaProvider plugins are loaded and queried in-process by the OCP pipeline
instead of broadcasting ovos.common_play.query over the bus.
- PluginTypes.MEDIA_PROVIDER / PluginConfigTypes.MEDIA_PROVIDER
("opm.media.provider" / ".config")
- templates/media_provider.py: MediaProvider base, three-axis routing
(media/modality/genre_filter) mirroring mediavocab MetadataProvider;
search() returns list[mediavocab.Release]; search_safe() for pool dispatch
- media_provider.py: find/load discovery + load_media_providers() with
is_available() + config-disabled filtering
- depend on mediavocab>=0.1.1 (Release is the canonical catalog entry)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: align MediaProvider routing with mediavocab four-axis gate
mediavocab dev replaced PlaybackModality (3-axis) with PlaybackType +
ContentForm (4-axis: media/playback_type/content_form/genre_filter).
Update the MediaProvider base class attrs and tests to match the canonical
provider_matches() contract. Note mediavocab.PlaybackType (audio/video/
paged/interactive) is distinct from ovos_utils.ocp.PlaybackType (the backend
selector) — bridged downstream, not in the template.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: align MediaProvider with mediavocab 1.0 three-axis gate
mediavocab 1.0 dropped content_form from the MetadataProvider routing gate
("no real provider filters on ContentForm"). Match the canonical contract:
MediaProvider routes on (media, playback_type, genre_filter). Require
mediavocab>=1.0.0 (the published 1.0 line; the earlier <1.0.0 cap predated it).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs: document MediaProvider plugin type (OVOS-OCP-1)
* fix: make mediavocab an optional dependency
opm only references mediavocab for type hints in the MediaProvider template and
one routing-gate call; the Release/Signals types and routing primitives belong to
the downstream provider plugins. Move the import under TYPE_CHECKING, lazy-import
provider_matches inside matches(), and move mediavocab from hard deps to a [media]
extra (also in [test]). opm now imports the media_provider template without
mediavocab installed; providers that use it declare their own mediavocab dep.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* build: require Python >=3.10 (mediavocab -> ovos-spec-tools needs >=3.10)
The new MediaProvider plugin type depends on mediavocab, which requires
ovos-spec-tools>=0.6.0a1; ovos-spec-tools is published only for Python >=3.10,
so the py3.9 build could not resolve dependencies. Python 3.9 is EOL and
ovos-core already targets >=3.10.
* ci: drop Python 3.9 from the build matrix (requires-python is now >=3.10)
* feat: context-aware MediaProvider — QueryContext + serves() gate
Providers gain a QueryContext (device-supported playback types + content policy +
locale/session) so the pipeline can gate them on what the device/user can actually
use — a video provider is skipped on an audio-only device, an adult provider is
skipped when the content filter blocks it — before any search runs. Additive:
matches() (3-axis) unchanged; serves()/search_context() default to permissive so
existing providers keep working.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor!: simplify MediaProvider to a single search(signals, context) method
Collapse the base class to plain boilerplate: drop is_available / matches /
serves / search_context / search_safe / featured_media and the three routing
ClassVars (media/playback_type/genre_filter). A provider now implements ONE
abstract method — search(signals, context) -> list[Release] — and returns [] when
it can't serve the query/context (availability/routing is the provider's own
concern, gated via the QueryContext it receives). QueryContext + its
allows_playback/allows_genres helpers are kept; the loader no longer filters on
is_available.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* refactor: drop QueryContext.extras bag
* refactor!: replace QueryContext with plain **context kwargs on search()
search(signals, lang='en-us', **context) is now the entire MediaProvider
contract — no QueryContext dataclass to import/maintain. The pipeline passes
supported_playback_types/blocked_genres/region/session_id as kwargs; providers
read what they need and ignore the rest.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* refactor: define explicit search() context kwargs (no **kwargs)
search(signals, lang, *, supported_playback_types, blocked_genres, region,
session_id) — the valid context arguments are named in the signature, not a
catch-all **context.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A pipeline whose match terminates or continues an already-active skill's participation (e.g. a stop) sets suppress_activation=True so the orchestrator dispatches the match without activating skill_id. Defaults False, so normal matches are unaffected. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: canonical transformer pipeline runner services Add ovos_plugin_manager.transformer_services with the six shared *TransformersService runners (utterance, metadata, intent, dialog, tts, audio) so downstream projects consume one implementation instead of maintaining per-repo copies. - config-gated opt-in loading with explicit config= injection - accepts full core config or the section mapping itself - OVOS-TRANSFORM-1 §4 ascending priority by default, legacy descending order available via sort_ascending=False - audio service supports top-level audio_transformers and the legacy listener.audio_transformers section - move TTS transformer helpers to ovos_plugin_manager.tts_transformers with backwards-compatible re-exports in dialog_transformers - fix TTSTransformer reading the dialog_transformers config section Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: patch module-local find_plugins reference The dialog transformer discovery test patched ovos_plugin_manager.utils.find_plugins, which only intercepts the call when the factory module has not been imported yet in the test session. Patch the module-local reference so the test is import-order independent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: cache sorted plugin order in transformer services Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: OVOS-TRANSFORM §4 explicit order and §8.1 cancellation in transformer services - explicit deployer order: an 'order' list in the config section wins over priorities; loaded plugins absent from the list are not run; plugins named only in the list are enabled without a config entry - cancellation: a valid canceled/cancel_reason pair stops the chain and the runner stamps cancel_by from the emitting plugin; an incomplete pair is logged, stripped and the chain proceeds - reserved config keys (order, blacklisted_skills) are never treated as plugin names Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Human review requested!