Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

- Increase the default Notification-T acknowledgement timeout from 5 seconds to 5 minutes and expose the sample Spring
setting as `a2a.notification-ack-timeout-seconds` /
`A2A_NOTIFICATION_ACK_TIMEOUT_SECONDS`.

## [0.0.5] — 2026-09-09

### Breaking: per-edge conditional routing
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ subscription remains open until the host-defined terminal event, explicit cancel

### 1. Add Maven dependency

The current engine release is `0.0.2` on [Maven Central](https://repo.maven.apache.org/maven2/net/openan/workflow/sdk/).
The current engine release is `0.0.6` on [Maven Central](https://repo.maven.apache.org/maven2/net/openan/workflow/sdk/).

A2A-T SDK `1.1.0` is published to Maven Central. Maven resolves it automatically; no SDK source checkout or local SDK
build is required. The engine depends only on
Expand All @@ -51,7 +51,7 @@ upgrade guidance.
<dependency>
<groupId>net.openan.workflow.sdk</groupId>
<artifactId>workflow-engine</artifactId>
<version>0.0.2</version>
<version>0.0.6</version>
</dependency>
```

Expand All @@ -60,8 +60,8 @@ For Spring Boot server-side integration:
```xml
<dependency>
<groupId>net.openan.workflow.sdk</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>0.0.2</version>
<artifactId>spring-boot-a2a-starter</artifactId>
<version>0.0.6</version>
</dependency>
```

Expand Down Expand Up @@ -162,7 +162,7 @@ graph TD
| Module | Description |
|-----------------------|---------------------------------------------------------------|
| `workflow-engine` | Core SDK: workflow execution, A2A transport, extensions, auth |
| `spring-boot-starter` | Spring Boot auto-configuration for A2A server side |
| `spring-boot-a2a-starter` | Spring Boot auto-configuration for A2A server side |
| `samples` | Demo applications (embedded + Spring Boot variants) |

## License
Expand Down
7 changes: 4 additions & 3 deletions docs/en/API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Builder-based configuration for the workflow engine client.
| `clientKeyPassword` | `String` | null | Password for an encrypted PKCS#8 private key |
| `crlPath` | `String` | null | X.509 CRL for HTTP/JSON-RPC; the default gRPC runtime rejects this unsupported combination |
| `sendTimeoutSeconds` | `long` | `600` | SSE stream timeout (10 min default) |
| `notificationAckTimeoutSeconds` | `long` | `5` | Wait for the first Notification-T ACK/event |
| `notificationAckTimeoutSeconds` | `long` | `300` | Wait for the first Notification-T ACK/event (five minutes by default) |
| `sendExecutorCoreSize` | `int` | `4` | Send executor core threads |
| `sendExecutorMaxSize` | `int` | `16` | Send executor maximum threads |
| `sendExecutorQueueCapacity` | `int` | `256` | Bounded send executor queue capacity |
Expand All @@ -136,6 +136,7 @@ WorkflowEngineClientConfig config = WorkflowEngineClientConfig.builder()
.clientCertPath("client-cert.pem")
.clientKeyPath("client-key.pem")
.sendTimeoutSeconds(900)
.notificationAckTimeoutSeconds(300)
.credentialsConfigPath("creds.json")
.maxNegotiationExchanges(5)
.authProvider(myProvider)
Expand Down Expand Up @@ -621,9 +622,9 @@ not add private negotiation-state keys to the wire message.

---

## spring-boot-starter Module
## spring-boot-a2a-starter Module

The `spring-boot-starter` module provides Spring Boot auto-configuration for the A2A **server** side (not the
The `spring-boot-a2a-starter` module provides Spring Boot auto-configuration for the A2A **server** side (not the
client/workflow side). In a Spring Boot web application, set `a2at.server.enabled=true` to register the A2A SDK server
components as Spring beans.

Expand Down
2 changes: 1 addition & 1 deletion docs/en/DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Add to your `pom.xml`:
<dependency>
<groupId>net.openan.workflow.sdk</groupId>
<artifactId>workflow-engine</artifactId>
<version>0.0.2</version>
<version>0.0.6</version>
</dependency>
```

Expand Down
14 changes: 9 additions & 5 deletions docs/en/INTEGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ callbacks own A2A-T generation, semantic validation, schemas and any LLM calls.
<dependency>
<groupId>net.openan.workflow.sdk</groupId>
<artifactId>workflow-engine</artifactId>
<version>0.0.2</version>
<version>0.0.6</version>
</dependency>
```

Expand Down Expand Up @@ -221,18 +221,18 @@ configuration without modifying system properties. Never log plaintext or the ke

**Encrypt a password**

Build the jar with `mvn -pl workflow-engine -am -Drevision=0.0.2 package`; commands below run from the repository root.
Build the jar with `mvn -pl workflow-engine -am -Drevision=0.0.6 package`; commands below run from the repository root.
`set` is Windows cmd syntax (PowerShell: `$env:A2AT_CRED_KEY='...'`). This CLI needs only the SDK jar and JDK.
Use disposable example values here: command-line passwords/keys can appear in shell history and process listings.
For production, obtain secrets securely in the host and use the Java encryption API.

```bash
# Option 1: set env var first
set A2AT_CRED_KEY=4f8a2b1c3d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
java -cp workflow-engine/target/workflow-engine-0.0.2.jar dev.openan.workflow.engine.client.CredentialCrypto "Admin@123"
java -cp workflow-engine/target/workflow-engine-0.0.6.jar dev.openan.workflow.engine.client.CredentialCrypto "Admin@123"

# Option 2: pass key as second argument
java -cp workflow-engine/target/workflow-engine-0.0.2.jar dev.openan.workflow.engine.client.CredentialCrypto "Admin@123" 4f8a2b1c3d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
java -cp workflow-engine/target/workflow-engine-0.0.6.jar dev.openan.workflow.engine.client.CredentialCrypto "Admin@123" 4f8a2b1c3d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
```

Output:
Expand All @@ -248,7 +248,7 @@ Paste the output into the `value` field of the credentials JSON.
1. Generate a new key: `openssl rand -hex 32`
2. Update the host secret store / explicit `credentialEncryptionKey`, or its OS/JVM `A2AT_CRED_KEY`
3. Re-encrypt all passwords:
`java -cp workflow-engine/target/workflow-engine-0.0.2.jar dev.openan.workflow.engine.client.CredentialCrypto "plaintext" new-key`
`java -cp workflow-engine/target/workflow-engine-0.0.6.jar dev.openan.workflow.engine.client.CredentialCrypto "plaintext" new-key`
4. Update the `enc:...` results in the credentials JSON file

> The `.env` file should not be committed to version control. Add it to `.gitignore`.
Expand Down Expand Up @@ -411,6 +411,10 @@ transport/runtime/context instances. The listener receives the handle and comple
host-defined terminal event. acknowledgement() and completion() separately represent ACK and actual stream exit;
neither is a workflow prerequisite.

`WorkflowEngineClientConfig.notificationAckTimeoutSeconds` controls the initial subscription ACK wait and defaults to
300 seconds. The Spring sample exposes it as `a2a.notification-ack-timeout-seconds` and
`A2A_NOTIFICATION_ACK_TIMEOUT_SECONDS`. It does not control SSE idle time after acknowledgement.

## 8. HTTPS Configuration

```java
Expand Down
7 changes: 4 additions & 3 deletions docs/zh/API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ handle 再开始 I/O,监听器直接收到 handle 和完整 ReceivedMessage。
| `clientKeyPassword` | `String` | null | 加密 PKCS#8 私钥密码 |
| `crlPath` | `String` | null | HTTP/JSON-RPC 的 X.509 CRL 路径;默认 gRPC runtime 暂不支持并会拒绝启动 |
| `sendTimeoutSeconds` | `long` | `600` | SSE 流超时(默认 10 分钟) |
| `notificationAckTimeoutSeconds` | `long` | `5` | Notification-T 首个 ACK/事件等待时间 |
| `notificationAckTimeoutSeconds` | `long` | `300` | Notification-T 首个 ACK/事件等待时间(默认 5 分钟) |
| `sendExecutorCoreSize` | `int` | `4` | 发送线程池核心线程数 |
| `sendExecutorMaxSize` | `int` | `16` | 发送线程池最大线程数 |
| `sendExecutorQueueCapacity` | `int` | `256` | 发送线程池有界队列容量 |
Expand All @@ -130,6 +130,7 @@ WorkflowEngineClientConfig config = WorkflowEngineClientConfig.builder()
.clientCertPath("client-cert.pem")
.clientKeyPath("client-key.pem")
.sendTimeoutSeconds(900)
.notificationAckTimeoutSeconds(300)
.credentialsConfigPath("creds.json")
.maxNegotiationExchanges(5)
.authProvider(myProvider)
Expand Down Expand Up @@ -588,9 +589,9 @@ getReceivedMessages() 是保留层级的响应来源,getOutputs() 为便利投

---

## spring-boot-starter 模块
## spring-boot-a2a-starter 模块

`spring-boot-starter` 模块为 A2A **服务端**(非客户端/工作流侧)提供 Spring Boot 自动配置。在 Spring Boot Web 应用中配置
`spring-boot-a2a-starter` 模块为 A2A **服务端**(非客户端/工作流侧)提供 Spring Boot 自动配置。在 Spring Boot Web 应用中配置
`a2at.server.enabled=true` 后,才会将 A2A SDK 服务端组件注册为 Spring Bean。

### A2AProperties
Expand Down
2 changes: 1 addition & 1 deletion docs/zh/DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<dependency>
<groupId>net.openan.workflow.sdk</groupId>
<artifactId>workflow-engine</artifactId>
<version>0.0.2</version>
<version>0.0.6</version>
</dependency>
```

Expand Down
14 changes: 9 additions & 5 deletions docs/zh/INTEGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ A2A-T 工作流执行引擎是一个 Java SDK,用于基于 A2A 协议和 A2A-T
<dependency>
<groupId>net.openan.workflow.sdk</groupId>
<artifactId>workflow-engine</artifactId>
<version>0.0.2</version>
<version>0.0.6</version>
</dependency>
```

Expand Down Expand Up @@ -212,17 +212,17 @@ A2AT_CRED_KEY=4f8a2b1c3d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b

**加密密码**

先执行 `mvn -pl workflow-engine -am -Drevision=0.0.2 package`,以下命令在仓库根目录运行,仅需 SDK jar 和 JDK。
先执行 `mvn -pl workflow-engine -am -Drevision=0.0.6 package`,以下命令在仓库根目录运行,仅需 SDK jar 和 JDK。
`set` 是 Windows cmd 语法,PowerShell 应使用 `$env:A2AT_CRED_KEY='...'`。
以下参数仅用于演示;命令行口令/密钥可能进入终端历史和进程参数。生产应由集成方安全读取密钥并调用 Java 加密 API。

```bash
# 方式一:先设置环境变量
set A2AT_CRED_KEY=4f8a2b1c3d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
java -cp workflow-engine/target/workflow-engine-0.0.2.jar dev.openan.workflow.engine.client.CredentialCrypto "Admin@123"
java -cp workflow-engine/target/workflow-engine-0.0.6.jar dev.openan.workflow.engine.client.CredentialCrypto "Admin@123"

# 方式二:密钥作为第二个参数
java -cp workflow-engine/target/workflow-engine-0.0.2.jar dev.openan.workflow.engine.client.CredentialCrypto "Admin@123" 4f8a2b1c3d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
java -cp workflow-engine/target/workflow-engine-0.0.6.jar dev.openan.workflow.engine.client.CredentialCrypto "Admin@123" 4f8a2b1c3d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
```

输出:
Expand All @@ -237,7 +237,7 @@ enc:uHQcTeKZMVNRM9Ga:o5vm4weRozBXBs04phrLq7j7+/yRVyDsrw==

1. 生成新密钥:`openssl rand -hex 32`
2. 更新集成方密钥存储及显式 `credentialEncryptionKey`,或 OS/JVM 的 `A2AT_CRED_KEY`;引擎不自动加载 `.env`
3. 用新密钥重新加密所有密码:`java -cp workflow-engine/target/workflow-engine-0.0.2.jar dev.openan.workflow.engine.client.CredentialCrypto "明文密码" 新密钥`
3. 用新密钥重新加密所有密码:`java -cp workflow-engine/target/workflow-engine-0.0.6.jar dev.openan.workflow.engine.client.CredentialCrypto "明文密码" 新密钥`
4. 将新的 `enc:...` 结果更新到凭证 JSON 文件

> `.env` 文件不应提交到版本库,建议加入 `.gitignore`。
Expand Down Expand Up @@ -390,6 +390,10 @@ NotificationSubscription openNotification(String agentName, MessageContent conte

宿主智能体生成最终 Authorization-T/Notification-T 内容后调用上述接口;使用三类独立 transport/runtime/context。订阅监听器收到 handle 与完整 ReceivedMessage,在宿主定义的终态事件上关闭。handle.acknowledgement() 和 completion() 分别表示 ACK 和真实流退出,两者都不是工作流前提。

`WorkflowEngineClientConfig.notificationAckTimeoutSeconds` 控制首次订阅 ACK 的等待时间,默认 300 秒;Spring 示例可通过
`a2a.notification-ack-timeout-seconds` 或环境变量 `A2A_NOTIFICATION_ACK_TIMEOUT_SECONDS` 覆盖。该参数不控制 ACK 后的 SSE
空闲时间。

## 8. HTTPS 配置

```java
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
Expand Down
2 changes: 1 addition & 1 deletion samples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
<!-- Spring Boot starter: auto-assembles A2A server beans, partner only implements AgentExecutor -->
<dependency>
<groupId>net.openan.workflow.sdk</groupId>
<artifactId>spring-boot-starter</artifactId>
<artifactId>spring-boot-a2a-starter</artifactId>
<version>${revision}</version>
</dependency>
<!-- Logging: Log4j2 (SLF4J 2.x binding) with console + rolling file appender -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* Spring Boot Workbench Agent -- northbound A2A server.
*
* <p>This is the Workbench Agent itself: a Spring Boot service that exposes A2A-T endpoints
* (message:send, message:stream) via the {@code spring-boot-starter} auto-configuration. The
* (message:send, message:stream) via the {@code spring-boot-a2a-starter} auto-configuration. The
* business logic lives in {@link
* dev.openan.workflow.engine.examples.workbench.SpringWorkbenchExecutor} (implements {@code
* AgentExecutor}).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package dev.openan.workflow.engine.examples.config;

import dev.openan.workflow.engine.client.WorkflowEngineClientConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

Expand All @@ -34,6 +35,8 @@ public class WorkbenchClientProperties {
private boolean taskCleanupFailFast = true;
private int taskCleanupPageSize = 100;
private int taskCleanupMaxTasks = 1000;
private long notificationAckTimeoutSeconds =
WorkflowEngineClientConfig.DEFAULT_NOTIFICATION_ACK_TIMEOUT_SECONDS;

/**
* Internal sample-host setting; SpringSpnDemo supplies its local-only default per application
Expand Down Expand Up @@ -111,4 +114,12 @@ public int getTaskCleanupMaxTasks() {
public void setTaskCleanupMaxTasks(int taskCleanupMaxTasks) {
this.taskCleanupMaxTasks = taskCleanupMaxTasks;
}

public long getNotificationAckTimeoutSeconds() {
return notificationAckTimeoutSeconds;
}

public void setNotificationAckTimeoutSeconds(long notificationAckTimeoutSeconds) {
this.notificationAckTimeoutSeconds = notificationAckTimeoutSeconds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public synchronized void start() {
properties.isTaskCleanupFailFast(),
properties.getTaskCleanupPageSize(),
properties.getTaskCleanupMaxTasks(),
localAgentName);
localAgentName,
properties.getNotificationAckTimeoutSeconds());
try {
candidate.start();
lifecycle = candidate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public final class WorkbenchExtensionLifecycle implements AutoCloseable {
private final int taskCleanupPageSize;
private final int taskCleanupMaxTasks;
private final String localAgentName;
private final long notificationAckTimeoutSeconds;
private final java.util.function.BiConsumer<
NotificationSubscription, dev.openan.workflow.engine.model.ReceivedMessage>
notificationCallback;
Expand All @@ -73,7 +74,8 @@ public WorkbenchExtensionLifecycle(
true,
100,
1000,
null);
null,
WorkflowEngineClientConfig.DEFAULT_NOTIFICATION_ACK_TIMEOUT_SECONDS);
}

public WorkbenchExtensionLifecycle(
Expand All @@ -92,7 +94,8 @@ public WorkbenchExtensionLifecycle(
true,
100,
1000,
null);
null,
WorkflowEngineClientConfig.DEFAULT_NOTIFICATION_ACK_TIMEOUT_SECONDS);
}

public WorkbenchExtensionLifecycle(
Expand All @@ -109,6 +112,36 @@ public WorkbenchExtensionLifecycle(
int taskCleanupPageSize,
int taskCleanupMaxTasks,
String localAgentName) {
this(
credentialsPath,
sslVerify,
a2atEnvPath,
runtimeSupplier,
notificationCallback,
authProvider,
taskCleanupEnabled,
taskCleanupFailFast,
taskCleanupPageSize,
taskCleanupMaxTasks,
localAgentName,
WorkflowEngineClientConfig.DEFAULT_NOTIFICATION_ACK_TIMEOUT_SECONDS);
}

public WorkbenchExtensionLifecycle(
String credentialsPath,
boolean sslVerify,
String a2atEnvPath,
Supplier<A2AJavaClientRuntime> runtimeSupplier,
java.util.function.BiConsumer<
NotificationSubscription, dev.openan.workflow.engine.model.ReceivedMessage>
notificationCallback,
dev.openan.workflow.engine.client.AuthProvider authProvider,
boolean taskCleanupEnabled,
boolean taskCleanupFailFast,
int taskCleanupPageSize,
int taskCleanupMaxTasks,
String localAgentName,
long notificationAckTimeoutSeconds) {
this.authProvider = authProvider;
this.credentialsPath = credentialsPath;
this.sslVerify = sslVerify;
Expand All @@ -120,6 +153,10 @@ public WorkbenchExtensionLifecycle(
this.taskCleanupPageSize = taskCleanupPageSize;
this.taskCleanupMaxTasks = taskCleanupMaxTasks;
this.localAgentName = localAgentName;
if (notificationAckTimeoutSeconds <= 0) {
throw new IllegalArgumentException("notificationAckTimeoutSeconds must be positive");
}
this.notificationAckTimeoutSeconds = notificationAckTimeoutSeconds;
}

private static long elapsedMillis(long startedNanos) {
Expand Down Expand Up @@ -151,6 +188,7 @@ public synchronized void start() {
.sslVerify(sslVerify)
.credentialsConfigPath(credentialsPath)
.authProvider(authProvider)
.notificationAckTimeoutSeconds(notificationAckTimeoutSeconds)
.build();
authorizationTransport = new A2ATransport(agentCards, authorizationRuntime, config);
notificationCandidate = new A2ATransport(agentCards, notificationRuntime, config);
Expand Down
1 change: 1 addition & 0 deletions samples/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ a2a:
task-cleanup-fail-fast: ${A2A_TASK_CLEANUP_FAIL_FAST:true}
task-cleanup-page-size: ${A2A_TASK_CLEANUP_PAGE_SIZE:100}
task-cleanup-max-tasks: ${A2A_TASK_CLEANUP_MAX_TASKS:1000}
notification-ack-timeout-seconds: ${A2A_NOTIFICATION_ACK_TIMEOUT_SECONDS:300}
Loading