From 770b53e292de5cf57d6c700f2e8dedd79cc7bd75 Mon Sep 17 00:00:00 2001 From: Alessandro <155005371+3clyp50@users.noreply.github.com> Date: Fri, 22 May 2026 17:03:04 +0200 Subject: [PATCH] Expose connector skill activation Add a protected skills_activate endpoint and context-aware skills_list support so connector clients can activate skills in live chats. Advertise the capability through the connector API. --- plugins/_a0_connector/api/v1/capabilities.py | 1 + .../_a0_connector/api/v1/skills_activate.py | 49 +++++++++++++++++++ plugins/_a0_connector/api/v1/skills_list.py | 9 +++- 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 plugins/_a0_connector/api/v1/skills_activate.py diff --git a/plugins/_a0_connector/api/v1/capabilities.py b/plugins/_a0_connector/api/v1/capabilities.py index 1120a6177..327188119 100644 --- a/plugins/_a0_connector/api/v1/capabilities.py +++ b/plugins/_a0_connector/api/v1/capabilities.py @@ -35,6 +35,7 @@ _OPTIONAL_FEATURES: dict[str, tuple[str, ...]] = { "agent_profile_set": ("api.agent_profile_set",), "agents_list": ("helpers.subagents",), "skills_list": ("helpers.skills", "helpers.files", "helpers.projects", "helpers.runtime"), + "skills_activate": ("helpers.skills", "helpers.persist_chat"), "skills_delete": ("helpers.skills", "helpers.files", "helpers.projects", "helpers.runtime"), "model_presets": ("plugins._model_config.helpers.model_config",), "model_switcher": ("plugins._model_config.helpers.model_config",), diff --git a/plugins/_a0_connector/api/v1/skills_activate.py b/plugins/_a0_connector/api/v1/skills_activate.py new file mode 100644 index 000000000..6c36bdda5 --- /dev/null +++ b/plugins/_a0_connector/api/v1/skills_activate.py @@ -0,0 +1,49 @@ +"""POST /api/plugins/_a0_connector/v1/skills_activate.""" +from __future__ import annotations + +import json +from typing import Any + +from helpers.api import Request, Response +import plugins._a0_connector.api.v1.base as connector_base + + +def _json_error(message: str, status: int) -> Response: + return Response( + response=json.dumps({"ok": False, "error": message}), + status=status, + mimetype="application/json", + ) + + +class SkillsActivate(connector_base.ProtectedConnectorApiHandler): + async def process(self, input: dict, request: Request) -> dict | Response: + from agent import AgentContext + from helpers import skills + from helpers.persist_chat import save_tmp_chat + + context_id = str(input.get("context_id", "") or "").strip() + if not context_id: + return _json_error("context_id is required", 400) + + context = AgentContext.get(context_id) + if context is None: + return _json_error("Context not found", 404) + + entries = skills.normalize_active_skills([input.get("skill")]) + if not entries: + return _json_error("skill is required", 400) + + skill_entry: dict[str, Any] = dict(entries[0]) + try: + active_skills = skills.activate_chat_skill(context.get_agent(), skill_entry) + save_tmp_chat(context) + except ValueError as exc: + return _json_error(str(exc), 400) + + return { + "ok": True, + "context_id": context.id, + "skill": skill_entry, + "active_skills": active_skills, + } diff --git a/plugins/_a0_connector/api/v1/skills_list.py b/plugins/_a0_connector/api/v1/skills_list.py index 320ddd260..7746af0e2 100644 --- a/plugins/_a0_connector/api/v1/skills_list.py +++ b/plugins/_a0_connector/api/v1/skills_list.py @@ -7,10 +7,17 @@ import plugins._a0_connector.api.v1.base as connector_base class SkillsList(connector_base.ProtectedConnectorApiHandler): async def process(self, input: dict, request: Request) -> dict | Response: + from agent import AgentContext from helpers import files, projects, skills + context_id = str(input.get("context_id", "") or "").strip() project_name = str(input.get("project_name", "")).strip() or None - skill_list = skills.list_skill_catalog(project_name=project_name or "") + context = AgentContext.get(context_id) if context_id else None + agent = context.get_agent() if context else None + if context is not None and not project_name: + project_name = projects.get_context_project_name(context) or None + + skill_list = skills.list_skill_catalog(project_name=project_name or "", agent=agent) agent_profile = str(input.get("agent_profile", "")).strip() or None if agent_profile: