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,15 +2,23 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from deepagents import create_deep_agent
|
||||
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
|
||||
from deepagents.backends.utils import create_file_data
|
||||
from langchain_openai import ChatOpenAI
|
||||
from langgraph.store.memory import InMemoryStore
|
||||
|
||||
from .config import Settings, load_settings
|
||||
from .tools import ToolContext, build_tools
|
||||
|
||||
|
||||
BUILDER_SKILL_SOURCE = "/.agent-builder/skills/"
|
||||
_BUILDER_SKILL_NAMESPACE = ("agent-builder", "skills")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BuilderContext:
|
||||
bucket: str
|
||||
@@ -38,6 +46,13 @@ small tool-calling DeepAgent with ``create_deep_agent`` plus
|
||||
``wrap_model_call`` middleware. Do not recreate this from memory: call
|
||||
``init_agent_template`` first and modify the generated files.
|
||||
|
||||
You have packaged DeepAgents skills loaded from ``/.agent-builder/skills/``.
|
||||
Use ``deepagent-agent-design`` before designing generated agent internals,
|
||||
``a2apack-agent-authoring`` when shaping the public A2A class and Card,
|
||||
``deepagents-implementation-patterns`` when wiring tools/subagents/skills,
|
||||
``workspace-artifact-safety`` when files or artifacts are involved, and
|
||||
``agent-quality-review`` before the final sandbox test/deploy pass.
|
||||
|
||||
The generated ``a2a.yaml`` looks like:
|
||||
|
||||
```yaml
|
||||
@@ -107,6 +122,13 @@ Your tools:
|
||||
- write_agent_file(name, path, content)
|
||||
— save agent.py / a2a.yaml / requirements.txt
|
||||
- read_agent_file(name, path) — re-read a file (for iteration)
|
||||
- write_agent_skill(name, skill_name, description, instructions,
|
||||
supporting_files_json="{}")
|
||||
— create ``skills/<skill_name>/SKILL.md``
|
||||
plus optional bundled resources for a
|
||||
generated DeepAgent. Use this for rich
|
||||
behavior before wiring ``skills=[...]``
|
||||
in agent.py.
|
||||
- test_agent_in_sandbox(name) — pip install + ``a2a card`` round-trip;
|
||||
check exit_code == 0 and the card JSON
|
||||
looks right
|
||||
@@ -150,6 +172,14 @@ Discipline:
|
||||
generated files instead of inventing boilerplate from memory.
|
||||
- Ensure all three core files (agent.py, a2a.yaml, requirements.txt)
|
||||
exist before testing — partial scaffolds break ``a2a card``.
|
||||
- For non-trivial agents, create one or more DeepAgents skills under
|
||||
``skills/<skill-name>/`` and wire ``create_deep_agent(..., skills=[...])``.
|
||||
Do not replace LLM reasoning with fake deterministic tools that return
|
||||
canned answers. Tools should do exact work; skills and subagents should
|
||||
carry reusable workflow knowledge and judgement-heavy behavior.
|
||||
- If generated agent.py calls ``ctx.workspace_backend()``, declare
|
||||
``workspace_access = WorkspaceAccess.dynamic(...)`` on the A2A agent class
|
||||
so local/dev/platform invocations actually receive a workspace grant.
|
||||
- Always run test_agent_in_sandbox before deploying. If exit_code != 0,
|
||||
read stderr, edit the offending file, retest. Do NOT deploy a broken
|
||||
scaffold.
|
||||
@@ -188,6 +218,7 @@ def build_agent_builder(ctx: BuilderContext) -> Any:
|
||||
backend = _build_project_backend(ctx, settings=settings)
|
||||
if backend is not None:
|
||||
kwargs["backend"] = backend
|
||||
kwargs["skills"] = [BUILDER_SKILL_SOURCE]
|
||||
return create_deep_agent(**kwargs)
|
||||
|
||||
|
||||
@@ -199,16 +230,16 @@ def _build_project_backend(ctx: BuilderContext, *, settings: Settings) -> Any |
|
||||
LangGraph state. Scope it to the project prefix, not the whole bucket.
|
||||
"""
|
||||
if not ctx.project_prefix:
|
||||
return None
|
||||
return _with_builder_skills(StateBackend())
|
||||
prefix = ctx.project_prefix.strip("/")
|
||||
if not prefix:
|
||||
return None
|
||||
return _with_builder_skills(StateBackend())
|
||||
try:
|
||||
from a2a_pack import Grant, WorkspaceAccess, WorkspaceMode
|
||||
from a2a_pack.deepagents import WorkspaceBackend
|
||||
from a2a_pack.workspace import MinIOWorkspaceClient
|
||||
except Exception: # noqa: BLE001
|
||||
return None
|
||||
return _with_builder_skills(StateBackend())
|
||||
|
||||
workspace = MinIOWorkspaceClient(
|
||||
bucket=ctx.bucket,
|
||||
@@ -234,4 +265,33 @@ def _build_project_backend(ctx: BuilderContext, *, settings: Settings) -> Any |
|
||||
outputs_prefix=None,
|
||||
)
|
||||
)
|
||||
return WorkspaceBackend(workspace)
|
||||
return _with_builder_skills(WorkspaceBackend(workspace))
|
||||
|
||||
|
||||
def _with_builder_skills(default_backend: Any) -> Any:
|
||||
skill_store = InMemoryStore()
|
||||
for path, content in _builder_skill_files().items():
|
||||
skill_store.put(
|
||||
_BUILDER_SKILL_NAMESPACE,
|
||||
"/" + path,
|
||||
create_file_data(content),
|
||||
)
|
||||
skill_backend = StoreBackend(
|
||||
store=skill_store,
|
||||
namespace=lambda _runtime: _BUILDER_SKILL_NAMESPACE,
|
||||
)
|
||||
return CompositeBackend(
|
||||
default=default_backend,
|
||||
routes={BUILDER_SKILL_SOURCE: skill_backend},
|
||||
)
|
||||
|
||||
|
||||
def _builder_skill_files() -> dict[str, str]:
|
||||
root = Path(__file__).with_name("skills")
|
||||
files: dict[str, str] = {}
|
||||
if not root.exists():
|
||||
return files
|
||||
for path in root.rglob("*"):
|
||||
if path.is_file():
|
||||
files[path.relative_to(root).as_posix()] = path.read_text(encoding="utf-8")
|
||||
return files
|
||||
|
||||
Reference in New Issue
Block a user