| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Build powerful, interoperable AI agents with the Agent-to-Agent (A2A) protocol
⚠️ Early Stage Warning: This project is in its early stages of development. Breaking changes are expected as the API evolves and improves. Please use pinned versions in production environments and be prepared to update your code when upgrading versions.
The A2A ADK (Agent Development Kit) is a Go library that simplifies building Agent-to-Agent (A2A) protocol compatible agents. A2A enables seamless communication between AI agents, allowing them to collaborate, delegate tasks, and share capabilities across different systems and providers.
Agent-to-Agent (A2A) is a standardized protocol that enables AI agents to:
go get github.com/inference-gateway/adkFor complete working examples, see the examples directory:
To run any example:
cd examples/minimal/server
go run main.goEach example includes its own README with setup instructions and usage details.
# Clone the repository
git clone https://github.com/inference-gateway/adk.git
cd adk
# Install dependencies
go mod download
# Install pre-commit hook
task precommit:install| Task | Description |
|---|---|
| task a2a:download-schema | Download the latest A2A schema |
| task a2a:generate-types | Generate Go types from A2A schema |
| task lint | Run linting and code quality checks |
| task test | Run all tests |
| task precommit:install | Install Git pre-commit hook (recommended) |
The ADK supports injecting agent metadata at build time using Go linker flags (LD flags). This makes agent information immutable and embedded in the binary, which is useful for production deployments.
The following build-time metadata variables can be set via LD flags:
Simple A2A Server Example:
package main
import (
"context"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time"
zap "go.uber.org/zap"
server "github.com/inference-gateway/adk/server"
config "github.com/inference-gateway/adk/server/config"
types "github.com/inference-gateway/adk/types"
)
func main() {
fmt.Println("🤖 Starting Simple A2A Server...")
// Initialize logger
logger, err := zap.NewDevelopment()
if err != nil {
log.Fatalf("failed to create logger: %v", err)
}
defer logger.Sync()
// Get port from environment or use default
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
// Configuration
cfg := config.Config{
AgentName: "simple-agent",
AgentDescription: "A simple A2A server with default handlers",
AgentVersion: "0.1.0",
Debug: true,
QueueConfig: config.QueueConfig{
CleanupInterval: 5 * time.Minute,
},
ServerConfig: config.ServerConfig{
Port: port,
},
}
// Build and start server with default handlers
a2aServer, err := server.NewA2AServerBuilder(cfg, logger).
WithDefaultTaskHandlers().
WithAgentCard(types.AgentCard{
Name: cfg.AgentName,
Description: cfg.AgentDescription,
Version: cfg.AgentVersion,
URL: fmt.Sprintf("http://localhost:%s", port),
ProtocolVersion: "0.3.0",
Capabilities: types.AgentCapabilities{
Streaming: &[]bool{true}[0],
PushNotifications: &[]bool{false}[0],
StateTransitionHistory: &[]bool{false}[0],
},
DefaultInputModes: []string{"text/plain"},
DefaultOutputModes: []string{"text/plain"},
Skills: []types.AgentSkill{},
}).
Build()
if err != nil {
logger.Fatal("failed to create A2A server", zap.Error(err))
}
logger.Info("✅ server created")
// Start server
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
if err := a2aServer.Start(ctx); err != nil {
logger.Fatal("server failed to start", zap.Error(err))
}
}()
logger.Info("🌐 server running on port " + port)
// Wait for shutdown signal
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
logger.Info("🛑 shutting down...")
// Graceful shutdown
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer shutdownCancel()
if err := a2aServer.Stop(shutdownCtx); err != nil {
logger.Error("shutdown error", zap.Error(err))
} else {
logger.Info("✅ goodbye!")
}
}See the Docker Support section for containerized builds.
For detailed development workflows, testing guidelines, and contribution processes, see the Contributing Guide.
The main server interface that handles A2A protocol communication. See server examples for complete implementation details.
Build A2A servers with custom configurations using a fluent interface. The builder provides methods for:
See examples for complete usage patterns.
The ADK provides two distinct interfaces for handling tasks:
Streaming handlers require an agent to be configured. See task handler examples for implementation details.
Build OpenAI-compatible agents using a fluent interface. Supports:
See AI-powered examples and callback examples for complete agent setup.
Client interface for communicating with A2A servers. Supports:
See client examples for usage patterns.
Beyond message/send, message/stream, and tasks/get, the client exposes every method in the A2A JSON-RPC surface. Each snippet below is runnable against any ADK-built server; see examples/protocol-methods/ for an end-to-end demo that ties them all together.
Cancel an in-flight task. Works for tasks in any non-terminal state (SUBMITTED, WORKING, INPUT_REQUIRED, AUTH_REQUIRED, UNSPECIFIED).
resp, err := a2a.CancelTask(ctx, types.TaskIdParams{ID: taskID})
if err != nil {
log.Fatalf("cancel failed: %v", err)
}
taskBytes, _ := json.Marshal(resp.Result)
var task types.Task
_ = json.Unmarshal(taskBytes, &task)
log.Printf("cancelled task %s → state=%s", task.ID, task.Status.State)List tasks the server knows about. Limit controls page size (server caps the limit at 100; default is 50) and Offset controls where the page starts. Iterate until offset >= TotalSize to walk the full result set.
const pageSize = 20
offset := 0
for {
resp, err := a2a.ListTasks(ctx, types.TaskListParams{
Limit: pageSize,
Offset: offset,
})
if err != nil {
log.Fatalf("list failed: %v", err)
}
listBytes, _ := json.Marshal(resp.Result)
var list types.TaskList
_ = json.Unmarshal(listBytes, &list)
for _, t := range list.Tasks {
log.Printf(" task %s [%s]", t.ID, t.Status.State)
}
offset += len(list.Tasks)
if len(list.Tasks) == 0 || offset >= list.TotalSize {
break
}
}You can also filter by ContextID or by State (e.g. only TASK_STATE_COMPLETED); both fields are optional pointers on TaskListParams.
Register, inspect, and remove webhook callbacks the server will POST to as a task changes state. The four methods share a common identifier (task.ID) and form a complete CRUD cycle.
configID := uuid.New().String()
authToken := "shared-secret"
// set: register a webhook for the task.
if _, err := a2a.SetTaskPushNotificationConfig(ctx, types.TaskPushNotificationConfig{
Name: taskID,
PushNotificationConfig: types.PushNotificationConfig{
ID: &configID,
URL: "https://example.com/webhook",
Token: &authToken,
},
}); err != nil {
log.Fatalf("set failed: %v", err)
}
// get: read the active config.
if _, err := a2a.GetTaskPushNotificationConfig(ctx, types.GetTaskPushNotificationConfigParams{
Name: taskID,
}); err != nil {
log.Fatalf("get failed: %v", err)
}
// list: enumerate every config attached to a task.
if _, err := a2a.ListTaskPushNotificationConfig(ctx, types.ListTaskPushNotificationConfigParams{
Parent: taskID,
}); err != nil {
log.Fatalf("list failed: %v", err)
}
// delete: tear the config down.
if _, err := a2a.DeleteTaskPushNotificationConfig(ctx, types.DeleteTaskPushNotificationConfigParams{
Name: taskID,
}); err != nil {
log.Fatalf("delete failed: %v", err)
}Server-side push notifications require CapabilitiesConfig.PushNotifications to be true on the server.
Re-attach to a streaming task after the original SSE connection has dropped. The server first re-emits the current task state, then forwards any further streaming events as they happen.
events, err := a2a.ResubscribeTask(ctx, types.TaskResubscriptionParams{
Name: taskID,
})
if err != nil {
log.Fatalf("resubscribe failed: %v", err)
}
for evt := range events {
payload, _ := json.Marshal(evt.Result)
log.Printf("event: %s", string(payload))
}The JSON-RPC counterpart to the public .well-known/agent-card.json endpoint. The response is the same AgentCard object, but the call passes through the JSON-RPC route and is therefore subject to the server's authentication middleware - useful when the extended card should only be visible to authenticated callers.
resp, err := a2a.GetAuthenticatedExtendedCard(ctx, types.GetAuthenticatedExtendedCardParams{})
if err != nil {
log.Fatalf("authenticated card fetch failed: %v", err)
}
cardBytes, _ := json.MarshalIndent(resp.Result, "", " ")
log.Println(string(cardBytes))Monitor agent operational status with three health states:
See client examples for implementation.
Create OpenAI-compatible LLM clients for agent integration. See AI examples for setup details.
Configure your A2A agent using environment variables. All configuration is optional and includes sensible defaults.
| Variable | Default | Description |
|---|---|---|
| PORT | 8080 | Server port |
| DEBUG | false | Enable debug logging |
| AGENT_URL | http://helloworld-agent:8080 | Agent URL for internal references |
| STREAMING_STATUS_UPDATE_INTERVAL | 1s | How often to send streaming status updates |
| Variable | Default | Description |
|---|---|---|
| AGENT_CLIENT_PROVIDER | - | LLM provider (openai, anthropic, groq, etc.) |
| AGENT_CLIENT_MODEL | - | Model name (e.g., openai/gpt-4) |
| AGENT_CLIENT_BASE_URL | - | Custom LLM endpoint URL |
| AGENT_CLIENT_API_KEY | - | API key for LLM provider |
| AGENT_CLIENT_TIMEOUT | 30s | Request timeout |
| AGENT_CLIENT_MAX_RETRIES | 3 | Maximum retry attempts |
| AGENT_CLIENT_MAX_CHAT_COMPLETION_ITERATIONS | 50 | Max chat completion rounds |
| AGENT_CLIENT_MAX_TOKENS | 4096 | Maximum tokens per response |
| AGENT_CLIENT_TEMPERATURE | 0.7 | LLM temperature (0.0-2.0) |
| AGENT_CLIENT_SYSTEM_PROMPT | - | System prompt for the agent |
| AGENT_CLIENT_ENABLE_USAGE_METADATA | true | Track token usage and execution metrics |
| Variable | Default | Description |
|---|---|---|
| CAPABILITIES_STREAMING | true | Enable streaming responses |
| CAPABILITIES_PUSH_NOTIFICATIONS | false | Enable webhook notifications |
| CAPABILITIES_STATE_TRANSITION_HISTORY | false | Track state changes |
| Variable | Default | Description |
|---|---|---|
| AUTH_ENABLED | false | Enable OIDC authentication |
| AUTH_ISSUER_URL | - | OIDC issuer URL |
| AUTH_CLIENT_ID | - | OIDC client ID |
| AUTH_CLIENT_SECRET | - | OIDC client secret |
See docs/authentication.md for the full card-driven auth flow: discovery, out-of-band credentials, the authenticated extended card, and authorization via callbacks.
| Variable | Default | Description |
|---|---|---|
| TASK_RETENTION_MAX_COMPLETED_TASKS | 100 | Max completed tasks to keep (0 = unlimited) |
| TASK_RETENTION_MAX_FAILED_TASKS | 50 | Max failed tasks to keep (0 = unlimited) |
| TASK_RETENTION_CLEANUP_INTERVAL | 5m | Cleanup frequency (0 = manual only) |
| Variable | Default | Description |
|---|---|---|
| QUEUE_PROVIDER | memory | Storage backend: memory or redis |
| QUEUE_URL | - | Redis connection URL (required when using Redis) |
| QUEUE_MAX_SIZE | 100 | Maximum queue size |
| QUEUE_CLEANUP_INTERVAL | 120s | How often to clean up completed tasks |
Storage Backends:
Redis Configuration Examples:
# Basic Redis setup
export QUEUE_PROVIDER=redis
export QUEUE_URL=redis://localhost:6379
# Redis with authentication
export QUEUE_URL=redis://:password@localhost:6379
export QUEUE_URL=redis://username:password@localhost:6379
# Redis with specific database
export QUEUE_URL=redis://localhost:6379/1
# Redis with TLS (Redis 6.0+)
export QUEUE_URL=rediss://username:password@redis.example.com:6380/0Connect the agent to MCP servers and expose their tools through a selector that keeps only tool metadata in the LLM context. Disabled by default and only useful when an LLM is configured. Enable with MCP_ENABLED=true and point MCP_SERVERS at one or more streamable-HTTP MCP servers; the full list of MCP_* variables (timeouts, retry, and polling-backoff tuning) is documented in docs/mcp.md.
Enable file artifacts support for downloadable files generated by your agent:
| Variable | Default | Description |
|---|---|---|
| ARTIFACTS_ENABLED | false | Enable artifacts support |
| ARTIFACTS_SERVER_HOST | localhost | Artifacts server host |
| ARTIFACTS_SERVER_PORT | 8081 | Artifacts server port |
| ARTIFACTS_STORAGE_PROVIDER | filesystem | Storage backend: filesystem or minio |
| ARTIFACTS_STORAGE_BASE_PATH | ./artifacts | Base path for filesystem storage |
| ARTIFACTS_STORAGE_BASE_URL | (auto-generated) | Override base URL for direct downloads |
| ARTIFACTS_STORAGE_ENDPOINT | - | MinIO/S3 endpoint URL |
| ARTIFACTS_STORAGE_ACCESS_KEY | - | MinIO/S3 access key |
| ARTIFACTS_STORAGE_SECRET_KEY | - | MinIO/S3 secret key |
| ARTIFACTS_STORAGE_BUCKET_NAME | artifacts | MinIO/S3 bucket name |
| ARTIFACTS_STORAGE_USE_SSL | true | Use SSL for MinIO/S3 connections |
| ARTIFACTS_RETENTION_MAX_ARTIFACTS | 5 | Max artifacts per task (0 = unlimited) |
| ARTIFACTS_RETENTION_MAX_AGE | 7d | Max artifact age (0 = no age limit) |
| ARTIFACTS_RETENTION_CLEANUP_INTERVAL | 24h | Cleanup frequency (0 = manual only) |
Storage Backends:
Download Modes:
MinIO Configuration Example:
# Enable artifacts with MinIO storage
export ARTIFACTS_ENABLED=true
export ARTIFACTS_STORAGE_PROVIDER=minio
export ARTIFACTS_STORAGE_ENDPOINT=localhost:9000
export ARTIFACTS_STORAGE_ACCESS_KEY=minioadmin
export ARTIFACTS_STORAGE_SECRET_KEY=minioadmin
export ARTIFACTS_STORAGE_USE_SSL=false
# Optional: Enable direct downloads (bypasses artifacts server)
export ARTIFACTS_STORAGE_BASE_URL=http://localhost:9000Benefits of Redis Storage:
| Variable | Default | Description |
|---|---|---|
| SERVER_TLS_ENABLED | false | Enable TLS/HTTPS |
| SERVER_TLS_CERT_PATH | - | Path to TLS certificate |
| SERVER_TLS_KEY_PATH | - | Path to TLS private key |
When enabled, the server exports metrics (Prometheus pull or OTLP push) and can export traces via OTLP over HTTP or gRPC. It also participates in W3C Trace Context propagation: incoming traceparent and baggage headers are extracted, a request-scoped a2a.request span is created, and the session.id / gen_ai.tool.call.id baggage items are surfaced as span attributes. Exporters are selected with the standard OTEL_* variables; the original TELEMETRY_* variables remain supported as deprecated aliases. See docs/telemetry.md for the full matrix.
TELEMETRY_ENABLED=true is the master switch; the OTEL_* variables then choose which exporters run per signal.
| Variable | Default | Description |
|---|---|---|
| TELEMETRY_ENABLED | false | Master switch for the telemetry subsystem |
| OTEL_METRICS_EXPORTER | prometheus | Metrics exporter: prometheus, otlp, or none |
| OTEL_TRACES_EXPORTER | otlp | Traces exporter: otlp or none |
| OTEL_EXPORTER_OTLP_ENDPOINT | http://localhost:4318 | OTLP endpoint base URL for traces and metrics |
| OTEL_EXPORTER_OTLP_PROTOCOL | http/protobuf | OTLP transport: http/protobuf or grpc |
| OTEL_EXPORTER_PROMETHEUS_HOST | - | Prometheus pull host (empty = all interfaces) |
| OTEL_EXPORTER_PROMETHEUS_PORT | 9090 | Prometheus pull port |
Attribute keys (default to OTel semantic conventions; used for both the baggage member and the span attribute):
| Variable | Default | Description |
|---|---|---|
| TELEMETRY_ATTR_SESSION_ID_KEY | session.id | Session id baggage/attribute key |
| TELEMETRY_ATTR_TOOL_CALL_ID_KEY | gen_ai.tool.call.id | Tool call id baggage/attribute key |
Deprecated aliases (superseded by the OTEL_* variables above, still honored):
| Variable | Default | Superseded by |
|---|---|---|
| TELEMETRY_METRICS_PORT | 9090 | OTEL_EXPORTER_PROMETHEUS_PORT |
| TELEMETRY_METRICS_HOST | - | OTEL_EXPORTER_PROMETHEUS_HOST |
| TELEMETRY_TRACE_ENDPOINT | http://localhost:4318 | OTEL_EXPORTER_OTLP_ENDPOINT |
| TELEMETRY_TRACE_HEADERS | - | OTEL_EXPORTER_OTLP_HEADERS |
| TELEMETRY_LOG_* | - | Reserved - OTLP log export not yet wired |
The tracing service name is taken from the agent card name (the build-time agent identity), not a separate variable.
Library consumers that already run their own OpenTelemetry setup can inject it with WithTelemetry() instead of letting the ADK build one from the environment. The injected instance activates the middleware, request spans, and /metrics endpoint regardless of TELEMETRY_ENABLED:
srv, err := server.NewA2AServerBuilder(cfg, logger).
WithTelemetry(myOtel).
WithAgentCard(card).
WithDefaultTaskHandlers().
Build()See configuration examples for complete setup patterns, including environment variables, custom config structs, and programmatic overrides.
For detailed implementation examples and patterns, see the examples directory:
This ADK is part of the broader Inference Gateway ecosystem:
Build and run your A2A agent application in a container. Here's an example Dockerfile for an application using the ADK:
FROM golang:1.26-alpine AS builder
# Build arguments for agent metadata
ARG AGENT_NAME="My A2A Agent"
ARG AGENT_DESCRIPTION="A custom A2A agent built with the ADK"
ARG AGENT_VERSION="0.1.0"
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go mod tidy && \
go build -ldflags "-X 'github.com/inference-gateway/adk/server.BuildAgentName=${AGENT_NAME}' -X 'github.com/inference-gateway/adk/server.BuildAgentDescription=${AGENT_DESCRIPTION}' -X 'github.com/inference-gateway/adk/server.BuildAgentVersion=${AGENT_VERSION}'" -o bin/agent .
FROM alpine:latest
RUN apk --no-cache add ca-certificates && \
addgroup -g 1001 -S a2a && \
adduser -u 1001 -S agent -G a2a
WORKDIR /home/agent
COPY --from=builder /app/bin/agent .
RUN chown agent:a2a ./agent
USER agent
CMD ["./agent"]Build with custom metadata:
docker build \
--build-arg AGENT_NAME="Weather Assistant" \
--build-arg AGENT_DESCRIPTION="AI-powered weather forecasting agent" \
--build-arg AGENT_VERSION="0.1.1" \
-t my-a2a-agent .This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
Contributions to the A2A ADK are welcome! Whether you're fixing bugs, adding features, improving documentation, or helping with testing, your contributions make the project better for everyone.
Please see the Contributing Guide for:
Quick Start for Contributors:
# Fork the repo and clone it
git clone https://github.com/your-username/adk.git
cd adk
# Install pre-commit hook
task precommit:installFor questions or help getting started, please open a discussion or check out the contributing guide.
| Back | FazBrowse Home | New Git URL |