Files
openworker/tests/test_skills.py
T
Rohit C Prasad 1299760400 Personas: requires_folder/subagents/scheduling traits replace family and the workspace enum
Manifest keeps a legacy family shim; telemetry wire fields unchanged.
No behavior change; spec in ocw-context/docs/workspace-scratch-design.md.
2026-08-20 21:19:56 -07:00

105 lines
3.4 KiB
Python

"""Agents (Code/Chat) + SKILL.md loader (catalog + load_skill)."""
from __future__ import annotations
from coworker.agent import build_engine
from coworker.agents import AgentContext, chat_agent, code_agent, get_agent
from coworker.providers import ModelCapabilities
from coworker.skills import SkillLoader, skill_catalog_text, skill_tools
from coworker.tools import ToolRegistry
from coworker.tools.shell import LocalExecutor
from coworker.tools.todo import TodoList
class _Stub:
def complete(self, **kwargs): # pragma: no cover
raise NotImplementedError
def capabilities(self, model):
return ModelCapabilities()
# -- agents ---------------------------------------------------------------------
def test_code_agent_tools(tmp_path):
ex = LocalExecutor(cwd=tmp_path, default_timeout=5)
try:
ctx = AgentContext(workspace=tmp_path, executor=ex, todo=TodoList())
names = {getattr(t, "__name__", "?") for t in code_agent().build_tools(ctx)}
assert {
"read_file",
"write_file",
"git_status",
"run_shell",
"todo_write",
} <= names
finally:
ex.close()
def test_chat_agent_has_no_workspace_tools():
assert chat_agent().build_tools(AgentContext()) == []
assert chat_agent().requires_folder is False
assert code_agent().requires_folder is True
def test_get_agent_fallback():
# Chat is removed (owner 2026-08-21): its id, like any unknown id, falls back to
# the default persona per the registry.
assert get_agent("chat").name == "cowork"
assert get_agent("nope").name == "cowork"
# -- SKILL.md loader ------------------------------------------------------------
def _make_skill(skills_dir, name, desc, body):
d = skills_dir / name
d.mkdir(parents=True)
(d / "SKILL.md").write_text(
f"---\nname: {name}\ndescription: {desc}\n---\n{body}", encoding="utf-8"
)
def test_skill_loader_catalog_and_load(tmp_path):
skills_dir = tmp_path / "skills"
_make_skill(
skills_dir, "pdf", "extract text from PDFs", "Use pdfplumber to extract text."
)
loader = SkillLoader([skills_dir])
assert loader.catalog() == [
{"name": "pdf", "description": "extract text from PDFs"}
]
assert "pdf: extract text from PDFs" in skill_catalog_text(loader)
reg = ToolRegistry()
reg.register_all(skill_tools(loader))
loaded = reg.execute("load_skill", {"name": "pdf"})
assert "pdfplumber" in loaded["instructions"]
assert reg.execute("load_skill", {"name": "missing"})["error"]
# -- engine assembly per agent --------------------------------------------------
def test_build_engine_chat(tmp_path):
engine = build_engine(agent=chat_agent(), provider=_Stub())
assert "load_skill" in engine.registry.names()
assert "read_file" not in engine.registry.names()
assert engine.executor is None
assert engine.agent_name == "chat"
def test_build_engine_code_has_agents_md_and_skills(tmp_path):
(tmp_path / "AGENTS.md").write_text("PROJECT RULE: prefer pathlib.")
engine = build_engine(agent=code_agent(), workspace=tmp_path, provider=_Stub())
try:
assert "prefer pathlib" in engine.messages[0]["content"]
assert "todo_write" in engine.registry.names()
assert "load_skill" in engine.registry.names()
assert engine.agent_name == "code"
finally:
engine.executor.close()