Skip to content

About

A2A protocol support for Lemonade — expose local AI systems as interoperable A2A agents.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Lemonade A2A 🍋

A first-class Agent2Agent (A2A) protocol surface for Lemonade local AI systems.

Lemonade A2A is an open-source reference implementation and upstream-oriented proposal for exposing models served by Lemonade as standards-compliant Agent2Agent (A2A) agents.

If Lemonade can serve intelligence locally, it should be able to expose that intelligence as an interoperable A2A agent.

The project intentionally uses local AI systems rather than AMD AI PCs as its platform concept. Lemonade is built for local AI across PCs and operating systems, with multiple CPU/GPU/NPU backends including AMD, NVIDIA, Apple Silicon, Vulkan and CPU execution. AMD acceleration remains an important optimization target, not a protocol requirement.

Why?

OpenAI-compatible APIs standardize model inference. A2A standardizes agent interoperability. Lemonade A2A adds the latter without inventing another agent framework or inference runtime.

Application / Agent Framework
          │
          ├──── OpenAI-compatible API ───► Model inference
          │
          └──── A2A ─────────────────────► Agent interoperability
                                               │
                                               ▼
                                            Lemonade
                                               │
                                  Local AI System Runtime
                                               │
                                    CPU / GPU / NPU backends

Goals

  • A2A v1-compatible protocol surface for Lemonade-hosted intelligence.
  • Automatic Agent Card generation.
  • A2A Message/Task/Artifact ↔ Lemonade inference translation.
  • Streaming and cancellation propagation.
  • Local-first operation with no mandatory cloud dependency.
  • Framework and hardware independence.
  • Thin protocol layer: this process does not load AI models.
  • Preserve Lemonade's backend abstraction rather than binding A2A to a particular accelerator.
  • Upstream-friendly architecture that can evolve toward native Lemonade integration.

Architecture

                    A2A Clients / Agent Frameworks
                               │
                            A2A v1
                               │
                               ▼
                  ┌─────────────────────────┐
                  │      Lemonade A2A       │
                  │                         │
                  │  Agent Card / Discovery│
                  │  Message Adapter        │
                  │  Task / Artifact Map    │
                  │  Streaming / Cancel     │
                  │  Security Policy        │
                  └────────────┬────────────┘
                               │
                       OpenAI-compatible
                       Lemonade endpoint
                               │
                               ▼
                  ┌─────────────────────────┐
                  │        Lemonade         │
                  │ Model / backend routing │
                  │ Local inference runtime │
                  └────────────┬────────────┘
                               │
             ┌─────────────────┼─────────────────┐
             ▼                 ▼                 ▼
            CPU               GPU               NPU
             │                 │                 │
             └────────── Local AI  ────────┘

A2A should remain above Lemonade's model/backend router. It should not know whether inference is ultimately executed by ROCm, CUDA, Vulkan, Metal, CPU, Ryzen AI or another backend. This keeps the protocol surface aligned with Lemonade's vision: standard local AI APIs with hardware-specific optimization behind the server boundary.

See docs/architecture.md.

Current status

