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
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Changelog

## [Unreleased]

- Keep Notification-T subscriptions open independently of task/result terminal states; maintain
stream activity tracking and explicit cancellation/resource ownership.
- Add independent registry HTTP authentication/TLS policy and orchestration account login for PSOP
loading. These APIs are current-source capabilities, not part of the published 0.1.1 artifact.
- Refresh bilingual examples, release boundaries and constructor/transport ownership guidance.

## [0.1.1] — 2026-09-23

Released from tag `v0.1.1` (`952cde2`). Compared with 0.1.0:

- Harden workflow joins, cancellation, failure propagation and sensitive-data logging.
- Keep active notification streams alive beyond the ordinary request deadline and release
streaming resources reliably. Later state-independent terminal-result handling is under Unreleased.
- Correct build-analysis exclusions and remove development-only vendor references from main.

## [0.1.0] — 2026-09-18

- Send SSE heartbeat comments on streaming endpoints (`message:stream`, `tasks/{id}:subscribe`) at a configurable
Expand Down Expand Up @@ -137,4 +154,4 @@
- Keep documentation host-neutral; sample class and AgentCard identifiers remain unchanged.

Published Maven artifacts use the version selected by the release tag. The default source-build
`revision=0.0.9-SNAPSHOT` is not a Maven Central release version.
`revision=0.1.0-SNAPSHOT` is not a Maven Central release version.
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ workflow-engine-sdk-java/
| +-- src/main/java/dev/openan/workflow/engine/
| |-- client/ A2A transport, authentication, extensions, runtime APIs
| |-- control/ User-facing: ControlPoint, EventCallback, EventType
| |-- core/ Internal: WorkflowExecutor, ContextBuilder (package-private)
| |-- core/ WorkflowExecutor (public), ContextBuilder (package-private)
| |-- model/ Data models
| |-- registry/ LoadPsop, RegistryClient
| |-- util/ Shared redaction and utility support
| +-- runner/ ExecutePsop (entry point)
|-- samples/ Demo applications
|-- docs/ Documentation
Expand Down
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# A2A-T Workflow Execution Engine (Java)

