feat(board): introduce new board agent templates and restructure existing files

This commit is contained in:
Abhimanyu Saharan
2026-02-15 00:45:28 +05:30
parent 313ce874f9
commit 2084405593
33 changed files with 795 additions and 903 deletions

View File

@@ -10,6 +10,7 @@ from uuid import UUID, uuid4
import pytest
import app.services.openclaw.provisioning_db as agent_service
from app.models.approvals import Approval
@dataclass
@@ -106,7 +107,11 @@ async def test_delete_gateway_main_agent_does_not_require_board_id(
called["delete_lifecycle"] += 1
return "/tmp/openclaw/workspace-gateway-x"
updated_models: list[type[object]] = []
async def _fake_update_where(*_args, **_kwargs) -> None:
if len(_args) >= 2 and isinstance(_args[1], type):
updated_models.append(_args[1])
return None
monkeypatch.setattr(service, "require_agent_access", _no_access_check)
@@ -124,4 +129,5 @@ async def test_delete_gateway_main_agent_does_not_require_board_id(
assert result.ok is True
assert called["delete_lifecycle"] == 1
assert Approval in updated_models
assert session.deleted and session.deleted[0] == agent

View File

@@ -10,6 +10,7 @@ import pytest
import app.services.openclaw.internal.agent_key as agent_key_mod
import app.services.openclaw.provisioning as agent_provisioning
from app.services.souls_directory import SoulRef
from app.services.openclaw.provisioning_db import AgentLifecycleService
from app.services.openclaw.shared import GatewayAgentIdentity
@@ -357,6 +358,68 @@ def test_is_missing_agent_error_matches_gateway_agent_not_found() -> None:
)
def test_select_role_soul_ref_prefers_exact_slug() -> None:
refs = [
SoulRef(handle="team", slug="security"),
SoulRef(handle="team", slug="security-auditor"),
SoulRef(handle="team", slug="security-auditor-pro"),
]
selected = agent_provisioning._select_role_soul_ref(refs, role="Security Auditor")
assert selected is not None
assert selected.slug == "security-auditor"
@pytest.mark.asyncio
async def test_resolve_role_soul_markdown_returns_best_effort(monkeypatch: pytest.MonkeyPatch) -> None:
refs = [SoulRef(handle="team", slug="data-scientist")]
async def _fake_list_refs() -> list[SoulRef]:
return refs
async def _fake_fetch(*, handle: str, slug: str, client=None) -> str:
_ = client
assert handle == "team"
assert slug == "data-scientist"
return "# SOUL.md - Data Scientist"
monkeypatch.setattr(
agent_provisioning.souls_directory,
"list_souls_directory_refs",
_fake_list_refs,
)
monkeypatch.setattr(
agent_provisioning.souls_directory,
"fetch_soul_markdown",
_fake_fetch,
)
markdown, source_url = await agent_provisioning._resolve_role_soul_markdown("Data Scientist")
assert markdown == "# SOUL.md - Data Scientist"
assert source_url == "https://souls.directory/souls/team/data-scientist"
@pytest.mark.asyncio
async def test_resolve_role_soul_markdown_returns_empty_on_directory_error(
monkeypatch: pytest.MonkeyPatch,
) -> None:
async def _fake_list_refs() -> list[SoulRef]:
raise RuntimeError("network down")
monkeypatch.setattr(
agent_provisioning.souls_directory,
"list_souls_directory_refs",
_fake_list_refs,
)
markdown, source_url = await agent_provisioning._resolve_role_soul_markdown("DevOps Engineer")
assert markdown == ""
assert source_url == ""
@pytest.mark.asyncio
async def test_delete_agent_lifecycle_ignores_missing_gateway_agent(monkeypatch) -> None:
class _ControlPlaneStub:

View File

@@ -101,7 +101,7 @@ async def test_gateway_coordination_nudge_success(monkeypatch: pytest.MonkeyPatc
board=board, # type: ignore[arg-type]
actor_agent=actor, # type: ignore[arg-type]
target_agent_id=str(target.id),
message="Please run BOOT.md",
message="Please run session startup checklist",
correlation_id="nudge-corr-id",
)
@@ -169,7 +169,7 @@ async def test_gateway_coordination_nudge_maps_gateway_error(
board=board, # type: ignore[arg-type]
actor_agent=actor, # type: ignore[arg-type]
target_agent_id=str(target.id),
message="Please run BOOT.md",
message="Please run session startup checklist",
correlation_id="nudge-corr-id",
)

View File

@@ -12,9 +12,7 @@ TEMPLATES_DIR = Path(__file__).resolve().parents[1] / "templates"
def test_heartbeat_templates_fit_in_injected_context_limit() -> None:
"""Heartbeat templates must stay under gateway injected-context truncation limit."""
targets = (
"HEARTBEAT_LEAD.md",
"HEARTBEAT_AGENT.md",
"MAIN_HEARTBEAT.md",
"BOARD_HEARTBEAT.md.j2",
)
for name in targets:
size = (TEMPLATES_DIR / name).stat().st_size