This repository has been archived on 2026-06-28. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
agent-builder/agent_builder/skills/a2apack-agent-authoring/SKILL.md
robert 137f84be6a
All checks were successful
build / build (push) Successful in 14s
Use sandbox client for builder validation
2026-06-06 20:25:15 -03:00

210 lines
7.7 KiB
Markdown

---
name: a2apack-agent-authoring
description: Author production a2a-pack agents with clear public @skill schemas, runtime declarations, caller-funded LLM credentials, optional agent BYOK, workspace grants, pricing, resources, and secure platform capabilities. Use when writing or reviewing agent.py for an A2A agent.
---
# A2A Pack Agent Authoring
An A2A agent should expose a small, stable public API and put rich reasoning
inside implementation helpers, DeepAgents skills, or subagents. The public
`@skill` methods are the contract shown on the Agent Card.
## Public Contract
Use `A2AAgent` class attributes for runtime and marketplace behavior:
- `name`, `description`, and `version` identify the agent.
- `config_model` and `auth_model` define agent configuration and caller auth.
- `llm_provisioning` tells the platform where LLM credentials come from.
- `pricing` tells callers what they pay and whether they supply LLM creds.
- `resources`, `egress`, `tools_used`, and `workspace_access` describe runtime
requirements.
- `wants_cp_jwt=True` is only for trusted platform agents. It forwards the
caller's control-plane token.
For hosted generated/user-owned agents that call an LLM, default to
`LLMProvisioning.PLATFORM` with `Pricing(..., caller_pays_llm=True, ...)` so
main-agent handoffs forward the caller's saved LLM credential for the callee.
`LLMProvisioning.CALLER_PROVIDED` is still acceptable for explicit BYOK wording.
Reserve `LLMProvisioning.PLATFORM_OR_CALLER_PROVIDED` for legacy compatibility.
In every mode, read `ctx.llm`;
never read `A2A_LITELLM_KEY`, `OPENAI_API_KEY`, provider keys, or platform
secrets directly. If `ctx.llm.api_key` is empty, return a clear setup/config
result before constructing a model or calling `create_a2a_deep_agent`.
`Pricing` only accepts `price_per_call_usd`, `caller_pays_llm`, and `notes`.
Do not put `runtime.pricing.compute`, `runtime.pricing.total_usd`, `compute=`,
or `total_usd=` in generated `agent.py`; the platform derives those values from
declared `Resources` and billing policy.
Keep each `@skill` method `async`, put `RunContext[...]` immediately after
`self`, and annotate every public argument. Do not use `*args` or `**kwargs`;
they are rejected and would not publish a useful schema.
## Code Example
```python
from __future__ import annotations
from typing import Any
from pydantic import BaseModel
from a2a_pack import (
A2AAgent,
EgressPolicy,
LLMProvisioning,
NoAuth,
Pricing,
Resources,
RunContext,
WorkspaceAccess,
WorkspaceMode,
skill,
)
class ResearchConfig(BaseModel):
default_depth: int = 3
class ResearchAgent(A2AAgent[ResearchConfig, NoAuth]):
name = "research-agent"
description = "Researches a topic and writes a concise cited report."
version = "0.1.0"
config_model = ResearchConfig
auth_model = NoAuth
llm_provisioning = LLMProvisioning.PLATFORM
pricing = Pricing(
price_per_call_usd=0.05,
caller_pays_llm=True,
notes="Uses the caller's saved LLM credential through ctx.llm.",
)
resources = Resources(cpu="1", memory="1Gi", max_runtime_seconds=900)
egress = EgressPolicy(allow_hosts=("api.openai.com",))
tools_used = ("deepagents", "langchain")
workspace_access = WorkspaceAccess.dynamic(
max_files=128,
allowed_modes=(WorkspaceMode.READ_ONLY, WorkspaceMode.READ_WRITE_OVERLAY),
require_reason=False,
)
@skill(
description="Research a topic, save report artifacts, and return a summary",
timeout_seconds=900,
cost_class="llm-heavy",
)
async def research(
self,
ctx: RunContext[NoAuth],
topic: str,
depth: int | None = None,
save_path: str = "outputs/research-report.md",
) -> dict[str, Any]:
creds = ctx.llm
await ctx.emit_progress(f"researching with {creds.model}")
if not creds.api_key:
return {
"summary": "LLM credentials were not available for this run.",
"artifact": None,
"path": save_path,
}
graph = self._build_graph(ctx)
state = await graph.ainvoke(
{
"messages": [
{
"role": "user",
"content": (
f"Research {topic!r} at depth {depth or self.config.default_depth}. "
f"Write the final markdown report to /workspace/{save_path}."
),
}
]
},
config={"recursion_limit": 500},
)
report_text = _last_message_text(state)
ref = await ctx.write_artifact(
"research-summary.md",
report_text.encode("utf-8"),
"text/markdown",
)
await ctx.emit_artifact(ref)
return {"summary": report_text, "artifact": ref.uri, "path": save_path}
```
## Schema Rules
Public arguments become the live A2A input schema. Prefer plain JSON-shaped
types: `str`, `int`, `float`, `bool`, `list[str]`, `dict[str, Any]`, or
Pydantic models. Provide defaults for optional knobs. Avoid exposing internal
implementation details such as model names, temporary paths, prompt fragments,
or unbounded command strings.
## Runtime Rules
If a skill calls `ctx.workspace_backend()` or `ctx.workspace`, declare
`workspace_access`. If it writes user-visible files, also emit artifacts with
`ctx.write_artifact` and `ctx.emit_artifact`.
If a skill runs code, renderers, converters, or data tools that create
downloadable files, run them through `await ctx.workspace_shell(...)` or
`await ctx.workspace_python(...)`. The sandbox persists `/workspace` writes
directly and mirrors changed files elsewhere in the guest rootfs under
`outputs/rootfs-captures/...`. In-process subprocesses write inside the agent
pod, not the caller's mounted or rootfs-captured workspace.
When invoking an inner DeepAgents graph, pass
`config={"recursion_limit": 500}` to `graph.ainvoke(...)` or
`graph.astream_events(...)`. Complex skill/subagent workflows can exceed
LangGraph defaults during normal operation.
If an agent needs system binaries, mirror the need in `a2a.yaml`:
```yaml
runtime:
apt_packages: [ffmpeg, poppler-utils]
resources:
cpu: "2"
memory: 2Gi
max_runtime_seconds: 900
```
If it calls external hosts, declare `egress` on the class. If it needs secrets,
use `required_secrets` and `ctx.secret("NAME")`; do not hard-code credentials.
## Packed Frontends
If the user asks for a usable app, dashboard, workflow UI, or customer-facing
demo surface, scaffold a packed frontend instead of a separate web app. Use
`init_agent_template(name, description, frontend="react")` for the React/Vite
starter or `frontend="static"` for a no-build HTML bundle.
The deployment manifest should keep the browser app under the agent source:
```yaml
frontend:
path: frontend
build: npm run build
dist: dist
mount: /app
auth: inherit
```
At runtime the platform serves the app from `/app`, exposes generated config at
`/app/config.json`, exposes a helper client at `/app/a2a-client.js`, and uses
the agent's public `@skill` schemas for callable operations. Frontend code
should load the generated config/client, call the public skills, and rely on
inherited platform auth. Do not put control-plane tokens, provider keys,
secrets, internal stack details, or private execution assumptions in frontend
source.
## A2A Skill vs DeepAgents Skill
Use A2A `@skill` for caller-visible operations and billing boundaries. Use
DeepAgents skills for internal procedural knowledge the LLM should apply. A
generated project can have one public `@skill` that invokes a DeepAgent loaded
with several internal `skills/<name>/SKILL.md` bundles.