Refresh local registry for local skill search

This commit is contained in:
who96 2026-03-26 09:18:17 +08:00 committed by Dennis-yxchen
parent f4451aa0ac
commit fb02862d44
2 changed files with 71 additions and 6 deletions

View file

@ -119,7 +119,6 @@ mcp = FastMCP("OpenSpace", **_fastmcp_kwargs)
_openspace_instance = None
_openspace_lock = asyncio.Lock()
_standalone_store = None
_local_skill_registry = None
# Internal state: tracks bot skill directories already registered this session.
_registered_skill_dirs: set = set()
@ -205,11 +204,9 @@ def _get_local_skill_registry():
This avoids initializing the full OpenSpace engine when callers only
want to inspect local skills. It mirrors the skill directory discovery
order used by the full engine, but skips LLM / provider startup.
The registry is rebuilt per call so later local searches can see
newly added skills without requiring a process restart.
"""
global _local_skill_registry
if _local_skill_registry is not None:
return _local_skill_registry
from openspace.config import get_config
from openspace.skill_engine import SkillRegistry
@ -253,7 +250,6 @@ def _get_local_skill_registry():
registry = SkillRegistry(skill_dirs=skill_paths)
registry.discover()
_local_skill_registry = registry
return registry

View file

@ -47,3 +47,72 @@ Find me when querying demo local skill.
item["name"] == "Demo Local Skill"
for item in payload["results"]
)
@pytest.mark.asyncio
async def test_local_search_skills_refreshes_registry_between_calls(monkeypatch, tmp_path):
skill_root = tmp_path / "skills"
first_skill_dir = skill_root / "first-local-skill"
first_skill_dir.mkdir(parents=True)
(first_skill_dir / "SKILL.md").write_text(
"""---
name: First Local Skill
description: First local skill for cache regression coverage
---
First local skill content.
""",
encoding="utf-8",
)
async def forbidden_get_openspace():
pytest.fail("_get_openspace should not run for source='local'")
monkeypatch.setenv("OPENSPACE_HOST_SKILL_DIRS", str(skill_root))
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
monkeypatch.delenv("OPENAI_BASE_URL", raising=False)
monkeypatch.setattr(mcp_server, "_get_openspace", forbidden_get_openspace)
monkeypatch.setattr(
"openspace.cloud.embedding.generate_embedding",
lambda text, api_key=None: None,
)
first_response = await mcp_server.search_skills(
query="first local skill",
source="local",
limit=5,
auto_import=False,
)
first_payload = json.loads(first_response)
assert any(
item["name"] == "First Local Skill"
for item in first_payload["results"]
)
second_skill_dir = skill_root / "second-local-skill"
second_skill_dir.mkdir(parents=True)
(second_skill_dir / "SKILL.md").write_text(
"""---
name: Second Local Skill
description: Second local skill created after the first search
---
Second local skill content.
""",
encoding="utf-8",
)
second_response = await mcp_server.search_skills(
query="second local skill",
source="local",
limit=5,
auto_import=False,
)
second_payload = json.loads(second_response)
assert any(
item["name"] == "Second Local Skill"
for item in second_payload["results"]
)