> **Release boundary**: Maven Central currently publishes `0.1.1` (tag v0.1.1, 952cde2). This guide follows current source. Independent center HTTP authentication/TLS, PSOP account login and task-state-independent Notification-T handling were added after that tag and are unreleased. Build an exact reviewed source revision with a unique unpublished version for those capabilities; do not overwrite a released coordinate. Source revision=0.1.0-SNAPSHOT is a development coordinate, not a newer release.

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
[![Java](https://img.shields.io/badge/Java-17+-orange.svg)](https://adoptium.net/)
[![Maven](https://img.shields.io/badge/Maven-3.6+-red.svg)](https://maven.apache.org/)
Expand Down Expand Up @@ -32,13 +34,14 @@ never sent under an A2A-T URI as a fallback.
The SDK is embedded in a host agent. It schedules workflow tasks to dispatched agents and returns complete results to
the host callbacks. Task-T, Authorization-T, and Notification-T use independent transport/runtime/context instances.
Authorization and Notification are independently triggered host-agent operations rather than DAG nodes; a notification
subscription remains open until the host-defined terminal event, explicit cancellation, or shutdown.
subscription is independent of task/result status. It remains open while transport activity continues;
explicit cancellation, host shutdown, stream exit/error, or the configured idle timeout ends it.

## Quick Start

### 1. Add Maven dependency

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

A2A-T SDK `1.1.1` 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 +54,7 @@ upgrade guidance.
<dependency>
<groupId>net.openan.workflow.sdk</groupId>
<artifactId>workflow-engine</artifactId>
<version>0.1.0</version>
<version>0.1.1</version>
</dependency>
```

Expand All @@ -61,7 +64,7 @@ For Spring Boot server-side integration:
<dependency>
<groupId>net.openan.workflow.sdk</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>0.1.0</version>
<version>0.1.1</version>
</dependency>
```

Expand Down Expand Up @@ -134,6 +137,7 @@ graph TD
root --> model
root --> registry
root --> runner
root --> util
```

| Package | Key Classes | Description |
Expand All @@ -143,6 +147,7 @@ graph TD
| `core` | `WorkflowExecutor`, `ContextBuilder` | DAG traversal, context assembly |
| `model` | `Workflow`, `WorkflowStep`, `Task`, `TaskRequest`, `MessageContent`, `TaskResult`, `NegotiationRequest`, `NegotiationReply`, `ExecutionResult` | Data models |
| `registry` | `LoadPsop`, `RegistryClient` | PSOP loading and AgentCard registry |
| `util` | `SensitiveDataRedactor` | Shared sensitive-data redaction |
| `runner` | `ExecutePsop` | Entry point for workflow execution |

> **Note:** `LlmHelper` lives in the **samples** module (`dev.openan.workflow.engine.examples`), not in the `client`
Expand Down
4 changes: 2 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

| Version | Supported |
|---------|--------------------|
| 1.0.x | :white_check_mark: |
| < 1.0 | :x: |
| Latest released 0.1.x | Report vulnerabilities against the latest release; fixes are evaluated on main |
| Older releases | Upgrade; no separate backport guarantee is documented |

## Reporting a Vulnerability

Expand Down
17 changes: 16 additions & 1 deletion docs/en/API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ Builder-based configuration for the workflow engine client.
| `sendExecutorCoreSize` | `int` | `4` | Send executor core threads |
| `sendExecutorMaxSize` | `int` | `16` | Send executor maximum threads |
| `sendExecutorQueueCapacity` | `int` | `256` | Bounded send executor queue capacity |
| `preferredProtocol` | `String` | null | Preferred declared AgentCard protocol; use supported transport identifiers, not a vendor name. |
| `authProvider` | `AuthProvider` | null | Custom auth provider |
| `credentialsConfigPath` | `String` | null | Path to credentials JSON; explicit missing or malformed files fail startup |
| `credentialEncryptionKey` | `String` | null | Host-supplied decryption key; never loaded from LLM .env |
Expand Down Expand Up @@ -197,7 +198,7 @@ the same header name throw `SecurityException` instead of silently overwriting e

Submit custom extensions via MessageContent(parts, metadata, extensions); no engine content-handler registration.
A2atMessages.from(MetadataContent, List<Part<?>>) preserves SDK metadata and activates the corresponding URI; contextOf
(ReceivedMessage) or contextOf(Map<String,Object>) reads/checks canonical negotiation context. This adapter uses
(ReceivedMessage) is the public context reader. The Map overload is package-private and cannot be called by host code. This adapter uses
a2a-t-core only, never content generation or semantic validation.

### A2AJavaClientRuntime
Expand All @@ -213,6 +214,20 @@ public interface A2AJavaClientRuntime {
Consumer<ClientEvent> eventSink,
Consumer<String> logSink);

// Optional task operations; default implementations throw UnsupportedOperationException.
default Task getTask(AgentCard card, String taskId, ClientCallContext context) {
throw new UnsupportedOperationException();
}
default ListTasksResult listTasks(AgentCard card, ListTasksParams params, ClientCallContext context) {
throw new UnsupportedOperationException();
}
default Task cancelTask(AgentCard card, String taskId, ClientCallContext context) {
throw new UnsupportedOperationException();
}
default CompletableFuture<SendMessageResult> subscribeToTask(
AgentCard card, String taskId, ClientCallContext context, Consumer<ClientEvent> sink) {
throw new UnsupportedOperationException();
}
void close();
}
```
Expand Down
22 changes: 14 additions & 8 deletions docs/en/BUSINESS_CALLBACKS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Business callback integration contract

Release `0.1.0` API; A2A-T SDK `1.1.1`, A2A Java `1.2.0.Final`. The engine owns DAG scheduling, standard A2A envelopes,
Current-source API baseline; A2A-T SDK `1.1.1`, A2A Java `1.2.0.Final`. The engine owns DAG scheduling, standard A2A envelopes,
auth, transport and task waiting. The host owns content, schemas, templates, semantic validation and any LLM calls.
The business contracts are independent of the transport runtime.

Expand All @@ -19,7 +19,7 @@ onTask returns final parts/metadata/extensions; the engine sends them without ge
onSelfTask returns local TaskResult, onRoute independently allows or denies one conditional edge, and onNegotiation
returns Send or Stop. Unconditional edges bypass onRoute and always run. Unimplemented callbacks fail explicitly. No
echo-success, implicit route approval or automatic consent.
See [Business callback contract](BUSINESS_CALLBACKS.md) for fields and working examples.
See the callback fields and examples below.

```java
ControlPoint callbacks = ControlPoint.builder()
Expand Down Expand Up @@ -220,7 +220,7 @@ sends; it does not automatically stop external business/LLM work. Hosts own canc
callback entry points must return promptly; place blocking operations in an asynchronous executor.
Missing/null/exceptional callbacks fail; uncertain sends are not blindly retried.

### 6.1 Standalone task
### 6.3 Standalone task

Use `WorkflowEngineClient.sendTask(agentName, finalContent)` for a task outside the DAG. The overload with
`NegotiationStrategy` supplies only that call's negotiation decisions. The host still owns content generation and
Expand All @@ -234,8 +234,13 @@ ExtensionSender.openNotification(agentName, finalContent, (handle, received) ->
Use host-generated Authorization-T or Notification-T content with the matching activated extension. The handle is
registered before I/O; early callbacks can call handle.close() without capturing an unassigned variable.
acknowledgement() reports actual ACK or failure; timeout is not a synthesized success. close() requests shutdown;
completion() completes after the stream actually exits. Retain it until the host-defined terminal event, explicit
cancellation, or host-agent shutdown, not just workflow completion.
completion() completes after the stream actually exits. Retain it across task/result terminal statuses and workflow
completion. Explicit cancellation, host-agent shutdown, stream exit/error, or the configured idle timeout ends it.

The bundled SPN sample has a separate business policy: `WorkbenchExtensionLifecycle.handleNotification` explicitly
closes its handle after a validated recovery result. This is sample-controlled cancellation, not SDK termination on
Task-T/Notification-T result status. For a continuously subscribed production host, replace that sample callback and
retain the handle across recovery results until an explicit unsubscribe or shutdown.

Task, authorization and notification use separate transports/runtimes/contexts. Neither extension success nor failure is
a prerequisite for workflow execution. Authorization controls only the host-defined action associated with that policy.
Expand Down Expand Up @@ -265,7 +270,7 @@ not the engine. Each role calls only the APIs needed for the message it owns.
For natural-language inputs choose generateTaskPromptFromText(text, templateUri), generateAuthPromptFromText(text,
templateUri), or generateNotificationPromptFromText(text, templateUri). Negotiation also offers phase-specific FromText
and typed FromData alternatives. Structured generation may still call the SDK's configured LLM. Wrap the returned
MetadataContent with A2atMessages.from(generated, List.of (new TextPart("business summary"))). Preserve full metadata,
MetadataContent with A2atMessages.from(generated, List.of(new TextPart("business summary"))). Preserve full metadata,
including templateUri and negotiationContext; provide nonempty parts. The parts summary is not the formal extension
validation input.

Expand All @@ -276,6 +281,7 @@ host disclosure denial produces SDK Reject. Authorization policy is a separate c

Authorization and Notification generation APIs create requests, not arbitrary business results. Authorization receipts
and notification events are dispatched-agent business outputs and must follow the selected template and application
contract. A subscription closes only on a host-defined terminal event, explicit cancellation, or shutdown; an ACK alone
is not a terminal business event. SDK rejection should preserve its safe code, slot errors, and extracted parameter keys.
contract. Task/result terminal statuses do not close a notification subscription; neither do ACKs. Explicit cancellation,
shutdown, stream exit/error, or the configured idle timeout ends it. SDK rejection should preserve its safe code,
slot errors, and extracted parameter keys.
Authorization and subscription failures still do not block workflow execution.
7 changes: 4 additions & 3 deletions docs/en/DESIGN.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# A2A-T Engine SDK - Design

> Architecture and design rationale for the A2A-T Workflow Execution Engine.
> This document describes the system as shipped in v1.0. It is written for
> This document describes the system as implemented by current source (see CHANGELOG for release boundaries). It is written for
> engineers integrating or extending the SDK, not as a walkthrough of any
> particular bug-fix history.

Expand Down Expand Up @@ -363,14 +363,15 @@ sequenceDiagram
ES->>A: Independent long-lived stream
A-->>H: ACK via acknowledgement()
A-->>H: listener(handle, ReceivedMessage)
H->>ES: handle.close() on terminal event/cancel/shutdown
Note over H,ES: Task/result terminal statuses do not close the notification stream
H->>ES: handle.close() on explicit cancellation/shutdown
ES-->>H: completion() after stream exits
```

## 9. Dependencies

workflow-engine uses A2A Java `1.2.0.Final` (REST/JSON-RPC/gRPC), a matching gRPC runtime,
`net.openan.a2a-t.sdk:a2a-t-core:1.1.0`, Jackson and SLF4J. Pure engine consumers do not transitively receive A2A-T
`net.openan.a2a-t.sdk:a2a-t-core:1.1.1`, Jackson and SLF4J. Pure engine consumers do not transitively receive A2A-T
client/server, LLM, prompt or resources. Host agents explicitly depend on a2a-t-client; dispatched-agent services that
validate received content additionally use a2a-t-server. Registry/orchestration discovery is host-owned;
RegistryClient/LoadPsop are optional helpers.
Expand Down
Loading
Loading