Require user LLM credentials
All checks were successful
build / build (push) Successful in 17s

This commit is contained in:
robert
2026-06-06 12:21:31 -03:00
parent 00ad0b8790
commit 64fd7c26f2
6 changed files with 40 additions and 48 deletions

View File

@@ -30,9 +30,9 @@ class BuilderContext:
sandbox: Any | None = None
grant_token: str | None = None
# LLM creds forwarded by the orchestrator according to this agent's Card.
# The builder accepts caller-selected creds and falls back to platform
# grants. Hosted generated agents should usually use platform grants too.
# Falls back to settings for local development.
# The builder uses the caller's saved LLM credential, usually proxied
# through LiteLLM by the control plane. Falls back to settings only for
# local development.
llm_base_url: str | None = None
llm_api_key: str | None = None
llm_model: str | None = None
@@ -49,28 +49,26 @@ user's workspace at ``agents/<name>/`` and then deploy it through the
control plane.
The default starter is the current a2a-pack DeepAgents scaffold. It declares
``LLMProvisioning.PLATFORM``, reads the scoped LLM grant from ``ctx.llm``,
builds a ``ChatOpenAI`` model from those credentials, and wires a small
``LLMProvisioning.PLATFORM``, reads the caller's saved LLM credential from
``ctx.llm``, builds a ``ChatOpenAI`` model from those credentials, and wires a 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.
Default hosted generated/user agents to ``LLMProvisioning.PLATFORM`` and
``caller_pays_llm=False`` so main-agent handoffs mint a scoped A2A LiteLLM grant
for the callee. The generated agent must still read ``ctx.llm`` and must never
``caller_pays_llm=True`` so main-agent handoffs forward the caller's saved LLM
credential for the callee. The generated agent must still read ``ctx.llm`` and must never
read ``A2A_LITELLM_KEY``, ``OPENAI_API_KEY``, LiteLLM master keys, or provider
keys directly. If the user explicitly asks for BYOK or caller-paid inference,
use ``LLMProvisioning.CALLER_PROVIDED`` with ``caller_pays_llm=True`` and make
missing ``ctx.llm.api_key`` a clear setup/config result before constructing
keys directly. ``LLMProvisioning.CALLER_PROVIDED`` is still acceptable for
explicit BYOK wording. Always make missing ``ctx.llm.api_key`` a clear setup/config result before constructing
``ChatOpenAI``.
``Pricing`` accepts only ``price_per_call_usd``, ``caller_pays_llm``, and
``notes``. Never set ``runtime.pricing.compute`` or
``runtime.pricing.total_usd`` in generated source; those are derived later by
the control plane/dashboard from declared ``Resources`` and billing policy.
``LLMProvisioning.PLATFORM_OR_CALLER_PROVIDED`` is reserved for trusted
platform/meta agents that should prefer caller-selected credentials and fall
back to a scoped platform grant; do not use it for ordinary generated agents
unless the user explicitly asks for that mixed billing mode.
``LLMProvisioning.PLATFORM_OR_CALLER_PROVIDED`` is retained only for backwards
compatibility; do not use it for ordinary generated agents unless the user
explicitly asks for that legacy mixed mode.
You have packaged DeepAgents skills loaded from ``/.agent-builder/skills/``.
Use ``deepagent-agent-design`` before designing generated agent internals,

View File

@@ -1,6 +1,6 @@
---
name: a2apack-agent-authoring
description: Author production a2a-pack agents with clear public @skill schemas, runtime declarations, platform LLM grants, optional caller-provided LLMs, workspace grants, pricing, resources, and secure platform capabilities. Use when writing or reviewing agent.py for an A2A agent.
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
@@ -22,12 +22,11 @@ Use `A2AAgent` class attributes for runtime and marketplace behavior:
caller's control-plane token.
For hosted generated/user-owned agents that call an LLM, default to
`LLMProvisioning.PLATFORM` with `Pricing(..., caller_pays_llm=False, ...)` so
main-agent handoffs mint a scoped A2A LiteLLM grant for the callee. Use
`LLMProvisioning.CALLER_PROVIDED` only when the user explicitly wants BYOK or
caller-paid inference. Reserve `LLMProvisioning.PLATFORM_OR_CALLER_PROVIDED`
for trusted platform/meta agents that must work with either the caller's
selected creds or a platform fallback grant. In every mode, read `ctx.llm`;
`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 `ChatOpenAI`.
@@ -79,8 +78,8 @@ class ResearchAgent(A2AAgent[ResearchConfig, NoAuth]):
llm_provisioning = LLMProvisioning.PLATFORM
pricing = Pricing(
price_per_call_usd=0.05,
caller_pays_llm=False,
notes="Uses a scoped platform LLM grant through ctx.llm.",
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",))

View File

@@ -35,10 +35,9 @@ Check these items:
only for trusted platform/meta agents and must also read `ctx.llm`.
- Hosted generated/user agents should default to
`llm_provisioning = LLMProvisioning.PLATFORM` and
`Pricing(..., caller_pays_llm=False, ...)`. Use
`LLMProvisioning.CALLER_PROVIDED` only when the user explicitly wants BYOK or
caller-paid inference. In both modes, the code must use `ctx.llm` and never
read LiteLLM/provider keys directly.
`Pricing(..., caller_pays_llm=True, ...)`. `LLMProvisioning.CALLER_PROVIDED`
is acceptable for explicit BYOK wording. In both modes, the code must use
`ctx.llm` and never read LiteLLM/provider keys directly.
- `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.