Agent Plugins

July 31, 2026 · View on GitHub

The agent plugin system extends OPM with composable NLP components for conversational AI, tool use, and text understanding. OPM discovers these plugins through Python entry points, the same way it discovers every other plugin type.

Base classes: ovos_plugin_manager/templates/agents.py, ovos_plugin_manager/templates/agent_tools.py


Entry Point Groups

GroupBase ClassPurpose
opm.agents.chatChatEngineMulti-turn chat and agentic loops, through continue_chat(messages) to AgentMessage
opm.agents.chat.multimodalMultimodalChatEngineChat with image/audio/file inputs
opm.agents.toolboxToolBoxGroups of callable AgentTool functions exposed to agents via bus or direct call
opm.agents.summarizerSummarizerEngine / ChatSummarizerEngineDocument or chat-history summarisation
opm.agents.retrievalRetrievalEngineKnowledge-base / vector-index query (query(q, lang, k)List[Tuple[str, float]])
opm.plugin.personadictStatic persona config dict, consumed by ovos-persona to wire a ChatEngine with a system prompt

AgentContextManager (agents.py:35) is an optional companion base class for plugins that augment conversation context (RAG, memory, history trimming). It is not a standalone entry point group. ChatEngine implementations use it internally.


Available ToolBoxes (opm.agents.toolbox)

Each ToolBox implements discover_tools() → List[AgentTool] (agent_tools.py:314). You can call tools directly with ToolBox.call_tool(name, kwargs), or over the OVOS bus with the ovos.persona.tools.{toolbox_id}.call message topic (agent_tools.py:102).

Plugin IDClassToolsPackageAPI Key
ovos-wikipedia-toolsWikipediaToolBoxsearch_wikipedia, get_wikipedia_sections, get_wikipedia_pageovos-wikipedia-solverNone, public Wikipedia REST API
ovos-ddg-toolsDuckDuckGoToolBoxsearch_duckduckgo, get_duckduckgo_infoboxovos-ddg-solver-pluginNone, DuckDuckGo Instant Answer API
ovos-wolfram-alpha-toolsWolframAlphaToolBoxcompute, compute_fullovos-wolfram-alpha-solverOptional, free key at developer.wolframalpha.com, and a demo key ships in the plugin
ovos-weather-toolsWeatherToolBoxget_current_weather, get_daily_forecast, get_hourly_forecastovos-skill-weatherNone, Open-Meteo public API
ovos-datetime-toolsDateTimeToolBoxget_current_datetime, convert_timezone, get_timezone_for_locationovos-skill-date-timeNone, stdlib + pytz
ovos-ip-toolsIPAddressToolBoxget_local_ip_addresses, get_public_ipovos-skill-ipNone
ovos-iss-toolsISSLocationToolBoxget_iss_position, get_iss_crewovos-skill-iss-locationOptional, geonames.org user for reverse geocoding
ovos-speedtest-toolsSpeedTestToolBoxrun_speedtestovos-skill-speedtestNone, Speedtest.net
ovos-wallpapers-toolsWallpapersToolBoxsearch_wallpapersovos-skill-wallpapersNone, wallhaven.cc public API
ovos-wikihow-toolsWikiHowToolBoxsearch_wikihow, get_wikihow_stepsovos-skill-wikihowNone, pywikihow scraper
ovos-wordnet-toolsWordNetToolBoxlookup_word, define_wordovos-skill-wordnetNone, local NLTK corpus
ovos-skill-md-toolboxSkillMDToolBoxdynamic: one tool per installed SKILL.mdovos-agentic-loopRequires a configured ChatEngine (brain)
ovos-filesystem-toolsFileSystemToolBoxread_file, write_file, list_directory, search_in_files, find_filesovos-agentic-loopNone
ovos-shell-toolsShellToolBoxrun_commandovos-agentic-loopNone
ovos-web-search-toolsWebSearchToolBoxweb_searchovos-agentic-loopNone
ovos-clock-toolsClockToolBoxget_current_datetimeovos-agentic-loopNone

Tool schema

Each AgentTool (agent_tools.py:40) carries:

  • name: snake_case identifier the LLM uses
  • description: natural-language purpose shown to the LLM
  • argument_schema: Pydantic ToolArguments subclass. JSON Schema is auto-generated from it for LLM tool-calling APIs
  • output_schema: Pydantic ToolOutput subclass, validated on every call
  • tool_call: the Python callable. It receives an instantiated ToolArguments and returns ToolOutput