Validated so far (details: roadmap, benchmarks):

  • official A2A SDK integration with JSON-RPC and HTTP+JSON bindings served at the base URL (legacy /a2a/jsonrpc and /a2a/rest paths kept);
  • automatic Agent Card, SSE streaming into A2A artifacts, cancellation that stops the real backend generation, backend failures mapped to FAILED tasks;
  • resource bounds (input size/parts, per-task deadline, concurrency cap with REJECTED, bounded task store, slow-consumer backpressure), exposure profiles, API-key auth with several named callers and per-user task isolation, rate limiting, TLS and mutual TLS, graceful shutdown, optional cancel-on-disconnect;
  • property-based fuzzing of messages, parts, metadata and backend stream output (it found and fixed two real defects);
  • a compatibility specification you can run: lemonade-a2a doctor cross-validates the installed a2a-sdk, lemonade-a2a and Lemonade after an upgrade against a generated manifest and a feature registry; strict/warn startup modes, feature flags, layered config, a support bundle, and a weekly canary against the lowest, latest and pre-release SDK (specification, upgrading);
  • OpenTelemetry observability: opt-in traces, metrics and logs with standard OTEL_* configuration, private by default (prompts are never exported unless you opt in), a measured overhead budget, and a ready dashboard and alerts (observability);
  • an extension API (backends, task stores, authenticators, telemetry) with a persistent SQLite task store as the reference plugin (extending);
  • reasoning models and backend errors handled honestly: thinking is dropped (or opt-in streamed as a separate artifact), and an error Lemonade reports inside a 200 stream fails the task instead of completing it empty;
  • the official A2A TCK against the protocol surface: 157 passed, 0 failed, 4 expected-fail (SHOULD), the rest skipped for capabilities not declared (see conformance for scope);
  • independent clients (A2A CLI, and the JavaScript, Go, .NET and Java SDKs, plus the Inspector's validators) pass over JSON-RPC and HTTP+JSON, on the mock and on real Lemonade (interoperability);
  • CI on Python 3.11-3.13 (ruff, ruff format, pytest) plus a deterministic mock-Lemonade end-to-end job;
  • a real Lemonade 2026.40.0 setup on llama.cpp CUDA, Vulkan and CPU with a 1.7B and a 4B model: the validator and an opt-in pytest suite pass, A2A adds roughly 5-15 ms TTFT within a defined overhead budget on those models (a 12B model on CUDA was over budget, likely noise, and is only partly measured), and concurrent load (up to 8) shows no adapter-added cost (throughput is bounded by the backend).

Not yet done: ITK (it tests SDKs against each other, so it does not apply to a standalone adapter), NPU/ROCm/Metal and non-llama.cpp backends (no hardware available so far), OAuth/OIDC inside the adapter (by decision, done at a gateway), URL/file fetching (disabled; its safety policy is written and tested first). The next milestone is cross-backend evidence on AMD hardware and the upstream-native design.

North-star developer experience

The north star is for A2A to become another standard Lemonade server surface rather than a permanently separate inference stack:

lemonade serve --a2a

Conceptually:

OpenAI API   http://localhost:13305/v1/...
A2A          http://localhost:13305/a2a/...
Agent Card   http://localhost:13305/.well-known/agent-card.json

The exact CLI and paths above are design targets, not claims about current upstream Lemonade behavior.

MVP

  1. Discovery — generate and serve an Agent Card.
  2. Messaging — translate A2A messages into Lemonade inference requests.
  3. Execution — expose Lemonade inference through an A2A AgentExecutor.
  4. Artifacts — return generated content using A2A-native messages/artifacts.
  5. Streaming — preserve incremental local generation.
  6. Lifecycle — propagate cancellation and map failures/timeouts correctly.
  7. Compatibility — validate against official A2A tooling/TCK.
  8. Runtime validation — prove the same surface against a real Lemonade installation and multiple Lemonade backends.

Quick start

Pre-alpha reference implementation. Pinning and API details may change while A2A v1 integration is validated.

python -m venv .venv
source .venv/bin/activate       # Windows: .venv\Scripts\activate
pip install -e .

export LEMONADE_BASE_URL=http://localhost:13305/v1
export LEMONADE_MODEL=your-model
lemonade-a2a                    # serves on http://127.0.0.1:9100

After installing or upgrading anything (pip install -U a2a-sdk lemonade-a2a), check the combination:

lemonade-a2a doctor             # versions, config, Lemonade, a tiny generation with --deep
lemonade-a2a capabilities       # what is on, what is available and how to switch it
lemonade-a2a config show        # effective settings and where each value came from
lemonade-a2a support-bundle     # a redacted archive for a bug report

The adapter expects a running Lemonade server exposing an OpenAI-compatible endpoint. It listens on 9100 by default because a stock Lemonade install already uses port 9000 for its WebSocket.

Configuration

Variable Default Purpose
LEMONADE_BASE_URL http://localhost:13305/v1 Lemonade OpenAI-compatible endpoint
LEMONADE_MODEL empty (server default) Model id sent to Lemonade
LEMONADE_A2A_HOST / LEMONADE_A2A_PORT 127.0.0.1 / 9100 Listen address
LEMONADE_A2A_PUBLIC_URL http://localhost:9100 URL advertised in the Agent Card; keep in sync with host/port
LEMONADE_A2A_AGENT_NAME / LEMONADE_A2A_AGENT_DESCRIPTION see config.py Agent Card text
LEMONADE_TIMEOUT_SECONDS 120 Backend request timeout
LEMONADE_A2A_MAX_INPUT_CHARS / LEMONADE_A2A_MAX_INPUT_PARTS 100000 / 32 Maximum input text / message parts
LEMONADE_A2A_MAX_REQUEST_BYTES 1048576 Maximum HTTP request body (413 above it)
LEMONADE_A2A_MAX_TASK_SECONDS 600 Per-task deadline (task fails when exceeded)
LEMONADE_A2A_MAX_CONCURRENT_TASKS 8 Running-task cap; extra tasks are REJECTED
LEMONADE_A2A_MAX_STORED_TASKS 1000 Task store size; oldest finished tasks are evicted
LEMONADE_A2A_PROFILE local How the adapter is exposed: local (loopback only), lan (needs auth), external (needs auth + TLS + rate limit). A mismatch stops startup, see docs/security.md
LEMONADE_A2A_API_KEY empty (no auth) Require Authorization: Bearer / X-API-Key; Agent Card and /healthz stay public
LEMONADE_A2A_API_KEYS empty Several callers: alice:key1,bob:key2. Each name owns its tasks; others cannot see them
LEMONADE_A2A_RATE_LIMIT_PER_MINUTE 0 (off) Per-identity request budget; HTTP 429 with Retry-After beyond it
LEMONADE_A2A_CANCEL_ON_DISCONNECT 0 Cancel a task when the streaming client that started it disconnects
LEMONADE_API_KEY empty Key sent to a protected Lemonade server
LEMONADE_A2A_SSL_CERTFILE / LEMONADE_A2A_SSL_KEYFILE empty Serve HTTPS (set both; use an https:// public URL)
LEMONADE_A2A_SSL_CA_CERTS / LEMONADE_A2A_SSL_REQUIRE_CLIENT_CERT empty / 0 Mutual TLS: refuse clients without a certificate signed by this CA
LEMONADE_A2A_REASONING drop A reasoning model's thinking: drop, or artifact to stream it as a separate lemonade-reasoning artifact
LEMONADE_A2A_TASK_STORE / LEMONADE_A2A_TASK_DB memory / lemonade-a2a-tasks.sqlite sqlite keeps tasks across restarts (needs lemonade-a2a[sqlite]; the file holds prompts and answers)
LEMONADE_A2A_COMPAT warn Startup compatibility gate: off, warn or strict (refuse to start on any failed or warned check)
LEMONADE_A2A_FEATURES empty Toggle registry features: +adapter.cancel_on_disconnect,-a2a.streaming (see lemonade-a2a capabilities)
LEMONADE_A2A_EXPOSE_CAPABILITIES 0 Serve the authenticated /.well-known/lemonade-a2a/capabilities endpoint and an optional card extension
LEMONADE_A2A_OTEL 0 Turn on OpenTelemetry (needs lemonade-a2a[otel]); exporters, sampling and resource come from the standard OTEL_* variables
LEMONADE_A2A_OTEL_CAPTURE none none, metadata (adds ids) or content (adds truncated prompt/response text; local use only)
LEMONADE_A2A_OTEL_PROMETHEUS / LEMONADE_A2A_LOG_FORMAT 0 / text Serve an authenticated /metrics; json logs carry trace_id and span_id
LEMONADE_A2A_BACKEND / _AUTHENTICATOR / _TELEMETRY_PLUGIN lemonade / empty / empty Select an extension by name
LEMONADE_A2A_CONFIG empty A TOML file ([lemonade_a2a] table of setting names); environment and command-line flags override it

Every setting can also be given in a TOML file or as a command-line flag (lemonade-a2a --config c.toml serve --port 9200); precedence is defaults, file, environment, command line, and lemonade-a2a config schema prints a JSON Schema of all of them. Invalid values fail at startup. See examples/ for an Agent Card and a client, and docs/real-lemonade-validation.md for validating against a real Lemonade install.

Design principles

Standards first. Use A2A rather than creating a proprietary agent protocol.

Thin data plane. A2A translation belongs here; model inference and backend selection belong in Lemonade.

Local first. A complete interaction can remain on the local AI system or trusted LAN.

Hardware agnostic at the protocol boundary. A2A clients should not need to know whether Lemonade selected CPU, GPU or NPU execution.

Untrusted by default. Agent Cards, messages, files, URLs, metadata and artifacts are external input.

Upstream friendly. Keep protocol boundaries explicit so the reference implementation can inform a future native Lemonade A2A surface.

What this project is not

Lemonade A2A is not a new agent reasoning framework. Model intelligence remains a Lemonade concern. The A2A layer is responsible for interoperability, lifecycle, streaming, discovery and policy—not inventing a second model-routing or reasoning stack.

If Lemonade later gains richer routing, model selection or scheduling capabilities, A2A should consume those capabilities through Lemonade rather than duplicate them here.

Next architecture milestone

The next step is to move from reference implementation validation toward an upstream-native A2A surface:

Today

A2A Client
    │
    ▼
Python Lemonade A2A reference adapter
    │
    ▼
OpenAI-compatible Lemonade API
    │
    ▼
Lemonade Router → backend → local hardware

Next

A2A Client                    OpenAI / Anthropic / Ollama clients
    │                                      │
    └──────────────┬───────────────────────┘
                   ▼
             Lemonade Server
                   │
        ┌──────────┴──────────┐
        │ Protocol/API layer  │
        │ OpenAI | ... | A2A │
        └──────────┬──────────┘
                   │
             Lemonade Router
                   │
          Model/backend manager
                   │
          CPU / GPU / NPU backends

Before implementing the native C++ surface, the reference adapter should pass real-runtime, lifecycle, conformance and overhead gates. That gives the upstream proposal measurable evidence rather than only an architectural concept.

Recommended next steps

  1. Hardware evidence: NPU, ROCm, Metal and non-llama.cpp engines need a machine with that hardware; the adapter has no hardware-specific code, so the check is to run lemonade-a2a doctor --deep, the validation script and the benchmarks there.
  2. Real inference on a second machine, and a first PyPI release (needs the owner's approval; the package build and manifest generation are ready).
  3. Draft the native Lemonade A2A API boundary and map it onto Lemonade's HTTP/router architecture, claiming features by the registry's ids and passing the same contract tests; then prototype the native endpoint and propose it upstream.

See docs/roadmap.md for the tracked TODO list.

Documentation

Status

Experimental / pre-alpha. The protocol surface passes the official TCK, the integration is validated against a deterministic mock and a real Lemonade server, and the adapter has basic resource bounds and optional auth/TLS. The project is moving into AMD-hardware evidence, interoperability testing and upstream-native design.

License

Apache License 2.0. See LICENSE.

Acknowledgements

Built on the open-source work of the Lemonade community and the Linux Foundation Agent2Agent project. This repository is an independent community project and is not an official AMD or Linux Foundation product.

About

A2A protocol support for Lemonade — expose local AI systems as interoperable A2A agents.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages