diff --git a/docs/content/posts/2026-06-10-a2a-java-sdk-1-0-0-final-released/annouce.png b/docs/content/posts/2026-06-10-a2a-java-sdk-1-0-0-final-released/annouce.png index b62caa5f9..00a8d3064 100644 Binary files a/docs/content/posts/2026-06-10-a2a-java-sdk-1-0-0-final-released/annouce.png and b/docs/content/posts/2026-06-10-a2a-java-sdk-1-0-0-final-released/annouce.png differ diff --git a/docs/content/posts/2026-06-29-a2a-java-sdk-1-1-0-final-released/announce.png b/docs/content/posts/2026-06-29-a2a-java-sdk-1-1-0-final-released/announce.png index 4b5652779..521a446f8 100644 Binary files a/docs/content/posts/2026-06-29-a2a-java-sdk-1-1-0-final-released/announce.png and b/docs/content/posts/2026-06-29-a2a-java-sdk-1-1-0-final-released/announce.png differ diff --git a/docs/content/posts/2026-08-06-a2a-java-sdk-1-2-0-final-released/announce.png b/docs/content/posts/2026-08-06-a2a-java-sdk-1-2-0-final-released/announce.png new file mode 100644 index 000000000..6484c6de1 Binary files /dev/null and b/docs/content/posts/2026-08-06-a2a-java-sdk-1-2-0-final-released/announce.png differ diff --git a/docs/content/posts/2026-08-06-a2a-java-sdk-1-2-0-final-released/index.adoc b/docs/content/posts/2026-08-06-a2a-java-sdk-1-2-0-final-released/index.adoc new file mode 100644 index 000000000..a61a24746 --- /dev/null +++ b/docs/content/posts/2026-08-06-a2a-java-sdk-1-2-0-final-released/index.adoc @@ -0,0 +1,271 @@ +--- +layout: post +title: 'A2A Java SDK 1.2.0.Final Released' +date: 2026-08-06 +tags: ai a2a +synopsis: 'A2A Java SDK 1.2.0.Final is now available -- with authorization hardening, stream lifecycle hooks, and improved spec compliance.' +author: kkhan +--- +image::announce.png[A2A Java SDK 1.2.0.Final announcement] + +I am happy to announce the release of link:https://github.com/a2aproject/a2a-java/releases/tag/v1.2.0.Final[A2A Java SDK 1.2.0.Final]. This release hardens the authorization model, adds stream lifecycle management, and fixes several protocol compliance issues. + +NOTE: This release contains **breaking changes**. See the <> section for details. + +== What's New + +=== Authorization Hardening + +The 1.1.0 release introduced the `TaskAuthorizationProvider` SPI for per-user task authorization. This release closes gaps in that model and makes the authorization API easier to use from non-CDI environments. + +==== Read authorization on referenced tasks + +Previously, when a request referenced existing tasks via `referenceTaskIds`, the SDK populated those tasks in the `RequestContext` without checking read authorization. An unauthorized caller could probe for task existence via `sendStreamingMessage` or `subscribeToTask`. This release enforces read authorization on all referenced task lookups (link:https://github.com/a2aproject/a2a-java/pull/1005[\#1005]). + +The fix touches all transports (JSON-RPC, gRPC, REST) and decorators (OpenTelemetry, authorization). `InMemoryTaskStore` now applies fail-closed authorization -- when authorization is configured but no call context is available, access is denied -- matching the existing `JpaDatabaseTaskStore` behavior. + +This is a **breaking change** -- see <> below. + +==== Referenced task population now enabled by default + +Previously, when using `DefaultRequestHandler` via CDI, referenced task IDs in messages were not resolved from the `TaskStore`. This has been fixed -- referenced tasks are now populated by default and made available via `RequestContext.getRelatedTasks()`. + +If you need to restore the previous behavior, set the following property: + +[source,properties] +---- +a2a.request-context.populate-referred-tasks=false +---- + +==== Fail-closed read-access helper + +A new static helper `TaskAuthorizationProvider.checkReadAccess()` centralizes the fail-closed logic for read checks: + +[source,java] +---- +// Returns true (allow) when no provider is configured. +// Returns false (deny) when a provider is present but no call context is available. +// Otherwise delegates to provider.checkRead(). +boolean allowed = TaskAuthorizationProvider.checkReadAccess( + provider, context, taskId, TaskOperation.GET_TASK); +---- + +This is the same logic used internally by `InMemoryTaskStore` and `JpaDatabaseTaskStore`, now available for custom `TaskStore` implementations. + +==== Programmatic auth wiring + +The `AuthorizationRequestHandlerDecorator` constructor is now `public` (link:https://github.com/a2aproject/a2a-java/pull/966[\#966]), enabling programmatic wiring in non-CDI runtimes like Spring Framework: + +[source,java] +---- +RequestHandler secured = new AuthorizationRequestHandlerDecorator( + delegate, myAuthorizationProvider); +---- + +`AuthenticatedUser` now supports arbitrary attributes via a `Map` -- useful for carrying claims, roles, or other identity data from your authentication layer: + +[source,java] +---- +AuthenticatedUser user = new AuthenticatedUser("alice", + Map.of("role", "admin", "tenant", "acme")); +Object role = user.getAttribute("role"); // "admin" +---- + +==== Security reporting + +We would like to thank the community members who responsibly reported security issues. If you discover a security vulnerability, please follow the process described in our link:https://github.com/a2aproject/a2a-java/blob/main/SECURITY.md[SECURITY.md] -- your reports help us keep the SDK safe for everyone. + +=== Task Stream Lifecycle Hook + +The new `TaskStreamLifecycleHook` SPI (link:https://github.com/a2aproject/a2a-java/issues/990[\#990]) lets you observe and control task stream lifecycle events. You can react when clients subscribe/unsubscribe to a task's event stream and when events are processed -- giving you the ability to close all active streams for a task on demand. + +This is useful for patterns like closing streams after a timeout, enforcing maximum subscriber limits, or cleaning up resources when all clients disconnect. + +To use it, implement the interface and register it as a CDI bean: + +[source,java] +---- +@ApplicationScoped +@Alternative +@Priority(1) +public class MyStreamHook implements TaskStreamLifecycleHook { + + @Override + public void onSubscribe(String taskId, StreamCloseHandle handle) { + // A client subscribed -- handle.getActiveSubscriberCount() includes this subscriber + } + + @Override + public void onUnsubscribe(String taskId, StreamCloseHandle handle) { + // A client disconnected + } + + @Override + public void onEvent(String taskId, Event event, StreamCloseHandle handle) { + // An event was persisted and distributed -- call handle.closeStreams() to shut down all streams + } +} +---- + +The hook is wired through `InMemoryQueueManager`, `MainEventBusProcessor`, and `ReplicatedQueueManager`, so it works across all deployment modes. A link:https://github.com/a2aproject/a2a-java/tree/main/examples/stream-lifecycle[stream-lifecycle example] with integration tests across all three transports is included. + +=== Hardened Spec Immutability + +All remaining spec records now enforce deep immutability (link:https://github.com/a2aproject/a2a-java/pull/968[\#968]). Collections in spec types like `SecurityRequirement`, `TaskArtifactUpdateEvent`, `TaskStatusUpdateEvent`, and `TextPart` are defensively copied, ensuring callers cannot mutate shared state. + +=== Multi-Version Documentation + +The link:https://a2aproject.github.io/a2a-java/[project website] now supports versioned documentation (link:https://github.com/a2aproject/a2a-java/pull/1000[\#1000]) with a version dropdown, per-version sidebar menus, and a version-scoped search filter. Each release produces a frozen documentation snapshot, while the `dev.next` version tracks the latest changes. + +=== Aggregated Javadoc + +A new `site-javadoc` Maven profile (link:https://github.com/a2aproject/a2a-java/pull/988[\#988]) generates unified cross-module Javadoc where `@see` and `@link` references across modules resolve as navigable HTML links. + +== Bug Fixes + +* **Reconcile blocking result with TaskStore** -- when an `AgentExecutor` returned a result synchronously, the task state could diverge from what was persisted. The reconciliation timeout is now configurable (link:https://github.com/a2aproject/a2a-java/pull/991[\#991]) +* **Avoid wrapping tasks in list responses** -- `ListTasksResult` was incorrectly double-wrapping `Task` objects in JSON-RPC serialization (link:https://github.com/a2aproject/a2a-java/pull/998[\#998]) +* **Apply historyLength to streaming responses** -- `historyLength` from `MessageSendConfiguration` was silently ignored for `SendStreamingMessage` calls (link:https://github.com/a2aproject/a2a-java/pull/983[\#983]) +* **Correct task/contextId in emitted Messages** -- `AgentEmitter` now populates the correct `taskId` and `contextId` on emitted messages (link:https://github.com/a2aproject/a2a-java/pull/976[\#976]) +* **Deprecate isFinal overrides in AgentEmitter** -- interrupted state methods now use the spec-defined `isFinal` value instead of allowing callers to override it (link:https://github.com/a2aproject/a2a-java/pull/989[\#989]) +* **Vert.x HTTP client race condition** -- fixed a race in non-SSE error response handling where small error bodies could be fully received before the pipe attached (link:https://github.com/a2aproject/a2a-java/pull/1005[\#1005]) + +[[migration]] +== Migration from 1.1.0.Final + +Update your BOM version: + +[source,xml] +---- + + + + org.a2aproject.sdk + a2a-java-sdk-bom + 1.2.0.Final + pom + import + + + +---- + +This release has three breaking changes: + +[[auth-migration]] +=== 1. Read authorization on referenced task lookup + +The `RequestHandler.validateRequestedTask()` method has been renamed to `authorizeTaskAccess()` with additional parameters: + +[source,java] +---- +// Before +void validateRequestedTask(@Nullable String requestedTaskId) throws A2AError; + +// After +void authorizeTaskAccess(@Nullable String requestedTaskId, ServerCallContext context, + TaskOperation operation) throws A2AError; +---- + +`DefaultRequestHandler.create()` has been replaced by a builder: + +[source,java] +---- +// Before +DefaultRequestHandler handler = DefaultRequestHandler.create( + agentExecutor, taskStore, queueManager, pushConfigStore, + mainEventBusProcessor, executor, eventConsumerExecutor); + +// After +DefaultRequestHandler handler = DefaultRequestHandler.builder() + .agentExecutor(agentExecutor) + .taskStore(taskStore) + .queueManager(queueManager) + .pushConfigStore(pushConfigStore) + .mainEventBusProcessor(mainEventBusProcessor) + .executor(executor) + .eventConsumerExecutor(eventConsumerExecutor) + .authorizationProvider(authProvider) // optional + .populateReferredTasks(true) // optional + .build(); +---- + +`SimpleRequestContextBuilder` now requires a third parameter: + +[source,java] +---- +// Before +new SimpleRequestContextBuilder(taskStore, shouldPopulateReferredTasks) + +// After -- pass null if you don't use task authorization +new SimpleRequestContextBuilder(taskStore, shouldPopulateReferredTasks, authorizationProvider) +---- + +=== 2. Split packages resolved + +Several packages were renamed so that no Java package spans multiple Maven modules. This affects your imports: + +[cols="1,1,1"] +|=== +| Module | Old Package | New Package + +| `spec` +| `org.a2aproject.sdk.util` +| `org.a2aproject.sdk.spec.util` + +| `extras/opentelemetry` +| `org.a2aproject.sdk.extras.opentelemetry` +| `org.a2aproject.sdk.extras.opentelemetry.server` + +| `extras/http-client-android` +| `org.a2aproject.sdk.client.http` +| `org.a2aproject.sdk.client.http.android` + +| `extras/http-client-vertx` +| `org.a2aproject.sdk.client.http` +| `org.a2aproject.sdk.client.http.vertx` +|=== + +The most common change: utility classes like `CollectionCopies`, `ErrorDetail`, `PageToken`, and `Utils` move from `org.a2aproject.sdk.util` to `org.a2aproject.sdk.spec.util`. + +SPI service files were updated, so `ServiceLoader`-based discovery continues to work automatically. + +=== 3. TaskState.UNRECOGNIZED renamed + +`TaskState.UNRECOGNIZED` has been renamed to `TaskState.TASK_STATE_UNSPECIFIED` to match the A2A specification. Its `isFinal` property also changed from `true` to `false`: + +[source,java] +---- +// Before +TaskState.UNRECOGNIZED // isFinal() == true + +// After +TaskState.TASK_STATE_UNSPECIFIED // isFinal() == false +---- + +If your code relied on `UNRECOGNIZED` being terminal, review your logic -- event queues will no longer auto-close and clients will not stop polling when a task is in this state. + +== Contributors + +Thank you to the contributors of this release! + +link:https://github.com/ehsavoie[@ehsavoie], link:https://github.com/kabir[@kabir], link:https://github.com/Sh1bari[@Sh1bari], link:https://github.com/JakubWorek[@JakubWorek], link:https://github.com/014-code[@014-code], link:https://github.com/jstar0[@jstar0] + +== Resources + +* link:https://github.com/a2aproject/a2a-java/releases/tag/v1.2.0.Final[Release Notes on GitHub] +* link:https://central.sonatype.com/artifact/org.a2aproject.sdk/a2a-java-sdk-parent/1.2.0.Final[Maven Central] +* link:https://javadoc.io/doc/org.a2aproject.sdk/[JavaDoc] +* link:https://a2a-protocol.org/v1.0.0/specification/[A2A Specification] +* link:https://a2aproject.github.io/a2a-java/[Project Website] +* link:https://github.com/a2aproject/a2a-java/tree/main/examples[Examples] + +== Come Join Us + +We value your feedback a lot so please report bugs, ask for improvements etc. Let's build something great together! + +If you are an A2A Java SDK user or just curious, don't be shy and join our welcoming community: + +* provide feedback on link:https://github.com/a2aproject/a2a-java/issues[GitHub]; +* craft some code and link:https://github.com/a2aproject/a2a-java/pulls[push a PR]; +* discuss with us in the `#a2a-java` channel on link:https://discord.gg/jTtSkJB74Q[Discord]; diff --git a/docs/pom.xml b/docs/pom.xml index 6f4bec977..070f37281 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -16,6 +16,8 @@ UTF-8 true 2.1.6 + 2.1.4 + 21 @@ -56,6 +58,11 @@ quarkus-roq-plugin-markdown ${roq.version} + + io.quarkiverse.roq + quarkus-roq-plugin-asciidoc + ${roq.version} + io.quarkiverse.roq quarkus-roq-plugin-sitemap @@ -96,6 +103,26 @@ + + maven-enforcer-plugin + ${maven-enforcer-plugin.version} + + + require-java-21 + + enforce + + + + + [21,) + The docs module requires Java 21+ (Roq ${roq.version} is compiled for Java 21) + + + + + + io.quarkus.platform quarkus-maven-plugin