initial: deepagents-driven agent generator + deployer
All checks were successful
build / build (push) Successful in 31s
All checks were successful
build / build (push) Successful in 31s
This commit is contained in:
114
agent_builder/builder.py
Normal file
114
agent_builder/builder.py
Normal file
@@ -0,0 +1,114 @@
|
||||
"""Build the inner deepagents graph that writes + tests + deploys a new agent."""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from deepagents import create_deep_agent
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
from .config import Settings, load_settings
|
||||
from .tools import ToolContext, build_tools
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BuilderContext:
|
||||
bucket: str
|
||||
cp_jwt: str | None = None
|
||||
settings: Settings | None = None
|
||||
# Optional caller-provided LLM creds (when the outer platform Card
|
||||
# declares llm_provisioning=caller_provided). Falls back to settings.
|
||||
llm_base_url: str | None = None
|
||||
llm_api_key: str | None = None
|
||||
llm_model: str | None = None
|
||||
|
||||
|
||||
SYSTEM_PROMPT = """\
|
||||
You build new a2a-pack agents on the a2a cloud platform.
|
||||
|
||||
Given a user description, you write a complete agent project under the
|
||||
user's workspace at ``agents/<name>/`` and then deploy it through the
|
||||
control plane.
|
||||
|
||||
What an a2a-pack agent looks like:
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
from a2a_pack import A2AAgent, NoAuth, RunContext, skill
|
||||
|
||||
|
||||
class <Name>Config(BaseModel):
|
||||
pass
|
||||
|
||||
|
||||
class <Name>(A2AAgent[<Name>Config, NoAuth]):
|
||||
name = "<slug>"
|
||||
description = "..."
|
||||
version = "0.1.0"
|
||||
config_model = <Name>Config
|
||||
auth_model = NoAuth
|
||||
|
||||
@skill(description="...", tags=["..."])
|
||||
async def <skill>(self, ctx: RunContext[NoAuth], ...) -> dict:
|
||||
await ctx.emit_progress("...")
|
||||
return {"ok": True, "...": "..."}
|
||||
```
|
||||
|
||||
You ALSO need an ``a2a.yaml`` like:
|
||||
|
||||
```yaml
|
||||
name: <slug>
|
||||
version: 0.1.0
|
||||
entrypoint: agent:<Name>
|
||||
description: <one line>
|
||||
expose:
|
||||
public: true
|
||||
```
|
||||
|
||||
And a ``requirements.txt`` listing any extra deps beyond a2a-pack
|
||||
itself (pandas, httpx, etc. — the base image ships a2a-pack already
|
||||
when you deploy through the control plane).
|
||||
|
||||
Your tools:
|
||||
|
||||
- list_agent_files(name) — see what's already at agents/<name>/
|
||||
- write_agent_file(name, path, content)
|
||||
— save agent.py / a2a.yaml / requirements.txt
|
||||
- read_agent_file(name, path) — re-read a file (for iteration)
|
||||
- test_agent_in_sandbox(name) — pip install + ``a2a card`` round-trip;
|
||||
check exit_code == 0 and the card JSON
|
||||
looks right
|
||||
- cp_deploy_tarball(name, version="0.1.0", public=True)
|
||||
— ship it to the platform; returns the
|
||||
public URL
|
||||
|
||||
Discipline:
|
||||
|
||||
- Pick a kebab-case slug for ``name`` (e.g. ``research-agent``,
|
||||
``csv-sanitizer``). Class name is PascalCase from the slug.
|
||||
- Write ALL THREE files (agent.py, a2a.yaml, requirements.txt) before
|
||||
testing — partial scaffolds break ``a2a card``.
|
||||
- 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.
|
||||
- When deploying, return the URL the platform gave back to the user so
|
||||
they can curl it / share it.
|
||||
- Don't fabricate functionality the user didn't ask for. One or two
|
||||
well-scoped @skill methods beats a kitchen sink.
|
||||
"""
|
||||
|
||||
|
||||
def build_agent_builder(ctx: BuilderContext) -> Any:
|
||||
settings = ctx.settings or load_settings()
|
||||
tools = build_tools(ToolContext(
|
||||
bucket=ctx.bucket, settings=settings, cp_jwt=ctx.cp_jwt,
|
||||
))
|
||||
model = ChatOpenAI(
|
||||
model=ctx.llm_model or settings.litellm_model,
|
||||
base_url=ctx.llm_base_url or (settings.litellm_url + "/v1"),
|
||||
api_key=ctx.llm_api_key or settings.litellm_key,
|
||||
temperature=0.0,
|
||||
)
|
||||
return create_deep_agent(
|
||||
model=model, tools=tools, system_prompt=SYSTEM_PROMPT,
|
||||
)
|
||||
Reference in New Issue
Block a user