Teach agent builder packed frontends
All checks were successful
build / build (push) Successful in 25s
All checks were successful
build / build (push) Successful in 25s
This commit is contained in:
@@ -9,6 +9,7 @@ from agent_builder.builder import (
|
||||
_builder_skill_files,
|
||||
_with_builder_skills,
|
||||
)
|
||||
from agent_builder.tools import A2A_PACK_MIN_VERSION
|
||||
from deepagents.backends import StateBackend
|
||||
|
||||
|
||||
@@ -28,9 +29,18 @@ class BuilderPromptTests(unittest.TestCase):
|
||||
"agent_builder/config.py"
|
||||
).read_text()
|
||||
|
||||
self.assertIn('sandbox_timeout_s=int(os.environ.get("SANDBOX_TIMEOUT_S", "1200"))', config_source)
|
||||
self.assertIn('os.environ.get("A2A_SANDBOX_TIMEOUT_S")', config_source)
|
||||
self.assertIn('os.environ.get("SANDBOX_TIMEOUT_S", "1200")', config_source)
|
||||
self.assertIn('deploy_wait_timeout_s=int(os.environ.get("DEPLOY_WAIT_TIMEOUT_S", "900"))', config_source)
|
||||
|
||||
def test_builder_requires_frontend_capable_a2a_pack(self) -> None:
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
requirements = root.joinpath("requirements.txt").read_text()
|
||||
tools_source = root.joinpath("agent_builder/tools.py").read_text()
|
||||
|
||||
self.assertIn(f"a2a-pack>={A2A_PACK_MIN_VERSION}", requirements)
|
||||
self.assertIn("a2a-pack>={A2A_PACK_MIN_VERSION}", tools_source)
|
||||
|
||||
def test_prompt_requires_resource_mirror_for_heavy_agents(self) -> None:
|
||||
self.assertIn("declare resources in BOTH places", SYSTEM_PROMPT)
|
||||
self.assertIn("resources = Resources", SYSTEM_PROMPT)
|
||||
@@ -50,6 +60,15 @@ class BuilderPromptTests(unittest.TestCase):
|
||||
self.assertIn("outputs/rootfs-captures/...", SYSTEM_PROMPT)
|
||||
self.assertIn("not workspace-mounted or rootfs-captured", SYSTEM_PROMPT)
|
||||
|
||||
def test_prompt_knows_packed_frontend_contract(self) -> None:
|
||||
self.assertIn('init_agent_template(..., frontend="react")', SYSTEM_PROMPT)
|
||||
self.assertIn("frontend:", SYSTEM_PROMPT)
|
||||
self.assertIn("mount: /app", SYSTEM_PROMPT)
|
||||
self.assertIn("/app/config.json", SYSTEM_PROMPT)
|
||||
self.assertIn("/app/a2a-client.js", SYSTEM_PROMPT)
|
||||
self.assertIn("https://docs.a2acloud.io/concepts/packed-frontends", SYSTEM_PROMPT)
|
||||
self.assertIn("frontend/src/App.jsx", SYSTEM_PROMPT)
|
||||
|
||||
def test_prompt_and_backend_load_packaged_builder_skills(self) -> None:
|
||||
expected = {
|
||||
"deepagent-agent-design",
|
||||
|
||||
@@ -41,12 +41,58 @@ class TemplateInitTests(unittest.TestCase):
|
||||
self.assertIn("create_deep_agent", files["agent.py"])
|
||||
self.assertIn("name: research-agent", files["a2a.yaml"])
|
||||
self.assertIn("entrypoint: agent:ResearchAgent", files["a2a.yaml"])
|
||||
self.assertNotIn("{{ frontend_block }}", files["a2a.yaml"])
|
||||
self.assertNotIn("frontend:", files["a2a.yaml"])
|
||||
self.assertIn("deepagents>=0.5.0", files["requirements.txt"])
|
||||
|
||||
def test_render_a2a_init_template_can_include_react_frontend(self) -> None:
|
||||
files = _render_a2a_init_template(
|
||||
"chart-agent",
|
||||
description="Chart helper",
|
||||
frontend="react",
|
||||
)
|
||||
|
||||
self.assertTrue(
|
||||
{
|
||||
"agent.py",
|
||||
"a2a.yaml",
|
||||
"requirements.txt",
|
||||
"frontend/package.json",
|
||||
"frontend/index.html",
|
||||
"frontend/vite.config.js",
|
||||
"frontend/src/main.jsx",
|
||||
"frontend/src/App.jsx",
|
||||
"frontend/src/a2a.js",
|
||||
"frontend/src/style.css",
|
||||
}.issubset(files)
|
||||
)
|
||||
self.assertIn("frontend:", files["a2a.yaml"])
|
||||
self.assertIn("build: npm run build", files["a2a.yaml"])
|
||||
self.assertIn("mount: /app", files["a2a.yaml"])
|
||||
self.assertIn("auth: inherit", files["a2a.yaml"])
|
||||
self.assertIn("Skill runner", files["frontend/src/App.jsx"])
|
||||
self.assertIn("callSkill", files["frontend/src/App.jsx"])
|
||||
self.assertIn("CONFIG_URL", files["frontend/src/a2a.js"])
|
||||
self.assertIn('"/invoke": agent', files["frontend/vite.config.js"])
|
||||
|
||||
def test_render_a2a_init_template_can_include_static_frontend(self) -> None:
|
||||
files = _render_a2a_init_template("status-agent", frontend="static")
|
||||
|
||||
self.assertIn("frontend/dist/index.html", files)
|
||||
self.assertIn("frontend:", files["a2a.yaml"])
|
||||
self.assertIn("dist: dist", files["a2a.yaml"])
|
||||
self.assertIn("mount: /app", files["a2a.yaml"])
|
||||
self.assertNotIn("build: npm run build", files["a2a.yaml"])
|
||||
self.assertIn("./a2a-client.js", files["frontend/dist/index.html"])
|
||||
|
||||
def test_render_a2a_init_template_rejects_invalid_names(self) -> None:
|
||||
with self.assertRaises(ValueError):
|
||||
_render_a2a_init_template("Bad Name")
|
||||
|
||||
def test_render_a2a_init_template_rejects_invalid_frontend(self) -> None:
|
||||
with self.assertRaises(ValueError):
|
||||
_render_a2a_init_template("demo-agent", frontend="vue")
|
||||
|
||||
def test_agent_projects_can_diverge_from_template(self) -> None:
|
||||
files = _render_a2a_init_template("regex-explainer")
|
||||
files["agent.py"] = "from a2a_pack import A2AAgent\n"
|
||||
|
||||
Reference in New Issue
Block a user