ToolBox.tool_json_list (agent_tools.py:290) converts all tools to the JSON Schema list format that OpenAI, Anthropic, and Gemini tool-calling endpoints expect.


Available Chat Engines (opm.agents.chat)

Plugin IDClassBackendPackage
ovos-chat-openai-pluginOpenAIChatEngineOpenAI APIovos-openai-plugin
ovos-chat-gemini-pluginGeminiChatEngineGoogle Geminiovos-gemini-plugin
ovos-chat-gemini-code-pluginGeminiCodeChatEngineGemini (code)ovos-gemini-plugin
ovos-chat-gemini-session-pluginGeminiSessionChatEngineGemini (session)ovos-gemini-plugin
ovos-chat-claude-pluginClaudeChatEngineAnthropic Claudeovos-claude-plugin
ovos-chat-claude-code-pluginClaudeCodeChatEngineClaude (code)ovos-claude-plugin
ovos-chat-claude-code-session-pluginClaudeCodeSessionChatEngineClaude (session)ovos-claude-plugin
ovos-chat-kilo-pluginKiloChatEngineKilo (Anthropic)ovos-kilo-plugin
ovos-chat-kilo-session-pluginKiloSessionChatEngineKilo (session)ovos-kilo-plugin
ovos-chat-gguf-pluginGGUFChatEngineLocal GGUF (llama.cpp)ovos-gguf-plugin
ovos-chat-qwen-code-pluginQwenCodeChatEngineQwen-Codeovos-qwen-code-plugin
ovos-chat-opencode-pluginOpenCodeChatEngineOpenCodeovos-opencode-plugin
ovos-chat-opencode-session-pluginOpenCodeSessionChatEngineOpenCode (session)ovos-opencode-plugin
ovos-wikigptWikiGPTSolverWikipedia RAGovos-wikipedia-solver
ovos-react-loopReActLoopEnginePluginReAct over any ChatEngine + ToolBoxesovos-agentic-loop
ovos-plan-execute-loopPlanAndExecuteEnginePluginPlan-and-Executeovos-agentic-loop
ovos-reflexion-loopReflexionEnginePluginReflexionovos-agentic-loop
ovos-self-ask-loopSelfAskEnginePluginSelf-Askovos-agentic-loop
ovos-chain-of-thought-loopChainOfThoughtEnginePluginChain-of-Thoughtovos-agentic-loop
ovos-mos-king-rerankerReRankerKingMoSPluginMixture-of-Solvers (reranker)ovos-MoS
ovos-mos-king-generativeGenerativeKingMoSPluginMoS (generative king)ovos-MoS
ovos-mos-democracyDemocracyMoSPluginMoS (majority vote)ovos-MoS
ovos-mos-duopoly-rerankerReRankerDuopolyMoSPluginMoS (duopoly reranker)ovos-MoS
ovos-mos-duopoly-generativeGenerativeDuopolyMoSPluginMoS (duopoly generative)ovos-MoS

Multimodal Chat Engines (opm.agents.chat.multimodal)

Plugin IDClassBackendPackage
ovos-chat-multimodal-gemini-pluginGeminiMultimodalChatEngineGeminiovos-gemini-plugin
ovos-chat-multimodal-claude-pluginClaudeMultimodalChatEngineClaudeovos-claude-plugin
ovos-chat-multimodal-kilo-pluginKiloMultimodalChatEngineKiloovos-kilo-plugin
ovos-chat-multimodal-qwen-code-pluginQwenCodeMultimodalChatEngineQwen-Codeovos-qwen-code-plugin

ChatEngine.continue_chat signature:

def continue_chat(self, messages: List[AgentMessage],
                  session_id: str = "default",
                  lang: Optional[str] = None,
                  units: Optional[str] = None,
                  tools: Optional[List[Dict[str, Any]]] = None) -> AgentMessage:

ChatEngine also provides stream_tokens, stream_sentences, and get_response helpers. Plugins only need to implement continue_chat.

Tool calling

A conversation can carry tool turns. MessageRole.TOOL is the role of a tool result. AgentMessage carries optional tool fields:

  • tool_calls: Optional[List[ToolCall]]: set on an ASSISTANT message that requests tool invocations (ToolCall(id, name, arguments)). content may be "".
  • tool_call_id / name: set on a TOOL message, and identify the ToolCall it answers.

