Skip to content

feat(a2a): adopt the standard A2A error envelope - #46

Merged
Zhoujie628 merged 4 commits into
project-openan:mainfrom
Zhoujie628:feat/a2a-error-envelope
Sep 4, 2026
Merged

Zhoujie628 merged 4 commits into
project-openan:mainfrom
Zhoujie628:feat/a2a-error-envelope

Conversation

@Zhoujie628

Copy link
Copy Markdown
Contributor

Closes #45

Summary

Aligns the engine with the A2A specification's error handling (pre-task failures as non-2xx + google.rpc.Status envelope; post-creation failures stay HTTP 200 + TASK_STATE_FAILED):

  • Engine client: standard-envelope detection on direct responses and SSE data, projected into stable workflow codes (a2a.<reason>, a2a.http.<status> fallback) with full errorDetails (httpStatus/code/status/reason/domain/details/Retry-After). Legacy {status,title,detail} compatibility removed. SSE streams that complete without any event now fail immediately instead of waiting out the send timeout; no fabricated HTTP statuses.
  • Spring starter: streaming endpoints return SseEmitter directly; pre-stream failures throw A2AError, mapped by @ExceptionHandler to a non-2xx application/a2a+json envelope. A wildcard ResponseEntity<?> return previously bypassed Spring's emitter handler and degraded every streaming response to HTTP 500. SDK pre-contracts (streaming capability, protocol version, required extensions, task access) enforced in SDK order; stream cleanup releases the Flow subscription and notifies the SDK event consumer.
  • Sample JDK server: the event bus processor thread is started and stopped explicitly (ensureStarted() is an intentional CDI no-op — manual wiring previously left the bus dead and tasks hung); SSL context created before binding; unified SSE write/cleanup paths.
  • Docs (en/zh): error contract, endpoint media types, zero-event fast-fail and stream cleanup semantics.

Test plan

  • Full main reactor mvn test: 292/292 (engine 192, starter 10, samples 90)
  • Failure E2E: 400 -> a2a.invalid_params, 429 -> a2a.active_task_limit_exceeded; northbound receives TASK_STATE_FAILED with errorDetails; no negotiation, no re-submission, merge step skipped
  • Success-path E2E, Negotiation-T and Notification-T lifecycle green
  • Negative protocol tests through MockMvc dispatch (unsupported version, missing task, streaming capability)
  • javadoc 0 warnings; git diff --check clean

🤖 Generated with Claude Code

Detect the google.rpc.Status error envelope on direct responses and SSE
data, projecting httpStatus, code, status, reason, domain, typed details
and Retry-After into stable workflow error codes (a2a.<reason>, with an
a2a.http.<status> fallback when no reason is observed).

Remove the legacy {status,title,detail} problem compatibility
(RemoteProblemException, ProblemDetectingHttpClient) per the agreement
that OMC returns the standard envelope for pre-task-creation failures.

Fail immediately when an SSE stream completes without delivering any
event instead of waiting out the send timeout; the observed HTTP status
is not fabricated when the transport cannot expose it. Stop logging
subscriber-initiated cancellations as transport failures and redact
failure messages in protocol logs.

Signed-off-by: Zhoujie628 <zhoujie628@users.noreply.github.com>
A wildcard ResponseEntity<?> return bypassed Spring's emitter handler,
so every message:stream and task subscription response degraded to an
HTTP 500 with an empty body; the client-side SDK then treated the
zero-event completion as success and callers waited out the send
timeout. Declare SseEmitter as the return type and throw A2AError for
pre-stream failures, mapped by an @ExceptionHandler to a non-2xx
application/a2a+json standard envelope.

Enforce the SDK pre-contracts in order (streaming capability, protocol
version, required extensions, task access) before dispatch. Release the
Flow subscription and notify the SDK event consumer on completion,
error, timeout and write failure. Declare text/event-stream produces on
the streaming mappings and return application/a2a+json on protocol
responses. The negative tests now go through MockMvc dispatch, which is
what would have caught the 500 regression.

Signed-off-by: Zhoujie628 <zhoujie628@users.noreply.github.com>
MainEventBusProcessor.ensureStarted() is an intentional CDI no-op, so
manual wiring must start the processor thread explicitly; the previous
replacement of the reflective start left the bus dead and every inbound
task hung. Start the thread in start(), interrupt and join it in
close(), create the SSL context before binding the listen address, and
unify the two SSE endpoints' write and cleanup paths including the SDK
event-consumer cancel callback.

Extend the failure E2E to assert that standard 400/429 envelopes reach
the northbound failure with stable error codes and no negotiation or
merge dispatch.

Signed-off-by: Zhoujie628 <zhoujie628@users.noreply.github.com>
Split pre-task-creation failures (non-2xx HTTP plus the google.rpc.Status
envelope) from post-creation task failures (HTTP 200 with
TASK_STATE_FAILED carrying business evidence). Document the zero-event
fast-fail, the rule against fabricating HTTP statuses the transport
cannot observe, the six server endpoints with their media types, and the
stream cleanup semantics.

Signed-off-by: Zhoujie628 <zhoujie628@users.noreply.github.com>
@Zhoujie628
Zhoujie628 requested a review from a team as a code owner September 4, 2026 12:43
@Zhoujie628
Zhoujie628 merged commit 10320d8 into project-openan:main Sep 4, 2026
3 checks passed
Zhoujie628 added a commit to Zhoujie628/workflow-engine-sdk-java that referenced this pull request Sep 4, 2026
Bring dev up to the merged main baseline (error-envelope PR project-openan#46 and the
module-view docs PR project-openan#44) while preserving the Eastcom Order overlay.
Resolution policy: workflow-engine and spring-boot-starter take main
verbatim; samples and root files keep main's newer common content plus
dev's Eastcom additions (gateway runtime factory, order transport mode,
mock gateway, Eastcom CI gate and docs); parallel-evolved tests take
main's canonical versions.

Signed-off-by: Zhoujie628 <zhoujie628@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adopt the standard A2A error envelope for pre-task failures

1 participant