Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions docs/user-guide/tools_integrations/tools/a2a-building-agents.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
id: a2a-building-agents
title: Building A2A-Compatible Agents
sidebar_label: Building A2A Agents
sidebar_position: 2
pagination_prev: user-guide/tools_integrations/tools/a2a
pagination_next: null
---

# Building A2A-Compatible Agents

This guide explains how to wrap an existing agent so that CodeMie (or any A2A 1.0 client) can call it. It covers the request-to-response mapping, the Agent Card, and the split between agent logic and protocol handling.

Worked examples reference the demo agents in [ai-run-demo-agents](https://github.com/epam-gen-ai-run/ai-run-demo-agents) (`python/agents/text-insights-agent` and `python/agents/howto-guide-agent`). Both use the `a2a-sdk` 1.x and implement the patterns described here.

## Core Pattern: Separate Agent Logic from Protocol

The recommended structure keeps agent logic entirely free of A2A types. All protocol work — receiving the request, dispatching the agent, emitting the result — lives in an _executor_ class. The agent itself knows nothing about A2A.

```
__main__.py ← executor: receives A2A request, calls agent, emits events
agent.py ← agent logic: no A2A types, no SDK imports
```

This separation means the same agent logic can be tested independently and adapted to other protocols without modification.

## Request: A2A Message to Agent Input

An incoming A2A request carries a `message` with one or more parts:

- **Text input.** Join the `text` fields from the message's parts and pass the result to the agent. The SDK exposes this as `context.get_user_input()`.
- **`contextId`.** CodeMie sets this to the chat conversation ID, so all messages in one conversation share it. Use it as a session or thread key if the agent maintains conversation memory. Stateless agents can ignore it.
- **`taskId`.** Present when the client continues an existing task. Stateless agents can ignore it.

CodeMie sends text parts only. Its own A2A endpoint also accepts text only, so a wrapper has no need to handle other part types for CodeMie calls.

## Response: Agent Result to A2A

### Non-streaming: return a Message

When the answer is short and ready in one step, enqueue a single `message` event. No task is created.

`text-insights-agent` uses this pattern: the executor calls the agent, formats the result as text, and enqueues a `message` with `role: ROLE_AGENT`. See `text-insights-agent/__main__.py` for the implementation.

The Agent Card for a non-streaming agent declares `capabilities.streaming: false`. CodeMie calls it with `SendMessage`.

### Streaming: return a Task and events

For multi-part or long-running work, enqueue events in this order:

1. A task with state `TASK_STATE_SUBMITTED`
2. One `artifactUpdate` per result part (the answer text)
3. A final `statusUpdate` carrying a terminal state (`TASK_STATE_COMPLETED`, `TASK_STATE_FAILED`, etc.)

`howto-guide-agent` uses this pattern. See `howto-guide-agent/__main__.py` for the executor code and SDK helper names.

Key rules for streaming:

- **The stream must end in a terminal state.** There is no `final` flag in A2A 1.0; the terminal state is the signal that the stream is complete. A stream that closes without one leaves the client without a verdict.
- **Artifacts carry the answer; status events carry progress.** Put answer text in `artifactUpdate` parts. Use `statusUpdate` for state transitions and short status messages. CodeMie displays artifact text as the chat response, one chunk per artifact event.
- **Map errors to a failed task** rather than raising an exception. Enqueue a `statusUpdate` with `TASK_STATE_FAILED` and include the error text.
- **Declare streaming on the card.** Set `capabilities.streaming: true`. CodeMie then calls `SendStreamingMessage`.

### Message or Task?

| Return type | When to use |
| ------------------ | --------------------------------------------------------------------- |
| `Message` | Short answer, no need to track progress or fetch it later |
| `Task` + artifacts | Work takes time, has multiple parts, or the client may poll `GetTask` |

## The Agent Card

The Agent Card is served at `/.well-known/agent-card.json` and is how CodeMie discovers and registers the agent.

Fields that matter to CodeMie:

- **`supportedInterfaces[].url`** — the JSON-RPC endpoint CodeMie will send requests to. This address must be reachable **from the CodeMie process**. Build it from a hostname the CodeMie container resolves — never `0.0.0.0`. Pass `--host <container-name>` when running the agent on a Docker network.
- **`capabilities.streaming`** — `true` or `false`; determines which method CodeMie uses.
- **Input/output modes** — CodeMie expects `text/plain`.
- **`skills`** — describes what the agent can do (shown in the UI after registration).

See the demo agents' `__main__.py` files for how to build the card with `AgentCard`, `AgentInterface`, `AgentCapabilities`, and `AgentSkill` from the SDK.

## Cancellation

CodeMie can send `CancelTask`. An agent that does not support cancellation should raise the SDK's unsupported-operation error; the client receives a protocol error (`-32004`) instead of a hang. Both demo agents follow this pattern.

## Checklist

- [ ] Agent logic has no A2A types — all protocol work is in an executor class
- [ ] Agent Card served at `/.well-known/agent-card.json` with a reachable JSON-RPC `supportedInterfaces[].url`
- [ ] `A2A-Version: 1.0` enforced on incoming requests (the SDK handles this automatically)
- [ ] Streaming agents: task first, artifacts next, one terminal status last
- [ ] Errors produce a failed task or a protocol error — never a silent empty response
- [ ] `capabilities.streaming` on the card matches the executor's actual behavior

## Learn More

- **[A2A Protocol](./a2a.mdx)** — setup, authentication, supported operations, and known limitations
- **[ai-run-demo-agents](https://github.com/epam-gen-ai-run/ai-run-demo-agents)** — complete source for both demo agents
- **[A2A Protocol Specification](https://google.github.io/A2A/#/documentation)** — official protocol reference
114 changes: 75 additions & 39 deletions docs/user-guide/tools_integrations/tools/a2a.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import TabItem from '@theme/TabItem';
CodeMie supports the **Agent-to-Agent (A2A) Protocol**, an open-standard protocol designed to enable seamless communication and collaboration between AI agents built with different frameworks and by different vendors.
A2A provides a common language that breaks down silos and fosters interoperability across the AI ecosystem.

With A2A integration, you can connect CodeMie to external AI agents—regardless of their framework or origin—allowing them to communicate effortlessly and work together on complex tasks.
With A2A integration, CodeMie connects to external AI agents—regardless of their framework or origin—allowing them to communicate and work together on complex tasks.

:::warning Protocol Version 1.0
CodeMie implements A2A protocol **version 1.0**. Agents built for the earlier v0.3 protocol are not compatible and will fail at registration. This includes agents that serve only a legacy `agent.json` card, agents using v0.3 method names, and Bedrock AgentCore remotes.
:::

## Key Features

Expand Down Expand Up @@ -236,72 +240,91 @@ After creating the integration:
2. When creating a remote assistant, select this integration in the **Integration (Optional)** dropdown.
3. CodeMie will automatically include the authentication credentials when communicating with the agent.

## Example: Currency Conversion Agent

A sample currency conversion agent built with LangGraph demonstrates A2A capabilities:

**Repository**: [ai-run-demo-agents](https://github.com/epam-gen-ai-run/ai-run-demo-agents)

**Sample Agent**: `/python/agents/currency_converter`

### Agent Capabilities
## Example: Demo Agents

- Real-time currency conversion using Frankfurter API
- Multi-turn conversations with follow-up questions
- Streaming status updates during processing
- Conversational memory across interactions
The [ai-run-demo-agents](https://github.com/epam-gen-ai-run/ai-run-demo-agents) repository provides two reference agents that implement A2A protocol 1.0:

### Example Queries
| Agent | Path | Style |
| --------------------- | ----------------------------------- | ----------------------------------------------------------- |
| `text-insights-agent` | `python/agents/text-insights-agent` | Non-streaming — returns a single message |
| `howto-guide-agent` | `python/agents/howto-guide-agent` | Streaming — returns a task with incremental artifact events |

```
"How much is 100 USD in EUR?"
"What's the exchange rate for USD to JPY?"
"Convert 50 EUR to GBP"
```
Both agents use the `a2a-sdk` 1.x and serve a v1.0 Agent Card at `/.well-known/agent-card.json`.

### Try It Yourself
### Run an Agent Locally

1. Clone the [ai-run-demo-agents](https://github.com/epam-gen-ai-run/ai-run-demo-agents) repository:
1. Clone the repository:

```bash
git clone https://github.com/epam-gen-ai-run/ai-run-demo-agents.git
cd ai-run-demo-agents/python/agents/currency_converter
cd ai-run-demo-agents/python/agents/text-insights-agent
```

2. Set up your environment variables:
2. Start the agent (see the agent's `README.md` for environment variables):

```bash
echo "CHAT_MODEL_PROVIDER=azure" > .env
echo "AZURE_OPENAI_API_KEY=your_api_key_here" >> .env
echo "AZURE_OPENAI_ENDPOINT=your_endpoint_url" >> .env
echo "AZURE_OPENAI_API_VERSION=2024-12-01-preview" >> .env
uv run .
```

3. Run the agent with ngrok to expose it publicly:
3. To expose the agent publicly for testing, use ngrok:

```bash
uv run . --ngrok_enabled
```

The agent will start and ngrok will provide a public URL:

![Agent running with ngrok](./images/a2a-agent-running-ngrok.png)
Copy the ngrok URL from the output and use it when creating the remote assistant in CodeMie.

4. Copy the ngrok URL from the terminal output (e.g., `https://easily-trasnocheoic-externally.ngrok-free.dev`)

5. In CodeMie, create a remote assistant using this URL as described in the [Create Remote Assistant](#create-remote-assistant) section
:::note Docker
When CodeMie runs in Docker, start the agent on the same Docker network and pass `--host <container-name>` so the Agent Card advertises an address the CodeMie container can reach.
:::

:::tip Developer Community
We encourage developers to create their own A2A-compatible agents and share them with the community. Check the [ai-run-demo-agents](https://github.com/epam-gen-ai-run/ai-run-demo-agents) repository for examples and contribution guidelines.
The [ai-run-demo-agents](https://github.com/epam-gen-ai-run/ai-run-demo-agents) repository provides examples and contribution guidelines for building A2A-compatible agents.
:::

## Call a CodeMie Assistant from an External Client

Every CodeMie assistant is also published as an A2A agent and can be called by any external A2A 1.0 client or another agent.

| Endpoint | Path |
| ----------------- | ------------------------------------------------------------------- |
| Agent Card | `GET /v1/a2a/assistants/{assistant_id}/.well-known/agent-card.json` |
| JSON-RPC endpoint | `POST /v1/a2a/assistants/{assistant_id}` |

Every JSON-RPC request must carry the header `A2A-Version: 1.0` (or the query parameter `A2A-Version=1.0`). Requests without this header are rejected with error `-32009`.

**Authentication:** the JSON-RPC endpoint always requires credentials. A private assistant's card also requires credentials; the card of a global assistant is public.

- With `IDP_PROVIDER=local`: log in via `POST /v1/local-auth/login` and include `Authorization: Bearer <token>`. The token is valid for 24 hours.
- With other identity providers: use the bearer token issued by that provider.

## Supported Operations

| Method | Support |
| -------------------------------------------------- | --------------------------------------------- |
| `SendMessage` | Supported — blocking; result is a task |
| `SendStreamingMessage` | Supported — server-sent events |
| `GetTask` | Supported |
| `CancelTask` | Supported (a completed task answers `-32002`) |
| `GetExtendedAgentCard` | Supported — returns the agent card |
| `ListTasks`, `SubscribeToTask`, push notifications | Not implemented — returns `-32601` |

## Known Limitations

- **Protocol version 1.0 only.** Pre-1.0 method names and agents without `A2A-Version: 1.0` are rejected.
- **Text parts only.** The card declares `text/plain` input and output modes. A request with `acceptedOutputModes` that excludes `text/plain` answers `-32005`.
- **`returnImmediately` is not supported** — returns `-32004`.
- **`ListTasks`, `SubscribeToTask`, and push notifications are not implemented** — return `-32601`.
- **Protocol errors are HTTP 200.** JSON-RPC errors (version mismatch, unknown method, invalid params) come back with HTTP 200 and a JSON-RPC `error` object. Authentication and lookup failures are plain HTTP errors (`401`, `403`, `404`).
- **An exception inside an assistant run** is reported as task state `TASK_STATE_INPUT_REQUIRED`, not `FAILED`.

## Important Notes

### Agent Compatibility

- External agents must implement the A2A protocol specification
- External agents must implement A2A protocol **version 1.0**
- Supported communication: JSON-RPC 2.0 over HTTP/HTTPS
- Required endpoints: agent card fetch, task send, task subscribe (for streaming)
- The Agent Card must be served at `/.well-known/agent-card.json`

### Network Requirements

Expand All @@ -328,9 +351,22 @@ Administrators can configure A2A timeout settings in the platform configuration:

See [API Configuration](../../../admin/configuration/codemie/api-configuration.md#agent-to-agent-a2a-communication) for details.

## Troubleshooting

| Symptom | Fix |
| -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registration fails with `HTTP 404` | The base URL is incorrect (do not include `/.well-known/agent-card.json` or any path), or the agent only supports an older protocol version. Verify with `curl <url>/.well-known/agent-card.json`. |
| Registration succeeds, chat fails with `ConnectError` | The Agent Card advertises an address the CodeMie container cannot reach (for example `http://0.0.0.0:<port>/`). Restart the agent with `--host <container-name>` on the CodeMie Docker network. |
| `-32009` on every JSON-RPC call | Add `A2A-Version: 1.0` to the request headers. |
| `401 Authentication required` | Token is missing or expired (24-hour lifetime). Log in again to obtain a fresh token. The `user-id` header alone is not accepted in non-local environments. |
| Slow first response | The remote agent calls an LLM. Raise `A2A_AGENT_REQUEST_TIMEOUT` in the platform configuration. |
| Registration fails with `Invalid agent card format` | The agent's `/.well-known/agent-card.json` is not valid JSON. Fix the agent card format. |
| Registration fails with `Agent card has no JSON-RPC interface` | Registration succeeded but chat fails because the card declares no JSON-RPC interface in `supportedInterfaces`. Add a JSON-RPC interface to the agent card. |

## Learn More

- **[A2A Protocol Documentation](https://google.github.io/A2A/#/documentation)** - Official A2A protocol specification
- **[Building A2A-Compatible Agents](./a2a-building-agents.mdx)** - Guide for wrapping an existing agent with the A2A protocol
- **[Demo Agents Repository](https://github.com/epam-gen-ai-run/ai-run-demo-agents)** - Example agents and implementation guides
- **[Sub-Assistants and Orchestration](../../assistants/sub-assistants-multi-assistant-orchestrator.md)** - Learn about agent-to-agent communication within CodeMie
- **[Sub-Assistants and Orchestration](../../assistants/sub-assistants-multi-assistant-orchestrator.md)** - Agent-to-agent communication within CodeMie
- **[API Configuration](../../../admin/configuration/codemie/api-configuration.md)** - Platform-level A2A settings
14 changes: 14 additions & 0 deletions faq/does-codemie-support-a2a-protocol-version-1-0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Does CodeMie support A2A protocol version 1.0?

Yes. CodeMie implements the Agent-to-Agent (A2A) protocol version 1.0 in both directions:
CodeMie can call external A2A agents as remote assistants, and any CodeMie assistant can be
called by an external A2A 1.0 client.

The earlier v0.3 protocol is not supported. Agents that serve only a legacy `agent.json` card,
use v0.3 method names, or are running on Bedrock AgentCore will fail at registration.
Every JSON-RPC request must carry the `A2A-Version: 1.0` header; requests without it are
rejected with error `-32009`.

## Sources

- [A2A Protocol](https://codemie-ai.github.io/docs/user-guide/tools_integrations/tools/a2a)
26 changes: 26 additions & 0 deletions faq/how-do-i-build-an-a2a-compatible-agent-for-codemie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# How do I build an A2A-compatible agent for CodeMie?

An A2A-compatible agent needs three things: a JSON-RPC endpoint that implements A2A protocol 1.0,
an Agent Card served at `/.well-known/agent-card.json`, and a structure that separates agent logic
from protocol handling.

The recommended pattern uses an _executor_ class in `__main__.py` that receives the A2A request,
extracts text input via `context.get_user_input()`, calls the existing agent logic, and emits
the result as either a `message` (for short non-streaming answers) or a `task` with artifact events
(for streaming or multi-part results). The agent logic itself contains no A2A types.

For streaming agents, events must be emitted in order: task (`TASK_STATE_SUBMITTED`), artifact
updates, and a final status update with a terminal state. The stream must always end in a terminal
state — there is no separate `final` flag in A2A 1.0.

The `supportedInterfaces[].url` field in the Agent Card must be an address reachable from the
CodeMie process. When running on a Docker network, use a container hostname rather than `0.0.0.0`.

Reference implementations using the `a2a-sdk` 1.x are available in the
[ai-run-demo-agents](https://github.com/epam-gen-ai-run/ai-run-demo-agents) repository:
`python/agents/text-insights-agent` (non-streaming) and `python/agents/howto-guide-agent` (streaming).

## Sources

- [Building A2A-Compatible Agents](https://codemie-ai.github.io/docs/user-guide/tools_integrations/tools/a2a-building-agents)
- [A2A Protocol](https://codemie-ai.github.io/docs/user-guide/tools_integrations/tools/a2a)
Loading