publisher =
- requestHandler.onSubscribeToTask(TaskIdParams.builder().id(taskId).tenant("").build(), ctx);
+ requestHandler.onSubscribeToTask(
+ TaskIdParams.builder().id(taskId).tenant("").build(), ctx);
return subscribeToEmitter(publisher, ctx);
} catch (A2AError e) {
log.warn("[SSE] Task subscription rejected before stream creation: {}", e.getMessage());
diff --git a/spring-boot-starter/src/main/java/dev/openan/workflow/engine/spring/A2AProperties.java b/spring-boot-starter/src/main/java/dev/openan/workflow/engine/spring/A2AProperties.java
index 116152d..df91261 100644
--- a/spring-boot-starter/src/main/java/dev/openan/workflow/engine/spring/A2AProperties.java
+++ b/spring-boot-starter/src/main/java/dev/openan/workflow/engine/spring/A2AProperties.java
@@ -40,8 +40,8 @@ public class A2AProperties {
private String pathPrefix = "/a2a/json";
/**
- * Whether to expose slash-style aliases for A2A action endpoints for gateways that reject
- * colons in published paths. Standard colon-style endpoints always remain available.
+ * Whether to expose slash-style aliases for A2A action endpoints for gateways that reject colons
+ * in published paths. Standard colon-style endpoints always remain available.
*/
private boolean slashActionAliasesEnabled = false;
diff --git a/spring-boot-starter/src/main/java/dev/openan/workflow/engine/spring/A2ASlashActionAliasController.java b/spring-boot-starter/src/main/java/dev/openan/workflow/engine/spring/A2ASlashActionAliasController.java
index a5ef9a8..56f3b0c 100644
--- a/spring-boot-starter/src/main/java/dev/openan/workflow/engine/spring/A2ASlashActionAliasController.java
+++ b/spring-boot-starter/src/main/java/dev/openan/workflow/engine/spring/A2ASlashActionAliasController.java
@@ -30,8 +30,8 @@
/**
* Optional slash-style aliases for A2A action endpoints.
*
- * Every operation delegates to {@link A2AController}; the aliases therefore retain the
- * canonical endpoint's authentication, A2A error envelope, streaming, and cleanup behavior.
+ *
Every operation delegates to {@link A2AController}; the aliases therefore retain the canonical
+ * endpoint's authentication, A2A error envelope, streaming, and cleanup behavior.
*/
@RestController
@ConditionalOnProperty(
diff --git a/spring-boot-starter/src/test/java/dev/openan/workflow/engine/spring/A2AAutoConfigurationTest.java b/spring-boot-starter/src/test/java/dev/openan/workflow/engine/spring/A2AAutoConfigurationTest.java
index 493953b..f722896 100644
--- a/spring-boot-starter/src/test/java/dev/openan/workflow/engine/spring/A2AAutoConfigurationTest.java
+++ b/spring-boot-starter/src/test/java/dev/openan/workflow/engine/spring/A2AAutoConfigurationTest.java
@@ -18,6 +18,7 @@
*/
package dev.openan.workflow.engine.spring;
+import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -29,12 +30,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-import static org.hamcrest.Matchers.containsString;
import java.lang.reflect.Modifier;
import java.util.concurrent.ExecutorService;
@@ -49,13 +49,12 @@
import org.a2aproject.sdk.server.requesthandlers.RequestHandler;
import org.a2aproject.sdk.spec.AgentCapabilities;
import org.a2aproject.sdk.spec.AgentCard;
-import org.a2aproject.sdk.spec.TaskNotFoundError;
import org.a2aproject.sdk.spec.StreamingEventKind;
+import org.a2aproject.sdk.spec.TaskNotFoundError;
import org.a2aproject.sdk.transport.rest.handler.RestHandler;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
-import org.springframework.http.ResponseEntity;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
@@ -169,26 +168,30 @@ public void cancel() {
assertEquals(0, controller.activeStreamCount());
}
-
@org.junit.jupiter.params.ParameterizedTest
@org.junit.jupiter.params.provider.ValueSource(
strings = {"before-subscribe", "after-subscribe", "during-request"})
- void synchronousPublisherFailureReleasesResourcesBeforeMvcDispatch(String phase) throws Exception {
+ void synchronousPublisherFailureReleasesResourcesBeforeMvcDispatch(String phase)
+ throws Exception {
for (String endpoint : new String[] {"/message:stream", "/tasks/task-1:subscribe"}) {
RestHandler restHandler = mock(RestHandler.class);
when(restHandler.createErrorResponse(any()))
- .thenReturn(new RestHandler.HTTPRestResponse(
- 500, "application/a2a+json",
- "{\"error\":{\"code\":500,\"status\":\"INTERNAL\",\"message\":\"Setup failed\"}}"));
+ .thenReturn(
+ new RestHandler.HTTPRestResponse(
+ 500,
+ "application/a2a+json",
+ "{\"error\":{\"code\":500,\"status\":\"INTERNAL\",\"message\":\"Setup failed\"}}"));
RequestHandler requestHandler = mock(RequestHandler.class);
AgentCard agentCard = mock(AgentCard.class);
- when(agentCard.capabilities()).thenReturn(AgentCapabilities.builder().streaming(true).build());
+ when(agentCard.capabilities())
+ .thenReturn(AgentCapabilities.builder().streaming(true).build());
var agentInterface = mock(org.a2aproject.sdk.spec.AgentInterface.class);
when(agentInterface.protocolVersion()).thenReturn("1.0");
when(agentCard.supportedInterfaces()).thenReturn(java.util.List.of(agentInterface));
AtomicInteger subscriptionCancellations = new AtomicInteger();
AtomicInteger eventConsumerCancellations = new AtomicInteger();
- AtomicReference> subscriber = new AtomicReference<>();
+ AtomicReference> subscriber =
+ new AtomicReference<>();
org.mockito.stubbing.Answer> answer =
invocation -> {
ServerCallContext context = invocation.getArgument(1);
@@ -196,19 +199,20 @@ void synchronousPublisherFailureReleasesResourcesBeforeMvcDispatch(String phase)
return receiver -> {
subscriber.set(receiver);
if (!phase.equals("before-subscribe")) {
- receiver.onSubscribe(new Flow.Subscription() {
- @Override
- public void request(long count) {
- if (phase.equals("during-request")) {
- throw new IllegalStateException("Request failed");
- }
- }
-
- @Override
- public void cancel() {
- subscriptionCancellations.incrementAndGet();
- }
- });
+ receiver.onSubscribe(
+ new Flow.Subscription() {
+ @Override
+ public void request(long count) {
+ if (phase.equals("during-request")) {
+ throw new IllegalStateException("Request failed");
+ }
+ }
+
+ @Override
+ public void cancel() {
+ subscriptionCancellations.incrementAndGet();
+ }
+ });
}
throw new IllegalStateException("Subscribe failed");
};
@@ -216,16 +220,20 @@ public void cancel() {
when(requestHandler.onSubscribeToTask(any(), any())).thenAnswer(answer);
when(requestHandler.onMessageSendStream(any(), any())).thenAnswer(answer);
var controller = new A2AController(restHandler, requestHandler, agentCard);
- MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller)
- .addPlaceholderValue("a2at.server.path-prefix", "/a2a/json")
- .build();
-
- mockMvc.perform(post("/a2a/json" + endpoint)
- .header("A2A-Version", "1.0")
- .contentType("application/json")
- .accept("text/event-stream")
- .content("{\"message\":{\"messageId\":\"m1\",\"role\":\"ROLE_USER\","
- + "\"parts\":[{\"text\":\"test\"}]}}"))
+ MockMvc mockMvc =
+ MockMvcBuilders.standaloneSetup(controller)
+ .addPlaceholderValue("a2at.server.path-prefix", "/a2a/json")
+ .build();
+
+ mockMvc
+ .perform(
+ post("/a2a/json" + endpoint)
+ .header("A2A-Version", "1.0")
+ .contentType("application/json")
+ .accept("text/event-stream")
+ .content(
+ "{\"message\":{\"messageId\":\"m1\",\"role\":\"ROLE_USER\","
+ + "\"parts\":[{\"text\":\"test\"}]}}"))
.andExpect(status().isInternalServerError())
.andExpect(request().asyncNotStarted())
.andExpect(content().contentTypeCompatibleWith("application/a2a+json"))
@@ -414,8 +422,7 @@ void slashActionAliasesAreOptIn() {
.withBean(A2AController.class, () -> canonical)
.withPropertyValues("a2at.server.enabled=true");
- runner.run(
- context -> assertFalse(context.containsBean("a2aSlashActionAliasController")));
+ runner.run(context -> assertFalse(context.containsBean("a2aSlashActionAliasController")));
runner
.withPropertyValues("a2at.server.slash-action-aliases-enabled=true")
.run(context -> assertTrue(context.containsBean("a2aSlashActionAliasController")));
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/A2AErrorDetectingHttpClient.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/A2AErrorDetectingHttpClient.java
index c602404..efdf37d 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/A2AErrorDetectingHttpClient.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/A2AErrorDetectingHttpClient.java
@@ -36,31 +36,74 @@ final class A2AErrorDetectingHttpClient implements A2AHttpClient {
this.delegate = delegate;
}
- @Override public GetBuilder createGet() { return new Get(delegate.createGet()); }
- @Override public PostBuilder createPost() { return new Post(delegate.createPost()); }
- @Override public DeleteBuilder createDelete() { return new Delete(delegate.createDelete()); }
+ @Override
+ public GetBuilder createGet() {
+ return new Get(delegate.createGet());
+ }
+
+ @Override
+ public PostBuilder createPost() {
+ return new Post(delegate.createPost());
+ }
+
+ @Override
+ public DeleteBuilder createDelete() {
+ return new Delete(delegate.createDelete());
+ }
private static A2AHttpResponse check(A2AHttpResponse response) {
- var error = RemoteA2AErrorException.fromResponse(
- response.status(), response.body(), response.headers().toMap());
+ var error =
+ RemoteA2AErrorException.fromResponse(
+ response.status(), response.body(), response.headers().toMap());
if (error != null) throw error;
return response;
}
private abstract static class Wrapped> implements Builder {
final T target;
- Wrapped(T target) { this.target = target; }
+
+ Wrapped(T target) {
+ this.target = target;
+ }
+
abstract T self();
- @Override public T url(String url) { target.url(url); return self(); }
- @Override public T addHeader(String name, String value) { target.addHeader(name, value); return self(); }
- @Override public T addHeaders(Map headers) { target.addHeaders(headers); return self(); }
+
+ @Override
+ public T url(String url) {
+ target.url(url);
+ return self();
+ }
+
+ @Override
+ public T addHeader(String name, String value) {
+ target.addHeader(name, value);
+ return self();
+ }
+
+ @Override
+ public T addHeaders(Map headers) {
+ target.addHeaders(headers);
+ return self();
+ }
}
private static final class Get extends Wrapped implements GetBuilder {
- Get(GetBuilder target) { super(target); }
- @Override GetBuilder self() { return this; }
- @Override public A2AHttpResponse get() throws IOException, InterruptedException { return check(target.get()); }
- @Override public CompletableFuture getAsyncSSE(
+ Get(GetBuilder target) {
+ super(target);
+ }
+
+ @Override
+ GetBuilder self() {
+ return this;
+ }
+
+ @Override
+ public A2AHttpResponse get() throws IOException, InterruptedException {
+ return check(target.get());
+ }
+
+ @Override
+ public CompletableFuture getAsyncSSE(
Consumer messages, Consumer errors, Runnable complete)
throws IOException, InterruptedException {
return stream(target::getAsyncSSE, messages, errors, complete);
@@ -68,11 +111,28 @@ private static final class Get extends Wrapped implements GetBuilder
}
private static final class Post extends Wrapped implements PostBuilder {
- Post(PostBuilder target) { super(target); }
- @Override PostBuilder self() { return this; }
- @Override public PostBuilder body(String body) { target.body(body); return this; }
- @Override public A2AHttpResponse post() throws IOException, InterruptedException { return check(target.post()); }
- @Override public CompletableFuture postAsyncSSE(
+ Post(PostBuilder target) {
+ super(target);
+ }
+
+ @Override
+ PostBuilder self() {
+ return this;
+ }
+
+ @Override
+ public PostBuilder body(String body) {
+ target.body(body);
+ return this;
+ }
+
+ @Override
+ public A2AHttpResponse post() throws IOException, InterruptedException {
+ return check(target.post());
+ }
+
+ @Override
+ public CompletableFuture postAsyncSSE(
Consumer messages, Consumer errors, Runnable complete)
throws IOException, InterruptedException {
return stream(target::postAsyncSSE, messages, errors, complete);
@@ -80,63 +140,93 @@ private static final class Post extends Wrapped implements PostBuil
}
private static final class Delete extends Wrapped implements DeleteBuilder {
- Delete(DeleteBuilder target) { super(target); }
- @Override DeleteBuilder self() { return this; }
- @Override public A2AHttpResponse delete() throws IOException, InterruptedException { return check(target.delete()); }
+ Delete(DeleteBuilder target) {
+ super(target);
+ }
+
+ @Override
+ DeleteBuilder self() {
+ return this;
+ }
+
+ @Override
+ public A2AHttpResponse delete() throws IOException, InterruptedException {
+ return check(target.delete());
+ }
}
private static CompletableFuture stream(
- StreamStarter starter, Consumer messages,
- Consumer errors, Runnable complete) throws IOException, InterruptedException {
+ StreamStarter starter,
+ Consumer messages,
+ Consumer errors,
+ Runnable complete)
+ throws IOException, InterruptedException {
var result = new CompletableFuture();
var upstream = new AtomicReference>();
var ended = new AtomicBoolean();
var eventReceived = new AtomicBoolean();
- Consumer fail = error -> {
- if (!ended.compareAndSet(false, true)) return;
- try { errors.accept(error); }
- catch (RuntimeException observerError) {
- if (observerError != error) error.addSuppressed(observerError);
- }
- finally { result.completeExceptionally(error); }
- };
- result.whenComplete((ignored, error) -> {
- if (error != null) {
- ended.set(true);
- var active = upstream.get();
- if (active != null) active.cancel(true);
- }
- });
- var active = starter.start(event -> {
- if (ended.get()) return;
- var remoteError = RemoteA2AErrorException.fromPayload(event.data());
- if (remoteError != null) fail.accept(remoteError);
- else {
- eventReceived.set(true);
- try { messages.accept(event); }
- catch (RuntimeException callbackError) { fail.accept(callbackError); }
- }
- }, fail, () -> {
- if (!eventReceived.get()) {
- fail.accept(new IOException("A2A streaming response closed without an event"));
- return;
- }
- if (ended.compareAndSet(false, true)) {
- try { complete.run(); result.complete(null); }
- catch (RuntimeException error) { result.completeExceptionally(error); }
- }
- });
+ Consumer fail =
+ error -> {
+ if (!ended.compareAndSet(false, true)) return;
+ try {
+ errors.accept(error);
+ } catch (RuntimeException observerError) {
+ if (observerError != error) error.addSuppressed(observerError);
+ } finally {
+ result.completeExceptionally(error);
+ }
+ };
+ result.whenComplete(
+ (ignored, error) -> {
+ if (error != null) {
+ ended.set(true);
+ var active = upstream.get();
+ if (active != null) active.cancel(true);
+ }
+ });
+ var active =
+ starter.start(
+ event -> {
+ if (ended.get()) return;
+ var remoteError = RemoteA2AErrorException.fromPayload(event.data());
+ if (remoteError != null) fail.accept(remoteError);
+ else {
+ eventReceived.set(true);
+ try {
+ messages.accept(event);
+ } catch (RuntimeException callbackError) {
+ fail.accept(callbackError);
+ }
+ }
+ },
+ fail,
+ () -> {
+ if (!eventReceived.get()) {
+ fail.accept(new IOException("A2A streaming response closed without an event"));
+ return;
+ }
+ if (ended.compareAndSet(false, true)) {
+ try {
+ complete.run();
+ result.complete(null);
+ } catch (RuntimeException error) {
+ result.completeExceptionally(error);
+ }
+ }
+ });
upstream.set(active);
if (result.isCompletedExceptionally()) active.cancel(true);
- active.whenComplete((ignored, error) -> {
- if (error != null) fail.accept(error);
- });
+ active.whenComplete(
+ (ignored, error) -> {
+ if (error != null) fail.accept(error);
+ });
return result;
}
@FunctionalInterface
private interface StreamStarter {
- CompletableFuture start(Consumer messages, Consumer errors,
- Runnable complete) throws IOException, InterruptedException;
+ CompletableFuture start(
+ Consumer messages, Consumer errors, Runnable complete)
+ throws IOException, InterruptedException;
}
}
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/A2ATransport.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/A2ATransport.java
index 1c514e0..f939274 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/A2ATransport.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/A2ATransport.java
@@ -542,10 +542,10 @@ public void closeConversation(AgentCard agentCard, String contextId) {
}
/**
- * Long-lived SSE stream for Notification-T subscription. Opens a daemon thread that keeps the
- * SSE response stream open. The eventSink callback processes events in real-time (subscribed ack
- * + later recovery results). The returned future completes on the first event carrying a
- * concrete task state; an artifact alone is application data, not a protocol acknowledgement.
+ * Long-lived SSE stream for Notification-T subscription. Opens a daemon thread that keeps the SSE
+ * response stream open. The eventSink callback processes events in real-time (subscribed ack +
+ * later recovery results). The returned future completes on the first event carrying a concrete
+ * task state; an artifact alone is application data, not a protocol acknowledgement.
*/
public NotificationSubscription openNotificationStream(
AgentCard agentCard,
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/CredentialHeaderContributor.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/CredentialHeaderContributor.java
index 0ea914a..d304eec 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/CredentialHeaderContributor.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/CredentialHeaderContributor.java
@@ -42,9 +42,7 @@ final class CredentialHeaderContributor implements HeaderContributor {
}
private static void addCredentialHeader(
- Map headers,
- Map schemeConfig,
- String credential) {
+ Map headers, Map schemeConfig, String credential) {
String authHeader = (String) schemeConfig.get("auth_header");
if (authHeader != null && !authHeader.isEmpty()) {
String prefix = (String) schemeConfig.getOrDefault("auth_header_prefix", "");
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/DefaultWorkflowEngineClient.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/DefaultWorkflowEngineClient.java
index 7c63ae4..68f9e64 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/DefaultWorkflowEngineClient.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/DefaultWorkflowEngineClient.java
@@ -441,8 +441,8 @@ private CompletableFuture advance(
/**
* Shared negotiation loop for both carriers: a task-anchored {@code INPUT_REQUIRED} status
* ({@code remoteTask} set) and a taskless bare-message Propose ({@code remoteTask == null},
- * pre-task A2A-T negotiation). The follow-up send reuses the remote task id when there is one
- * and stays taskless otherwise.
+ * pre-task A2A-T negotiation). The follow-up send reuses the remote task id when there is one and
+ * stays taskless otherwise.
*/
private CompletableFuture negotiate(
AgentCard card, Invocation invocation, SendMessageResult result, String remoteTask) {
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/ObservedHttpClient.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/ObservedHttpClient.java
index d6d07f4..e54740d 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/ObservedHttpClient.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/ObservedHttpClient.java
@@ -181,16 +181,18 @@ void failure(Throwable error) {
if (cancelledBySubscriber.get()) return;
// Body subscriber and sendAsync completion can report the same exchange failure.
if (!failureLogged.compareAndSet(false, true)) return;
- String message = SensitiveDataRedactor.redact(Objects.toString(error.getMessage(), ""))
- .replace("\r", "\\r")
- .replace("\n", "\\n");
+ String message =
+ SensitiveDataRedactor.redact(Objects.toString(error.getMessage(), ""))
+ .replace("\r", "\\r")
+ .replace("\n", "\\n");
emit(
"FAILURE",
null,
Map.of(),
"transport-error",
"",
- "errorType=" + error.getClass().getSimpleName()
+ "errorType="
+ + error.getClass().getSimpleName()
+ (message.isBlank() ? "" : "; errorMessage=" + message));
}
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/RemoteA2AErrorException.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/RemoteA2AErrorException.java
index b820f26..b359519 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/RemoteA2AErrorException.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/RemoteA2AErrorException.java
@@ -120,7 +120,9 @@ public static RemoteA2AErrorException fromResponse(
/** Finds or projects a standard A2A error in a wrapped SDK/transport exception chain. */
public static RemoteA2AErrorException findIn(Throwable error) {
Set seen = Collections.newSetFromMap(new IdentityHashMap<>());
- for (Throwable current = error; current != null && seen.add(current); current = current.getCause()) {
+ for (Throwable current = error;
+ current != null && seen.add(current);
+ current = current.getCause()) {
if (current instanceof RemoteA2AErrorException remote) return remote;
if (current instanceof A2AClientHTTPError http) {
RemoteA2AErrorException parsed =
@@ -196,10 +198,7 @@ private static String safeText(JsonNode node, String key) {
/** Stable workflow-facing error code that does not expose SDK exception class names. */
public String workflowErrorCode() {
String normalizedReason =
- reason
- .toLowerCase(Locale.ROOT)
- .replaceAll("[^a-z0-9]+", "_")
- .replaceAll("^_+|_+$", "");
+ reason.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9]+", "_").replaceAll("^_+|_+$", "");
if (!normalizedReason.isBlank()) return "a2a." + normalizedReason;
return "a2a.http." + httpStatus;
}
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/TransportFailures.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/TransportFailures.java
index 1b50af2..508a42d 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/TransportFailures.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/TransportFailures.java
@@ -23,7 +23,9 @@
import java.util.Locale;
import java.util.concurrent.CancellationException;
-/** Classifies transport termination without making provider-specific messages the primary signal. */
+/**
+ * Classifies transport termination without making provider-specific messages the primary signal.
+ */
final class TransportFailures {
private TransportFailures() {}
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/package-info.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/package-info.java
index 0f0ff69..20bb65d 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/client/package-info.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/client/package-info.java
@@ -18,6 +18,7 @@
*/
/**
- * Protocol adaptation: transport runtimes, authentication, negotiation correlation, independent subscriptions, and wire observability. Content generation stays with the host.
+ * Protocol adaptation: transport runtimes, authentication, negotiation correlation, independent
+ * subscriptions, and wire observability. Content generation stays with the host.
*/
package dev.openan.workflow.engine.client;
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/control/package-info.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/control/package-info.java
index 7c8c867..f0c2246 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/control/package-info.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/control/package-info.java
@@ -18,6 +18,7 @@
*/
/**
- * The four business callback contracts (onTask, onSelfTask, onRoute, onNegotiation) plus the engine event callback surface.
+ * The four business callback contracts (onTask, onSelfTask, onRoute, onNegotiation) plus the engine
+ * event callback surface.
*/
package dev.openan.workflow.engine.control;
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/core/package-info.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/core/package-info.java
index b4d4bfb..d9ac0b0 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/core/package-info.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/core/package-info.java
@@ -18,6 +18,7 @@
*/
/**
- * The scheduler: workflow graph validation, traversal, parallel dispatch, upstream context windows, and failure mapping.
+ * The scheduler: workflow graph validation, traversal, parallel dispatch, upstream context windows,
+ * and failure mapping.
*/
package dev.openan.workflow.engine.core;
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/model/BusinessInput.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/model/BusinessInput.java
index 1750964..f39bbeb 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/model/BusinessInput.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/model/BusinessInput.java
@@ -19,7 +19,6 @@
package dev.openan.workflow.engine.model;
-
/** Business content, not a protocol message. Exactly one of text/data is present. */
public record BusinessInput(String text, Object data) {
public BusinessInput {
diff --git a/workflow-engine/src/main/java/dev/openan/workflow/engine/model/ExecutionResult.java b/workflow-engine/src/main/java/dev/openan/workflow/engine/model/ExecutionResult.java
index 0bf5a27..645bb43 100644
--- a/workflow-engine/src/main/java/dev/openan/workflow/engine/model/ExecutionResult.java
+++ b/workflow-engine/src/main/java/dev/openan/workflow/engine/model/ExecutionResult.java
@@ -36,10 +36,13 @@
@Builder
public class ExecutionResult {
private boolean success;
+
/** Per-step records in execution order. */
private List