continue_chat accepts an optional tools argument. Pass ToolBox object(s) directly (preferred), OpenAI tool dicts, or both. The engine coerces the argument with ToolBox.normalize_tools(tools) (see api/agent-tools.md). An engine that can use tools sets the class attribute supports_tools = True, and returns an assistant AgentMessage whose tool_calls are populated when the model requests them. An engine that does not support tools leaves supports_tools = False and ignores the argument. The kwarg is optional, so existing 4-arg continue_chat overrides keep working unchanged.

Providers expect this ordering: an assistant message that carries tool_calls must be followed by one TOOL message per ToolCall.id. The orchestration loop that drives this lives in ovos-agentic-loop (NativeToolCallEngine), not in the provider engines.


Available Personas (opm.plugin.persona)

Each persona entry is a dict that defines chat_engine, system_prompt, and optionally toolboxes. The ovos-persona service loads and wires each entry.

Persona IDBackendPackage
OpenAIovos-chat-openai-pluginovos-openai-plugin
Claudeovos-chat-claude-pluginovos-claude-plugin
Geminiovos-chat-gemini-pluginovos-gemini-plugin
Kiloovos-chat-kilo-pluginovos-kilo-plugin
QwenCodeovos-chat-qwen-code-pluginovos-qwen-code-plugin
OpenCodeovos-chat-opencode-pluginovos-opencode-plugin
WikipediaWikipedia solverovos-wikipedia-solver
WikiGPTovos-wikigptovos-wikipedia-solver
DuckDuckGoDDG solverovos-ddg-solver-plugin
Wolfram AlphaWolfram solverovos-wolfram-alpha-solver
WikiHowWikiHow solverovos-skill-wikihow
WordnetWordNet solverovos-skill-wordnet

How to Implement a ToolBox

Register under opm.agents.toolbox in pyproject.toml:

[project.entry-points."opm.agents.toolbox"]
my-tools = "my_package.toolbox:MyToolBox"

Minimal implementation (agent_tools.py:56):

from ovos_plugin_manager.templates.agent_tools import AgentTool, ToolArguments, ToolBox, ToolOutput
from pydantic import Field

class MyArgs(ToolArguments):
    query: str = Field(..., description="Input text.")

class MyOutput(ToolOutput):
    result: str = Field(..., description="Tool result.")

class MyToolBox(ToolBox):
    def __init__(self, config=None, bus=None):
        super().__init__(toolbox_id="my-tools", config=config, bus=bus)

    def discover_tools(self):
        return [AgentTool(
            name="my_tool",
            description="Does something useful.",
            argument_schema=MyArgs,
            output_schema=MyOutput,
            tool_call=lambda args: MyOutput(result=args.query.upper()),
        )]

ToolBox.call_tool validates input and output against the Pydantic schemas automatically (agent_tools.py:195). discover_tools runs once at init, and again lazily if a tool is not found in the cache (agent_tools.py:104).


How to Implement a ChatEngine

Register under opm.agents.chat in pyproject.toml:

[project.entry-points."opm.agents.chat"]
my-chat-engine = "my_package.chat:MyChatEngine"

Minimal implementation (agents.py:195):

from ovos_plugin_manager.templates.agents import ChatEngine, AgentMessage, MessageRole
from typing import List, Optional

class MyChatEngine(ChatEngine):
    def continue_chat(self, messages: List[AgentMessage],
                      session_id: str = "default",
                      lang: Optional[str] = None,
                      units: Optional[str] = None) -> AgentMessage:
        # messages[-1] is the latest user message
        reply = call_my_llm_api([m.__dict__ for m in messages])
        return AgentMessage(role=MessageRole.ASSISTANT, content=reply)

For streaming, override stream_tokens (token-level) or stream_sentences (sentence-level, TTS-ready) (agents.py:228–278). The default implementations fall back to continue_chat.


Configuration

Config is passed as a plain dict to __init__. OPM reads plugin config from the OVOS Configuration() singleton under the plugin's entry point name. Standard keys used by most agent plugins:

KeyTypeDefaultDescription
langstrsession langBCP-47 language code
system_promptstr""System prompt for AgentContextManager plugins (agents.py:61)
context_ttlint120Seconds before coreference context is pruned (agents.py:598)

Each plugin's module docstring documents its ToolBox-specific keys.


← Voice Cloning · Home