Use sandbox client for builder validation
All checks were successful
build / build (push) Successful in 14s
All checks were successful
build / build (push) Successful in 14s
This commit is contained in:
@@ -321,6 +321,7 @@ def build_agent_builder(ctx: BuilderContext) -> Any:
|
||||
settings=settings,
|
||||
cp_jwt=ctx.cp_jwt,
|
||||
workspace=ctx.workspace,
|
||||
sandbox=ctx.sandbox,
|
||||
grant_token=ctx.grant_token,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -29,7 +29,7 @@ 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 `ChatOpenAI`.
|
||||
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=`,
|
||||
|
||||
@@ -41,8 +41,8 @@ Check these items:
|
||||
- `Pricing` contains only `price_per_call_usd`, `caller_pays_llm`, and `notes`.
|
||||
Reject `runtime.pricing.compute`, `runtime.pricing.total_usd`, `compute=`, or
|
||||
`total_usd=` in `agent.py`; those are derived platform fields.
|
||||
- Any code path that builds `ChatOpenAI` checks `ctx.llm.api_key` first or
|
||||
returns a clear setup/config result before the model constructor runs.
|
||||
- DeepAgents code uses `create_a2a_deep_agent` or another `ctx.llm`-backed
|
||||
resolver, and checks `ctx.llm.api_key` before model construction.
|
||||
- Any use of DeepAgents file tools passes `backend=ctx.workspace_backend()`.
|
||||
- Any project skills are seeded into the backend and passed with
|
||||
`skills=skill_sources or None`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: deepagent-agent-design
|
||||
description: Design generated A2A agents around DeepAgents skills, subagents, durable workspace backends, and ctx.llm-backed reasoning. Use whenever building or modifying an agent, deciding whether to add tools, creating skill bundles, wiring create_deep_agent, or avoiding shallow fake tools.
|
||||
description: Design generated A2A agents around DeepAgents skills, subagents, durable workspace backends, and ctx.llm-backed reasoning. Use whenever building or modifying an agent, deciding whether to add tools, creating skill bundles, wiring create_a2a_deep_agent, or avoiding shallow fake tools.
|
||||
---
|
||||
# DeepAgent Agent Design
|
||||
|
||||
@@ -13,8 +13,8 @@ planning, file work, skill selection, and subagent delegation.
|
||||
Use this shape for non-trivial generated agents:
|
||||
|
||||
1. Keep one or two public A2A `@skill` methods with clear typed parameters.
|
||||
2. Inside each method, read `ctx.llm`, verify credentials are available before
|
||||
constructing `ChatOpenAI`, and build a DeepAgent with `create_deep_agent`.
|
||||
2. Inside each method, read `ctx.llm`, verify credentials are available, and
|
||||
build a DeepAgent with `create_a2a_deep_agent`.
|
||||
3. Pass `backend=ctx.workspace_backend()` so DeepAgents file tools write to the
|
||||
caller's durable workspace instead of LangGraph state.
|
||||
4. Seed project skills into the current grant's write prefix and pass
|
||||
@@ -44,7 +44,7 @@ linked from `SKILL.md`.
|
||||
|
||||
Project `skills/` files are source files in the agent image. DeepAgents loads
|
||||
skills from its backend, so seed those files into the invocation workspace
|
||||
before `create_deep_agent`:
|
||||
before `create_a2a_deep_agent`:
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
@@ -84,8 +84,9 @@ Then:
|
||||
```python
|
||||
backend = ctx.workspace_backend()
|
||||
skill_sources = _seed_runtime_skills(backend, ctx)
|
||||
return create_deep_agent(
|
||||
model=model,
|
||||
return create_a2a_deep_agent(
|
||||
ctx,
|
||||
creds=creds,
|
||||
backend=backend,
|
||||
skills=skill_sources or None,
|
||||
tools=[small_deterministic_tool],
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
name: deepagents-implementation-patterns
|
||||
description: Implement DeepAgents inside a2a-pack agents with real deterministic tools, project skills, custom subagents, workspace-backed files, and ctx.llm-backed ChatOpenAI models. Use when editing create_deep_agent calls or deciding what belongs in tools, skills, or subagents.
|
||||
description: Implement DeepAgents inside a2a-pack agents with real deterministic tools, project skills, custom subagents, workspace-backed files, and ctx.llm-backed model resolution. Use when editing create_a2a_deep_agent calls or deciding what belongs in tools, skills, or subagents.
|
||||
---
|
||||
# DeepAgents Implementation Patterns
|
||||
|
||||
DeepAgents supplies the inner agent loop. In this platform, the reliable shape
|
||||
is: `ctx.llm`-backed `ChatOpenAI`, A2A workspace backend, project DeepAgents
|
||||
skills, and a small number of exact tools. Hosted generated agents should
|
||||
is: `ctx.llm`-backed `create_a2a_deep_agent`, A2A workspace backend, project
|
||||
DeepAgents skills, and a small number of exact tools. Hosted generated agents should
|
||||
declare `LLMProvisioning.PLATFORM`; explicit BYOK agents can declare
|
||||
`CALLER_PROVIDED`, but both modes still read the same `ctx.llm` object.
|
||||
|
||||
@@ -20,8 +20,7 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from langchain_core.tools import tool
|
||||
from langchain_openai import ChatOpenAI
|
||||
from deepagents import create_deep_agent
|
||||
from a2a_pack.deepagents import create_a2a_deep_agent
|
||||
|
||||
RUNTIME_SKILLS_DIR = "research-agent/.deepagents/skills/"
|
||||
|
||||
@@ -39,13 +38,6 @@ def build_graph(ctx: Any) -> Any:
|
||||
"LLM credentials were not available; declare PLATFORM for hosted "
|
||||
"generated agents or configure caller-provided credentials."
|
||||
)
|
||||
model = ChatOpenAI(
|
||||
model=creds.model,
|
||||
base_url=creds.base_url,
|
||||
api_key=creds.api_key,
|
||||
temperature=0.0,
|
||||
)
|
||||
|
||||
@tool
|
||||
def validate_citations(items_json: str) -> str:
|
||||
"""Validate that each citation has title, url, and claim fields."""
|
||||
@@ -58,8 +50,9 @@ def build_graph(ctx: Any) -> Any:
|
||||
|
||||
backend = ctx.workspace_backend()
|
||||
skill_sources = seed_runtime_skills(backend, ctx)
|
||||
return create_deep_agent(
|
||||
model=model,
|
||||
return create_a2a_deep_agent(
|
||||
ctx,
|
||||
creds=creds,
|
||||
backend=backend,
|
||||
skills=skill_sources or None,
|
||||
tools=[validate_citations],
|
||||
|
||||
@@ -26,7 +26,7 @@ Pass the backend into DeepAgents:
|
||||
|
||||
```python
|
||||
backend = ctx.workspace_backend()
|
||||
graph = create_deep_agent(model=model, backend=backend, skills=skill_sources or None)
|
||||
graph = create_a2a_deep_agent(ctx, backend=backend, skills=skill_sources or None)
|
||||
```
|
||||
|
||||
For stable, human-readable paths, ask model-created files to use
|
||||
|
||||
@@ -31,7 +31,7 @@ if TYPE_CHECKING:
|
||||
from .config import Settings
|
||||
|
||||
|
||||
A2A_PACK_MIN_VERSION = "0.1.60"
|
||||
A2A_PACK_MIN_VERSION = "0.1.75"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -40,6 +40,7 @@ class ToolContext:
|
||||
settings: "Settings"
|
||||
cp_jwt: str | None = None
|
||||
workspace: Any | None = None
|
||||
sandbox: Any | None = None
|
||||
grant_token: str | None = None
|
||||
|
||||
|
||||
@@ -444,6 +445,29 @@ def build_tools(ctx: ToolContext) -> list[Any]:
|
||||
" a2a frontend info --project . || true\n"
|
||||
"fi\n"
|
||||
)
|
||||
if ctx.sandbox is not None:
|
||||
try:
|
||||
out = await ctx.sandbox.run_shell(
|
||||
script,
|
||||
image=settings.image,
|
||||
workspace=bucket,
|
||||
memory_mib=512,
|
||||
timeout_seconds=settings.sandbox_timeout_s,
|
||||
)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
return json.dumps({
|
||||
"error": f"sandbox {type(exc).__name__}",
|
||||
"detail": str(exc)[:1000],
|
||||
})
|
||||
result: dict[str, Any] = {
|
||||
"exit_code": getattr(out, "exit_code", None),
|
||||
"stdout": (getattr(out, "stdout", "") or "")[:4000],
|
||||
"stderr": (getattr(out, "stderr", "") or "")[:4000],
|
||||
}
|
||||
if sanitized_fields:
|
||||
result["sanitized_agent_card_fields"] = list(sanitized_fields)
|
||||
return json.dumps(result)
|
||||
|
||||
headers = _sandbox_headers(settings.sandbox_token, ctx.grant_token)
|
||||
async with httpx.AsyncClient(timeout=settings.sandbox_timeout_s + 30) as c:
|
||||
r = await c.post(
|
||||
|
||||
Reference in New Issue
Block a user