Teach builder to author DeepAgents skills
All checks were successful
build / build (push) Successful in 26s
All checks were successful
build / build (push) Successful in 26s
This commit is contained in:
@@ -2,7 +2,13 @@ from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from agent_builder.builder import SYSTEM_PROMPT
|
||||
from agent_builder.builder import (
|
||||
BUILDER_SKILL_SOURCE,
|
||||
SYSTEM_PROMPT,
|
||||
_builder_skill_files,
|
||||
_with_builder_skills,
|
||||
)
|
||||
from deepagents.backends import StateBackend
|
||||
|
||||
|
||||
class BuilderPromptTests(unittest.TestCase):
|
||||
@@ -17,3 +23,33 @@ class BuilderPromptTests(unittest.TestCase):
|
||||
self.assertIn("class GeneratedDeck(Slide)", SYSTEM_PROMPT)
|
||||
self.assertIn("manim-slides render --CE -ql", SYSTEM_PROMPT)
|
||||
self.assertIn("render: bool = False", SYSTEM_PROMPT)
|
||||
|
||||
def test_prompt_and_backend_load_packaged_builder_skills(self) -> None:
|
||||
expected = {
|
||||
"deepagent-agent-design",
|
||||
"a2apack-agent-authoring",
|
||||
"deepagents-implementation-patterns",
|
||||
"workspace-artifact-safety",
|
||||
"agent-quality-review",
|
||||
}
|
||||
for skill_name in expected:
|
||||
self.assertIn(skill_name, SYSTEM_PROMPT)
|
||||
self.assertIn("deepagent-agent-design", SYSTEM_PROMPT)
|
||||
self.assertIn("write_agent_skill", SYSTEM_PROMPT)
|
||||
self.assertIn("workspace_access = WorkspaceAccess.dynamic", SYSTEM_PROMPT)
|
||||
|
||||
files = _builder_skill_files()
|
||||
self.assertTrue(
|
||||
{path.split("/", 1)[0] for path in files}.issuperset(expected)
|
||||
)
|
||||
self.assertIn("skills=[RUNTIME_SKILLS_ROOT]", files["deepagent-agent-design/SKILL.md"])
|
||||
self.assertIn("from a2a_pack import", files["a2apack-agent-authoring/SKILL.md"])
|
||||
self.assertIn("create_deep_agent", files["deepagents-implementation-patterns/SKILL.md"])
|
||||
self.assertIn("ctx.write_artifact", files["workspace-artifact-safety/SKILL.md"])
|
||||
self.assertIn("live_skills[].input_schema", files["agent-quality-review/SKILL.md"])
|
||||
|
||||
backend = _with_builder_skills(StateBackend())
|
||||
listing = backend.ls(BUILDER_SKILL_SOURCE)
|
||||
paths = [entry["path"] for entry in (listing.entries or [])]
|
||||
for skill_name in expected:
|
||||
self.assertIn(f"{BUILDER_SKILL_SOURCE}{skill_name}/", paths)
|
||||
|
||||
@@ -6,10 +6,13 @@ import unittest
|
||||
|
||||
from agent_builder.tools import (
|
||||
_BUILDER_STATE_FILE,
|
||||
_BUILDER_INTERNAL_PREFIX,
|
||||
_deployment_drift_error,
|
||||
_files_from_tarball,
|
||||
_parse_supporting_skill_files,
|
||||
_replace_workspace_files,
|
||||
_render_a2a_init_template,
|
||||
_render_skill_md,
|
||||
_tarball_workspace_dir,
|
||||
)
|
||||
|
||||
@@ -25,6 +28,9 @@ class TemplateInitTests(unittest.TestCase):
|
||||
self.assertIn('name = "research-agent"', files["agent.py"])
|
||||
self.assertIn('description = "Research helper"', files["agent.py"])
|
||||
self.assertIn("LLMProvisioning.CALLER_PROVIDED", files["agent.py"])
|
||||
self.assertIn("WorkspaceAccess.dynamic", files["agent.py"])
|
||||
self.assertIn("RUNTIME_SKILLS_ROOT", files["agent.py"])
|
||||
self.assertIn("skills=skill_sources or None", files["agent.py"])
|
||||
self.assertIn("ctx.llm", files["agent.py"])
|
||||
self.assertIn("ctx.workspace_backend()", files["agent.py"])
|
||||
self.assertIn("create_deep_agent", files["agent.py"])
|
||||
@@ -85,6 +91,7 @@ class TemplateInitTests(unittest.TestCase):
|
||||
s3 = _FakeS3({
|
||||
prefix + "agent.py": b"print('ok')\n",
|
||||
prefix + _BUILDER_STATE_FILE: b'{"repo_head_sha":"abc1234"}',
|
||||
prefix + _BUILDER_INTERNAL_PREFIX + "skills/x/SKILL.md": b"hidden",
|
||||
})
|
||||
|
||||
bundle = _tarball_workspace_dir(s3, "bucket", prefix)
|
||||
@@ -92,6 +99,29 @@ class TemplateInitTests(unittest.TestCase):
|
||||
with tarfile.open(fileobj=io.BytesIO(bundle), mode="r:gz") as tf:
|
||||
self.assertEqual(tf.getnames(), ["agent.py"])
|
||||
|
||||
def test_render_skill_md_creates_valid_frontmatter(self) -> None:
|
||||
text = _render_skill_md(
|
||||
"market-research",
|
||||
"Plan market research and synthesize findings.",
|
||||
"Use subagents for separate market segments.",
|
||||
)
|
||||
|
||||
self.assertIn("name: market-research", text)
|
||||
self.assertIn('description: "Plan market research', text)
|
||||
self.assertIn("# market-research", text)
|
||||
|
||||
def test_parse_supporting_skill_files_rejects_unsafe_paths(self) -> None:
|
||||
with self.assertRaises(ValueError):
|
||||
_parse_supporting_skill_files('{"../secrets.txt": "bad"}')
|
||||
|
||||
files = _parse_supporting_skill_files(
|
||||
'{"references/schema.md": "schema", "scripts/check.py": "print(1)"}'
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(files),
|
||||
["references/schema.md", "scripts/check.py"],
|
||||
)
|
||||
|
||||
def test_files_from_tarball_rejects_unsafe_paths(self) -> None:
|
||||
bundle = _tarball({"../agent.py": "bad"})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user