Merge pull request #760 from Molecule-AI/refactor/issue-741-extract-medo-plugin

refactor(#741): extract medo.py from builtin_tools to opt-in plugin
This commit is contained in:
molecule-ai[bot] 2026-04-17 16:21:32 +00:00 committed by GitHub
commit 0f94fb2443
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 68 additions and 16 deletions

4
.gitignore vendored
View File

@ -125,5 +125,7 @@ org-templates/**/.auth-token
# Cloned-via-manifest dirs — populated locally by scripts/clone-manifest.sh,
# tracked in their own standalone repos. Never commit to core.
/org-templates/
/plugins/
/plugins/*
# Exception: molecule-medo lives here until it gets its own standalone repo.
!/plugins/molecule-medo/
/workspace-configs-templates/

View File

@ -0,0 +1,6 @@
name: molecule-medo
version: 0.1.0
description: Baidu MeDo no-code AI platform integration (hackathon / China-region)
author: Molecule AI
tags: [hackathon, baidu, medo, china]
runtimes: [claude_code, deepagents, langgraph]

View File

@ -0,0 +1,27 @@
---
name: MeDo Tools
description: >
Create, update, and publish applications on Baidu MeDo (摩搭), a no-code AI
application builder. Used in the Molecule AI hackathon integration (May 2026).
tags: [hackathon, baidu, medo, china, no-code]
examples:
- "Create a chatbot app on MeDo called 'Customer Support'"
- "Update the content of my MeDo app abc123"
- "Publish my MeDo app to production"
---
# MeDo Tools
Provides three tools for interacting with the Baidu MeDo no-code platform:
- **create_medo_app** — Scaffold a new application from a template (blank, chatbot, form, dashboard).
- **update_medo_app** — Push content or configuration changes to an existing application.
- **publish_medo_app** — Publish a draft application to production or staging.
## Setup
Set `MEDO_API_KEY` as a workspace secret. Optionally override the base URL via `MEDO_BASE_URL`
(default: `https://api.moda.baidu.com/v1`).
When `MEDO_API_KEY` is absent the tools run in mock mode and return stub responses — safe for
local development and testing.

View File

@ -1,4 +1,4 @@
"""MeDo builtin tools — Baidu MeDo no-code AI platform integration.
"""MeDo tools — Baidu MeDo no-code AI platform integration.
MeDo (摩搭, moda.baidu.com) is Baidu's no-code AI application builder used in
the Molecule AI hackathon integration (May 2026). Three core operations:

View File

@ -0,0 +1,21 @@
"""Minimal conftest for molecule-medo plugin tests.
langchain_core is a declared dependency of workspace-template (>=0.3.0) and
is expected to be present in the test environment. If it is absent, mock it
so the @tool decorator in medo.py is a no-op and the tests can still run.
"""
import sys
from types import ModuleType
def _mock_langchain_if_missing():
if "langchain_core" not in sys.modules:
lc_mod = ModuleType("langchain_core")
lc_tools_mod = ModuleType("langchain_core.tools")
lc_tools_mod.tool = lambda f: f # @tool becomes identity decorator
sys.modules["langchain_core"] = lc_mod
sys.modules["langchain_core.tools"] = lc_tools_mod
_mock_langchain_if_missing()

View File

@ -1,16 +1,11 @@
"""Tests for workspace-template/builtin_tools/medo.py.
"""Tests for plugins/molecule-medo/skills/medo-tools/scripts/medo.py.
All tests exercise the mock backend (no MEDO_API_KEY required).
NOTE: conftest.py mocks builtin_tools with __path__=[] and mocks
langchain_core.tools.tool as a no-op (lambda f: f) so adapters can be
imported without heavy deps. Consequence: direct package import of
builtin_tools.medo is blocked (empty __path__ prevents filesystem
lookup), and @tool returns the raw async function rather than a LangChain
StructuredTool so .ainvoke() is unavailable.
Fix: load medo.py via importlib (bypasses the mock package root) and
call functions directly, not via .ainvoke().
NOTE: @tool is a LangChain decorator that returns a StructuredTool rather than
the raw async function. conftest.py mocks langchain_core.tools.tool as an
identity decorator so that calling the functions directly (without .ainvoke())
works in tests matching the original test approach.
"""
import importlib.util
@ -19,14 +14,15 @@ from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
_MEDO_PATH = ROOT / "builtin_tools" / "medo.py"
# plugin root: plugins/molecule-medo/
_PLUGIN_ROOT = Path(__file__).resolve().parents[1]
_MEDO_PATH = _PLUGIN_ROOT / "skills" / "medo-tools" / "scripts" / "medo.py"
def _load_medo():
spec = importlib.util.spec_from_file_location("builtin_tools.medo", _MEDO_PATH)
spec = importlib.util.spec_from_file_location("medo_plugin_tools", _MEDO_PATH)
mod = importlib.util.module_from_spec(spec)
sys.modules["builtin_tools.medo"] = mod # register before exec to handle self-refs
sys.modules["medo_plugin_tools"] = mod # register before exec to handle self-refs
spec.loader.exec_module(mod)
return mod