Configure subagent profiles from runtime files

This commit is contained in:
jxxghp
2026-06-14 10:27:26 +08:00
parent 25dbe491fe
commit 0f3e9574ab
11 changed files with 549 additions and 148 deletions

View File

@@ -45,6 +45,22 @@ class TestAgentRuntimeConfig(unittest.TestCase):
/ "PERSONA.md"
).exists()
)
self.assertTrue(
(
self.agent_root
/ "runtime"
/ "subagents"
/ "general-purpose"
/ "SUBAGENT.md"
).exists()
)
self.assertIn(
"media-researcher",
[
subagent.subagent_id
for subagent in runtime_config.available_subagents
],
)
def test_legacy_root_markdown_is_migrated_to_memory_directory(self):
self.agent_root.mkdir(parents=True, exist_ok=True)
@@ -109,6 +125,8 @@ class TestAgentRuntimeConfig(unittest.TestCase):
self.assertIn("<agent_persona>", sections)
self.assertIn("Active persona: `default`", sections)
self.assertIn("`guide`", sections)
self.assertIn("Available subagents:", sections)
self.assertIn("`media-researcher`", sections)
def test_set_active_persona_supports_id_and_alias(self):
manager = self._manager()

View File

@@ -0,0 +1,172 @@
import textwrap
from pathlib import Path
from app.agent.runtime import AgentRuntimeManager
import app.agent.middleware.subagents as subagent_module
def _write_current_persona(defaults_root: Path) -> None:
"""写入最小可用的人格激活配置。"""
defaults_root.mkdir(parents=True, exist_ok=True)
(defaults_root / "CURRENT_PERSONA.md").write_text(
textwrap.dedent(
"""\
---
version: 3
active_persona: default
extra_context_files: []
deprecated_phrases: []
---
# CURRENT_PERSONA
"""
),
encoding="utf-8",
)
persona_dir = defaults_root / "personas" / "default"
persona_dir.mkdir(parents=True, exist_ok=True)
(persona_dir / "PERSONA.md").write_text(
textwrap.dedent(
"""\
---
version: 1
persona_id: default
label: 默认
description: 默认人格
aliases: []
---
# PERSONA
测试人格。
"""
),
encoding="utf-8",
)
def _write_subagent(
root: Path,
subagent_id: str,
*,
version: int = 1,
description: str = "测试子代理",
body: str = "测试子代理提示。",
) -> Path:
"""写入一个子代理定义文件。"""
subagent_dir = root / "subagents" / subagent_id
subagent_dir.mkdir(parents=True, exist_ok=True)
path = subagent_dir / "SUBAGENT.md"
path.write_text(
textwrap.dedent(
f"""\
---
version: {version}
subagent_id: {subagent_id}
label: 测试
description: {description}
include_tags:
- media
- web
exclude_tags:
- write
- message
---
# SUBAGENT
{body}
"""
),
encoding="utf-8",
)
return path
def test_runtime_syncs_and_parses_subagent_definitions(tmp_path):
"""运行时应同步并解析 defaults/subagents 下的子代理定义。"""
defaults_root = tmp_path / "defaults"
_write_current_persona(defaults_root)
_write_subagent(
defaults_root,
"custom-reader",
description="Custom reader subagent.",
body="Only inspect custom media signals.",
)
manager = AgentRuntimeManager(
agent_root_dir=tmp_path / "agent",
bundled_defaults_dir=defaults_root,
)
runtime_config = manager.load_runtime_config()
copied_path = (
tmp_path
/ "agent"
/ "runtime"
/ "subagents"
/ "custom-reader"
/ "SUBAGENT.md"
)
subagent = runtime_config.available_subagents[0]
assert copied_path.exists()
assert subagent.subagent_id == "custom-reader"
assert subagent.description == "Custom reader subagent."
assert subagent.include_tags == ["media", "web"]
assert subagent.exclude_tags == ["write", "message"]
assert "Only inspect custom media signals." in subagent.text
def test_runtime_updates_bundled_subagent_when_version_increases(tmp_path):
"""内置子代理版本升高时应覆盖用户目录里的旧版副本。"""
defaults_root = tmp_path / "defaults"
_write_current_persona(defaults_root)
_write_subagent(
defaults_root,
"custom-reader",
version=1,
body="version one",
)
manager = AgentRuntimeManager(
agent_root_dir=tmp_path / "agent",
bundled_defaults_dir=defaults_root,
)
manager.ensure_layout()
_write_subagent(
defaults_root,
"custom-reader",
version=2,
body="version two",
)
manager.invalidate_cache()
runtime_config = manager.load_runtime_config()
subagent = runtime_config.available_subagents[0]
assert subagent.version == 2
assert "version two" in subagent.text
def test_middleware_profiles_are_loaded_from_runtime_config(monkeypatch, tmp_path):
"""子代理中间件应从运行时 YAML 定义生成 profile。"""
defaults_root = tmp_path / "defaults"
_write_current_persona(defaults_root)
_write_subagent(
defaults_root,
"custom-reader",
description="Runtime custom reader.",
body="Runtime-only prompt.",
)
manager = AgentRuntimeManager(
agent_root_dir=tmp_path / "agent",
bundled_defaults_dir=defaults_root,
)
monkeypatch.setattr(subagent_module, "agent_runtime_manager", manager)
subagent_module._builtin_subagent_profiles.cache_clear()
subagent_module.builtin_subagent_names.cache_clear()
profiles = subagent_module._builtin_subagent_profiles()
assert [profile.name for profile in profiles] == ["custom-reader"]
assert profiles[0].description == "Runtime custom reader."
assert profiles[0].include_tags == frozenset({"media", "web"})
assert "Runtime-only prompt." in profiles[0].prompt